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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions reference/core/control-center/gaps/gap-reference-catalog.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -7424,6 +7424,36 @@ Serie histórica de gaps registrada en el antiguo `gap-analysis-core.es.md`, pre
**Referencias:** src/apps/core-api/src/presentation/dtos/evaluation.dto.ts; src/apps/core-api/src/main.ts (ValidationPipe); src/packages/core-domain/src/evaluation/contracts/evaluation-context.ts; bloquea el criterio 2 de CP-04 en `evolith_tracker`.
- **Principal:** `S` · **Interés:** `LOW` · **Base:** `estimate`

#### GT-654

**Title:** Las tres superficies no coinciden en la forma de `/health`

- **Purpose / Problem:** `core-api` responde con el sobre ADR-0073 — `{success, data: {status: "OK", timestamp, service}, meta: {...}}`. `mcp` responde un objeto plano `{"status":"ok","transport":"http","protocol":"mcp","probe":"health"}`. `agent-runtime` responde otro plano `{"status":"ok","service":"agent-runtime-api","version":"0.1.0","uptimeSeconds":88}`. Tres servicios de un mismo producto, tres formas, y el literal del veredicto además cambia de caja (`OK` vs `ok`).
- **What it means:** cualquiera que sondee las tres tiene que tratar cada una como un caso especial. Un comprobador escrito contra el sobre del Core lee `data.status` y no encuentra nada en las otras dos; uno escrito contra la forma plana lee `status` y no encuentra nada en el Core. No es hipotético: esta misma divergencia produjo un fallo falso el 2026-08-03, cuando una sonda cross-cluster casó `"status":"ok"` literalmente y reportó como inalcanzables dos servicios que estaban sirviendo.
- **Component:** `Evolith Core` · **Criticality:** P2 · **Complexity:** S
- **Provenance:** Medido el 2026-08-03 contra los tres servicios desplegados en un clúster kind, leyendo las respuestas vivas en sus node ports en vez del código.
- **Principal:** `S` · **Interés:** `LOW` · **Base:** `estimate`
- **Esto es una DECISIÓN antes que un trabajo.** El sobre es el contrato declarado del Core, así que la respuesta obvia es que las tres lo adopten. La respuesta obvia no sale gratis: `/health` es lo que leen una sonda de Kubernetes y un balanceador, y hoy están configurados contra una forma. Vaya como vaya, la resolución es una decisión escrita y luego las superficies obedeciéndola — no tres servicios convergiendo por su cuenta.
- **Acceptance criteria:**
- [ ] Una decisión registra qué forma usa `/health` en las tres superficies, y por qué, incluyendo qué implica para las sondas desplegadas.
- [ ] Las tres superficies responden esa forma, verificado contra respuestas vivas y no contra el código.
- [ ] Una comprobación contrasta las tres, para que la siguiente superficie que se añada no pueda inventar una cuarta forma.

#### GT-655

**Title:** Cuatro operaciones declaradas en las tres superficies no las ha invocado nunca ninguna prueba

- **Purpose / Problem:** `satellite-create`, `pattern-list`, `pattern-get` y `pattern-list-by-topology` están declaradas `exposed: true` en CLI, MCP y REST en la matriz de paridad, y el arnés de exploración cross-superficie **no tiene binding** para ninguna — 48 de 73 operaciones lo llevan; estas cuatro no. Ninguna invocación ha llegado nunca a ellas, en ninguna superficie.
- **What it means:** la matriz afirma que existen en tres superficies y nada les ha pedido nunca que lo demuestren. Es justo la clase que el arnés se construyó para cerrar, y el arnés las reporta honestamente en `uncoveredTriangleOps` en vez de redondearlas — pero reportar no es cubrir.
- **`satellite-create` es la que importa.** Aprovisiona un repositorio real de GitHub y escribe el registro local (`satellite-create.tool.ts:219`), así que es a la vez la de más consecuencia de las cuatro y la razón de que el binding no sea trivial: ejercitarla exige un efecto que el arnés pueda deshacer, o un camino de dry-run del que pueda fiarse.
- **Component:** `Evolith Core` · **Criticality:** P2 · **Complexity:** M
- **Provenance:** `src/tests/exploration/.out/coverage.json` del 2026-08-04, `uncoveredTriangleOps`, re-medido tras relanzar la suite con `npm run test:exploration`.
- **Principal:** `M` · **Interés:** `LOW` · **Base:** `estimate`
- **Acceptance criteria:**
- [ ] Las tres de solo lectura (`pattern-list`, `pattern-get`, `pattern-list-by-topology`) llevan binding y se invocan en las tres superficies.
- [ ] `satellite-create` lleva binding con un camino deshacible o de dry-run, o la matriz registra por qué queda exenta — una operación no comprobable que no dice nada de sí misma es peor que una declarada no comprobable.
- [ ] `uncoveredTriangleOps` está vacío, o cada entrada restante tiene una razón escrita.

