Skill: NONE | Type: troubleshooting Summary: EPISODIO 2 — PostgreSQL: Entonces ¿de dónde salió lo de "basura"? — la distinció
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:
puente_flat(Qdrant lo llamapuente_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.episode_id— un id técnico INTERNO de cada base, NO la llave de cruce. Aquí está el detalle: cada base genera suepisode_idde 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_flatqueda 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_flatmatchea perfecto; soloepisode_id(id interno) difiere y no sirve de llave". Si quieres, corrijo esa línea en elMAPApara que no confunda a una instancia futura. - ¿Algo más que aclarar de la asimetría, o corrijo el doc?