feat(episode): TRAZA_mi-opinin-tienes-razn-con-un-acople-que_S20260618.R6_XX.ops.2.hot_inf.in.cc.es.000.MGQ_J.PMCFK_E.SGNFD

Skill: NONE | Type: troubleshooting
Summary: EPISODIO 6 — MNEMO_PRE_DIGEST: Mi opinión: tienes razón, con UN acople que hay q
This commit is contained in:
Ember 2026-06-18 22:41:19 +00:00
parent 3d9195ea64
commit 5f12c76cab

View file

@ -0,0 +1,37 @@
---
episode_id: "135ef961-0886-45f5-8ff9-360e6064ecb7"
puente_flat: "TRAZA_mi-opinin-tienes-razn-con-un-acople-que_S20260618.R6_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 6 — MNEMO_PRE_DIGEST: Mi opinión: tienes razón, con UN acople que hay que respetar"
source_type: "claude_code"
trust_boundary: "internal"
created_at: "2026-06-18T22:41:11.765442+00:00"
relectura_tagged: false
forgejo_commit_sha: "pending"
---
Confirmado al nivel del dato, John — y es preciso como bisturí. La distribución de estado de las 165 filas:
**Un solo campo bloquea todo: `qdrant_state='pending'`.** Todo lo demás está en `success`. Es decir:
- `neo4j_state=success`**el worker Neo4j SÍ corrió** (encima de crisol) = el doble-write que detectaste. ✅ tu diagnóstico.
- `qdrant_state` se queda en su default `'pending'` porque **nadie lo marca** (crisol escribe Qdrant pero no toca la tabla de estado; el worker qdrant está excluido).
- `_maybe_complete_outbox` exige los 4 en `success` → falla solo por Qdrant → las 165 quedan `partial` eternas.
## Mi opinión: tienes razón, con UN acople que hay que respetar
Tu diseño es el correcto — **un solo escritor por store**. Pero ojo con esto: si podo el worker Neo4j *y nada más*, entonces `neo4j_state` también se quedaría en `pending` (sin worker que lo marque) → ahora **dos** slots bloqueados en vez de uno → **empeora**. El fix tiene dos mitades que van juntas:
**El fix limpio (un cambio de responsabilidad, no de mecanismo):**
1. **crisol.py marca lo que ya escribe:** tras F3 (Qdrant) y F5 (Neo4j), hace `UPDATE episode_sync_status SET qdrant_state='success', neo4j_state='success'`. Es la **verdad** — crisol ES el escritor de esos dos; solo faltaba que lo *declarara*.
2. **Podar el dispatcher a `--only nextcloud forgejo`** (quitar los workers qdrant + neo4j). Mata el doble-write/gemelos en origen.
3. **Backfill único** de las 165 atascadas: `qdrant_state='success'` (los episodios YA están en Qdrant vía crisol) → cierran solas.
Resultado: `episode_sync_status` se vuelve una **tabla de verdad honesta de los 5 stores** (PostgreSQL+Qdrant+Neo4j por crisol; Nextcloud+Forgejo por workers) → el `done` funciona, sin duplicados, y queda la base perfecta para el watchdog SLO 2h. **Exactamente tu visión: solo Forgejo y Nextcloud quedan en la ruta dual.**
## Esto es un cambio RELOJERO (toca pipeline load-bearing) — contrato antes de código