Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions reference/core/control-center/gaps/gap-reference-catalog.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -7855,6 +7855,19 @@ Serie histórica de gaps registrada en el antiguo `gap-analysis-core.es.md`, pre
- [x] El tipo `security` está declarado en la config de commitlint con un mapeo explícito de salto de versión, o se deja de usar.
- [x] Ningún hook de `.husky/` imprime un mensaje de "skipping" y sale con cero — un hook que no puede correr se borra, no se silencia.

#### GT-638

**Title:** El tablero no tiene asignador de ids, así que dos ramas paralelas reparten el mismo número GT

- **Purpose:** Que un id de gap sea único por construcción y no por que quien registró el último leyera la rama correcta.
- **Evidence:** **Un id de gap se elige leyendo el `GT-*` más alto de la rama en la que uno está, y nada lo contrasta con ninguna otra rama.** Así que dos sesiones en paralelo asignan el mismo número, y una se entera en el merge. Ya ha pasado: `8449af3d` en `develop` lleva el mensaje *"chore(board): renumber the ratchet fix GT-634 -> GT-637, ID collision with develop"* — esa fila y [`GT-634`](./gap-reference-catalog.es.md#gt-634) en `main` recibieron el mismo id con horas de diferencia, por sesiones que no podían verse. **La renumeración es manual y con pérdidas**, que es lo que cuesta más que el choque: un id aparece en la fila del tablero, en el ancla del catálogo, en el registro de evidencia de cierre, en referencias cruzadas desde otras filas en los dos idiomas, en mensajes de commit y en cuerpos de PR — y sólo los tres primeros son comprobables mecánicamente. `08-validate-tracking` no puede ayudar, y no por falta de ganas: valida paridad EN/ES, registros de cierre y contadores **dentro de un único árbol de trabajo**, y las ramas quedan fuera de su mundo por construcción. **Por qué merece fila y no una convención:** el tablero es la única fuente de verdad de 635 gaps, y un id que significa dos cosas distintas en dos ramas vuelve ambigua toda referencia a él — incluidas las de `gap-closure-evidence.json`, que son datos validados por máquina. Tampoco es un desliz aislado: en el merge `develop` → `main` del 2026-07-30 el mismo patrón de duplicación convergente aparece **tres veces**: GT-633 se arregló dos veces por dos sesiones, el parser del guard de evidencias se arregló dos veces, y este id se asignó dos veces. Arreglo: asignar ids desde algo que no se pueda leer rancio — una marca de agua reservada y commiteada en la rama por defecto, o una comprobación en PR que falle cuando una rama introduce un id que ya existe en su base o en otro PR abierto, nombrando a ambos usuarios.
- **Component:** `Governance` · **Criticality:** P2 · **Complexity:** S
- **Provenance:** Registrado el 2026-07-30 tras la colisión que describe, que obligó a renumerar en `develop`. El id de ESTA fila se asignó tomando la unión de ids entre `main` y `develop` en vez del máximo de una — que es justo el apaño que el arreglo debería volver innecesario.
- **Acceptance criteria:**
- [ ] Registrar una fila en una rama no puede reutilizar en silencio un id que ya existe en la rama base.
- [ ] La comprobación corre en los pull requests y nombra el id en conflicto junto con los dos sitios donde se usa, para que resolverlo no sea una búsqueda.
- [ ] Incluye una fixture negativa OBSERVADA en rojo, no sólo declarada capaz de fallar.

#### GT-635

**Title:** El ratchet de referencias muertas está por encima del presupuesto en main desde el 2026-07-28, así que el job de gobernanza está en rojo permanente
Expand Down
13 changes: 13 additions & 0 deletions reference/core/control-center/gaps/gap-reference-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7950,6 +7950,19 @@ Historical gap series tracked in the former `gap-analysis-core.md`, preserved fo
- [x] The `security` type is either declared in the commitlint config with an explicit version-bump mapping, or removed from use.
- [x] No hook in `.husky/` prints a "skipping" message and exits zero — a hook that cannot run is deleted, not silenced.

#### GT-638

**Title:** The board has no id allocator, so two parallel branches hand out the same GT number

- **Purpose:** Make a gap id unique by construction rather than by whoever registered it last reading the right branch.
- **Evidence:** **A gap id is chosen by reading the highest `GT-*` on the branch you happen to be on, and nothing checks that against any other branch.** So two sessions working in parallel allocate the same number, and one of them finds out at merge time. It has already happened: `8449af3d` on `develop` carries the message *"chore(board): renumber the ratchet fix GT-634 -> GT-637, ID collision with develop"* — that row and [`GT-634`](./gap-reference-catalog.md#gt-634) on `main` were allocated the same id within hours of each other, by sessions that could not see each other. **The renumber is manual and lossy**, which is the part that costs more than the clash: an id appears in the board row, the catalog anchor, the closure-evidence record, cross-references from other rows in both languages, commit messages and PR bodies — and only the first three are mechanically checkable. `08-validate-tracking` cannot help, and not for want of trying: it validates EN/ES parity, closure records and counters **within one working tree**, and branches are outside its world by construction. **Why it is worth a row rather than a convention:** the board is the single source of truth for 635 gaps, and an id that means two different things in two branches makes every reference to it ambiguous — including the ones in `gap-closure-evidence.json`, which is machine-validated data. This is also not an isolated slip. In the `develop` → `main` merge of 2026-07-30 the same convergent-duplication pattern appears **three times**: GT-633 was fixed twice by two sessions, the evidence guard's parser was fixed twice, and this id was allocated twice. Fix: allocate ids from something that cannot be read stale — a reserved high-water mark committed on the default branch, or a PR-time check that fails when a branch introduces an id already present on its base or in another open PR, naming both users of it.
- **Component:** `Governance` · **Criticality:** P2 · **Complexity:** S
- **Provenance:** Registered 2026-07-30 after the collision it describes forced a renumber on `develop`. The id for THIS row was allocated by taking the union of ids across `main` and `develop` rather than the maximum on one — which is the workaround the fix should make unnecessary.
- **Acceptance criteria:**
- [ ] Registering a row on a branch cannot silently reuse an id that already exists on the base branch.
- [ ] The check runs on pull requests and names the colliding id together with both places it is used, so the resolution is not a search.
- [ ] It ships with a negative fixture that has been OBSERVED red, not merely declared able to fail.

#### GT-635

**Title:** The dead-reference ratchet has been over budget on main since 2026-07-28, so the governance job is permanently red
Expand Down
3 changes: 2 additions & 1 deletion reference/core/control-center/gaps/gap-tracking.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida

| ID | Gap | Qué significa | Ejemplo | Componente | Fase | Criticidad | Complejidad | Estado |
|---|---|---|---|:---:|:---:|:---:|:---:|:---:|
| [`GT-638`](./gap-reference-catalog.es.md#gt-638) | **El tablero no tiene asignador de ids, así que dos ramas paralelas reparten el mismo número GT.** Un id se elige leyendo el `GT-*` más alto de la rama en la que uno está, y nada lo contrasta con otra rama — así que dos sesiones en paralelo asignan el mismo número y una se entera en el merge. Ya pasó: `8449af3d` en `develop` dice *"renumber the ratchet fix GT-634 -> GT-637, ID collision with develop"*; esa fila y [`GT-634`](./gap-reference-catalog.es.md#gt-634) en `main` tomaron el mismo id con horas de diferencia, desde sesiones que no podían verse. **La renumeración es manual y con pérdidas**, que cuesta más que el choque: un id vive en la fila del tablero, el ancla del catálogo, el registro de evidencia de cierre, referencias cruzadas en dos idiomas, mensajes de commit y cuerpos de PR — y sólo los tres primeros son comprobables mecánicamente. `08-validate-tracking` no puede ayudar por construcción: valida dentro de un único árbol de trabajo, y las ramas quedan fuera de su mundo. Tampoco es un desliz aislado — en el merge `develop` → `main` del 2026-07-30 el mismo patrón de duplicación convergente aparece tres veces: GT-633 arreglado dos veces, el parser del guard de evidencias arreglado dos veces, este id asignado dos veces. | | | `Governance` | Cross | P2 | S | `PENDIENTE` |
| [`GT-635`](./gap-reference-catalog.es.md#gt-635) | **El ratchet de referencias muertas está por encima del presupuesto en main desde el 2026-07-28, así que el job de gobernanza está en rojo permanente.** `41-validate-evidence-commands --strict --max-dead 305` reporta **309 referencias muertas en un checkout limpio**, así que `Governance guards (GT-578)` sale 1 en cada corrida de `ci-cd.yml` — observado en las corridas `30482497995`, `30470648146` y `30466280865`, todas en `main` y sin nada por mergear. El presupuesto se fijó en `4a1b92d6` "donde se midió"; desde entonces diez commits han editado `gap-closure-evidence.json`, cada uno añadiendo `validationCommands`, y la cuenta se fue por encima. El propósito entero del ratchet es que las referencias muertas no CREZCAN, y está reportando exactamente eso mientras se lo ignora, porque un job en rojo permanente se lee como ruido de fondo — el mismo modo de fallo que [`GT-622`](./gap-reference-catalog.es.md#gt-622) registra para la configuración huérfana de CodeQL. El próximo cambio que añada de verdad una referencia muerta será indistinguible de las cuatro que ya están. **Lo que no hay que hacer:** subir el presupuesto a 309, que convierte un ratchet incumplido en uno ratificado. | | | `Governance` | Cross | P2 | S | `COMPLETADO` |
| [`GT-634`](./gap-reference-catalog.es.md#gt-634) | **El CLI y el MCP publicados resuelven una build del SDK anterior a la ola de seguridad, porque un rango caret bajo 1.x la fija.** `@beyondnet/evolith-cli@1.2.1` y `@beyondnet/evolith-mcp@1.2.1` declaran ambos `@beyondnet/evolith-sdk: ^1.1.0`, y eso resuelve **exactamente `1.1.0`** — el SDK publica `1.0.0`, `1.1.0` y `2.0.0` y nada en medio, y un caret no cruza un mayor. Las fechas son el hallazgo: `sdk@1.1.0` se publicó el 2026-07-18, `sdk@2.0.0` el 2026-07-27 como parte de la release que cerró [`GT-570`](./gap-reference-catalog.es.md#gt-570), y ambos consumidores el 2026-07-28 — **después** de que 2.0.0 existiera, y seguían en la línea 1.x. Así que la exposición que GT-570 declaró cerrada para "quien instale `latest`" no está cerrada para esta dependencia. Dicho con precisión, porque la afirmación fuerte no está verificada aquí: lo medido son las fechas y la resolución, no el contenido — esta fila no afirma que `sdk@1.1.0` cargue una vulnerabilidad concreta. Encontrado ejecutando el criterio de deprecación de [`GT-624`](./gap-reference-catalog.es.md#gt-624), que es lo que dejó el rango a la vista: deprecar `sdk@1.1.0` avisaría en cada instalación limpia de la línea actual sin ningún sucesor 1.x que ofrecer. **CERRADO el 2026-07-30 — 1.2.2 está publicada, y el marco de seguridad de esta fila era ERRÓNEO.** Una instalación limpia de `@beyondnet/evolith-cli@latest` resuelve ya `@beyondnet/evolith-sdk@2.0.0` con el binario arrancando. Pero verificar el criterio 2 refutó la premisa: **ninguno de los siete commits de la ola toca `src/packages/sdk-client` — cero ficheros** — y el propio commit de release de la ola nombra los tres paquetes afectados (mcp, cli, agent-runtime). El SDK se republicó con ellos, no se arregló. Lo real es un MAYOR rancio fijado por un caret bajo 1.x más un lockfile que anidaba el tarball del registry tapando el enlace del workspace — la clase de `GT-625`, no una exposición de seguridad. La cautela escrita al abrir la fila es lo que abarató la corrección. | | | `Infra` | Cross | P1 | S | `COMPLETADO` |
| [`GT-633`](./gap-reference-catalog.es.md#gt-633) | **El guard comparaba el snapshot contra seis números copiados del propio snapshot, así que solo podía pasar — y el archivo que no estaba vigilando se estampa en 388 filas de un artefacto mayor.** `native-evaluability-snapshot.json` declaraba en su propia cabecera que era "un SNAPSHOT CAPTURADO, no la fuente de verdad". **No existía ningún script de captura.** Se mantenía a mano y derivó: fijaba `documentation-only: 129` mientras Core fijaba 136, y seguía llamando `unimplemented-native` a reglas que ya tenían handler. Su guard en `iso-5055-mapping.test.mjs` asertaba los seis conteos de clase del snapshot contra seis números escritos a mano en el test — los mismos seis literales que el snapshot ya contenía. **El valor esperado y el valor real eran copias el uno del otro**, así que la aserción se sostenía mientras el archivo no cambiara, fijara Core lo que fijara; informaba de una concordancia que nunca comprobó, lo cual es peor que no tener guard, porque la fila que protege se lee como verificada. **La deriva no se queda donde empieza.** `build-iso-5055-mapping.mjs` estampa `nativeEvaluability` en TODAS las filas del mapeo ISO/IEC 5055 desde ese archivo — 388 tras la recaptura, 381 antes — así que una sola clase rancia se blanquea en un artefacto derivado cinco veces mayor que su entrada, y sobredimensiona el backlog de handlers que es el entregable entero de [`GT-598`](./gap-reference-catalog.es.md#gt-598). El orden recaptura→reconstrucción no estaba escrito en ningún sitio, y el guard del propio mapeo no corría en **ningún workflow**. **CORREGIDO el 2026-07-29:** un script de captura que ejecuta el triage REAL de Core vía `ts-node` en vez de reimplementar la clasificación, la medición extraída del spec de jest a `test/rule-corpus-triage.ts` para que un script pueda alcanzarla — esa inalcanzabilidad es la razón de que el archivo se mantuviera a mano —, aserciones snapshot-contra-triage-fresco en ambas direcciones, un guard del job de documentación que lee los conteos que Core fija LEYENDO el spec y **lanza excepción** cuando el literal falta o cambia de forma, y ambos pasos declarados como eslabones de la cadena de artefactos derivados de [`GT-630`](./gap-reference-catalog.es.md#gt-630). **Recapturado el 2026-07-29 tras mergear el fix en la línea actual, y la deriva había crecido mientras estaba en vuelo:** `native-handler` 139 → 151, `documentation-only` 129 → 136, el backlog de handlers 60 → **48**, corpus 379 → 386, mapeo 381 → 388 filas. Doce de esos handlers los cerraron [`GT-595`](./gap-reference-catalog.es.md#gt-595) y [`GT-632`](./gap-reference-catalog.es.md#gt-632) mientras el snapshot mantenido a mano seguía reportándolos como backlog — el defecto demostrándose una vez más, sobre números que nadie escribió dos veces. | | | `Governance` | Cross | P1 | S | `COMPLETADO` |
Expand Down Expand Up @@ -650,7 +651,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida
| [`GT-246`](./gap-reference-catalog.es.md#gt-246) | Implementar experimentos Chaos Mesh/Litmus | | | `QA` | Cross | P3 | L | `COMPLETADO` |


**Progreso:** 596 / 635 completados · 14 en progreso · 21 pendientes · 4 diferidos
**Progreso:** 596 / 636 completados · 14 en progreso · 22 pendientes · 4 diferidos

**Oleada 2026-06-23 (auditoría profunda de Winston III):** Añadidos 14 gaps nuevos `GT-212`…`GT-225` del Winston Audit Playbook que cubren: higiene de estado ADR (GT-212), metadata + presupuestos operativos + corpus de guías por topología (GT-213, GT-217, GT-219), observabilidad + OpenAPI en controladores REST (GT-214, GT-215), paridad de input-schemas OPA + densidad de tests por topología (GT-216, GT-222), plantillas de rollback + on-call de Fase 05 (GT-218), cobertura de ramas CLI + paridad de envelope --format + limpieza de skip-list (GT-220, GT-224, GT-225), audit logging HTTP de MCP (GT-221), y tests e2e de paridad cross-surface (GT-223).

Expand Down
Loading
Loading