feat(episode): TRAZA_por-qu-postgresql-no-necesita-marca-es-e_S20260618.R8_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD

Skill: NONE | Type: troubleshooting
Summary: EPISODIO 8 — MNEMO Pipeline: Por qué PostgreSQL no necesita "marca" (es el ancla
This commit is contained in:
Ember 2026-06-18 23:25:55 +00:00
parent 4259c7d0f4
commit 44d4a7d8fd

View file

@ -0,0 +1,43 @@
---
episode_id: "82c1c7ea-1e5c-48ce-8008-ca9c817571c4"
puente_flat: "TRAZA_por-qu-postgresql-no-necesita-marca-es-e_S20260618.R8_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD"
session_code: "S20260618.VERIFY_FIRST_PASSPORT_FIX"
acto_dialogico: "informar"
actor_flujo: "multi_actor"
criticidad_aegis: "low"
skill_dominante: "NONE"
fase_proyecto: "operations"
tipo_semantico: "troubleshooting"
summary_one_line: "EPISODIO 8 — MNEMO Pipeline: Por qué PostgreSQL no necesita "marca" (es el ancla)"
source_type: "claude_code"
trust_boundary: "internal"
created_at: "2026-06-18T23:25:45.680276+00:00"
relectura_tagged: false
forgejo_commit_sha: "pending"
---
Buena observación, John — y la respuesta te va a gustar porque **confirma tu modelo, no lo contradice.** No saqué PostgreSQL. crisol **sí escribe los 3 stores en el mismo flujo síncrono** (Qdrant en F3, PostgreSQL+Neo4j en F5, `INSERT INTO episode` línea 722). Solo nombré Qdrant y Neo4j en el *fix* por una razón concreta: **PostgreSQL ya está resuelto — es el ancla del sistema.**
## Por qué PostgreSQL no necesita "marca" (es el ancla)
Dos hechos verificados en el código/schema lo explican:
1. **`postgresql_state` tiene `default 'success'`** en `episode_sync_status` (lo verifiqué en el schema: `postgresql_state | text | 'success'::text`). Los otros 4 (qdrant/neo4j/nextcloud/forgejo) nacen en `'pending'`.
2. **El libro mayor NACE de la escritura a PostgreSQL.** El trigger `trg_episode_after_write_outbox` dispara *después* del `INSERT INTO episode` → crea las filas de outbox/sync. O sea: **si la fila del libro mayor existe, es porque PostgreSQL ya grabó el episodio.** Su éxito es precondición, no algo que haya que verificar.
3. Más aún — la función de cierre `_maybe_complete_outbox` **ni siquiera chequea `postgresql_state`**: `SELECT qdrant_state, neo4j_state, nextcloud_state, forgejo_state` (solo los 4). PostgreSQL es la fuente de verdad; su éxito es implícito.
## El cuadro completo de los 5 stores (para que quede cristalino)
| Store | Quién escribe | Estado hoy | Tras el fix |
|---|---|---|---|
| **PostgreSQL** | crisol F5 (síncrono) | `success` (ancla, default) | igual — ya correcto ✅ |
| **Qdrant** | crisol F3 (síncrono) | `pending` (nadie marca) ❌ | **crisol lo marca** `success` |
| **Neo4j** | crisol F5 (síncrono) | lo marca el worker (doble-write) | **crisol lo marca** (poda worker) |
| **Nextcloud** | nextcloud_worker (async) | `success` | igual ✅ |
| **Forgejo** | forgejo_worker (async) | `success` | igual ✅ |
Entonces el fix solo toca Qdrant y Neo4j porque **eran los 2 que crisol escribe pero que quedaban sin marcar** (Qdrant en `pending` eterno; Neo4j marcado por un worker que duplica). PostgreSQL ya está perfecto como ancla. **Tu modelo es exacto:** los 3 del núcleo síncronos (PostgreSQL incluido), Forgejo+Nextcloud asíncronos.
¿Te cuadra ahora? Con eso confirmado, sigo esperando tu **GO** (🟢 A ejecuto / 🟡 B te muestro diff+SQL / ⚪ C fix + reconciliación + SLO 2h) + las 2 preguntas (¿SLO 2h? ¿Forgejo/Nextcloud respaldo o primera-clase?).