Incidente s80 — wikiProposeMirrorUpdate generaba PRs destructivos en docs largos
Resumen ejecutivo
El handler MCP wikiProposeMirrorUpdate usaba MAX_BODY=8000 para recortar el mirror_body antes de pasarlo a Haiku 4.5. Para documentos de 20-60KB (onboardings, team-processes), Haiku solo veía los primeros ~8KB, los reescribía, y devolvía ese fragmento como proposed_body completo. El resultado: PRs con diffs del tipo +20/-600 que borraban la mayor parte del mirror al aplicarse.
Detectado en producción mediante E2E real con onboardings. Dos PRs destructivos fueron abiertos y cerrados sin merge antes de identificar la causa raíz.
Cronología
| Fecha | Evento |
|---|---|
| 2026-05-22 | PR #66 abierto: +16/-602 LOC — cerrado sin merge |
| 2026-05-22 | PR #67 abierto: +23/-226 LOC — cerrado sin merge |
| 2026-05-22 | @Esquembri identifica la causa raíz: MAX_BODY=8000 en wikiProposeMirrorUpdate |
| 2026-05-22T13:33:01Z | Fix mergeado en main (commit@67f7b4a) |
Causa raíz
En functions/api/mcp/handlers/wiki.ts, función wikiProposeMirrorUpdate:
// ANTES del fix (incorrecto)
const MAX_BODY = 8000;
const truncatedBody = mirrorBody.slice(0, MAX_BODY); // 8KB de ~50KB
// → Haiku solo veía primeros 8KB y devolvía ese fragmento como proposed_body entero
Haiku 4.5 acepta hasta 200K tokens de contexto, pero el límite arbitrario de 8000 chars (~2KB útiles) era radicalmente bajo para documentos de onboarding y team-processes que típicamente pesan 20-60KB.
El modelo actuaba de buena fe: recibía un fragmento y lo mejoraba. No sabía que debía conservar el resto.
Impacto
- Severidad: Alta — pérdida de contenido irreversible si el PR hubiera sido mergeado.
- Ámbito: Todo documento cuyo
mirror_bodysupere ~8000 chars (estimado: ≥30% de los mirrors activos en wikis de onboarding/team-processes). - Docs afectados en esta sesión: los mirrors objetivo de PR #66 y PR #67 (no identificados por nombre en el commit; ver task workspace #65).
- Datos perdidos: ninguno — los PRs fueron interceptados antes del merge.
Fix aplicado (commit@67f7b4a)
Cuatro cambios en wikiProposeMirrorUpdate:
1. MAX_BODY 8000 → 32000
const MAX_BODY = 32000; // era 8000
Proporcional al contexto real de documentos largos. Haiku 4.5 puede manejar este input con holgura.
2. max_tokens output 4000 → 8000
// Llamada a Haiku: max_tokens subido de 4000 a 8000
Evita truncado en la respuesta cuando el proposed_body es largo.
3. Nuevo ABORT_BODY=50000
const ABORT_BODY = 50000;
if (mirrorBody.length > ABORT_BODY) {
return JSON.stringify({
should_propose: false,
reasoning: `mirror_body excede ${ABORT_BODY} chars (${mirrorBody.length}). Revisa a mano...`,
});
}
Para docs extremadamente largos: mejor skip con mensaje explícito que riesgo de PR destructivo.
4. Safety check post-Haiku (ratio de reducción sospechosa)
const SUSPICIOUS_REDUCTION_RATIO = 0.5;
if (shouldPropose && proposedBodyRaw.length < mirrorBody.length * SUSPICIOUS_REDUCTION_RATIO) {
shouldPropose = false;
reasoning = `[safety] Propose descartado: proposed_body (${proposedBodyRaw.length} chars) < 50% del mirror_body...`;
}
Si Haiku devuelve un proposed_body menor al 50% del mirror_body original, se descarta automáticamente como sospechoso de truncado o reescritura destructiva. El reasoning incluye el contexto original de Haiku para debug.
Lecciones aprendidas
- Límites de input a LLMs deben reflejar la distribución real de datos, no estimaciones conservadoras arbitrarias. Un límite de 8KB para documentos de onboarding es estructuralmente incorrecto.
- Safety checks post-LLM son necesarios cuando el output puede causar pérdida de datos. No basta con confiar en que el modelo “hará lo correcto” con input incompleto.
- Los diffs de PRs deben auditarse antes del merge en pipelines que usan LLMs para proponer cambios. Un PR con ratio
-600/+16debe disparar alarma automática. - Abort explícito > fallback silencioso: para docs >50KB, retornar
should_propose: falsecon mensaje claro es preferible a cualquier intento de propuesta parcial.
Estado
- Resuelto — fix en producción desde
2026-05-22T13:33:01Z. - PRs destructivos #66 y #67 cerrados y sin impacto en datos.
- Seguimiento en task workspace #65.
Véase también
- [[entity—workers—function—wiki-propose-mirror-update]]