Deriva del indice de busqueda y CDC roto
La busqueda responde 200 y lo que devuelve esta mal: el indice se desincroniza de a un documento por vez y nada dispara una alerta.
📈 Que cambia para el negocio
Elimina la categoria entera de 'el producto existe pero no aparece', que en un catalogo son productos que no se pueden comprar.
💼 Que demuestra tecnicamente
Muestra un modo de falla que no rompe nada: 98,95% de recall no se ve como un incidente, se ve como una busqueda que anda. Y ordena a los siete stacks por que hace cada lenguaje cuando el programador no mira el resultado de una escritura.
✅ Evidencia que deja
- Contrasta /search-drifted y /search-reconciled con recall y precision medidos con consultas reales.
- Separa las tres caras de la deriva: missing no se encuentra, stale se encuentra mal, orphan es fantasma.
- Expone drift_age_ms, la metrica que dice si algo va a reparar la deriva solo.
👀 Que mirar al ejecutarlo
- Si drift_count es mayor que cero en el dual-write y exactamente cero con outbox mas barrido.
- Si recall y precision bajan lo suficiente para doler y poco para que nadie mire (98,95% y 98,02%).
- Si el checkpoint se frena en el cambio que no entra en vez de saltearlo.
Como esta resuelto en cada stack
Dual-write sin transaccion comun contra outbox + checkpoint durable + barrido de reconciliacion, con las tres caras de la deriva separadas (missing, stale, orphan). El caso ordena por una dimension que ningun otro usa: que hace el lenguaje cuando el programador no mira. Rust con #[must_use] y deny(unused_must_use) — el bug original NO compila —, Go con el _ = auditable y errcheck, .NET con Except/Join tipados y la pereza de LINQ como trampa, Python con el algebra de conjuntos mas corta del lab y el except desnudo mas corto tambien, PHP con checkpoint durable por obligacion del modelo share-nothing, Java con ConcurrentSkipListMap.tailMap y @Transactional que sugiere una atomicidad que no alcanza al indice, y Node donde el bug se produce por NO escribir await
| Stack | Health check local | Compose | Detalle |
|---|---|---|---|
| 🐘 PHP 8.3 | http://localhost:8100/19/health | compose.root.yml | README del stack |
| 🐍 Python 3.12 | http://localhost:8200/19/health | compose.python.yml | README del stack |
| 🟢 Node.js 22 | http://localhost:8300/19/health | compose.nodejs.yml | README del stack |
| ☕ Java 21 | http://localhost:8400/19/health | compose.java.yml | README del stack |
| 🔵 .NET 8 | http://localhost:8500/19/health | compose.dotnet.yml | README del stack |
| 🐹 Go 1.23 | http://localhost:8600/19/health | compose.go.yml | README del stack |
| 🦀 Rust 1.83 | http://localhost:8700/19/health | compose.rust.yml | README del stack |
El expediente completo
El caso no empieza en el codigo: empieza en el sintoma y termina en el postmortem.