#### GT-653

**Title:** La detección de secretos no puede bloquear, y en los PR de Dependabot nunca corre
Expand Down
30 changes: 30 additions & 0 deletions reference/core/control-center/gaps/gap-reference-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7519,6 +7519,36 @@ Historical gap series tracked in the former `gap-analysis-core.md`, preserved fo
**References:** src/apps/core-api/src/presentation/dtos/evaluation.dto.ts; src/apps/core-api/src/main.ts (ValidationPipe); src/packages/core-domain/src/evaluation/contracts/evaluation-context.ts; blocks `evolith_tracker` CP-04 criterion 2.
- **Principal:** `S` · **Interest:** `LOW` · **Basis:** `estimate`

#### GT-654

**Title:** The three surfaces disagree on the shape of `/health`

- **Purpose / Problem:** `core-api` answers the ADR-0073 envelope — `{success, data: {status: "OK", timestamp, service}, meta: {...}}`. `mcp` answers a bare `{"status":"ok","transport":"http","protocol":"mcp","probe":"health"}`. `agent-runtime` answers a bare `{"status":"ok","service":"agent-runtime-api","version":"0.1.0","uptimeSeconds":88}`. Three services of one product, three shapes, and the verdict literal differs in case as well (`OK` vs `ok`).
- **What it means:** anything that probes all three has to special-case each one. A health checker written against the Core's envelope reads `data.status` and finds nothing on the other two; one written against the bare shape reads `status` and finds nothing on the Core. That is not hypothetical — this exact divergence produced a false failure on 2026-08-03, when a cross-cluster probe matched `"status":"ok"` literally and reported two healthy services as unreachable while they were serving.
- **Component:** `Evolith Core` · **Criticality:** P2 · **Complexity:** S
- **Provenance:** Measured on 2026-08-03 against all three services deployed to a kind cluster, reading the live responses on their node ports rather than the source.
- **Principal:** `S` · **Interest:** `LOW` · **Basis:** `estimate`
- **This is a DECISION before it is work.** The envelope is the Core's stated contract, so the obvious answer is that all three adopt it. The obvious answer is not free: `/health` is what a Kubernetes probe and a load balancer read, and those are configured against a shape today. Whichever way it goes, the resolution is a written decision followed by the surfaces obeying it — not three services quietly converging.
- **Acceptance criteria:**
- [ ] A decision records which shape `/health` uses across the three surfaces, and why, including what it means for the deployed probes.
- [ ] The three surfaces answer that shape, verified against live responses rather than source.
- [ ] A check contrasts the three, so the next surface added cannot invent a fourth shape.

#### GT-655

**Title:** Four operations declared on all three surfaces have never been invoked by any test

