From c32212761cf015a7c77d8c4d63fcad500f366bfc Mon Sep 17 00:00:00 2001 From: aarroyo Date: Thu, 30 Jul 2026 08:34:58 -0500 Subject: [PATCH] =?UTF-8?q?docs(gaps):=20register=20GT-633,=20GT-634=20and?= =?UTF-8?q?=20GT-635=20on=20main=20=E2=80=94=20the=20rows,=20and=20nothing?= =?UTF-8?q?=20else?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything else that was on the `claude/happy-rubin-634587` branch has landed from other sessions, so this carries only what the board is still missing. The branch is abandoned rather than merged, and what superseded each piece is recorded here so the history is not a mystery: - the capture script and the extracted triage -> PR #276 - the two derived-artifact chain links -> PR #287 (identical to the specification: same producer, checkArgs, the three `consumes` sources and both written artifacts, in the position after the ABAC link) - the SDK range and the 1.2.2 release -> PR #285 - GT-624's deprecations and its gate -> PR #288 GT-633 (DONE) — the failure mode is the content, not the fix: a guard whose expected value was a copy of its actual value, and a derived artifact that launders a stale input into one five times its size. Recorded with how it actually landed, because three sessions converged on it: #276 and #287 on main, and a SECOND independent implementation on develop as #279 — an in-spec renderer instead of a standalone script. Both recaptured the same numbers, which corroborates the measurement; two generators for one artifact is this row's own defect one level up, and reconciling them is the open blocker on develop -> main. That reconciliation is deliberately NOT done here: choosing which generator survives belongs to the sessions that wrote the two halves. GT-634 (PENDING, and it stays that way) — 1.2.2 is on main and NOT published. A range in the repository is not a range on the registry; until npm serves it, the published `latest` of the CLI and the MCP still installs the 2026-07-18 SDK. GT-635 (DONE) — closed the way the row asked, by someone else, within the hour. `f34a10f1` migrated the recorded commands onto the paths this repository has and `600dd7a9` moved the budget 304 -> 40 from the count that produced: 269 of the 309 dead references were REPAIRED, not exempted. The row's value was making a permanently red job visible, not owning the repair, and the record says so. Verified: 08-validate-tracking (635 gaps, 611/611 EN/ES sections, 577 closure records), 41 at 38 dead on a clean checkout against a budget of 40 — these two new closure records add none — 01-validate-docs (1491 files), 04 bilingual parity, 46 chain current and at a fixed point. Counters 593/632 -> 595/635. Co-Authored-By: Claude Opus 5 --- .../evidence/gap-closure-evidence.json | 42 +++++++++++++++++++ .../gaps/gap-reference-catalog.es.md | 39 +++++++++++++++++ .../gaps/gap-reference-catalog.md | 39 +++++++++++++++++ .../control-center/gaps/gap-tracking.es.md | 5 ++- .../core/control-center/gaps/gap-tracking.md | 5 ++- .../maturity-reports/executive-summary.es.md | 18 ++++---- .../maturity-reports/executive-summary.md | 18 ++++---- .../maturity-reconciliation.json | 8 ++-- 8 files changed, 150 insertions(+), 24 deletions(-) diff --git a/reference/core/control-center/evidence/gap-closure-evidence.json b/reference/core/control-center/evidence/gap-closure-evidence.json index c8aee44d..66601741 100644 --- a/reference/core/control-center/evidence/gap-closure-evidence.json +++ b/reference/core/control-center/evidence/gap-closure-evidence.json @@ -8853,6 +8853,48 @@ ], "dependencyDisposition": "accepted-scope", "dependencyRationale": "What this gate does NOT do is stated rather than left to be discovered. It detects a security-marked commit that no published version contains; it cannot detect a security fix nobody marked, which is a convention problem and belongs to GT-623 (release-please derives no bump from the non-conventional `security(...)` type this repository has used twice). It also reports, but does not fail on, a package whose published version is absent from this history -- an INEXACT boundary after a history rewrite -- because scanning the whole history conservatively is better than skipping the package silently. Finally, the gate needs the network: without a registry answer the package is skipped and named, and a run where EVERY package is skipped is a failure rather than a pass." + }, + { + "id": "GT-633", + "closedAt": "2026-07-30", + "closureCommit": "29e940d4", + "evidence": [ + "src/rulesets/standards/capture-native-evaluability-snapshot.mjs", + "src/packages/core-domain/test/rule-corpus-triage.ts", + "src/packages/core-domain/src/application/validators/rule-corpus-triage.spec.ts", + "src/rulesets/standards/native-evaluability-snapshot.json", + "src/rulesets/standards/iso-5055-mapping.test.mjs", + ".harness/scripts/ci/46-validate-derived-artifact-order.mjs", + ".github/workflows/docs.yml" + ], + "validationCommands": [ + "THE FAILURE MODE, which is the content worth keeping: the guard's expected value was a copy of its actual value. iso-5055-mapping.test.mjs asserted the snapshot's six class counts against six numbers typed into the test -- the same six literals native-evaluability-snapshot.json already contained -- so it passed for as long as the file was unchanged, whatever Core actually pinned. It reported an agreement it never checked.", + "SECOND failure mode: build-iso-5055-mapping.mjs stamps `nativeEvaluability` onto every row of the ISO/IEC 5055 mapping from that snapshot (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 GT-598 handler backlog.", + "node src/rulesets/standards/capture-native-evaluability-snapshot.mjs --check -> the end-to-end re-derivation; it runs Core's real triage through ts-node rather than reimplementing the classification, because a second implementation would be the second source of truth the fix removes.", + "node --test src/rulesets/standards/iso-5055-mapping.test.mjs -> the documentation-job guard now reads Core's pinned counts OUT of the spec that pins them and THROWS when the literal is missing or reshaped: failing to find the source of truth must never read as agreement with it.", + "node .harness/scripts/ci/46-validate-derived-artifact-order.mjs -> 5 links / 7 artifacts, current AND at a fixed point. The recapture->rebuild order is data, not prose: rebuilding the mapping before recapturing the snapshot is a guard failure.", + "RECAPTURED: native-handler 139 -> 151, documentation-only 129 -> 136, handler backlog 60 -> 48, corpus 379 -> 386, mapping 381 -> 388 rows. Twelve handlers had been closed by GT-595 and GT-632 while the hand-maintained snapshot went on reporting them as backlog -- the defect demonstrating itself.", + "HOW IT LANDED, recorded because three sessions converged: the capture script and extracted triage as PR #276, the two chain links as PR #287, and a SECOND independent implementation on develop as PR #279 (an in-spec renderer). Both recaptured the same numbers, which corroborates the measurement; two generators for one artifact is this row's own defect one level up, and reconciling them is open work that blocks develop -> main." + ], + "dependencyDisposition": "accepted-scope", + "dependencyRationale": "Closed on the implementation that is on main. The parallel implementation on develop (PR #279) is NOT reconciled here: choosing which generator survives is a design decision belonging to the sessions that wrote the two halves, and it is tracked as the blocker on develop -> main rather than resolved inside a board registration." + }, + { + "id": "GT-635", + "closedAt": "2026-07-30", + "closureCommit": "600dd7a9", + "evidence": [ + "reference/core/control-center/evidence/gap-closure-evidence.json", + ".harness/scripts/ci/41-validate-evidence-commands.mjs", + ".github/workflows/ci-cd.yml" + ], + "validationCommands": [ + "CLOSED THE WAY THE ROW ASKED, which was the whole point: the budget was not raised to ratify the breach. `f34a10f1` migrated the recorded closure commands onto the paths this repository actually has, and `600dd7a9` then moved the budget 304 -> 40 from the count that migration produced.", + "node .harness/scripts/ci/41-validate-evidence-commands.mjs --strict --max-dead 40 -> 40 dead over 1045 recorded commands in 575 closures. The corpus went 309 -> 40: 269 references were REPAIRED, not exempted, which subsumes the four this row was opened for.", + "Governance guards (GT-578) passed on the runner for PR #288, which is the check that had been red on main for at least three consecutive runs (30482497995, 30470648146, 30466280865).", + "Registered by one session and closed by another within the hour. Recorded plainly: the value of the row was making a permanently red required-adjacent job visible, not owning the repair." + ], + "dependencyDisposition": "none" } ] } 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 8680e550..72d4eb79 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,45 @@ 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-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 + +- **Purpose:** Que un ratchet incumplido o se respete o se vuelva a medir — un gate que nadie puede satisfacer enseña a la gente a ignorarlo. +- **Evidence:** **`Governance guards (GT-578)` falla en `main` mismo, y lleva al menos tres corridas consecutivas así.** `41-validate-evidence-commands --strict --max-dead 305` reporta **309 referencias muertas en un checkout limpio**, así que el job sale 1 en cada corrida de `ci-cd.yml`. Observado en las corridas `30482497995` (2026-07-29 19:00Z), `30470648146` (16:25Z) y `30466280865` (15:31Z) — todas en `main`, ninguna con cambios sin mergear. El presupuesto se fijó en 305 en `4a1b92d6` (2026-07-28) con el mensaje "put the ratchet back where it was measured"; **desde entonces diez commits han editado `gap-closure-evidence.json`**, cada uno añadiendo `validationCommands`, y la cuenta se fue por encima del número que se midió. Las cuatro referencias muertas de más no son atribuibles a ninguno en concreto solo por la cuenta. **Por qué es más que contabilidad:** el propósito entero del ratchet es que las referencias muertas no CREZCAN, y ahora mismo 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. Además implica que 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 y seguir. Eso convierte un ratchet incumplido en un ratchet ratificado, que es exactamente cómo se llegó a un corpus de 309 referencias muertas. Las dos opciones honestas son arreglar las cuatro (reapuntar los comandos a referentes que existen) o volver a medir y declarar, en el commit, qué se aceptó y por qué. **CERRADO el 2026-07-30, y no subiendo el presupuesto — que es justo lo que la fila pedía no hacer.** `f34a10f1` migró los comandos de cierre registrados a las rutas que este repositorio tiene de verdad, y `600dd7a9` movió después el presupuesto **304 → 40** desde la cuenta que produjo esa migración. El corpus pasó de 309 referencias muertas a 40 sobre 1045 comandos registrados: 269 se REPARARON, no se eximieron, lo que subsume las cuatro por las que se abrió la fila. `Governance guards (GT-578)` pasó en el runner en el PR #288. Registrada por una sesión y cerrada por otra en menos de una hora — vale la pena decirlo, porque el valor de la fila era hacer visible el incumplimiento, no quedarse el arreglo. +- **Component:** `Governance` · **Criticality:** P2 · **Complexity:** S +- **Provenance:** Encontrado el 2026-07-29 diagnosticando cuatro checks en rojo del PR #277. Tres de los cuatro eran preexistentes en `main`; este es el que traía el número idéntico (309 vs 305) en ambos lados, y eso es lo que probó que el PR no lo había causado. +- **Acceptance criteria:** + - [x] `Governance guards (GT-578)` pasa en `main` sin haber subido el presupuesto para dar cabida a referencias que ya estaban muertas — se BAJÓ, 304 → 40, tras reparar el corpus. + - [x] Cada una de las cuatro referencias añadidas desde `4a1b92d6` queda reparada o nombrada en el commit que la acepta, con el motivo — subsumido: 269 de las 309 se repararon de golpe con la migración de rutas. + - [x] El guard reporta la base del ratchet sobre un checkout limpio, para que el presupuesto no vuelva a calibrarse contra una máquina que resulta tener algo construido. + +#### GT-634 + +**Title:** 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 + +- **Purpose:** Que `npm install @beyondnet/evolith-cli@latest` deje de arrastrar una dependencia publicada antes de los fixes que anuncia su propio CHANGELOG. +- **Evidence:** **`@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, así que un rango caret bajo 1.x no puede alcanzar 2.0.0 — un caret está acotado por el siguiente 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 `cli@1.2.1` / `mcp@1.2.1` el **2026-07-28** — *después* de que 2.0.0 existiera, y seguían apuntando a 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: el `latest` de ambas superficies instala un SDK construido antes de la ola del 2026-07-23. **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, solo que es anterior a la ola y que la release que la trajo fue un mayor al que los consumidores no llegan. Verificar qué fixes hay en `sdk@2.0.0` es parte de cerrarla. **Encontrado porque bloqueaba otra cosa:** deprecar `sdk@1.1.0` para [`GT-624`](./gap-reference-catalog.es.md#gt-624) habría impreso un aviso en cada instalación limpia de la línea actual sin ningún sucesor 1.x que ofrecer, y eso es lo que dejó el rango a la vista. Arreglo: reapuntar ambos rangos a `^2.0.0` (un salto mayor de dependencia, así que exige revisar los breaking changes del SDK contra ambos call sites) o publicar un `sdk@1.2.x` con los fixes, y entonces deprecar `sdk@1.1.0` y cerrar de verdad el primer criterio de GT-624. **RANGOS REAPUNTADOS el 2026-07-29, y hacerlo demostró que la fila se quedaba corta.** `package-lock.json` no sólo registraba el rango — fijaba el tarball del registry de `sdk@1.1.0` en `src/sdk/cli/node_modules/@beyondnet/evolith-sdk` **y** en `src/packages/mcp-server/node_modules/@beyondnet/evolith-sdk`, con hashes de integridad. Así que un `npm ci` en checkout limpio descargaba el SDK anterior a la ola y lo anidaba dentro de cada consumidor, donde **tapa el enlace del workspace**: el symlink de primer nivel al 2.0.0 local es lo que lee todo el mundo, y el 1.1.0 anidado es lo que resuelve de verdad una instalación fresca. Es la misma clase que [`GT-625`](./gap-reference-catalog.es.md#gt-625) — el workspace tapando lo que hace una instalación real — y es la razón de que nada lo cazara. Ambas entradas anidadas desaparecieron al mover el rango a `^2.0.0`, porque entonces el propio 2.0.0 del workspace lo satisface; el diff del lockfile son exactamente dos cadenas de rango y esas dos eliminaciones, sin deriva colateral, y se usó `npm install --package-lock-only` para confirmar que escribe byte a byte lo mismo que la edición a mano en vez de fiarse de ella. La superficie del SDK que ambos consumidores usan de verdad es estrecha — sólo `EvolithRestClient` — así que el breaking change de 2.0.0 (tipos de payload re-exportados de `core-domain`, `.passed` → `.verdict`, severidad `'info'` retirada) no toca ninguno de los dos call sites. Verificado contra 2.0.0: CLI **1436/1436** en 99 suites, mcp-server **433/433** en 53. **1.2.2 está en `main` (PR #285) y NO publicada.** La fila sigue ABIERTA y ése es justo el punto: un rango en el repositorio no es un rango en el registry, y el criterio 1 sólo se cumple cuando npm lo sirve. Hasta entonces el `latest` publicado de ambas superficies sigue instalando el SDK del 2026-07-18. +- **Component:** `Infra` · **Criticality:** P1 · **Complexity:** S +- **Provenance:** Encontrado el 2026-07-29 ejecutando el criterio de deprecación de GT-624. Registrado en vez de sorteado: saltarse la deprecación en silencio habría dejado el rango — y la instalación — exactamente como están. +- **Acceptance criteria:** + - [ ] `npm view @beyondnet/evolith-cli@latest dependencies` muestra un rango de SDK que resuelve a una versión publicada el 2026-07-27 o después, e igual `evolith-mcp`. + - [ ] Los fixes que reclama la ola de seguridad del 2026-07-23 se verifican presentes en la versión del SDK que el CLI y el MCP resuelven de verdad, en vez de asumirse por el número de versión. + - [ ] `@beyondnet/evolith-sdk@1.1.0` queda deprecada en cuanto exista un sucesor al que sus consumidores puedan llegar. + +#### GT-633 + +**Title:** Un guard cuyo valor esperado era una copia de su valor real, sobre una entrada que se blanquea en un artefacto cinco veces mayor + +- **Purpose:** Eliminar dos clases de fallo que trascienden este archivo — un guard que lee su expectativa del artefacto que vigila, y un generador que estampa un campo mantenido a mano sobre todo lo que va detrás de él. +- **Evidence:** **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) en tantas reglas como Core haya cerrado desde entonces. El orden que marca la diferencia (recapturar y DESPUÉS reconstruir) 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** (rama `claude/fervent-cohen-08ea01`): `capture-native-evaluability-snapshot.mjs` ejecuta el triage REAL de Core vía `ts-node` en vez de reimplementar la clasificación — una segunda implementación aquí sería una segunda fuente de verdad, que es justo el defecto que se está quitando — y para que el triage fuera alcanzable fuera de jest se movió del spec a `src/packages/core-domain/test/rule-corpus-triage.ts`; esa inalcanzabilidad es precisamente la razón de que el snapshot se mantuviera a mano. Tres comprobaciones sustituyen a la tautología, cada una en el job que puede permitírsela: `rule-corpus-triage.spec.ts` asserta el snapshot commiteado contra un triage RECIÉN CALCULADO, en ambas direcciones; el guard del job de documentación, que no tiene `node_modules`, lee los conteos que Core fija LEYENDO el spec que los fija y **lanza excepción** cuando el literal falta o cambia de forma, de modo que no encontrar la fuente de verdad jamás pueda leerse como acuerdo con ella; y `--check` es la re-derivación de extremo a extremo. **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. El merge además arrastraba una segunda instancia del patrón que registró GT-595: el `test/rule-corpus-triage.ts` extraído había perdido el campo `enforce`, así que el instrumento de medida habría vuelto a medir un corpus distinto del que evalúa producción; queda restaurado. Ambos pasos son ya eslabones de la cadena de artefactos derivados de [`GT-630`](./gap-reference-catalog.es.md#gt-630), que exige el orden recaptura→reconstrucción como datos y no como prosa. **Cómo aterrizó de verdad, registrado porque convergieron tres sesiones:** el script de captura y el triage extraído llegaron a `main` como PR #276, los dos links del chain como PR #287, y una SEGUNDA implementación independiente del mismo fix llegó a `develop` como PR #279 — un renderer dentro del spec accionado por `UPDATE_EVALUABILITY_SNAPSHOT=1` en vez de un script aparte. Ambas recapturaron los mismos números, lo cual corrobora la medición; pero dos generadores para un artefacto es el defecto de esta misma fila reproducido un nivel más arriba, y reconciliarlos es trabajo abierto que bloquea `develop` → `main`. +- **Component:** `Governance` · **Criticality:** P1 · **Complexity:** S +- **Provenance:** Defecto derivado de [`GT-598`](./gap-reference-catalog.es.md#gt-598), encontrado el 2026-07-29 al extender su mapeo: el snapshot sobre el que GT-598 se construyó no lo capturaba nada, y el guard que lo cubría era tautológico. Se registra aparte porque el hallazgo es una clase de diseño de guards, no una corrección al mapeo de GT-598. +- **Acceptance criteria:** + - [x] El snapshot lo produce un script que ejecuta el triage propio de Core en lugar de mantenerse a mano, y `capture-native-evaluability-snapshot.mjs --check` lo re-deriva de extremo a extremo. + - [x] Ningún guard sobre el snapshot toma su valor esperado del snapshot: uno recalcula el triage y el otro lee los conteos de Core del spec que los fija, fallando ruidosamente cuando no los encuentra. + - [x] El orden recaptura→reconstrucción se exige como datos — ambos eslabones están declarados en la cadena de `46-validate-derived-artifact-order` — y el guard del mapeo corre en un workflow, cuando no corría en ninguno. + #### GT-632 **Title:** La política ABAC compilada se resuelve en una ruta previa al refactor, denegando toda herramienta MCP en producción diff --git a/reference/core/control-center/gaps/gap-reference-catalog.md b/reference/core/control-center/gaps/gap-reference-catalog.md index 1a10a43b..c001a3ea 100644 --- a/reference/core/control-center/gaps/gap-reference-catalog.md +++ b/reference/core/control-center/gaps/gap-reference-catalog.md @@ -7950,6 +7950,45 @@ 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-635 + +**Title:** The dead-reference ratchet has been over budget on main since 2026-07-28, so the governance job is permanently red + +- **Purpose:** Make a ratchet that has been breached either hold or be re-measured — a gate nobody can satisfy trains people to ignore it. +- **Evidence:** **`Governance guards (GT-578)` fails on `main` itself, and has for at least three consecutive runs.** `41-validate-evidence-commands --strict --max-dead 305` reports **309 dead references on a clean checkout**, so the job exits 1 on every run of `ci-cd.yml`. Observed on runs `30482497995` (2026-07-29 19:00Z), `30470648146` (16:25Z) and `30466280865` (15:31Z) — all on `main`, none carrying an unmerged change. The budget was set to 305 in `4a1b92d6` (2026-07-28) with the message "put the ratchet back where it was measured"; **ten commits have since edited `gap-closure-evidence.json`**, each adding `validationCommands`, and the count drifted past the number that was measured. The four extra dead references are not attributable to any single one of them from the count alone. **Why this is more than bookkeeping:** the ratchet's whole purpose is that dead references must not GROW, and it is currently 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. It also means 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 and move on. That converts a breached ratchet into a ratified one, which is how a corpus of 309 dead references was reached in the first place. The two honest options are to fix the four (retarget the commands at referents that exist) or to re-measure and state, in the commit, what was accepted and why. **CLOSED 2026-07-30, and not by raising the budget — which is what the row said not to do.** `f34a10f1` migrated the recorded closure commands onto the paths this repository actually has, and `600dd7a9` then moved the budget **304 → 40** from the count that migration produced. The corpus went from 309 dead references to 40 over 1045 recorded commands: 269 were REPAIRED, not exempted, which subsumes the four this row was opened for. `Governance guards (GT-578)` passed on the runner for PR #288. Registered by one session and closed by another within the hour — worth noting, because the value of the row was making the breach visible, not owning the fix. +- **Component:** `Governance` · **Criticality:** P2 · **Complexity:** S +- **Provenance:** Found on 2026-07-29 while diagnosing four red checks on PR #277. Three of the four were pre-existing on `main`; this is the one whose number was identical (309 vs 305) on both sides, which is what proved the PR had not caused it. +- **Acceptance criteria:** + - [x] `Governance guards (GT-578)` passes on `main` without the budget being raised to accommodate references that are already dead — it was LOWERED, 304 → 40, after the corpus was repaired. + - [x] Each of the four references added since `4a1b92d6` is either repaired or named in the commit that accepts it, with the reason — subsumed: 269 of the 309 were repaired wholesale by the path migration. + - [x] The guard reports the ratchet basis on a clean checkout, so the budget can never again be calibrated against a machine that happens to have built something. + +#### GT-634 + +**Title:** The published CLI and MCP resolve an SDK build that predates the security wave, because a caret range under 1.x pins it + +- **Purpose:** Make `npm install @beyondnet/evolith-cli@latest` stop pulling a dependency published before the fixes its own CHANGELOG announces. +- **Evidence:** **`@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, so a caret range under 1.x cannot reach 2.0.0 — a caret is bounded by the next 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 `cli@1.2.1` / `mcp@1.2.1` on **2026-07-28** — *after* 2.0.0 existed, still pointing at the 1.x line. So the exposure GT-570 declared closed for "anyone installing `latest`" is not closed for this dependency: `latest` of both surfaces installs an SDK built before the 2026-07-23 wave. **Stated precisely, because the stronger claim is not verified 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, only that it predates the wave and that the release which shipped the wave was a major the consumers cannot reach. Verifying which fixes are in `sdk@2.0.0` is part of closing it. **Found because it blocked something else:** deprecating `sdk@1.1.0` for [`GT-624`](./gap-reference-catalog.md#gt-624) would have printed a warning on every fresh install of the current line with no 1.x successor to offer, which is what exposed the range. Fix: retarget both ranges to `^2.0.0` (a major bump of a dependency, so it needs the SDK's breaking changes reviewed against both call sites) or publish an `sdk@1.2.x` carrying the fixes, then deprecate `sdk@1.1.0` and close GT-624's first criterion for real. **RANGES RETARGETED 2026-07-29, and doing it proved the row understated the defect.** `package-lock.json` did not merely record the range — it pinned the registry tarball of `sdk@1.1.0` at `src/sdk/cli/node_modules/@beyondnet/evolith-sdk` **and** `src/packages/mcp-server/node_modules/@beyondnet/evolith-sdk`, with integrity hashes. So `npm ci` on a clean checkout fetched the pre-wave SDK and nested it inside each consumer, where it **shadows the workspace link**: the top-level symlink to the local 2.0.0 is what every developer reads, and the nested 1.1.0 is what a fresh install actually resolves. That is the same class as [`GT-625`](./gap-reference-catalog.md#gt-625) — the workspace hiding what a real install does — and it is why nothing caught this. Both nested entries disappeared once the range moved to `^2.0.0`, because the workspace's own 2.0.0 then satisfies it; the lockfile diff is exactly two range strings and those two removals, with no collateral drift, and `npm install --package-lock-only` was used to confirm it writes byte-for-byte what the hand edit did rather than trusting the edit. The SDK surface both consumers actually use is narrow — `EvolithRestClient` only — so the 2.0.0 breaking change (payload types re-exported from `core-domain`, `.passed` → `.verdict`, `'info'` severity retired) touches neither call site. Verified against 2.0.0: CLI **1436/1436** in 99 suites, mcp-server **433/433** in 53. **1.2.2 is on `main` (PR #285) and NOT published.** The row stays OPEN and that is the point: a range in the repository is not a range on the registry, and criterion 1 is met only when npm serves it. Until then the published `latest` of both surfaces still installs the 2026-07-18 SDK. +- **Component:** `Infra` · **Criticality:** P1 · **Complexity:** S +- **Provenance:** Found on 2026-07-29 while executing GT-624's deprecation criterion. Registered rather than worked around: skipping the deprecation quietly would have left the range — and the install — exactly as they are. +- **Acceptance criteria:** + - [ ] `npm view @beyondnet/evolith-cli@latest dependencies` shows an SDK range that resolves to a version published on or after 2026-07-27, likewise `evolith-mcp`. + - [ ] The fixes claimed by the 2026-07-23 security wave are verified present in the SDK version the CLI and MCP actually resolve, rather than assumed from the version number. + - [ ] `@beyondnet/evolith-sdk@1.1.0` is deprecated once a successor its consumers can reach exists. + +#### GT-633 + +**Title:** A guard whose expected value was a copy of its actual value, over an input laundered into an artifact five times its size + +- **Purpose:** Remove two failure classes that generalise well beyond this file — a guard that reads its expectation from the artifact it is guarding, and a generator that stamps a hand-maintained field onto everything downstream of it. +- **Evidence:** **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 by however many rules Core has since closed. The order that makes the difference (recapture, THEN rebuild) was written down nowhere, and the mapping's own guard ran in **no workflow at all**. **Fixed on 2026-07-29** (branch `claude/fervent-cohen-08ea01`): `capture-native-evaluability-snapshot.mjs` runs Core's REAL triage through `ts-node` rather than reimplementing the classification — a second implementation here would be a second source of truth, which is the defect being removed — and to make the triage reachable outside jest it moved from the spec into `src/packages/core-domain/test/rule-corpus-triage.ts`; that unreachability is precisely why the snapshot was maintained by hand in the first place. Three checks replace the tautology, each in the job that can afford it: `rule-corpus-triage.spec.ts` asserts the committed snapshot against a FRESHLY COMPUTED triage in both directions; the documentation-job guard, which has no `node_modules`, reads Core's pinned counts OUT of the spec that pins them and **throws** when the literal is missing or reshaped, so failing to find the source of truth can never read as agreement with it; and `--check` is the end-to-end re-derivation. **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. The merge also carried a second instance of the pattern GT-595 recorded: the extracted `test/rule-corpus-triage.ts` had dropped the `enforce` field, so the measuring instrument would again have measured a different corpus than production evaluates; it is restored. Both steps are now links in the [`GT-630`](./gap-reference-catalog.md#gt-630) derived-artifact chain, which enforces the recapture→rebuild order as data instead of prose. **How it actually landed, recorded because three sessions converged on it:** the capture script and the extracted triage reached `main` as PR #276, the two chain links as PR #287, and a SECOND, independent implementation of the same fix reached `develop` as PR #279 — an in-spec renderer driven by `UPDATE_EVALUABILITY_SNAPSHOT=1` rather than a standalone script. Both recaptured the same numbers, which is mutual corroboration of the measurement; but two generators for one artifact is the defect of this very row reproduced one level up, and reconciling them is open work that blocks `develop` → `main`. +- **Component:** `Governance` · **Criticality:** P1 · **Complexity:** S +- **Provenance:** Follow-on defect from [`GT-598`](./gap-reference-catalog.md#gt-598), found on 2026-07-29 while extending its mapping: the snapshot GT-598 built on was never captured by anything, and the guard over it was tautological. Registered separately because the finding is a guard-design class, not a correction to GT-598's mapping. +- **Acceptance criteria:** + - [x] The snapshot is produced by a script that runs Core's own triage instead of by hand, and `capture-native-evaluability-snapshot.mjs --check` re-derives it end to end. + - [x] No guard over the snapshot takes its expected value from the snapshot: one recomputes the triage, the other reads Core's counts out of the spec that pins them and fails loudly when it cannot find them. + - [x] The recapture→rebuild order is enforced as data — both links are declared in the `46-validate-derived-artifact-order` chain — and the mapping guard runs in a workflow, having run in none. + #### GT-632 **Title:** The compiled ABAC policy is resolved at a pre-refactor path, denying every MCP tool in production diff --git a/reference/core/control-center/gaps/gap-tracking.es.md b/reference/core/control-center/gaps/gap-tracking.es.md index 65235911..006eeecd 100644 --- a/reference/core/control-center/gaps/gap-tracking.es.md +++ b/reference/core/control-center/gaps/gap-tracking.es.md @@ -13,6 +13,9 @@ 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-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. | | | `Infra` | Cross | P1 | S | `PENDIENTE` | +| [`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` | | [`GT-632`](./gap-reference-catalog.es.md#gt-632) | **El MCP denegaba todas sus herramientas en producción por una ruta mal escrita, y la prueba de que funcionaba era estado local sin versionar.** `abac-evaluator.ts:322` resolvía la política compilada en `/sdk/cli/rulesets/opa/policy.wasm` — la ruta ANTERIOR al refactor `src/`. El fichero vive en `src/sdk/cli/…`. Cuando el stat falla, el evaluador deniega fail-closed en producción, así que en un checkout limpio con `NODE_ENV=production` la política compilada nunca se carga y TODA herramienta MCP se rechaza. Parecía verde porque `policy.wasm` está gitignorado: un fichero rancio dejado en la ruta vieja por una época anterior hacía que la carga funcionara en local, y el test que lo cubre pasaba contra un artefacto que ningún checkout fresco tendría. Misma forma que `GT-625` — un verde que dependía de estado no versionado — pero en el camino de autorización. Encontrado el 2026-07-29 investigando por qué `abac-rego-parity.spec.ts` se había puesto rojo; el rego era correcto (`opa eval` devuelve `allow: true` para un arquitecto en producción). **`40-validate-path-literals` no puede ver esta clase:** barre literales de cadena, y esto es una construcción `path.join(corePath, 'sdk', 'cli', …)`. Sobreviven doce joins así en `src/**` — los otros once están en `opa-input-builder.ts` y `cli-release-rule.handler.ts`, donde una ruta equivocada produce un falso NEGATIVO en un evaluador en vez de una denegación, que es más silencioso y no menos incorrecto. **CORREGIDO para el camino de autorización el 2026-07-29:** el evaluador prueba ahora ambas ubicaciones, la nueva primero — no es dejadez, es lo que mantiene funcionando una imagen ya desplegada mientras se corrige la ruta. Revertir el arreglo pone `abac-rego-parity.spec.ts` en rojo (1 de 11); con él, mcp-server va 434/434. Quedan los otros once joins y el punto ciego del guard. **Criterio 2 CERRADO el 2026-07-29 — y dos de las once estaban mal de una forma que el prefijo por sí solo no arreglaba.** Ocho eran supervivientes simples del movimiento a `src/` y admitieron el prefijo. Las otras tres eran peores: dos apuntaban a `sdk/cli/src/core/mcp/server.ts`, un fichero que salió del CLI por completo cuando mcp-server pasó a ser su propio paquete (hoy `src/packages/mcp-server/src/mcp/mcp-server.service.ts`); y una exigía un `package-lock.json` por paquete, cosa que los WORKSPACES de npm impiden — hay exactamente un lockfile, en la raíz, así que esa comprobación solo podía ser falsa. Una regla que nadie puede satisfacer no es una regla más estricta. **Las specs y las fixtures de paridad también codificaban el layout viejo** (`cli-release-readiness.fixture.json`, `mcp.fixture.json`), y por eso llevaban tiempo en verde sobre rutas que no existen: la fixture y el código coincidían entre sí y ninguno coincidía con el repositorio. Ambas corregidas. core-domain 1367/1367, `28-native-evaluator-parity` exit 0. **Criterio 3 CERRADO el 2026-07-29 — la primera corrida del guard estuvo casi toda equivocada, que es el hallazgo.** `47-validate-joined-paths` reportó 19 rutas rotas; solo 3 eran defectos. Cada una de las otras 16 habría empeorado el código: seis tenían base `root`, un PARÁMETRO que nombra el workspace del cliente, así que corregirlas rompería la evaluación de todos los satélites; nueve eran miembros de CADENAS DE FALLBACK correctas cuando uno de cuatro layouts resuelve, y la forma natural de callarlas es borrar los fallbacks, rompiendo imágenes desplegadas; una era una PROHIBICIÓN cuya ausencia ES el estado que aprueba, así que corregirla habría invertido la regla. Las cadenas se detectan ahora estructuralmente (hermanos de array, o las ramas de un ternario); las prohibiciones no pueden, y llevan razón escrita. Los tres defectos reales: `opa-evaluator.ts` resolvía `policy.wasm` y los esquemas de entrada sin el prefijo `src/`, misma clase fail-closed que el P0 de arriba; `satellite-upgrade-diff.ts` sondeaba `rulesets` detrás de un return temprano, reportando cero cambios de rulesets en cada upgrade de satélite; `artifact-path-resolver.ts` nombraba un `adr-matrix.json` que no existe en ningún layout. 11 fixtures negativas, los dos suelos anti-vacuos, y `43-validate-guard-negative-fixtures` lo OBSERVÓ en rojo sobre 36 guards. Una indulgencia conocida (dos joins como argumentos hermanos) queda anotada en su cabecera en vez de escondida. | | | `MCP Server` | Cross | P0 | M | `COMPLETADO` | | [`GT-631`](./gap-reference-catalog.es.md#gt-631) | **Extraído de [`GT-573`](./gap-reference-catalog.es.md#gt-573) para que su mitad cross-repo se siga en vez de absorberse en un cierre.** La mitad del Core del tercer criterio de GT-573 está hecha: `evaluation-context` y `evaluation-result` están fijados en `MACHINE_CONTRACT_SET` junto a `gate-evidence` y `output-envelope`, así que un cambio en cualquiera de esas formas ya rompe `10-validate-contract-conformance` en vez de llegar en silencio a los consumidores. Lo que queda está en otro repositorio y no se puede hacer desde aquí: el **Tracker** debe re-fijar esos dos esquemas en su propio `contracts/evolith-core-contracts.json` con su sha256, enlazar las tres fixtures publicadas (`EVALUATION_RESULT_PASS/FAIL/OPA_GATE_FAIL`) en un test de binding de DTOs, quitar o documentar `resolvedTopology` (que el resultado canónico nunca llevó), renombrar su `phase` de gate a `phaseId`, y eliminar su caída a `SKIPPED` para un payload que trae un `overallVerdict` no vacío. Hasta entonces, un cambio de forma del lado Core se caza aquí y sigue sorprendiendo al consumidor. | | | `Evolith Tracker` | Cross | P1 | S | `PENDIENTE` | | [`GT-630`](./gap-reference-catalog.es.md#gt-630) | **Los artefactos derivados tienen un ORDEN de dependencia y nada lo exigía — costó tres checks requeridos en rojo solo el 2026-07-28.** `generate-executive-summary.mjs` lee `maturity-reconciliation.json`, que a su vez se deriva del tablero de gaps. Generar el resumen ANTES de reconciliar captura un valor que el reconciliador está a punto de mover. El `--check` de cada artefacto pasa en ese momento — el resumen coincide de verdad con lo que se acaba de escribir — así que `ci-runner governance` sale verde en local y `Validate documentation` sale rojo en el runner, donde los pasos corren en el orden declarado. No es un fallo de artefacto rancio, que los `--check` individuales ya cazan; es un fallo de ORDEN, invisible para cualquier comprobación que mire un artefacto cada vez. La secuencia correcta (reconciliar → suite → generar → validar) no estaba escrita en ningún sitio del repositorio, que es la razón de que el mismo error se cometiera tres veces en una sesión por alguien a quien ya le había mordido dos. **CERRADO al registrarse.** La cadena es ahora DATOS en `46-validate-derived-artifact-order.mjs` — productor, qué consume, qué escribe — recorrida en orden de dependencia y cableada en `Validate documentation`. Informa del PRIMER eslabón rancio con el comando que lo arregla y las entradas que deben estar al día antes que él, porque un artefacto construido sobre entrada rancia no está mal por sí mismo. Escribir los tests acotó cuánto vale la pasada de punto fijo, y ese límite queda recogido en el guard: con generadores deterministas, la comprobación de orden ya la subsume; se gana su sitio ante un generador cuya salida no depende solo de sus entradas declaradas, que es el caso que ejercita el autotest. 8 autotests, cuatro de ellos anti-vacuos. Registrado en `guard-classification.mjs`; 58 guards clasificados, 35 vistos fallar. | | | `Governance` | Cross | P2 | S | `COMPLETADO` | @@ -647,7 +650,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:** 593 / 632 completados · 14 en progreso · 21 pendientes · 4 diferidos +**Progreso:** 595 / 635 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 e2205664..01d95fdf 100644 --- a/reference/core/control-center/gaps/gap-tracking.md +++ b/reference/core/control-center/gaps/gap-tracking.md @@ -13,6 +13,9 @@ 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-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. | | | `Infra` | Cross | P1 | S | `PENDING` | +| [`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` | | [`GT-632`](./gap-reference-catalog.md#gt-632) | **The MCP denied every tool in production from a path typo, and the evidence that it worked was untracked local state.** `abac-evaluator.ts:322` resolved the compiled policy at `/sdk/cli/rulesets/opa/policy.wasm` — the PRE-`src/`-refactor path. The file lives at `src/sdk/cli/…`. When the stat fails the evaluator denies fail-closed in production, so on a clean checkout with `NODE_ENV=production` the compiled policy never loads and EVERY MCP tool is refused. It looked green because `policy.wasm` is gitignored: a stale file left at the old path by an earlier era made the load succeed locally, and the test that covers it passed against an artifact no fresh checkout would have. Same shape as `GT-625` — a green that depended on untracked state — but on the authorization path. Found on 2026-07-29 while investigating why `abac-rego-parity.spec.ts` had gone red; the rego itself was correct (`opa eval` returns `allow: true` for an architect in production). **`40-validate-path-literals` cannot see this class:** it scans string literals, and this is a `path.join(corePath, 'sdk', 'cli', …)` construction. Twelve such joins survive the refactor across `src/**` — the other eleven are in `opa-input-builder.ts` and `cli-release-rule.handler.ts`, where a wrong path produces a false NEGATIVE in an evaluator rather than a denial, which is quieter and no less wrong. **FIXED for the authorization path on 2026-07-29:** the evaluator now tries both locations, newest first — not sloppiness, but what keeps an already-deployed image working while the path is corrected. Reverting the fix turns `abac-rego-parity.spec.ts` red (1 of 11); with it, mcp-server is 434/434. The other eleven joins and the guard blind spot remain. **Criterion 2 CLOSED 2026-07-29 — and two of the eleven were wrong in a way the prefix alone would not have fixed.** Eight were plain survivors of the `src/` move and took the prefix. The other three were worse: two pointed at `sdk/cli/src/core/mcp/server.ts`, a file that left the CLI entirely when mcp-server became its own package (now `src/packages/mcp-server/src/mcp/mcp-server.service.ts`); and one asserted a per-package `package-lock.json`, which npm WORKSPACES forbids — there is exactly one lockfile, at the root, so that check could only ever be false. A rule nobody can satisfy is not a stricter rule. **The specs and parity fixtures encoded the old layout too** (`cli-release-readiness.fixture.json`, `mcp.fixture.json`), which is why they had stayed green over paths that do not exist: the fixture and the code agreed with each other and neither agreed with the repository. Both are corrected. core-domain 1367/1367, `28-native-evaluator-parity` exit 0. **Criterion 3 CLOSED 2026-07-29 — the guard's first run was mostly wrong, which is the finding.** `47-validate-joined-paths` reported 19 broken paths; only 3 were defects. The other 16 would each have been made WORSE by a fix: six had base `root`, a PARAMETER naming the customer workspace under evaluation, so correcting them would break evaluation for every satellite; nine were members of FALLBACK CHAINS that are correct when one of four layouts resolves, and the natural way to silence those is to delete the fallbacks, breaking deployed images; one was a PROHIBITION whose absence IS the passing state, so correcting it would have inverted the rule. Chains are now detected structurally (array siblings, or the arms of a ternary); prohibitions cannot be, so they carry a written reason. The three real defects: `opa-evaluator.ts` resolved `policy.wasm` and the input schemas without the `src/` prefix, same fail-closed class as the P0 above; `satellite-upgrade-diff.ts` probed `rulesets` behind an early return, reporting zero ruleset changes on every satellite upgrade; `artifact-path-resolver.ts` named an `adr-matrix.json` present in no layout. 11 negative fixtures, both anti-vacuous floors, and `43-validate-guard-negative-fixtures` OBSERVED it red across 36 guards. A known leniency (two joins as sibling arguments) is recorded in its header rather than hidden. | | | `MCP Server` | Cross | P0 | M | `DONE` | | [`GT-631`](./gap-reference-catalog.md#gt-631) | **Carved out of [`GT-573`](./gap-reference-catalog.md#gt-573) so its cross-repo half is tracked rather than absorbed into a closure.** The Core half of GT-573's third criterion is done: `evaluation-context` and `evaluation-result` are pinned in `MACHINE_CONTRACT_SET` alongside `gate-evidence` and `output-envelope`, so a change to either shape now fails `10-validate-contract-conformance` instead of silently reaching consumers. What remains is in another repository and cannot be done from here: the **Tracker** must re-pin those two schemas in its own `contracts/evolith-core-contracts.json` with their sha256, bind the three published fixtures (`EVALUATION_RESULT_PASS/FAIL/OPA_GATE_FAIL`) in a DTO binding test, drop or document `resolvedTopology` (which the canonical result never carried), rename its gate `phase` to `phaseId`, and delete its fall-through to `SKIPPED` for a payload carrying a non-blank `overallVerdict`. Until it does, a Core-side shape change is caught here and still surprises the consumer. | | | `Evolith Tracker` | Cross | P1 | S | `PENDING` | | [`GT-630`](./gap-reference-catalog.md#gt-630) | **Derived artifacts have a dependency ORDER and nothing enforced it — it cost three red required checks on 2026-07-28 alone.** `generate-executive-summary.mjs` reads `maturity-reconciliation.json`, which is itself derived from the gap board. Generate the summary BEFORE reconciling and it captures a value the reconciler is about to move. Each artifact's own `--check` then passes at that moment — the summary genuinely matches what was just written — so `ci-runner governance` goes green locally and `Validate documentation` goes red on the runner, where the steps run in the declared order. That is not a stale-artifact bug, which the individual `--check` modes already catch; it is an ORDER bug, invisible to any check that looks at one artifact at a time. The correct sequence (reconcile → suite → generate → validate) was written down nowhere in the repository, which is why the same mistake was made three times in one session by someone who had already been bitten by it twice. **CLOSED on registration.** The chain is now DATA in `46-validate-derived-artifact-order.mjs` — producer, what it consumes, what it writes — walked in dependency order, wired into `Validate documentation`. It reports the FIRST stale link with the command that fixes it and the inputs that must be current before it, because an artifact built on stale input is not independently wrong. Writing the tests bounded what the fixed-point pass is worth, and the bound is recorded in the guard: with deterministic generators, currency-in-order already subsumes it; it earns its place on a generator whose output does not depend only on its declared inputs, which is the case the self-test exercises. 8 self-tests, four of them anti-vacuous. Registered in `guard-classification.mjs`; 58 guards classified, 35 observed failing. | | | `Governance` | Cross | P2 | S | `DONE` | @@ -647,7 +650,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:** 593 / 632 done · 14 in progress · 21 pending · 4 deferred +**Progress:** 595 / 635 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 d372f522..318a8f71 100644 --- a/reference/core/control-center/maturity-reports/executive-summary.es.md +++ b/reference/core/control-center/maturity-reports/executive-summary.es.md @@ -27,8 +27,8 @@ La forma correcta de usar este resumen es simple: si necesitas contexto, abre so |---:|---|---|---| | 1 | Bloqueadores P0 | Impiden afirmar readiness productivo o release mayor. | [GT-602](../gaps/gap-reference-catalog.es.md#gt-602), [GT-603](../gaps/gap-reference-catalog.es.md#gt-603), [GT-604](../gaps/gap-reference-catalog.es.md#gt-604), [GT-435](../gaps/gap-reference-catalog.es.md#gt-435) | | 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 | +| 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), [GT-634](../gaps/gap-reference-catalog.es.md#gt-634) | +| 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-634](../gaps/gap-reference-catalog.es.md#gt-634), [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), +7 | | 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 | ## Bloqueadores Actuales @@ -45,23 +45,23 @@ 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 | 632 | -| Gaps cerrados | 593 | -| Gaps pendientes | 39 | +| Gaps totales | 635 | +| Gaps cerrados | 595 | +| Gaps pendientes | 40 | | P0 abiertos | 4 | -| P1 abiertos | 14 | +| P1 abiertos | 15 | | P2 abiertos | 18 | -| Cierre total | 93.8% | -| Registros de evidencia de cierre | 575 | +| Cierre total | 93.7% | +| Registros de evidencia de cierre | 577 | | Readiness registrado | 4 PASS | | Área | Pendientes | P0 | P1 | Primeros IDs | |---|---:|---:|---:|---| | `Evolith Core` | 8 | 0 | 2 | [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), +4 | +| `Infra` | 5 | 0 | 3 | [GT-597](../gaps/gap-reference-catalog.es.md#gt-597), [GT-634](../gaps/gap-reference-catalog.es.md#gt-634), [GT-324](../gaps/gap-reference-catalog.es.md#gt-324), [GT-622](../gaps/gap-reference-catalog.es.md#gt-622), +1 | | `Cross` | 2 | 1 | 1 | [GT-435](../gaps/gap-reference-catalog.es.md#gt-435), [GT-448](../gaps/gap-reference-catalog.es.md#gt-448) | | `Evolith MCP` | 2 | 1 | 1 | [GT-602](../gaps/gap-reference-catalog.es.md#gt-602), [GT-606](../gaps/gap-reference-catalog.es.md#gt-606) | | `Evolith Suite` | 2 | 1 | 1 | [GT-604](../gaps/gap-reference-catalog.es.md#gt-604), [GT-605](../gaps/gap-reference-catalog.es.md#gt-605) | -| `Evolith Tracker` | 2 | 1 | 1 | [GT-603](../gaps/gap-reference-catalog.es.md#gt-603), [GT-631](../gaps/gap-reference-catalog.es.md#gt-631) | ## Fuente y Regla de Actualización diff --git a/reference/core/control-center/maturity-reports/executive-summary.md b/reference/core/control-center/maturity-reports/executive-summary.md index e8d146c8..f73b17da 100644 --- a/reference/core/control-center/maturity-reports/executive-summary.md +++ b/reference/core/control-center/maturity-reports/executive-summary.md @@ -27,8 +27,8 @@ Use this summary with a simple rule: if you need context, open only the linked I |---:|---|---|---| | 1 | P0 blockers | They prevent production-readiness or major-release confidence. | [GT-602](../gaps/gap-reference-catalog.md#gt-602), [GT-603](../gaps/gap-reference-catalog.md#gt-603), [GT-604](../gaps/gap-reference-catalog.md#gt-604), [GT-435](../gaps/gap-reference-catalog.md#gt-435) | | 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 | +| 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), [GT-634](../gaps/gap-reference-catalog.md#gt-634) | +| 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-634](../gaps/gap-reference-catalog.md#gt-634), [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), +7 | | 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 | ## Current Blockers @@ -45,23 +45,23 @@ 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 | 632 | -| Closed gaps | 593 | -| Open gaps | 39 | +| Total gaps | 635 | +| Closed gaps | 595 | +| Open gaps | 40 | | Open P0 | 4 | -| Open P1 | 14 | +| Open P1 | 15 | | Open P2 | 18 | -| Total closure | 93.8% | -| Closure evidence records | 575 | +| Total closure | 93.7% | +| Closure evidence records | 577 | | Recorded readiness | 4 PASS | | Area | Open | P0 | P1 | First IDs | |---|---:|---:|---:|---| | `Evolith Core` | 8 | 0 | 2 | [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), +4 | +| `Infra` | 5 | 0 | 3 | [GT-597](../gaps/gap-reference-catalog.md#gt-597), [GT-634](../gaps/gap-reference-catalog.md#gt-634), [GT-324](../gaps/gap-reference-catalog.md#gt-324), [GT-622](../gaps/gap-reference-catalog.md#gt-622), +1 | | `Cross` | 2 | 1 | 1 | [GT-435](../gaps/gap-reference-catalog.md#gt-435), [GT-448](../gaps/gap-reference-catalog.md#gt-448) | | `Evolith MCP` | 2 | 1 | 1 | [GT-602](../gaps/gap-reference-catalog.md#gt-602), [GT-606](../gaps/gap-reference-catalog.md#gt-606) | | `Evolith Suite` | 2 | 1 | 1 | [GT-604](../gaps/gap-reference-catalog.md#gt-604), [GT-605](../gaps/gap-reference-catalog.md#gt-605) | -| `Evolith Tracker` | 2 | 1 | 1 | [GT-603](../gaps/gap-reference-catalog.md#gt-603), [GT-631](../gaps/gap-reference-catalog.md#gt-631) | ## Source and Refresh Rule diff --git a/reference/core/control-center/maturity-reports/maturity-reconciliation.json b/reference/core/control-center/maturity-reports/maturity-reconciliation.json index dc32aa02..d0ea1559 100644 --- a/reference/core/control-center/maturity-reports/maturity-reconciliation.json +++ b/reference/core/control-center/maturity-reports/maturity-reconciliation.json @@ -3,14 +3,14 @@ "scope": "evolith-core", "asOf": "2026-07-26", "gaps": { - "total": 632, - "done": 593, - "pending": 21, + "total": 635, + "done": 595, + "pending": 22, "inProgress": 14, "deferred": 4 }, "evidence": { - "closureRecords": 575, + "closureRecords": 577, "cliPackage": "@beyondnet/evolith-cli@1.2.2", "adrCount": 139, "rulesetCount": 175,