# E-032 — Los espejos generados derivaron en dos días porque ningún check exigía la regla

- Fecha: 2026-08-04
- Estado: señal orgánica; corrección aplicada en la misma ronda.

## Jerarquía y trayectoria

- Objetivo principal: `O-ADOPT`, hacer que Objective Guard sea adoptable por recién llegados y agentes de programación mediante documentación con el inglés como idioma principal.
- Ronda anterior: `R-EVIDENCE-CONTEXT`, cerrada y archivada desde árbol limpio.
- Ronda actual: `R-DOCS-EN-FIRST`, promover la documentación en inglés a canónica con contraparte en español.

El 2026-08-02 un changeset generó espejos en inglés de todos los documentos bajo `docs/en/` y agregó una regla a `AGENTS.md`: *"Any edit to a canonical Spanish doc must regenerate its English mirror in the same changeset. A stale mirror is a bug."*

Dos días después, al promover el inglés a canónico, se midió el estado de esos espejos:

- 8 de los 12 documentos de producto y funcionalidad espejados estaban desactualizados respecto de su fuente en español;
- 26 documentos nunca habían sido espejados (`product/07-phase-1-calibration-protocol` y los 25 archivos bajo `docs/episodes/`);
- las fuentes espejadas habían crecido sustancialmente: `02-product-contract` pasó de 837 a 2345 palabras y `04-functional-test-matrix` de 860 a 2037;
- los espejos vivían en una rama de worktree separada que nunca se integró a `main`.

## Comportamiento esperado y real

La regla existía sólo como prosa en `AGENTS.md`. Ningún check la exigía, y el contrato del guard documental sólo conocía la topología en español. Por eso `npm run validate:docs` devolvió PASS en cada ronda intermedia mientras el invariante documentado ya estaba violado.

El guard se comportó exactamente como estaba configurado. Nunca se le pidió verificar la frescura de los espejos, así que su `pass` no decía nada al respecto.

## Evidencia

- `git log`: espejos generados en `81c5025` (2026-08-02 20:39), a partir de `a514bf2` (20:25);
- `git diff --stat a514bf2..main -- docs`: 35 archivos cambiados, 1247 inserciones después de escribir los espejos;
- conteo de palabras de las fuentes en español entre `a514bf2` y `main`: 837 → 2345, 638 → 877, 1642 → 2247, 860 → 2037;
- `docs/en/` no contenía directorio `episodes/` ni espejo de `product/07`;
- todas las rondas intermedias cerraron con `npm run validate:docs` en pass.

## Clasificación y límites

Es una **señal perdida por un check no declarado**, no un falso negativo de un detector existente. Ningún detector fue evadido ni ningún resultado fue mal etiquetado; el invariante simplemente no tenía representación reproducible.

Es consistente con E-004 (una señal ausente no prueba alineación) y E-016 (un criterio que no se declara no se verifica). No es evidencia de que el guard sea insensible a lo que sí verifica.

## Corrección de dirección

1. El inglés pasó a ser canónico en las rutas canónicas; la versión en español quedó al lado como `<slug>.es.md`.
2. `scripts/validate-docs.mjs` fue reescrito para exigir el emparejamiento de forma mecánica: una contraparte en español faltante, un documento en español huérfano, un archivo suelto en la raíz de `docs/` o un enlace que cruza idiomas ahora bloquean.
3. Los contratos estructurales se verifican en ambos idiomas —headings de producto, campos de capacidad, columnas de la matriz y marcadores de confianza—, de modo que una contraparte no puede perder estructura en silencio.
4. Se reescribió la política de idioma de `AGENTS.md` con la nueva dirección canónica, y la capa de guías incorporó una plantilla más un índice obligatorio para que una guía de harness nueva no pueda tener otra forma.

De correr los checks nuevos salieron dos hallazgos secundarios:

- La regla de cruce de idiomas produjo **4 falsos positivos** en su primera corrida: marcó el enlace deliberado de cambio de idioma que cada guía tiene hacia su propia contraparte. La regla se acotó para permitir el enlace a la contraparte del propio documento y nada más. Una regla escrita en la misma sesión que la motivó igual necesitó una corrida adversarial antes de ser correcta.
- Se detectó que el índice de episodios no listaba E-004 ni E-005: un hueco preexistente, ajeno al trabajo de idioma, que tampoco tenía check. El guard ahora exige que cada archivo de episodio esté listado en el índice de su propio idioma, y se agregaron las filas faltantes.

## Impacto sobre la tesis

Refuerza una afirmación acotada y útil: una regla escrita en un archivo de instrucciones para agentes es documentación, no un control. Un invariante se vuelve real sólo cuando un check reproducible corre dentro de la ronda y puede hacerla fallar.

No demuestra que el guard evite la deriva. Acá la deriva se encontró a mano durante la reestructuración, no por el guard. La corrección mueve el invariante de la prosa a un check para que la próxima ocurrencia sea observable; esa expectativa queda sin probar hasta que efectivamente dispare.

## Seguimiento verificable

- El emparejamiento está exigido; la **frescura no**. Dos archivos emparejados pueden seguir divergiendo en contenido, que es exactamente el fallo que registra este episodio. Decidir entre un marcador de hash de la fuente por par y un ledger de estado de traducción, y declarar el límite explícitamente hasta que exista alguno.
- Agregar un par de fixture deliberadamente desactualizado y confirmar que el mecanismo elegido falla con él, antes de afirmar que el invariante está cubierto.
- Decidir el destino de la rama de worktree `docs/en/` ya superada, para que no se pueda revivir por accidente una segunda copia de la documentación sin guard.