- **Purpose / Problem:** `satellite-create`, `pattern-list`, `pattern-get` and `pattern-list-by-topology` are declared `exposed: true` on CLI, MCP and REST in the surface-parity matrix, and the cross-surface exploration harness has **no binding** for any of them — 48 of 73 operations carry one; these four do not. No invocation has ever reached them, on any surface.
- **What it means:** the parity matrix asserts they exist on three surfaces and nothing has ever asked them to prove it. That is precisely the class the exploration harness was built to close, and the harness reports them honestly in `uncoveredTriangleOps` rather than rounding them away — but reporting is not covering.
- **`satellite-create` is the one that matters.** It provisions a live GitHub repository and writes the local registry (`satellite-create.tool.ts:219`), so it is both the most consequential of the four and the reason a binding is not trivial: exercising it needs an effect the harness can undo, or a dry-run path it can trust.
- **Component:** `Evolith Core` · **Criticality:** P2 · **Complexity:** M
- **Provenance:** `src/tests/exploration/.out/coverage.json` on 2026-08-04, `uncoveredTriangleOps`, re-measured after the suite was re-run through `npm run test:exploration`.
- **Principal:** `M` · **Interest:** `LOW` · **Basis:** `estimate`
- **Acceptance criteria:**
- [ ] The three read-only ones (`pattern-list`, `pattern-get`, `pattern-list-by-topology`) carry a binding and are invoked on all three surfaces.
- [ ] `satellite-create` either carries a binding with an undoable or dry-run path, or the matrix records why it is exempt — an untestable operation that says nothing about itself is worse than one declared untestable.
- [ ] `uncoveredTriangleOps` is empty, or every remaining entry has a written reason.

#### GT-653

