ember-memory-test/episodes/EXPLORA_entonces-de-dnde-sali-lo-de-basura-la-d_S20260621.R2_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD.md
Ember 4057702e2b feat(episode): EXPLORA_entonces-de-dnde-sali-lo-de-basura-la-d_S20260621.R2_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD
Skill: NONE | Type: troubleshooting
Summary: EPISODIO 2 — PostgreSQL: Entonces ¿de dónde salió lo de "basura"? — la distinció
2026-06-21 18:53:52 +00:00

3.6 KiB


episode_id: "48c81239-bdbe-4735-852e-e5ccb7c84058" puente_flat: "EXPLORA_entonces-de-dnde-sali-lo-de-basura-la-d_S20260621.R2_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD" session_code: "S20260621.CRONICA_SEMANAL_C15" acto_dialogico: "informar" actor_flujo: "multi_actor" criticidad_aegis: "low" skill_dominante: "NONE" fase_proyecto: "operations" tipo_semantico: "troubleshooting" summary_one_line: "EPISODIO 2 — PostgreSQL: Entonces ¿de dónde salió lo de "basura"? — la distinción cla" source_type: "claude_code" trust_boundary: "internal" created_at: "2026-06-21T18:53:44.877123+00:00" relectura_tagged: false forgejo_commit_sha: "pending"

Tienes toda la razón, John — y mi redacción en el doc fue confusa. Lo confirmo en vivo con el mismo episodio en los 3 stores:

Store episode_id puente_flat / puente_id
PostgreSQL e29a5a0b-…-450755c5 (uuid4) DEPURA_la-historia-…-R4_…SGNFD
Qdrant 500ea674-…-291347a (uuid5) DEPURA_la-historia-…-R4_…SGNFD
Neo4j 500ea674-…-291347a (uuid5) DEPURA_la-historia-…-R4_…SGNFD

El puente_flat/puente_id es BYTE-A-BYTE IDÉNTICO en los 3 → matchea perfecto, exactamente como tú dices. No da basura.

Entonces ¿de dónde salió lo de "basura"? — la distinción clave

Cada episodio tiene DOS identificadores distintos, y yo los mezclé al explicarte:

  1. puente_flat (Qdrant lo llama puente_id) — la llave de cruce semántica. Diseñada a propósito para ser idéntica en los 3 (ADR_S20260514). Es la que matchea, la que tú tienes en mente. Funciona perfecto.
  2. episode_id — un id técnico INTERNO de cada base, NO la llave de cruce. Aquí está el detalle: cada base genera su episode_id de forma distinta:
    • PostgreSQL le pone un uuid4 aleatorio (es la llave primaria estándar de su tabla — un número al azar).
    • Qdrant y Neo4j usan un uuid5 derivado del hash del contenido (content_sha256) — para que el mismo contenido SIEMPRE caiga en el mismo punto (idempotencia / anti-duplicados).
    • Como uno es "al azar" y el otro es "calculado del contenido", nunca coinciden entre sí.

La "basura" fue MI error, no del sistema

En mi primer reconciliador uní los stores por episode_id (la llave equivocada) → como el uuid4 de PostgreSQL nunca iguala el uuid5 de Qdrant, salió "todo disjunto, 92 huérfanos" → basura. Cuando lo corregí a puente_flat (la llave correcta, la que tú dices), matcheó perfecto: 0 huérfanos en Qdrant.

En una frase: el sistema SÍ tiene un identificador idéntico que une los 3 (puente_flat) — tu intuición es correcta. "Da basura" solo si uno se equivoca y cruza por episode_id, que es un id interno distinto en cada base y nunca fue la llave de cruce. La lección (que ya aprendí): cruzar siempre por puente_flat, nunca por episode_id.

(El único "no-match" legítimo que vimos no es de id sino de ausencia: ~15-18 episodios que están en una base y faltan en otra — ese es el drift real y pequeño, no un problema de identificadores.)

📍 PARA JOHN — R1

  • Tu intuición: correcta — puente_flat queda idéntico en los 3 y matchea (probado arriba con el mismo episodio).
  • Mi corrección: la frase del doc "unir por episode_id da basura" es técnicamente cierta pero engañosa; debí decir "cruzar por puente_flat matchea perfecto; solo episode_id (id interno) difiere y no sirve de llave". Si quieres, corrijo esa línea en el MAPA para que no confunda a una instancia futura.
  • ¿Algo más que aclarar de la asimetría, o corrijo el doc?