From c2a763d9ae45e0d784b6ecb51461c9a217cd8175 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Thu, 30 Jul 2026 09:57:22 -0500 Subject: [PATCH] =?UTF-8?q?docs(gaps):=20register=20GT-638=20=E2=80=94=20t?= =?UTF-8?q?he=20board=20has=20no=20id=20allocator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A gap id is chosen by reading the highest `GT-*` on whichever branch you are on, and nothing contrasts that with any other branch. Two parallel sessions therefore allocate the same number and one finds out at merge time. IT ALREADY HAPPENED, which is why this is a row and not a note. `8449af3d` on develop reads "renumber the ratchet fix GT-634 -> GT-637, ID collision with develop": that row and GT-634 on main took the same id within hours, from sessions that could not see each other. The renumber is manual and LOSSY, and that costs more than the clash. An id lives 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 by construction: it validates within one working tree, and branches are outside its world. Nor is it an isolated slip. In the 2026-07-30 develop -> main merge 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. A merge does not fix that. THE ID FOR THIS ROW was allocated by taking the UNION of ids across main and develop rather than the maximum on one — main was at 635, develop already had 636 and 637 — which is exactly the workaround the fix should make unnecessary. Doing it any other way would have reproduced the defect while registering it. Registered PENDING, P2/S, with criteria that ask for a check at PR time naming both users of a colliding id, and a negative fixture OBSERVED red rather than declared able to fail. Verified: 08-validate-tracking (636 gaps, 612/612 EN/ES sections, 578 closure records), 01-validate-docs (1491 files), 04 bilingual parity, 41 at 38 dead on a clean checkout against a budget of 40, 46 chain current and at a fixed point. Counters 596/635 -> 596/636, pending 21 -> 22. Co-Authored-By: Claude Opus 5 --- .../control-center/gaps/gap-reference-catalog.es.md | 13 +++++++++++++ .../control-center/gaps/gap-reference-catalog.md | 13 +++++++++++++ .../core/control-center/gaps/gap-tracking.es.md | 3 ++- reference/core/control-center/gaps/gap-tracking.md | 3 ++- .../maturity-reports/executive-summary.es.md | 10 +++++----- .../maturity-reports/executive-summary.md | 10 +++++----- .../maturity-reports/maturity-reconciliation.json | 4 ++-- 7 files changed, 42 insertions(+), 14 deletions(-) diff --git a/reference/core/control-center/gaps/gap-reference-catalog.es.md b/reference/core/control-center/gaps/gap-reference-catalog.es.md index fdcfd1d4c..a407d8a2a 100644 --- a/reference/core/control-center/gaps/gap-reference-catalog.es.md +++ b/reference/core/control-center/gaps/gap-reference-catalog.es.md @@ -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 diff --git a/reference/core/control-center/gaps/gap-reference-catalog.md b/reference/core/control-center/gaps/gap-reference-catalog.md index 046fcb95e..8585dde20 100644 --- a/reference/core/control-center/gaps/gap-reference-catalog.md +++ b/reference/core/control-center/gaps/gap-reference-catalog.md @@ -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 diff --git a/reference/core/control-center/gaps/gap-tracking.es.md b/reference/core/control-center/gaps/gap-tracking.es.md index e50555aba..87bbebd51 100644 --- a/reference/core/control-center/gaps/gap-tracking.es.md +++ b/reference/core/control-center/gaps/gap-tracking.es.md @@ -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` | @@ -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). diff --git a/reference/core/control-center/gaps/gap-tracking.md b/reference/core/control-center/gaps/gap-tracking.md index 56cb81e83..a7c2d3cb7 100644 --- a/reference/core/control-center/gaps/gap-tracking.md +++ b/reference/core/control-center/gaps/gap-tracking.md @@ -13,6 +13,7 @@ This board is the single source of truth for technical debt, gaps, opportunities | ID | Gap | What it means | Example | Component | Phase | Criticality | Complexity | Status | |---|---|---|---|:---:|:---:|:---:|:---:|:---:| +| [`GT-638`](./gap-reference-catalog.md#gt-638) | **The board has no id allocator, so two parallel branches hand out the same GT number.** An id is chosen by reading the highest `GT-*` on the branch you happen to be on, and nothing contrasts that with any other branch — so two sessions in parallel allocate the same number and one finds out at merge time. It already happened: `8449af3d` on `develop` reads *"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` took the same id within hours, from sessions that could not see each other. **The renumber is manual and lossy**, which costs more than the clash: an id lives in the board row, the catalog anchor, the closure-evidence record, cross-references in both languages, commit messages and PR bodies — and only the first three are mechanically checkable. `08-validate-tracking` cannot help by construction: it validates within one working tree, and branches are outside its world. Not an isolated slip either — in the 2026-07-30 `develop` → `main` merge the same convergent-duplication pattern appears three times: GT-633 fixed twice, the evidence guard's parser fixed twice, this id allocated twice. | | | `Governance` | Cross | P2 | S | `PENDING` | | [`GT-635`](./gap-reference-catalog.md#gt-635) | **The dead-reference ratchet has been over budget on main since 2026-07-28, so the governance job is permanently red.** `41-validate-evidence-commands --strict --max-dead 305` reports **309 dead references on a clean checkout**, so `Governance guards (GT-578)` exits 1 on every run of `ci-cd.yml` — observed on runs `30482497995`, `30470648146` and `30466280865`, all on `main` with nothing unmerged. The budget was set in `4a1b92d6` "where it was measured"; ten commits have edited `gap-closure-evidence.json` since, each adding `validationCommands`, and the count drifted past it. The ratchet's whole purpose is that dead references must not GROW, and it is reporting exactly that while being ignored, because a permanently red job reads as background noise — the same failure mode [`GT-622`](./gap-reference-catalog.md#gt-622) records for the orphaned CodeQL configuration. The next change that genuinely adds a dead reference will be indistinguishable from the four already there. **What not to do:** raise the budget to 309, which converts a breached ratchet into a ratified one. | | | `Governance` | Cross | P2 | S | `DONE` | | [`GT-634`](./gap-reference-catalog.md#gt-634) | **The published CLI and MCP resolve an SDK build that predates the security wave, because a caret range under 1.x pins it.** `@beyondnet/evolith-cli@1.2.1` and `@beyondnet/evolith-mcp@1.2.1` both declare `@beyondnet/evolith-sdk: ^1.1.0`, and that resolves to **exactly `1.1.0`** — the SDK publishes `1.0.0`, `1.1.0` and `2.0.0` and nothing in between, and a caret cannot cross a major. The dates are the finding: `sdk@1.1.0` was published 2026-07-18, `sdk@2.0.0` on 2026-07-27 as part of the release that closed [`GT-570`](./gap-reference-catalog.md#gt-570), and both consumers on 2026-07-28 — **after** 2.0.0 existed, still on the 1.x line. So the exposure GT-570 declared closed for "anyone installing `latest`" is not closed for this dependency. Stated precisely, because the stronger claim is unverified here: what is measured is the dates and the resolution, not the contents — this row does not assert that `sdk@1.1.0` carries a specific vulnerability. Found while executing [`GT-624`](./gap-reference-catalog.md#gt-624)'s deprecation criterion, which is what exposed the range: deprecating `sdk@1.1.0` would warn on every fresh install of the current line with no 1.x successor to offer. **CLOSED 2026-07-30 — 1.2.2 is published, and the security framing of this row was WRONG.** A clean install of `@beyondnet/evolith-cli@latest` now resolves `@beyondnet/evolith-sdk@2.0.0` with the binary booting. But verifying criterion 2 refuted the premise: **none of the seven security-wave commits touches `src/packages/sdk-client` — zero files** — and the wave's own release commit names the three packages it affected (mcp, cli, agent-runtime). The SDK was republished alongside them, not fixed. What was real is a stale MAJOR pinned by a caret under 1.x plus a lockfile that nested the registry tarball where it shadowed the workspace link — the `GT-625` class, not a security exposure. The hedge written in when the row was opened is what made the correction cheap. | | | `Infra` | Cross | P1 | S | `DONE` | | [`GT-633`](./gap-reference-catalog.md#gt-633) | **The guard compared the snapshot against six numbers copied out of the snapshot, so it could only ever pass — and the file it was failing to guard is stamped onto 388 rows of a larger artifact.** `native-evaluability-snapshot.json` declared in its own header that it was "a CAPTURED SNAPSHOT, not the source of truth". **No capture script existed.** It was hand-maintained and it drifted: it pinned `documentation-only: 129` while Core pinned 136, and went on calling rules `unimplemented-native` after they had handlers. Its guard in `iso-5055-mapping.test.mjs` asserted the snapshot's six class counts against six numbers typed into the test — the same six literals the snapshot already contained. **Expected value and actual value were copies of each other**, so the assertion held for as long as the file was unchanged, whatever Core actually pinned; it reported an agreement it never checked, which is worse than no guard, because the row it protects reads as verified. **The drift does not stay where it starts.** `build-iso-5055-mapping.mjs` stamps `nativeEvaluability` onto EVERY row of the ISO/IEC 5055 mapping from that file — 388 rows after the recapture, 381 before — so one stale class is laundered into a derived artifact five times the size of its input, and overstates the handler backlog that is [`GT-598`](./gap-reference-catalog.md#gt-598)'s entire deliverable. The recapture→rebuild order was written down nowhere, and the mapping's own guard ran in **no workflow at all**. **FIXED 2026-07-29:** a capture script that runs Core's REAL triage through `ts-node` instead of reimplementing the classification, the measurement extracted out of the jest spec into `test/rule-corpus-triage.ts` so a script can reach it — that unreachability is why the file was maintained by hand — snapshot-vs-fresh-triage assertions in both directions, a documentation-job guard that reads Core's pinned counts OUT of the spec and **throws** when the literal is missing or reshaped, and both steps declared as links in the [`GT-630`](./gap-reference-catalog.md#gt-630) derived-artifact chain. **Recaptured on 2026-07-29 after merging the fix into the current line, and the drift had grown while it was in flight:** `native-handler` 139 → 151, `documentation-only` 129 → 136, the handler backlog 60 → **48**, corpus 379 → 386, mapping 381 → 388 rows. Twelve of those handlers were closed by [`GT-595`](./gap-reference-catalog.md#gt-595) and [`GT-632`](./gap-reference-catalog.md#gt-632) while the hand-maintained snapshot went on reporting them as backlog — the defect demonstrating itself one more time, on numbers nobody typed twice. | | | `Governance` | Cross | P1 | S | `DONE` | @@ -650,7 +651,7 @@ This board is the single source of truth for technical debt, gaps, opportunities | [`GT-246`](./gap-reference-catalog.md#gt-246) | Implement Chaos Mesh/Litmus experiments | | | `QA` | Cross | P3 | L | `DONE` | -**Progress:** 596 / 635 done · 14 in progress · 21 pending · 4 deferred +**Progress:** 596 / 636 done · 14 in progress · 22 pending · 4 deferred **Wave 2026-06-23 (Winston deep audit III):** Added 14 new gaps `GT-212`…`GT-225` from the Winston Audit Playbook covering: ADR status hygiene (GT-212), topology manifest metadata + operational budgets + guidance corpus (GT-213, GT-217, GT-219), REST controller observability + OpenAPI (GT-214, GT-215), OPA input-schema parity + per-topology test density (GT-216, GT-222), SDLC Phase 05 rollback + on-call templates (GT-218), CLI branch coverage + envelope format coverage + skip-list cleanup (GT-220, GT-224, GT-225), MCP HTTP audit logging (GT-221), and cross-surface parity e2e tests (GT-223). diff --git a/reference/core/control-center/maturity-reports/executive-summary.es.md b/reference/core/control-center/maturity-reports/executive-summary.es.md index 88120ed59..423904302 100644 --- a/reference/core/control-center/maturity-reports/executive-summary.es.md +++ b/reference/core/control-center/maturity-reports/executive-summary.es.md @@ -29,7 +29,7 @@ La forma correcta de usar este resumen es simple: si necesitas contexto, abre so | 2 | Área de mayor riesgo | `Evolith Core` tiene la mayor carga ponderada abierta. | [GT-583](../gaps/gap-reference-catalog.es.md#gt-583), [GT-589](../gaps/gap-reference-catalog.es.md#gt-589), [GT-614](../gaps/gap-reference-catalog.es.md#gt-614), [GT-587](../gaps/gap-reference-catalog.es.md#gt-587), [GT-591](../gaps/gap-reference-catalog.es.md#gt-591), [GT-590](../gaps/gap-reference-catalog.es.md#gt-590), +2 | | 3 | Ganancias rápidas | Alta criticidad con complejidad XS/S. | [GT-597](../gaps/gap-reference-catalog.es.md#gt-597), [GT-631](../gaps/gap-reference-catalog.es.md#gt-631) | | 4 | Ola P1 | Endurecimiento siguiente después de limpiar P0. | [GT-597](../gaps/gap-reference-catalog.es.md#gt-597), [GT-631](../gaps/gap-reference-catalog.es.md#gt-631), [GT-324](../gaps/gap-reference-catalog.es.md#gt-324), [GT-578](../gaps/gap-reference-catalog.es.md#gt-578), [GT-580](../gaps/gap-reference-catalog.es.md#gt-580), [GT-584](../gaps/gap-reference-catalog.es.md#gt-584), [GT-605](../gaps/gap-reference-catalog.es.md#gt-605), [GT-606](../gaps/gap-reference-catalog.es.md#gt-606), +6 | -| 5 | P2/P3 | Solo después de estabilizar seguridad, CI, reglas y contratos. | [GT-622](../gaps/gap-reference-catalog.es.md#gt-622), [GT-444](../gaps/gap-reference-catalog.es.md#gt-444), [GT-464](../gaps/gap-reference-catalog.es.md#gt-464), [GT-614](../gaps/gap-reference-catalog.es.md#gt-614), [GT-616](../gaps/gap-reference-catalog.es.md#gt-616), [GT-617](../gaps/gap-reference-catalog.es.md#gt-617), +12 | +| 5 | P2/P3 | Solo después de estabilizar seguridad, CI, reglas y contratos. | [GT-622](../gaps/gap-reference-catalog.es.md#gt-622), [GT-444](../gaps/gap-reference-catalog.es.md#gt-444), [GT-464](../gaps/gap-reference-catalog.es.md#gt-464), [GT-614](../gaps/gap-reference-catalog.es.md#gt-614), [GT-616](../gaps/gap-reference-catalog.es.md#gt-616), [GT-617](../gaps/gap-reference-catalog.es.md#gt-617), +13 | ## Bloqueadores Actuales @@ -45,13 +45,13 @@ La forma correcta de usar este resumen es simple: si necesitas contexto, abre so | Indicador | Valor | |---|---:| | Fecha canónica del tablero | 2026-07-26 | -| Gaps totales | 635 | +| Gaps totales | 636 | | Gaps cerrados | 596 | -| Gaps pendientes | 39 | +| Gaps pendientes | 40 | | P0 abiertos | 4 | | P1 abiertos | 14 | -| P2 abiertos | 18 | -| Cierre total | 93.9% | +| P2 abiertos | 19 | +| Cierre total | 93.7% | | Registros de evidencia de cierre | 578 | | Readiness registrado | 4 PASS | diff --git a/reference/core/control-center/maturity-reports/executive-summary.md b/reference/core/control-center/maturity-reports/executive-summary.md index 244556908..4ba656e17 100644 --- a/reference/core/control-center/maturity-reports/executive-summary.md +++ b/reference/core/control-center/maturity-reports/executive-summary.md @@ -29,7 +29,7 @@ Use this summary with a simple rule: if you need context, open only the linked I | 2 | Highest-risk area | `Evolith Core` has the largest weighted open load. | [GT-583](../gaps/gap-reference-catalog.md#gt-583), [GT-589](../gaps/gap-reference-catalog.md#gt-589), [GT-614](../gaps/gap-reference-catalog.md#gt-614), [GT-587](../gaps/gap-reference-catalog.md#gt-587), [GT-591](../gaps/gap-reference-catalog.md#gt-591), [GT-590](../gaps/gap-reference-catalog.md#gt-590), +2 | | 3 | Quick wins | High criticality with XS/S complexity. | [GT-597](../gaps/gap-reference-catalog.md#gt-597), [GT-631](../gaps/gap-reference-catalog.md#gt-631) | | 4 | P1 wave | Next hardening after P0 is cleared. | [GT-597](../gaps/gap-reference-catalog.md#gt-597), [GT-631](../gaps/gap-reference-catalog.md#gt-631), [GT-324](../gaps/gap-reference-catalog.md#gt-324), [GT-578](../gaps/gap-reference-catalog.md#gt-578), [GT-580](../gaps/gap-reference-catalog.md#gt-580), [GT-584](../gaps/gap-reference-catalog.md#gt-584), [GT-605](../gaps/gap-reference-catalog.md#gt-605), [GT-606](../gaps/gap-reference-catalog.md#gt-606), +6 | -| 5 | P2/P3 | Only after security, CI, rules, and contracts stabilize. | [GT-622](../gaps/gap-reference-catalog.md#gt-622), [GT-444](../gaps/gap-reference-catalog.md#gt-444), [GT-464](../gaps/gap-reference-catalog.md#gt-464), [GT-614](../gaps/gap-reference-catalog.md#gt-614), [GT-616](../gaps/gap-reference-catalog.md#gt-616), [GT-617](../gaps/gap-reference-catalog.md#gt-617), +12 | +| 5 | P2/P3 | Only after security, CI, rules, and contracts stabilize. | [GT-622](../gaps/gap-reference-catalog.md#gt-622), [GT-444](../gaps/gap-reference-catalog.md#gt-444), [GT-464](../gaps/gap-reference-catalog.md#gt-464), [GT-614](../gaps/gap-reference-catalog.md#gt-614), [GT-616](../gaps/gap-reference-catalog.md#gt-616), [GT-617](../gaps/gap-reference-catalog.md#gt-617), +13 | ## Current Blockers @@ -45,13 +45,13 @@ Use this summary with a simple rule: if you need context, open only the linked I | Indicator | Value | |---|---:| | Canonical board date | 2026-07-26 | -| Total gaps | 635 | +| Total gaps | 636 | | Closed gaps | 596 | -| Open gaps | 39 | +| Open gaps | 40 | | Open P0 | 4 | | Open P1 | 14 | -| Open P2 | 18 | -| Total closure | 93.9% | +| Open P2 | 19 | +| Total closure | 93.7% | | Closure evidence records | 578 | | Recorded readiness | 4 PASS | diff --git a/reference/core/control-center/maturity-reports/maturity-reconciliation.json b/reference/core/control-center/maturity-reports/maturity-reconciliation.json index f29872a3b..60bf3fbb5 100644 --- a/reference/core/control-center/maturity-reports/maturity-reconciliation.json +++ b/reference/core/control-center/maturity-reports/maturity-reconciliation.json @@ -3,9 +3,9 @@ "scope": "evolith-core", "asOf": "2026-07-26", "gaps": { - "total": 635, + "total": 636, "done": 596, - "pending": 21, + "pending": 22, "inProgress": 14, "deferred": 4 },