**Title:** Secret detection cannot block, and never runs on Dependabot PRs
Expand Down
4 changes: 3 additions & 1 deletion reference/core/control-center/gaps/gap-tracking.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -666,9 +666,11 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida
| [`GT-651`](./gap-reference-catalog.es.md#gt-651) | **La mitad de adaptadores de marketplace de `GT-532`, separada para que su cierre no la sepulte.** `GT-532` se cerró por sus dos criterios de aceptación —vistas de portafolio y paquetes de gobernanza por tenant, ambos ya ciertos— pero su TÍTULO nombraba además adaptadores estilo marketplace, que los criterios nunca pidieron y que no se entregaron. Se registra aparte en vez de dejarla dentro de una fila cerrada, porque una intención no dicha dentro de un `DONE` es justo la obsolescencia que este tablero sigue encontrando. **Deliberadamente sin acotar:** qué es un marketplace de adaptadores para Evolith —un catálogo de conectores de proveedor, un canal de distribución de paquetes de gobernanza, o ambos— es una decisión de producto, y adivinarla aquí produciría criterios de aceptación que nadie ha acordado. | `Tracker` | Cross | P3 | L | `PENDIENTE` |
| [`GT-652`](./gap-reference-catalog.es.md#gt-652) | **El cable no puede llevar cinco campos que el motor lee, y una nota de cierre ya llamaba al DTO «full canonical mirror».** `main.ts` corre el ValidationPipe global con `forbidNonWhitelisted: true`, así que un campo ausente de `EvaluationContextDto` no llega recortado: hace 400 la evaluación entera. Y el controlador hace `body as unknown as EvaluationContext`, un cast directo, lo que convierte esa clase en la superficie ALCANZABLE del contrato. `requester`, `repositoryRevision`, `qualitySignals`, `repoFacts` y `baselineRepoFacts` están declarados en `EvaluationContext` y el dominio los consume hoy, y ninguno se podía enviar. **Por qué nadie lo vio:** cada prueba unitaria construye un `EvaluationContext` en TypeScript y pasa, mientras que un llamante real que mande ese mismo objeto por HTTP es rechazado — el defecto es invisible desde dentro del Core y sólo lo sufre un consumidor. Es lo que bloquea el criterio 2 de CP-04 en `evolith_tracker`. **Qué significa:** el motor sabe leer cinco datos que la puerta de entrada se niega a aceptar. **Ejemplo:** el Tracker no puede decirle al Core quién pidió una evaluación ni qué revisión juzgó, así que ambos hechos viajan como cadenas sin tipo en una bolsa de paso. | `Evolith Core` | Cross | P1 | S | `COMPLETADO` |
| [`GT-653`](./gap-reference-catalog.es.md#gt-653) | **La detección de secretos es estructuralmente incapaz de detener nada, y en los PR de Dependabot directamente no corre.** El job `secret-detection` de `sdk-cli-ci.yml` lleva `continue-on-error: true` y no está entre los siete contextos requeridos de `main` ni de `develop`, así que una fuga real aparece como una marca roja que ninguna compuerta consulta. La segunda mitad es más estrecha y se midió: el secreto `GITLEAKS_LICENSE` existe en el almacén de Actions, pero el **almacén de secretos de Dependabot está vacío**, y las corridas disparadas por Dependabot solo leen ese almacén — así que la licencia llega en blanco y el paso falla antes de escanear. **Por qué nadie lo vio:** en `develop`, `main` y ramas humanas el job está verde (últimas 8 corridas), que es justo donde nadie buscaba el agujero; el fallo solo asoma en los PR de Dependabot, la única clase de cambio que escribe un actor externo automatizado. **Qué significa:** la superficie que más merece un escaneo independiente de secretos es la única que nunca se escanea, y donde sí escanea no puede bloquear. **Ejemplo:** los PR #370–#374 se mergearon el 2026-08-03 con `Secret Detection (gitleaks)` fallando en los cinco; ninguna compuerta objetó, correctamente, porque ninguna está cableada para hacerlo. **ARREGLO (2026-08-03):** la dependencia de licencia desaparece en vez de satisfacerse — el job instala el binario pineado de gitleaks (MIT; solo el envoltorio de la action exigía licencia) y corre `gitleaks dir . --no-banner --redact --exit-code 1`, así que el punto ciego de Dependabot no puede reabrirse y no hace falta ningún secreto de admin. `continue-on-error` retirado. El guard `60-validate-secret-scan-gate.mjs` corre en cada corrida: extrae el comando del workflow, planta una credencial y exige exit 1, y exige que un árbol limpio salga 0. Su primera versión plantaba el canónico `AKIAIOSFODNN7EXAMPLE`, que gitleaks lleva como stopword — pasó sin haber visto nunca bloquear la compuerta, el mismo defecto reproducido dentro de su propia prueba. Los 15 hallazgos preexistentes eran todos sintéticos (fixtures de las pruebas de redacción y ejemplos `curl` de README) y quedan fijados en `.gitleaksignore` por huella, no por ruta. **Pendiente:** la promoción a contexto requerido en `main`/`develop`, retenida hasta que el job reporte verde en ambas — activarla antes dejaría bloqueado todo PR abierto, como pasó con el PR #218. | `Security` | Cross | P2 | S | `COMPLETADO` |
| [`GT-654`](./gap-reference-catalog.es.md#gt-654) | **Tres servicios de un mismo producto responden `/health` en tres formas.** `core-api` devuelve el sobre ADR-0073 (`data.status = "OK"`); `mcp` y `agent-runtime` devuelven objetos planos (`status = "ok"`) — cambia el anidamiento y también la caja. **Qué significa:** quien sondee las tres trata cada una como caso especial, y una sonda escrita contra cualquiera de las formas reporta las otras dos como rotas. **Ejemplo:** el 2026-08-03 una sonda cross-cluster casó `"status":"ok"` literalmente y reportó como inalcanzables dos servicios que estaban sirviendo. **Es una decisión antes que un trabajo:** el sobre es el contrato declarado del Core, pero `/health` es lo que lee una sonda de Kubernetes y hoy están configuradas contra la forma actual. | `Evolith Core` | Cross | P2 | S | `PENDIENTE` |
| [`GT-655`](./gap-reference-catalog.es.md#gt-655) | **Cuatro operaciones declaradas en las tres superficies no las ha invocado nunca ninguna prueba.** `satellite-create`, `pattern-list`, `pattern-get` y `pattern-list-by-topology` están `exposed: true` en CLI, MCP y REST, y el arnés de exploración no tiene binding para ninguna — 48 de 73 operaciones lo llevan. **Qué significa:** la matriz de paridad afirma que existen en tres superficies y nada les ha pedido nunca demostrarlo; el arnés las reporta en `uncoveredTriangleOps` en vez de redondearlas, pero reportar no es cubrir. **`satellite-create` es la difícil:** aprovisiona un repo real de GitHub y escribe el registro, así que su binding exige un camino deshacible o de dry-run. | `Evolith Core` | Cross | P2 | M | `PENDIENTE` |


**Progreso:** 637 / 651 completados · 3 en progreso · 4 pendientes · 7 diferidos
**Progreso:** 637 / 653 completados · 3 en progreso · 6 pendientes · 7 diferidos

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

Expand Down
Loading
Loading