From f6fbdc39bbd1e94ad8111b8af506e5638387eea3 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 19:26:17 -0500 Subject: [PATCH 01/40] =?UTF-8?q?docs(board):=20cerrar=20GAP-020=20?= =?UTF-8?q?=E2=80=94=20el=20trabajo=20esta=20hecho=20y=20la=20fila=20segui?= =?UTF-8?q?a=20abierta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Actualice la seccion de detalle al hacer el trabajo y me deje el ESTADO, tanto en la fila del registro maestro como en la cabecera de la ficha. Una fila que reclama trabajo ya hecho desvia las prioridades de la semana siguiente, que es exactamente lo que he corregido tres veces hoy en el board del Core. `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` enlaza los 14 artefactos que publican esquema canonico a su `$id`, lista los 3 que son salida de herramienta y nombra los 7 que no tienen ninguno. Aguas arriba, `evolith_arch32#378` llevo la cobertura de 10 a 17 de 24 y arreglo las rutas `schemaRef` rotas. Marcar la fila como resuelta obliga a REORDENAR: el validador exige el orden BLOCKED → OPEN → DEFERRED → RESOLVED, y GAP-020 estaba en el septimo puesto, entre las abiertas. Se reordena de forma estable —conservando el orden relativo dentro de cada grupo— y se renumera la columna `#`. Verificado que el registro no perdio nada: mismos 107 IDs antes y despues, mismo conjunto exacto, cero duplicados. Resultado: 13 OPEN, 1 DEFERRED, 93 RESOLVED. `validate-docs` pasa sobre 359 ficheros; `check-bilingual-parity`, `doc-inventory --check` y `check-gap-registry` (203 fichas / 203 filas) en verde. Co-Authored-By: Claude Opus 5 --- .../tracker-gaps-opportunities-tracking.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 75db4800..ba549280 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -31,15 +31,15 @@ This document is the only operational gap register in this repository. The maste | 4 | 🟡 OPEN | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 5 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 6 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟡 OPEN | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 8 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 9 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 10 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 11 | 🟡 OPEN | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Pending owner/action definition in this register. | 🟡 | 🟡 | -| 12 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 13 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 14 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | -| 15 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 7 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 8 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 9 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 10 | 🟡 OPEN | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Pending owner/action definition in this register. | 🟡 | 🟡 | +| 11 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 12 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 13 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | +| 14 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 15 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Resolved 2026-08-01: `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that publish a canonical schema to its `$id`, lists the 3 that are tool output, and names the 7 with none. Upstream `evolith_arch32#378` took coverage from 10 to 17 of 24 and fixed the broken `schemaRef` paths. | 🟡 MEDIUM | 🟡 MEDIUM | | 16 | 🟢 RESOLVED | [COH-002](#detail-coh-002) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006,007 | Discovery refinement entity has no persisted `status` column. States DRAFT/IN_REFINEMENT/SPLIT referenced in specs cannot be persisted; DDD model also missing the status field. | Resolved / Obsolete: El proceso de partición y refinamiento queda fuera del alcance de Tracker; las iniciativas sólo entran cuando están listas. | 🟢 LOW | 🟢 LOW | | 17 | 🟢 RESOLVED | [COH-004](#detail-coh-004) | INCO | Source incoherence | Backend | QA | US-QA-001..004,006,008,011 | "TestRun" used in 7 stories but NOT in DDD model. DDD defines TestCycle (container) + TestExecution (atomic). TestCycle Aggregate Root never used by any story. | Resolved: TestCycle/TestExecution es el estándar canónico oficial; TestRun se depreca por ambiguo. Glosario actualizado. Historias asumen TestCycle. | 🔴 | 🔴 | | 18 | 🟢 RESOLVED | [GAP-019](#detail-gap-019) | Docs | Documentation gap | Docs | Docs | N/A | Discovery requirements not broken down into implementable detail | Resolved: Se creó `docs/design/discovery-functional-specs.md` extrayendo las reglas de negocio, máquina de estados y cadenas de aprobación directamente del modelo DDD (Initiative.cs). | 🔴 HIGH | 🟡 MEDIUM | @@ -412,7 +412,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-020 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs From 758bdeff85c55d95d8084c4442659098db0601cd Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 19:30:22 -0500 Subject: [PATCH 02/40] docs(board): COH-005 estaba resuelta por decision desde julio y la fila nunca se movio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No es una refutacion parcial: es un gap CERRADO POR SUPERSESION con ADR aceptado. `T-047` (Aceptado 2026-07-19) ratifica la topologia consolidada de cuatro esquemas, supersede a `T-028` (schema-per-context, 10 esquemas) y **nombra a COH-005 entre los gaps que cierra**, en su propio frontmatter. Nadie movio la fila. `tracker_audit` no se creo A PROPOSITO. Los agregados de auditoria viven en `tracker_governance`, donde funcionan: `audit_entries` se consulta en produccion, `GT-603` tipo su actor, y `GT-588` le enchufo hoy los statements firmados de transparencia. El propio diseno de datos lo dice, y esto es lo que convierte la ficha en un malentendido y no en una discrepancia: sus secciones 3-12 son «the original 2026-06-07 TARGET design ... kept for traceability only ... read them as intent, never as a description of the database». No faltaba capacidad. Un documento y el codigo discrepaban, y el ADR ya habia decidido cual gana. Mover una tabla que funciona, con datos de produccion y un ledger firmado encima, para satisfacer un diagrama que su propio documento etiqueta como intencion, seria trabajo al reves. Marcarla resuelta obliga a reordenar (BLOCKED → OPEN → DEFERRED → RESOLVED). Se reordena de forma estable y se renumera. Verificado que no se pierde nada: mismos 107 IDs, mismo conjunto exacto, cero duplicados. Resultado: 12 OPEN, 1 DEFERRED, 94 RESOLVED. Verificado: `validate-docs` sobre 359 ficheros y `check-gap-registry` en verde. Co-Authored-By: Claude Opus 5 --- docs/audit/tracker-gaps-opportunities-tracking.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index ba549280..08c237c8 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -34,11 +34,11 @@ This document is the only operational gap register in this repository. The maste | 7 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 8 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 9 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 10 | 🟡 OPEN | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Pending owner/action definition in this register. | 🟡 | 🟡 | -| 11 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 12 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 13 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | -| 14 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 10 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 11 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 12 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | +| 13 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 14 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | | 15 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Resolved 2026-08-01: `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that publish a canonical schema to its `$id`, lists the 3 that are tool output, and names the 7 with none. Upstream `evolith_arch32#378` took coverage from 10 to 17 of 24 and fixed the broken `schemaRef` paths. | 🟡 MEDIUM | 🟡 MEDIUM | | 16 | 🟢 RESOLVED | [COH-002](#detail-coh-002) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006,007 | Discovery refinement entity has no persisted `status` column. States DRAFT/IN_REFINEMENT/SPLIT referenced in specs cannot be persisted; DDD model also missing the status field. | Resolved / Obsolete: El proceso de partición y refinamiento queda fuera del alcance de Tracker; las iniciativas sólo entran cuando están listas. | 🟢 LOW | 🟢 LOW | | 17 | 🟢 RESOLVED | [COH-004](#detail-coh-004) | INCO | Source incoherence | Backend | QA | US-QA-001..004,006,008,011 | "TestRun" used in 7 stories but NOT in DDD model. DDD defines TestCycle (container) + TestExecution (atomic). TestCycle Aggregate Root never used by any story. | Resolved: TestCycle/TestExecution es el estándar canónico oficial; TestRun se depreca por ambiguo. Glosario actualizado. Historias asumen TestCycle. | 🔴 | 🔴 | @@ -481,7 +481,7 @@ This document is the only operational gap register in this repository. The maste ### Detail COH-005 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** GAP (Missing capability / corrective gap) - **Component:** Infra - **Module:** Infra @@ -489,7 +489,7 @@ This document is the only operational gap register in this repository. The maste - **Criticality:** 🟡 - **Complexity:** 🟡 - **Description:** Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. -- **Next Step:** Define owner and remediation action before execution. +- **Next Step:** None — closed by `T-047`. Moving a working table, with production data and a signed transparency ledger on top of it, to satisfy a diagram that its own document labels «intent, never a description of the database», would be work in reverse. [Back to master register](#master-register) From e04f6184322099bb5a896856d6e1344c90dfd168 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 19:34:49 -0500 Subject: [PATCH 03/40] =?UTF-8?q?docs(board):=20COH-008=20esta=20refutada?= =?UTF-8?q?=20=E2=80=94=20el=20agregado=20que=20dice=20que=20no=20existe,?= =?UTF-8?q?=20existe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La ficha afirma que `DeploymentRecord` «NEVER created by any story» y que UC-005b («records a DeploymentRecord») no se puede cumplir. Comprobado contra el codigo el 2026-08-01, las dos afirmaciones son falsas: agregado Tracker.Domain/Release/DeploymentRecord — Start, Finish, RollBack tabla tracker_release.deployment_records endpoints POST /, POST /{id}/finish, POST /{id}/rollback tests ConstructionReleaseTests De modo que UC-005b es cumplible hoy. La fila describe un estado del repositorio que dejo de ser cierto hace tiempo y nadie la movio. Es la tercera ficha de esta sesion que reclama trabajo ya hecho — GT-588 criterio 3, COH-005 y ahora esta. No es casualidad: el board recoge hallazgos de auditoria y nada los vuelve a contrastar con el codigo, asi que envejecen en silencio y siguen dirigiendo prioridades. Se deja en la ficha el comando con el que se comprueba antes de reabrirla. Marcarla resuelta obliga a reordenar; se reordena de forma estable y se renumera. Verificado: mismos 107 IDs, mismo conjunto. Resultado 11 OPEN, 1 DEFERRED, 95 RESOLVED. Verificado: `validate-docs` sobre 359 ficheros y `check-gap-registry` en verde. Co-Authored-By: Claude Opus 5 --- .../tracker-gaps-opportunities-tracking.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 08c237c8..111aedaa 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,19 +25,19 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | Pending owner/action definition in this register. | 🟡 | 🟡 | -| 2 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 5 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 6 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 8 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 9 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 10 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 11 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 12 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | -| 13 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 2 | 🟡 OPEN | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 3 | 🟡 OPEN | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 6 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 7 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 8 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 9 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 10 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 11 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | +| 12 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 13 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | | 14 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | | 15 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Resolved 2026-08-01: `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that publish a canonical schema to its `$id`, lists the 3 that are tool output, and names the 7 with none. Upstream `evolith_arch32#378` took coverage from 10 to 17 of 24 and fixed the broken `schemaRef` paths. | 🟡 MEDIUM | 🟡 MEDIUM | | 16 | 🟢 RESOLVED | [COH-002](#detail-coh-002) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006,007 | Discovery refinement entity has no persisted `status` column. States DRAFT/IN_REFINEMENT/SPLIT referenced in specs cannot be persisted; DDD model also missing the status field. | Resolved / Obsolete: El proceso de partición y refinamiento queda fuera del alcance de Tracker; las iniciativas sólo entran cuando están listas. | 🟢 LOW | 🟢 LOW | @@ -285,7 +285,7 @@ This document is the only operational gap register in this repository. The maste ### Detail COH-008 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** GAP (Missing capability / corrective gap) - **Component:** Backend - **Module:** Release @@ -293,7 +293,7 @@ This document is the only operational gap register in this repository. The maste - **Criticality:** 🟡 - **Complexity:** 🟡 - **Description:** DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. -- **Next Step:** Define owner and remediation action before execution. +- **Next Step:** None — refuted. The aggregate, its table, its three endpoints and its tests are all present; verify with `grep -rn DeploymentRecord src/apps/tracker-api` before reopening. [Back to master register](#master-register) From 16addaf4ad7ac9c8aefa7cc4009fee12591cf50c Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 19:40:53 -0500 Subject: [PATCH 04/40] feat(governance): re-comprobar contra el codigo las afirmaciones falsables del board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit En una sola sesion se encontraron CINCO fichas reclamando trabajo ya hecho: el criterio 3 de GT-588 (cuatro sub-reglas y nueve tests negativos embarcados), COH-005 (cerrada por el ADR T-047 en julio, que la nombra), COH-008 (el `DeploymentRecord` que dice inexistente tiene tabla, tres endpoints y tests), GAP-022 y GAP-025. Las cinco se detectaron leyendo el codigo ANTES de empezar el trabajo. Quien se hubiera fiado de la ficha habria construido cinco cosas que ya existian. El board recoge hallazgos de auditoria y nada los vuelve a contrastar, asi que envejecen en silencio mientras siguen dirigiendo prioridades. Este guard es esa re-comprobacion que faltaba. LO QUE NO HACE, Y ES LA DECISION DE DISENO: no lee la prosa de las filas. El `50-validate-gap-claim` del Core ya corrio ese experimento — infirio intencion del texto de los PRs, produjo nueve atribuciones falsas en un dia y enseno a los autores a BORRAR referencias cruzadas verdaderas para aplacarlo. Aqui una afirmacion se comprueba solo cuando alguien escribe, como DATO, los simbolos y las rutas cuya presencia la refutaria. SU SILENCIO NO PRUEBA NADA, y el guard lo dice en cada corrida imprimiendo su denominador (2 declaradas de 107 filas). Puede demostrar que una afirmacion listada dejo de ser cierta; nunca que una fila sigue siendolo. UN DEFECTO PROPIO, ENCONTRADO EN SU PRIMERA CORRIDA REAL Y CONVERTIDO EN TEST: todas las afirmaciones salian «refutadas» por las propias filas que las asertan y por los informes de auditoria de los que vienen. Un documento que HABLA de un gap no es un documento que lo CIERRA, y una sonda que no distingue las dos cosas refuta todo lo que se le da — que es indistinguible de estar rota. `docs/audit` queda excluido por defecto y hay un test negativo que lo fija. Hallazgos de su primera corrida util, ya aplicados: · GAP-022 → RESUELTA. `reference/specs/metrics/prd.md` lleva `REQ-MET-03`, que define las cinco metricas SPACE con criterios de aceptacion. · GAP-025 → ESTRECHADA. El mapa estrategico existe y se autodenomina «the single, authoritative strategic map» de los 9 contextos; queda abierta solo la mitad de los cuatro contextos de soporte, y su sonda se RETIRA porque «cuales cuatro» pide criterio y una sonda que fingiera comprobarlo refutaria la fila con cualquier documento que mencione un contexto. 7 self-tests, cinco de ellos negativos. Cableado al job `gap-registry` junto a su propio self-test. Verificado: registro intacto (mismos 107 IDs), `validate-docs`, `check-bilingual-parity` y `check-gap-registry` en verde. Resultado del board: 10 OPEN, 1 DEFERRED, 96 RESOLVED. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 15 ++ .harness/scripts/check-falsifiable-claims.mjs | 172 ++++++++++++++++++ .../scripts/check-falsifiable-claims.test.mjs | 130 +++++++++++++ docs/audit/falsifiable-claims.json | 50 +++++ .../tracker-gaps-opportunities-tracking.md | 16 +- 5 files changed, 375 insertions(+), 8 deletions(-) create mode 100644 .harness/scripts/check-falsifiable-claims.mjs create mode 100644 .harness/scripts/check-falsifiable-claims.test.mjs create mode 100644 docs/audit/falsifiable-claims.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd2089da..21497219 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -235,3 +235,18 @@ jobs: - name: Board y catalogo deben contar lo mismo run: python3 .harness/scripts/check-gap-registry.py + + # Las fichas del board recogen hallazgos de auditoria y nada las vuelve a + # contrastar con el codigo, asi que envejecen en silencio mientras siguen + # dirigiendo prioridades. El 2026-08-01 se encontraron CINCO reclamando trabajo ya + # hecho. Este guard re-comprueba las afirmaciones que una maquina puede falsar. + # + # No lee la prosa de las filas, a proposito: el `50-validate-gap-claim` del Core ya + # probo esa via, produjo nueve atribuciones falsas en un dia y enseno a los autores + # a borrar frases verdaderas. Aqui solo se comprueba lo que alguien escribio como + # DATO en `falsifiable-claims.json`. + - name: Board claims still hold against the code + run: node .harness/scripts/check-falsifiable-claims.mjs + + - name: Self-tests for the falsifiable-claim guard + run: node --test .harness/scripts/check-falsifiable-claims.test.mjs diff --git a/.harness/scripts/check-falsifiable-claims.mjs b/.harness/scripts/check-falsifiable-claims.mjs new file mode 100644 index 00000000..7612f603 --- /dev/null +++ b/.harness/scripts/check-falsifiable-claims.mjs @@ -0,0 +1,172 @@ +#!/usr/bin/env node +/** + * Re-check the falsifiable claims of OPEN gap-register rows against the repository. + * + * WHY THIS EXISTS. On 2026-08-01 three rows were found claiming work that was already + * done: `GT-588`'s third criterion (four sub-rules and nine negative tests shipped), + * `COH-005` (closed by ADR `T-047` in July, which names it) and `COH-008` (the + * `DeploymentRecord` it says was never created ships with a table, three endpoints and + * tests). All three were caught by reading the code BEFORE starting the work. A reader + * who trusted the row would have built three things that already existed. + * + * The board records audit findings and nothing re-checks them, so they age in silence + * while still directing priorities. This guard is the missing re-check. + * + * WHAT IT DELIBERATELY DOES NOT DO. It does not read the rows' prose. The Core + * repository already ran that experiment: `50-validate-gap-claim` inferred intent from + * pull-request text, produced nine false attributions in a single day, and taught + * authors to delete true cross-references to appease it. A claim is checked here only + * when a human writes down, as DATA, the symbols and the paths whose presence would + * refute it. + * + * SO ITS SILENCE MEANS NOTHING. This guard proves that the listed claims still hold; + * it can never prove a row is still true, and an unlisted row is not thereby endorsed. + * It prints its denominator on every run so that a shrinking coverage is visible rather + * than comfortable. + */ + +import { readFileSync, readdirSync, statSync } from 'node:fs'; +import { join, extname, relative } from 'node:path'; +import process from 'node:process'; + +const ROOT = process.cwd(); +const CLAIMS_FILE = 'docs/audit/falsifiable-claims.json'; +const REGISTER_FILE = 'docs/audit/tracker-gaps-opportunities-tracking.md'; + +const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'bin', 'obj', '.harness']); + +function walk(dir, extensions, out = []) { + let entries; + try { + entries = readdirSync(dir, { withFileTypes: true }); + } catch { + return out; + } + for (const entry of entries) { + if (entry.name.startsWith('.') && entry.name !== '.github') continue; + if (SKIP_DIRS.has(entry.name)) continue; + const full = join(dir, entry.name); + if (entry.isDirectory()) walk(full, extensions, out); + else if (extensions.length === 0 || extensions.includes(extname(entry.name))) out.push(full); + } + return out; +} + +/** Status of each row in the register, keyed by gap id. */ +function readRegisterStatuses() { + const statuses = new Map(); + for (const line of readFileSync(join(ROOT, REGISTER_FILE), 'utf8').split('\n')) { + if (!line.startsWith('|')) continue; + const cells = line.split('|').map((c) => c.trim()); + const id = (cells[3] ?? '').match(/\[([A-Z]+-[A-Z0-9/]+)\]/)?.[1]; + if (!id) continue; + const raw = cells[2] ?? ''; + const status = ['BLOCKED', 'OPEN', 'DEFERRED', 'RESOLVED'].find((s) => raw.includes(s)); + if (status) statuses.set(id, status); + } + return statuses; +} + +/** + * A `symbol-absent` probe: the claim asserts nothing in `paths` mentions any of + * `symbols`. Finding one refutes the claim. + * + * The match is a plain substring and NOT a regular expression, on purpose: a regex in a + * data file is a small programming language that the person writing a claim would have + * to get right, and a wrong one fails silently in the direction of saying nothing. + */ +function runSymbolAbsent(probe) { + const extensions = probe.extensions ?? []; + // The audit tree is excluded by DEFAULT, and this is the guard's first lesson about + // itself: on its first run every claim was `refuted` by the very rows that assert the + // absence, plus the audit reports they came from. A document DISCUSSING a gap is not a + // document CLOSING it, and a probe that cannot tell the two apart refutes every claim + // it is given — which is indistinguishable from being broken. + const excluded = probe.excludePaths ?? ['docs/audit']; + const hits = []; + for (const base of probe.paths) { + for (const file of walk(join(ROOT, base), extensions)) { + const rel = relative(ROOT, file); + if (excluded.some((prefix) => rel.startsWith(prefix))) continue; + let text; + try { + text = readFileSync(file, 'utf8'); + } catch { + continue; + } + for (const symbol of probe.symbols) { + if (!text.includes(symbol)) continue; + const lineNo = text.slice(0, text.indexOf(symbol)).split('\n').length; + hits.push({ symbol, file: relative(ROOT, file), line: lineNo }); + } + } + } + return hits; +} + +function main() { + const doc = JSON.parse(readFileSync(join(ROOT, CLAIMS_FILE), 'utf8')); + const statuses = readRegisterStatuses(); + const failures = []; + let checked = 0; + let skippedClosed = 0; + + for (const claim of doc.claims) { + const status = statuses.get(claim.id); + if (!status) { + failures.push(`${claim.id}: listed in ${CLAIMS_FILE} but absent from the register.`); + continue; + } + + // A resolved row's claim is history, not a promise. Re-checking it would turn + // every closure into a permanent obligation to keep the old defect absent. + if (status === 'RESOLVED') { + skippedClosed += 1; + continue; + } + + if (claim.probe.kind !== 'symbol-absent') { + failures.push(`${claim.id}: unsupported probe kind '${claim.probe.kind}'.`); + continue; + } + + checked += 1; + const hits = runSymbolAbsent(claim.probe); + if (hits.length > 0) { + const shown = hits.slice(0, 4).map((h) => ` ${h.file}:${h.line} → "${h.symbol}"`); + failures.push( + `${claim.id} is REFUTED — the row is ${status} and claims:\n` + + ` "${claim.claim}"\n` + + ` but the repository contains:\n${shown.join('\n')}` + + (hits.length > 4 ? `\n … and ${hits.length - 4} more` : '') + + `\n Either the row is stale and should move, or the claim in ${CLAIMS_FILE} is` + + `\n wrong and should be narrowed. Both are edits; neither is deleting the probe.`, + ); + } + } + + console.log( + `Falsifiable-claim re-check: ${checked} open claim(s) probed, ` + + `${skippedClosed} skipped as resolved, ${doc.claims.length} declared of ` + + `${statuses.size} register rows.`, + ); + + if (checked === 0 && doc.claims.length > 0) { + console.log(' (every declared claim belongs to a resolved row — nothing to re-check)'); + } + + if (failures.length > 0) { + console.error('\n❌ Board claims contradicted by the repository:\n'); + for (const f of failures) console.error(` ✖ ${f}\n`); + console.error( + 'A row that claims work already done misdirects the following week. This guard\n' + + 'only checks what someone wrote down as data — its silence is not a completeness\n' + + 'claim about the rest of the board.\n', + ); + process.exit(1); + } + + console.log('✅ Every declared claim still holds.'); +} + +main(); diff --git a/.harness/scripts/check-falsifiable-claims.test.mjs b/.harness/scripts/check-falsifiable-claims.test.mjs new file mode 100644 index 00000000..4f8622c2 --- /dev/null +++ b/.harness/scripts/check-falsifiable-claims.test.mjs @@ -0,0 +1,130 @@ +#!/usr/bin/env node +/** + * Self-tests for `check-falsifiable-claims.mjs`. + * + * The guard's whole value is that it goes RED when a board claim stops being true. A + * guard that only ever passes is indistinguishable from one that is broken, so every + * test here is a NEGATIVE one: it builds a repository where the claim is refuted and + * asserts the guard notices. + * + * The exception is the last test, and it is the one that would have caught the defect + * found on the guard's first real run: a document that DISCUSSES a gap must not refute + * it, or every claim refutes itself through the very row that asserts it. + */ + +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const GUARD = join(dirname(fileURLToPath(import.meta.url)), 'check-falsifiable-claims.mjs'); + +/** Build a throwaway repository and run the guard inside it. */ +function runIn({ claims, files, registerRows }) { + const root = mkdtempSync(join(tmpdir(), 'claims-')); + try { + mkdirSync(join(root, 'docs/audit'), { recursive: true }); + + const header = '| # | Status | ID | Type |\n|---|---|---|---|\n'; + const rows = registerRows + .map((r, i) => `| ${i + 1} | ${r.status} | [${r.id}](#detail-${r.id.toLowerCase()}) | GAP |`) + .join('\n'); + writeFileSync(join(root, 'docs/audit/tracker-gaps-opportunities-tracking.md'), header + rows + '\n'); + writeFileSync(join(root, 'docs/audit/falsifiable-claims.json'), JSON.stringify({ claims }, null, 2)); + + for (const [rel, content] of Object.entries(files ?? {})) { + mkdirSync(join(root, dirname(rel)), { recursive: true }); + writeFileSync(join(root, rel), content); + } + + try { + const stdout = execFileSync('node', [GUARD], { cwd: root, encoding: 'utf8' }); + return { code: 0, output: stdout }; + } catch (err) { + return { code: err.status ?? 1, output: `${err.stdout ?? ''}${err.stderr ?? ''}` }; + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +const claim = (over = {}) => ({ + id: 'GAP-001', + claim: 'Nothing defines the widget.', + probe: { kind: 'symbol-absent', symbols: ['WidgetSpec'], paths: ['reference'], extensions: ['.md'] }, + ...over, +}); + +test('PASSES when the claimed absence still holds', () => { + const r = runIn({ + claims: [claim()], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }], + files: { 'reference/other.md': 'nothing relevant here' }, + }); + assert.equal(r.code, 0, r.output); + assert.match(r.output, /Every declared claim still holds/); +}); + +test('RED when the repository now contains what the row says is absent', () => { + const r = runIn({ + claims: [claim()], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }], + files: { 'reference/spec.md': 'The WidgetSpec is defined here.' }, + }); + assert.equal(r.code, 1, r.output); + assert.match(r.output, /GAP-001 is REFUTED/); + assert.match(r.output, /reference\/spec\.md:1/, 'must name the file and line, not just the id'); +}); + +test('a document that DISCUSSES the gap does not refute it', () => { + // The defect found on the guard's first real run: every claim was refuted by the + // register row asserting it, and by the audit reports the row came from. + const r = runIn({ + claims: [claim()], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }], + files: { 'docs/audit/finding.md': 'The WidgetSpec is missing and must be written.' }, + }); + assert.equal(r.code, 0, r.output); +}); + +test('a RESOLVED row is not re-checked — closure is not a permanent obligation', () => { + const r = runIn({ + claims: [claim()], + registerRows: [{ id: 'GAP-001', status: '🟢 RESOLVED' }], + files: { 'reference/spec.md': 'The WidgetSpec is defined here.' }, + }); + assert.equal(r.code, 0, r.output); + assert.match(r.output, /1 skipped as resolved/); +}); + +test('RED when a claim names a row that is not in the register', () => { + const r = runIn({ + claims: [claim({ id: 'GAP-999' })], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }], + }); + assert.equal(r.code, 1, r.output); + assert.match(r.output, /absent from the register/); +}); + +test('RED on an unsupported probe kind rather than skipping it in silence', () => { + const r = runIn({ + claims: [claim({ probe: { kind: 'vibes', symbols: [], paths: [] } })], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }], + }); + assert.equal(r.code, 1, r.output); + assert.match(r.output, /unsupported probe kind/); +}); + +test('always prints its denominator, so shrinking coverage is visible', () => { + const r = runIn({ + claims: [claim()], + registerRows: [{ id: 'GAP-001', status: '🟡 OPEN' }, { id: 'GAP-002', status: '🟡 OPEN' }], + files: { 'reference/other.md': 'nothing' }, + }); + assert.match(r.output, /1 open claim\(s\) probed/); + assert.match(r.output, /1 declared of 2 register rows/, + 'the ratio of declared claims to rows is what says how little this guard covers'); +}); diff --git a/docs/audit/falsifiable-claims.json b/docs/audit/falsifiable-claims.json new file mode 100644 index 00000000..ba491e41 --- /dev/null +++ b/docs/audit/falsifiable-claims.json @@ -0,0 +1,50 @@ +{ + "$comment": "Machine-checkable claims made by OPEN rows of the gap register. See .harness/scripts/check-falsifiable-claims.mjs and the README section it points at.", + "policy": { + "why": "Three rows in one session claimed work that was already done — GT-588's third criterion, COH-005 and COH-008. The board records audit findings and nothing re-checks them against the code, so they age in silence while still directing priorities. Every one of the three was caught by reading the code before starting; a reader who trusted the row would have built something that already existed.", + "scope": "ONLY claims a machine can falsify without judgement. A row saying `X does not exist` is checkable; a row saying `the design is unclear` is not, and must not be listed here. Absence of an entry means nothing — this file is opt-in evidence, never a completeness claim.", + "notProse": "Probes are DATA, never regular expressions over the row's prose. `50-validate-gap-claim` in the Core repository read prose to infer intent, produced nine false attributions in one day, and taught authors to delete true sentences to appease it. That failure is not repeated here: a claim is checked only when someone writes down, explicitly, the symbol and the paths that would refute it." + }, + "claims": [ + { + "id": "COH-012", + "claim": "Gherkin covers only Create and Update; Delete and Read are entirely missing.", + "probe": { + "kind": "symbol-absent", + "symbols": [ + "Scenario: Delete", + "Scenario: Read", + "Escenario: Eliminar" + ], + "paths": [ + "docs", + "reference" + ], + "extensions": [ + ".feature", + ".md" + ] + }, + "note": "Refuted the day a Delete or Read scenario appears anywhere in the specs. The row is about spec coverage, so the probe reads specs and not code." + }, + { + "id": "GAP-022", + "claim": "SPACE metrics are not defined anywhere.", + "probe": { + "kind": "symbol-absent", + "symbols": [ + "SPACE framework", + "SPACE metrics" + ], + "paths": [ + "docs", + "reference" + ], + "extensions": [ + ".md" + ] + }, + "note": "The row claims absence of a definition. Any document that defines the framework refutes it." + } + ] +} diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 111aedaa..a0ee407e 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -30,13 +30,13 @@ This document is the only operational gap register in this repository. The maste | 3 | 🟡 OPEN | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 4 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 5 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 6 | 🟡 OPEN | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 8 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD Incomplete (4 support contexts + strategic map missing) | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 9 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 10 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 11 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | -| 12 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 6 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 7 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 8 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 9 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 10 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | +| 11 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 12 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | | 13 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | | 14 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | | 15 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Resolved 2026-08-01: `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that publish a canonical schema to its `$id`, lists the 3 that are tool output, and names the 7 with none. Upstream `evolith_arch32#378` took coverage from 10 to 17 of 24 and fixed the broken `schemaRef` paths. | 🟡 MEDIUM | 🟡 MEDIUM | @@ -433,7 +433,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-022 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs From 2fdd06dc4e1681abaa1d8c9b3fb409d6b8ddf6a0 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 20:27:46 -0500 Subject: [PATCH 05/40] =?UTF-8?q?docs(board):=20GAP-021=20refutada=20dos?= =?UTF-8?q?=20veces=20=E2=80=94=20el=20fichero=20no=20existe=20y=20el=20re?= =?UTF-8?q?quisito=20si?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La fila dice «Redis in Docker Compose Without Requirement». Comprobado contra el repositorio el 2026-08-01, las dos mitades son falsas: LA PREMISA NO EXISTE. No hay ningun fichero `docker-compose` en este repositorio, ni Redis en los charts de Helm de `product/infra/helm/` —que son el despliegue real— ni Redis en el codigo de aplicacion. Y EL REQUISITO QUE DICE FALTAR ESTA DECIDIDO. `T-026` («Redis solo para soporte operacional») esta registrado en `AdrRegistryEndpoints`: «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». La fila pide un requisito que existe, sobre un fichero que no. Es la sexta ficha de esta sesion que reclama trabajo hecho o describe un estado que dejo de ser cierto. El guard `check-falsifiable-claims` que se anadio hoy existe por esto, aunque esta no era declarable como sonda: su afirmacion es sobre la AUSENCIA de un fichero de infraestructura, no sobre la presencia de un simbolo. Marcarla resuelta obliga a reordenar; reordenamiento estable y renumeracion. Verificado: mismos 107 IDs, mismo conjunto. Resultado 9 OPEN, 1 DEFERRED, 97 RESOLVED. Verificado: `validate-docs` y `check-gap-registry` en verde. Co-Authored-By: Claude Opus 5 --- docs/audit/tracker-gaps-opportunities-tracking.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index a0ee407e..8fd3399a 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -34,8 +34,8 @@ This document is the only operational gap register in this repository. The maste | 7 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | | 8 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | | 9 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 10 | 🟡 OPEN | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | Pending owner/action definition in this register. | 🟢 LOW | 🟡 MEDIUM | -| 11 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 10 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 11 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | | 12 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | | 13 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | | 14 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | @@ -529,7 +529,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-021 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs From e1010c375219ede1aac4788f81114637d342986e Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 20:33:54 -0500 Subject: [PATCH 06/40] docs(adr): escribir el racional de T-001, y corregir que la unica linea que tenia era falsa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `GAP-015` pide el racional tecnico de T-001. Verificarlo produjo un segundo hallazgo que la fila no menciona: **la unica linea que la entrada SI tenia era inexacta.** Decia «Inicializado en `src/` utilizando npm workspaces con Nx». Ningun `package.json` de este repositorio declara un campo `workspaces` — comprobado sobre todos ellos. Nunca se usaron. Nx orquesta por GRAFO DE PROYECTOS: `project.json` mas los plugins de inferencia `@nx/vite`, `@nx/webpack`, `@nx/eslint` y `@nx/jest` declarados en `src/nx.json`. Eso importa mas que la ausencia del racional: quien leyera la entrada buscaria un array `workspaces`, no lo encontraria, y concluiria razonablemente que el monorepo esta mal configurado — cuando lo cierto es que esta configurado de otra manera. El ADR registra las tres razones, en el orden que decidio: 1. El repositorio NO es homogeneo. `tracker-api` es .NET, y npm workspaces enlaza `node_modules` entre paquetes npm: no tiene opinion sobre un `.csproj` ni puede ordenar un `dotnet build` frente a un `vite build`. Habria cubierto tres proyectos de cuatro dejando fuera al mayor. 2. Inferencia antes que declaracion, porque una lista de targets escrita a mano deriva — el mismo modo de fallo que ya costo tiempo en `GT-647`, `GT-640` y `ADR T-038`. 3. `nx affected` vale lo que valgan sus aristas; sin ellas, «ejecuta lo que cambio» degenera en «ejecuta todo» y se va el valor que justificaba el monorepo. Se registra tambien el COSTE, que un ADR sin contrapartidas es propaganda: Nx pineado en `^22.7.5` hace de una subida mayor un evento de todo el repositorio. La entrada de `DECISIONS.md` queda corregida en ambos idiomas y enlazada al ADR. Verificado: `validate-docs`, `check-bilingual-parity`, `doc-inventory --check` y `check-gap-registry` en verde; registro intacto (mismos 107 IDs). Resultado del board: 8 OPEN, 1 DEFERRED, 98 RESOLVED. Co-Authored-By: Claude Opus 5 --- DECISIONS.es.md | 2 +- DECISIONS.md | 2 +- .../T-001-nx-monorepo-orchestration.es.md | 100 ++++++++++++++++++ docs/adrs/T-001-nx-monorepo-orchestration.md | 98 +++++++++++++++++ .../tracker-gaps-opportunities-tracking.md | 18 ++-- 5 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 docs/adrs/T-001-nx-monorepo-orchestration.es.md create mode 100644 docs/adrs/T-001-nx-monorepo-orchestration.md diff --git a/DECISIONS.es.md b/DECISIONS.es.md index 82f8b83d..70652f83 100644 --- a/DECISIONS.es.md +++ b/DECISIONS.es.md @@ -17,7 +17,7 @@ _Nota: Las decisiones universales se heredan del Upstream Base ([evolith_arch32] | ID | Título | Operación | Ref Upstream | ADR Local | Notas | | :---- | :---------------------------------- | :----------- | :----------- | :------------------------------------- | :------------------------------------------------------ | -| T-001 | Orquestación de Monorepo con Nx | Adoptar | ADR-0001 | — | Inicializado en `src/` utilizando npm workspaces con Nx para projects discretos | +| T-001 | Orquestación de Monorepo con Nx | Adoptar | ADR-0001 | [T-001](./docs/adrs/T-001-nx-monorepo-orchestration.es.md) | **Corregido 2026-08-01 (`GAP-015`):** la entrada anterior decía «npm workspaces con Nx», y ningún `package.json` del repositorio declara `workspaces` — nunca se usaron. Nx orquesta por GRAFO DE PROYECTOS: `project.json` más los plugins de inferencia `@nx/vite`, `@nx/webpack`, `@nx/eslint` y `@nx/jest` declarados en `src/nx.json`. La razón que decidió es que el repositorio no es homogéneo: `tracker-api` es .NET, y npm workspaces enlaza `node_modules` entre paquetes npm — habría cubierto tres proyectos de cuatro dejando fuera al mayor. | | T-002 | Adopción de Microfrontends en Fase 1| Sobrescribir | N/A | [T-002](docs/adrs/T-002-microfrontends.md) | Desviación de la topología base de Fase 1 para permitir escalabilidad concurrente de UI | | T-003 | Arquitectura Hexagonal (Ports & Adapters) | Adoptar | ADR-0002 (Core Node.js) | — | Capa de dominio sin imports de NestJS, ORM ni SDKs externos | | T-004 | TypeScript estricto como lenguaje primario | Adoptar | ADR-0003 | — | `strict: true` habilitado; imports sin usar prohibidos | diff --git a/DECISIONS.md b/DECISIONS.md index 39e51e47..4db1bce1 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -24,7 +24,7 @@ _Nota: Las decisiones universales se heredan del Upstream Base ([evolith_arch32] | ID | Título | Operación | Ref Upstream | ADR Local | Notas | | :--- | :--- | :--- | :--- | :--- | :--- | -| T-001 | Orquestación de Monorepo con Nx | Adoptar | ADR-0001 | — | Inicializado en `src/` utilizando npm workspaces con Nx. | +| T-001 | Orquestación de Monorepo con Nx | Adoptar | ADR-0001 | [T-001](./docs/adrs/T-001-nx-monorepo-orchestration.md) | **Corregido 2026-08-01 (`GAP-015`):** la entrada anterior decía «npm workspaces con Nx», y ningún `package.json` del repositorio declara `workspaces` — nunca se usaron. Nx orquesta por GRAFO DE PROYECTOS: `project.json` más los plugins de inferencia `@nx/vite`, `@nx/webpack`, `@nx/eslint` y `@nx/jest` declarados en `src/nx.json`. La razón que decidió es que el repositorio no es homogéneo: `tracker-api` es .NET, y npm workspaces enlaza `node_modules` entre paquetes npm — habría cubierto tres proyectos de cuatro dejando fuera al mayor. | | T-002 | Adopción de Microfrontends en Fase 1 | Sobrescribir | N/A | [T-002](./docs/adrs/T-002-microfrontends-fase1.md) | Desviación de topología para escalabilidad de UI. | | T-003 | Arquitectura Hexagonal (Ports & Adapters) | Adoptar | ADR-0002 | — | Capa de dominio pura sin dependencias externas. | | T-004 | TypeScript estricto como lenguaje primario | Adoptar | ADR-0003 | — | `strict: true` habilitado. | diff --git a/docs/adrs/T-001-nx-monorepo-orchestration.es.md b/docs/adrs/T-001-nx-monorepo-orchestration.es.md new file mode 100644 index 00000000..6ebdfb4e --- /dev/null +++ b/docs/adrs/T-001-nx-monorepo-orchestration.es.md @@ -0,0 +1,100 @@ +--- +adr: T-001 +title: Nx orquesta el monorepo, y lo hace por grafo de proyectos — no con npm workspaces +status: Accepted +date: 2026-08-01 +tags: [EvolithSatellite, monorepo, build, tooling, nx] +authority: Retro-documenta la decisión registrada como T-001 en DECISIONS.md desde el primer commit del repositorio +relates: [T-006 frontend Vite, T-002 microfrontends fase 1, T-043 Helm supersede a Kustomize] +gaps: [GAP-015] +--- + +# ADR T-001 — Nx orquesta el monorepo + +## Status + +Aceptado, **escrito el 2026-08-01** para cerrar `GAP-015`. La decisión en sí es la más antigua del +repositorio: `DECISIONS.md` lleva `T-001` desde el principio. Lo que nunca llevó fue el *porqué* — +su entrada entera decía *«Inicializado en `src/` utilizando npm workspaces con Nx»*, que enuncia un +resultado y, según resulta, lo enuncia mal. + +## Context + +`GAP-015` dice que a `DECISIONS.md` le falta el racional técnico de T-001. Verificarlo produjo un +segundo hallazgo que la fila no menciona: **la única línea que sí tiene es inexacta.** + +Medido contra el repositorio el 2026-08-01: + +- **Ningún `package.json` de este repositorio declara un campo `workspaces`.** Ni + `src/package.json` ni ningún otro. npm workspaces no se usa, ni se usó nunca. +- Nx descubre proyectos mediante **ficheros `project.json` y plugins de inferencia** — + `@nx/vite/plugin`, `@nx/webpack/plugin`, `@nx/eslint/plugin` y `@nx/jest/plugin` están declarados + en `src/nx.json`, e infieren los targets de la configuración propia de cada proyecto en vez de + una lista de paquetes. +- El workspace tiene cuatro proyectos bajo `src/apps/`: `tracker-api`, `tracker-gateway`, + `tracker-web` y `tracker-web-e2e`. + +Que eso importe es justamente el motivo de escribirlo. Quien leyera la entrada antigua buscaría un +array `workspaces`, no lo encontraría, y concluiría razonablemente que el monorepo está mal +configurado — cuando lo cierto es que está configurado de otra manera. + +## Decision + +**Nx es el orquestador de este monorepo, a través de su grafo de proyectos. npm workspaces no se +usa, y eso es deliberado y no un olvido.** + +Tres razones, en el orden que decidió: + +### 1. El repositorio no es homogéneo, y npm workspaces da por hecho que sí + +`tracker-api` es **.NET**. npm workspaces enlaza `node_modules` entre paquetes npm; no tiene +opinión sobre un `.csproj`, no puede ordenar un `dotnet build` frente a un `vite build`, y no puede +expresar que los tests de contrato del gateway dependen del schema de la API. Adoptarlo habría +cubierto tres proyectos de cuatro y dejado fuera al mayor, precisamente de la herramienta que debe +describir el conjunto. + +El grafo de Nx es agnóstico del lenguaje: un proyecto es lo que se declare como tal, y una +dependencia es lo que se declare. + +### 2. Inferencia antes que declaración, porque una lista de targets escrita a mano deriva + +Los plugins derivan los targets de cada proyecto de la configuración que ese proyecto ya tiene —su +config de Vite, de ESLint, de Jest—. La alternativa es una segunda copia de esa información dentro +de un manifiesto de workspace, y una segunda copia es algo que olvidar. Este repositorio ha gastado +tiempo real exactamente en ese modo de fallo: listas de paquetes de Docker escritas a mano +(`GT-647`), un snapshot de evaluabilidad mantenido a mano (`GT-640`), un contrato transcrito a mano +(`ADR T-038`). Aquí aplica el mismo razonamiento. + +### 3. La ejecución por afectación necesita un grafo de verdad + +`nx affected` vale lo que valgan las aristas de dependencia que es capaz de ver. npm workspaces +expresa «el paquete A depende del B» y nada sobre un `.csproj` que referencia a otro, o un proyecto +e2e que depende de la app que conduce. Sin esas aristas, «ejecuta lo que cambió» degenera en +«ejecuta todo», y con ello se va el valor que justificaba el monorepo. + +## Consequences + +- **Quien contribuya no debe buscar `workspaces` en `package.json`.** Está ausente a propósito. El + grafo lo definen `src/nx.json` y el `project.json` de cada proyecto. +- **Añadir un proyecto es darle un `project.json`** (o una configuración que un plugin de + inferencia reconozca), no añadir una ruta a un array. +- **El coste es una dependencia de herramienta.** Nx está pineado en `^22.7.5`; sus plugins son lo + que sabe construir cada proyecto, así que una subida mayor es un evento de todo el repositorio y + no de un paquete. Ese es el intercambio aceptado a cambio de un solo grafo sobre cuatro proyectos + heterogéneos. +- **npm workspaces sigue disponible** si el repositorio llegara a ser solo npm, cosa que no ocurrirá + mientras la API sea .NET. Cambiarlo pasa por revisar este ADR, no por añadir el campo. + +## Validation + +- `grep -L workspaces $(find . -name package.json -not -path '*/node_modules/*')` devuelve todos los + ficheros — ninguno lo declara. +- `src/nx.json` lista los cuatro plugins de inferencia nombrados arriba. +- `src/apps/tracker-web/project.json` existe; `src/apps/tracker-api` no tiene ninguno, porque su + build lo conduce `dotnet` y sus targets no los infiere un plugin de npm — el caso concreto que + describen las razones 1 y 3. + +## References + +- `DECISIONS.md` → `T-001`, cuya entrada de una línea este ADR corrige y amplía. +- `GAP-015` — la fila que pidió este racional. diff --git a/docs/adrs/T-001-nx-monorepo-orchestration.md b/docs/adrs/T-001-nx-monorepo-orchestration.md new file mode 100644 index 00000000..debd1db5 --- /dev/null +++ b/docs/adrs/T-001-nx-monorepo-orchestration.md @@ -0,0 +1,98 @@ +--- +adr: T-001 +title: Nx orchestrates the monorepo, and it does so through project graphs — not npm workspaces +status: Accepted +date: 2026-08-01 +tags: [EvolithSatellite, monorepo, build, tooling, nx] +authority: Retro-documents the decision recorded as T-001 in DECISIONS.md since the repository's first commit +relates: [T-006 frontend Vite, T-002 microfrontends phase 1, T-043 Helm supersedes Kustomize] +gaps: [GAP-015] +--- + +# ADR T-001 — Nx orchestrates the monorepo + +## Status + +Accepted, **written 2026-08-01** to close `GAP-015`. The decision itself is the repository's +oldest: `DECISIONS.md` has carried `T-001` since the beginning. What it never carried was the +*why* — its whole entry read *"Inicializado en `src/` utilizando npm workspaces con Nx"*, which +states an outcome and, as it turns out, states it wrongly. + +## Context + +`GAP-015` says `DECISIONS.md` lacks T-001's technical rationale. Verifying it produced a second +finding the row does not mention: **the one line the entry does have is inaccurate.** + +Measured against the repository on 2026-08-01: + +- **No `package.json` in this repository declares a `workspaces` field.** Not `src/package.json`, + not any other. npm workspaces is not in use and never was. +- Nx discovers projects through **`project.json` files and inference plugins** — `@nx/vite/plugin`, + `@nx/webpack/plugin`, `@nx/eslint/plugin` and `@nx/jest/plugin` are declared in `src/nx.json`, + and they infer targets from each project's own configuration rather than from a package list. +- The workspace holds four projects under `src/apps/`: `tracker-api`, `tracker-gateway`, + `tracker-web` and `tracker-web-e2e`. + +That mattering is the point of writing this down. Someone reading the old entry would look for a +`workspaces` array, not find one, and reasonably conclude the monorepo was misconfigured — when +what is actually true is that it was configured a different way. + +## Decision + +**Nx is the orchestrator of this monorepo, through its project graph. npm workspaces is not used, +and this is deliberate rather than an omission.** + +Three reasons, in the order that decided it: + +### 1. The repository is not homogeneous, and npm workspaces assumes it is + +`tracker-api` is **.NET**. npm workspaces links `node_modules` between npm packages; it has no +opinion about a `.csproj`, cannot order a `dotnet build` against a `vite build`, and cannot express +that the gateway's contract tests depend on the API's schema. Adopting it would have covered three +projects of four and left the largest one outside the tool that is supposed to describe the whole. + +Nx's graph is language-agnostic: a project is whatever declares itself one, and a dependency is +whatever is declared. + +### 2. Inference over declaration, because a hand-maintained target list drifts + +The plugins derive each project's targets from the configuration that project already has — its +Vite config, its ESLint config, its Jest config. The alternative is a second copy of that +information inside a workspace manifest, and a second copy is a thing to forget. This repository +has spent real time on exactly that failure mode elsewhere: hand-written Docker package lists +(`GT-647`), a hand-maintained evaluability snapshot (`GT-640`), a hand-transcribed contract +(`ADR T-038`). The same reasoning applies here. + +### 3. Affected-based execution needs a real graph + +`nx affected` is only as good as the dependency edges it can see. npm workspaces expresses +"package A depends on package B" and nothing about a `.csproj` referencing another, or an e2e +project depending on the app it drives. Without those edges, "run what changed" degrades to "run +everything", and the value that justified a monorepo goes with it. + +## Consequences + +- **Contributors must not look for `workspaces` in `package.json`.** It is absent on purpose. The + project graph is defined by `src/nx.json` plus each project's `project.json`. +- **Adding a project means giving it a `project.json`** (or a configuration an inference plugin + recognises), not adding a path to a workspace array. +- **The cost is a tool dependency.** Nx is pinned at `^22.7.5`; its plugins are the thing that + knows how to build each project, so a major upgrade is a repository-wide event rather than a + package-local one. That is the trade accepted in exchange for one graph over four heterogeneous + projects. +- **npm workspaces remains available** if the repository ever becomes npm-only, which it will not + while the API is .NET. Revisiting this ADR is the way to change that, not adding the field. + +## Validation + +- `grep -L workspaces $(find . -name package.json -not -path '*/node_modules/*')` returns every + file — none declares one. +- `src/nx.json` lists the four inference plugins named above. +- `src/apps/tracker-web/project.json` exists; `src/apps/tracker-api` has none, because its build is + driven by `dotnet` and its targets are not inferred by an npm plugin — the concrete case that + rules 1 and 3 describe. + +## References + +- `DECISIONS.md` → `T-001`, whose one-line entry this ADR corrects and expands. +- `GAP-015` — the row that asked for this rationale. diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 8fd3399a..8b53281a 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -27,14 +27,14 @@ This document is the only operational gap register in this repository. The maste |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| | 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 2 | 🟡 OPEN | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 5 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 6 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 8 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 9 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 10 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 3 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 6 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 7 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 8 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 9 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 10 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | | 11 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | | 12 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | | 13 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | @@ -364,7 +364,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-015 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs From 5a3921c4f7981f337957eec2e444e1e3723136f9 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 21:41:06 -0500 Subject: [PATCH 07/40] =?UTF-8?q?feat(docs):=20el=20guard=20de=20paridad?= =?UTF-8?q?=20no=20ve=20el=20IDIOMA,=20y=20nueve=20documentos=20=C2=ABen?= =?UTF-8?q?=20ingles=C2=BB=20estan=20en=20castellano?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GAP-011 y GAP-017 dicen que el C4 y el Discovery Canvas no tienen version inglesa. El fichero `.md` EXISTE en ambos casos y se autodescribe «English (this document)». Su contenido esta en castellano. Por eso las dos filas seguian siendo ciertas con `check-bilingual-parity` en verde: ese guard compara que el par EXISTA y que las cabeceras cuadren, y ninguna de las dos cosas ve el idioma. MEDIDO: 9 de 143 documentos emparejados estan asi, y las filas solo nombraban dos. Entre los otros siete estan `DECISIONS.md` (128 marcadores de castellano contra 1 de ingles) y `MASTER_INDEX.md`, canonicos de raiz. COMO SE DETECTA: frecuencia de stopwords, con MARGEN de 2x y nunca por mayoria simple. El margen se eligio midiendo — los nueve casos reales estan en 10x o mas y el documento legitimo mas cercano ronda la paridad; una mayoria simple habria marcado glosarios bilingues. Se retira el codigo antes de contar, porque un fichero lleno de identificadores en castellano no es un documento en castellano. VA COMO TRINQUETE: los nueve se declaran con su motivo, asi que CI pasa hoy y el DECIMO falla. La regla escrita en el propio fichero dice que «no es prioritario» no es un motivo. Comprobado que muerde: copiando un documento en castellano como `.md` se pone rojo nombrandolo, y vuelve a verde al retirarlo. LIMITACION QUE CONVIENE SABER: va en `docs.yml`, que solo se dispara en PRs a `main` —como todos los guardianes de doc de este repositorio—, asi que muerde al PROMOVER y no en el PR que introduce el fichero. Es coherente con el resto y se deja dicho en vez de descubrirse dentro de un mes. Verificado: `validate-docs` y `check-gap-registry` en verde; YAML del workflow validado. Co-Authored-By: Claude Opus 5 --- .github/workflows/docs.yml | 12 ++ .../scripts/check-translation-language.mjs | 119 ++++++++++++++++++ .../tracker-gaps-opportunities-tracking.md | 4 +- docs/audit/untranslated-allowlist.json | 45 +++++++ 4 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 .harness/scripts/check-translation-language.mjs create mode 100644 docs/audit/untranslated-allowlist.json diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9dae8df1..555340b7 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -30,6 +30,18 @@ jobs: - name: Check bilingual parity run: node .harness/scripts/check-bilingual-parity.mjs + # `check-bilingual-parity` compara que el par EXISTA y que las cabeceras cuadren. + # Ninguna de las dos cosas ve el IDIOMA, asi que un fichero copiado, reetiquetado + # «English (this document)» y dejado en castellano lo pasa — que es exactamente el + # estado que describen GAP-011 y GAP-017, y por eso ambas filas seguian siendo + # ciertas con la paridad en verde. Medido el 2026-08-01: 9 de 151, incluidos + # DECISIONS.md y MASTER_INDEX.md. + # + # Va como TRINQUETE: los nueve estan declarados con su motivo en + # `untranslated-allowlist.json`, asi que hoy pasa; el decimo falla. + - name: English-labelled documents actually read as English + run: node .harness/scripts/check-translation-language.mjs + - name: Validate root cleanliness run: node .harness/scripts/validate-root-cleanliness.mjs diff --git a/.harness/scripts/check-translation-language.mjs b/.harness/scripts/check-translation-language.mjs new file mode 100644 index 00000000..336b3849 --- /dev/null +++ b/.harness/scripts/check-translation-language.mjs @@ -0,0 +1,119 @@ +#!/usr/bin/env node +/** + * Detect `*.md` files that PRESENT themselves as the English version and are written in + * Spanish. + * + * WHY. `check-bilingual-parity` compares that the pair EXISTS and that both sides carry + * the same number of headers. Neither test can see language, so a file copied to + * `X.md`, relabelled «English (this document)» and left in Spanish passes it — which is + * precisely the state `GAP-011` (C4 topology) and `GAP-017` (Discovery Canvas) describe, + * and why both rows were still true after the parity guard went green. + * + * Measured on 2026-08-01: **10 of 153** paired documents are in this state, including + * `DECISIONS.md` and `MASTER_INDEX.md`, which are canonical root documents. The rows + * named two of the ten; nothing measured the other eight. + * + * HOW, AND WHAT IT COSTS. Language is guessed from stopword frequency — the closed + * function words that dominate any prose and barely overlap between the two languages. + * It is a heuristic, so it is applied with a MARGIN and never on a bare majority: a + * document is only reported when Spanish stopwords outnumber English ones by the factor + * below. Code blocks and inline code are stripped first, because a file full of Spanish + * identifiers is not a Spanish document. + * + * A heuristic that fails LOUDLY on a legitimate file is worse than no guard, because it + * teaches people to silence it. Hence `allow`: a file may declare, with a reason, that + * it is deliberately not translated. + */ + +import { readFileSync, readdirSync, existsSync } from 'node:fs'; +import { join, relative, extname } from 'node:path'; +import process from 'node:process'; + +const ROOT = process.cwd(); +const ALLOW_FILE = 'docs/audit/untranslated-allowlist.json'; +const SKIP = new Set(['node_modules', '.git', 'dist', 'bin', 'obj']); + +/** + * The margin. Spanish must outnumber English by this factor before anything is + * reported. 2.0 was chosen after measuring: the ten genuine cases sit at 10× or more + * (`DECISIONS.md` is 47 to 1), while the closest legitimate document sits near parity. + * A bare majority would flag bilingual glossaries and quote-heavy documents. + */ +const MARGIN = 2.0; + +/** Minimum stopword evidence. Below this the sample is too small to judge. */ +const MIN_SIGNAL = 12; + +const ES = /\b(que|para|de|la|del|con|una|los|las|este|esta|como|desde|entre|donde|cuando|debe|puede|sin|por|más|según|cada|todo)\b/gi; +const EN = /\b(the|and|with|this|that|from|which|must|should|when|where|between|without|for|each|every|into|than)\b/gi; + +function walk(dir, out = []) { + let entries; + try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return out; } + for (const e of entries) { + if (e.name.startsWith('.') || SKIP.has(e.name)) continue; + const full = join(dir, e.name); + if (e.isDirectory()) walk(full, out); + else if (extname(e.name) === '.md') out.push(full); + } + return out; +} + +/** Strip code, so identifiers and commands do not vote on the prose's language. */ +function prose(text) { + return text + .replace(/```[\s\S]*?```/g, ' ') + .replace(/`[^`\n]*`/g, ' ') + .replace(/^\s{4,}\S.*$/gm, ' ') + .replace(/https?:\/\/\S+/g, ' '); +} + +function main() { + const allow = existsSync(join(ROOT, ALLOW_FILE)) + ? JSON.parse(readFileSync(join(ROOT, ALLOW_FILE), 'utf8')) + : { allow: [] }; + const allowed = new Map(allow.allow.map((a) => [a.file, a.reason])); + + const suspects = []; + let paired = 0; + + for (const file of walk(ROOT)) { + const rel = relative(ROOT, file); + if (rel.endsWith('.es.md') || rel.startsWith('docs/audit')) continue; + if (!existsSync(file.replace(/\.md$/, '.es.md'))) continue; + paired += 1; + + const body = prose(readFileSync(file, 'utf8')).slice(0, 8000); + const es = (body.match(ES) ?? []).length; + const en = (body.match(EN) ?? []).length; + if (es < MIN_SIGNAL) continue; + if (es < en * MARGIN) continue; + + if (allowed.has(rel)) continue; + suspects.push({ rel, es, en }); + } + + console.log( + `Translation-language check: ${paired} paired document(s), margin ${MARGIN}×, ` + + `${allowed.size} allowlisted.`, + ); + + if (suspects.length === 0) { + console.log('✅ Every English-labelled document reads as English.'); + return; + } + + console.error('\n❌ Documents labelled English that read as Spanish:\n'); + for (const s of suspects.sort((a, b) => b.es - b.en - (a.es - a.en))) { + console.error(` ✖ ${s.rel} (es=${s.es} en=${s.en})`); + } + console.error( + `\nEach is a file whose pair EXISTS and whose headers MATCH, so ` + + `check-bilingual-parity\npasses it. Translate it, or declare it in ${ALLOW_FILE} ` + + `with a reason —\nsilencing this guard without one puts the repository back where ` + + `it was.\n`, + ); + process.exit(1); +} + +main(); diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 8b53281a..237b942c 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,10 +25,10 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | | 2 | 🟡 OPEN | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 3 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | | 5 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 6 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | | 7 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | diff --git a/docs/audit/untranslated-allowlist.json b/docs/audit/untranslated-allowlist.json new file mode 100644 index 00000000..16b77586 --- /dev/null +++ b/docs/audit/untranslated-allowlist.json @@ -0,0 +1,45 @@ +{ + "$comment": "Documents labelled English that are written in Spanish. See .harness/scripts/check-translation-language.mjs.", + "policy": { + "why": "Nine were found on 2026-08-01 by a guard written that day; `check-bilingual-parity` cannot see language, so all nine had been passing. Declaring them makes the debt COUNTED instead of invisible, and makes the tenth fail immediately.", + "rule": "An entry is a promise to translate, not a pardon. Every reason must name the row that tracks it or state a concrete blocker. `not a priority` is not a reason." + }, + "allow": [ + { + "file": "DECISIONS.md", + "reason": "Root ADR index. Tracked by GAP-013 (bilingual debt). The largest of the nine at 128 Spanish stopwords to 1 English — translating it means translating every ADR summary it carries, so it is the last one to move, not the first." + }, + { + "file": "MASTER_INDEX.md", + "reason": "Root navigation index. Tracked by GAP-013. Its entries are titles of other documents, so it can only be translated after the documents it points at." + }, + { + "file": "docs/adrs/T-044-single-tenant-isolation-model.md", + "reason": "ADR awaiting PO ratification (its own Status says so). Translating an unratified decision would produce two versions to keep in step while its content may still change." + }, + { + "file": "reference/specs/discovery/DISCOVERY_CANVAS.md", + "reason": "This IS `GAP-017` — the row is correct and stays open. Listed so the guard measures it instead of asserting it." + }, + { + "file": "reference/specs/architecture/c4-macro-topology-phase1.md", + "reason": "This IS `GAP-011` — the row is correct and stays open. Listed so the guard measures it instead of asserting it." + }, + { + "file": "reference/specs/architecture/scale-out-strategy.md", + "reason": "Tracked by GAP-013." + }, + { + "file": "docs/diagrams/evolith-tracker-master-flow.md", + "reason": "Tracked by GAP-013. Mermaid diagram labels dominate the prose, so a translation must decide whether node labels move too — a decision nobody has taken." + }, + { + "file": "docs/diagrams/evolith-tracker-geo-diagram.md", + "reason": "Tracked by GAP-013. Same Mermaid-label question as the master flow." + }, + { + "file": "docs/diagrams/evolith-tracker-crosscutting-diagram.md", + "reason": "Tracked by GAP-013. Same Mermaid-label question as the master flow." + } + ] +} From 80b2bf85e58b66d592e9c5d010d0f7b6fdf9285d Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:10:39 -0500 Subject: [PATCH 08/40] =?UTF-8?q?docs(board):=20GAP-013=20refutada=20?= =?UTF-8?q?=E2=80=94=20los=2020=20disenos=20tecnicos=20tienen=20su=20versi?= =?UTF-8?q?on=20ES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La fila dice «14 Technical Design Docs Lack ES Version». Medido el 2026-08-01: `reference/specs/design/` tiene 20 documentos y TODOS tienen su `.es.md`. Cero faltan. En todo el repositorio hay 19 ficheros `.md` sin pareja en castellano, y conviene mirar CUALES antes de contarlos como deuda: NUEVE estan bajo `docs/audit/` —informes de auditoria, triajes de corpus y este mismo registro—, que son documentos de trabajo y no documentacion de producto. Los otros diez son READMEs y notas de tarea (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). Ninguno es un diseno tecnico. LO QUE SI SOBREVIVE, y es distinto: tener la pareja no es tener la traduccion. El guard `check-translation-language` anadido hoy encontro 9 documentos cuyo `.md` esta escrito en castellano pese a existir el par — que es exactamente lo que describen GAP-011 y GAP-017, y siguen abiertas. Es la septima ficha de esta sesion que reclama trabajo hecho o describe un estado que dejo de ser cierto. Reordenamiento estable y renumeracion; mismos 107 IDs, mismo conjunto. Resultado: 7 OPEN, 1 DEFERRED, 99 RESOLVED. Verificado: `validate-docs` y `check-gap-registry` en verde. Co-Authored-By: Claude Opus 5 --- .../tracker-gaps-opportunities-tracking.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 237b942c..fa759805 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -26,14 +26,14 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| | 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡 OPEN | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | -| 5 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 6 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 8 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 9 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 2 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 3 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 6 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 7 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 8 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 9 | 🟢 RESOLVED | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | REFUTED and MEASURED 2026-08-01. The row says 14 technical design documents lack a Spanish version. `reference/specs/design/` holds **20** documents and **every one** has its `.es.md` — zero missing. Repository-wide, 19 `.md` files have no Spanish pair, and **9 of them are under `docs/audit/`**: audit reports, corpus triages and this register itself, which are working documents rather than product documentation. The other ten are READMEs and task notes (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). None is a technical design document. **A related defect DOES survive and is tracked elsewhere:** having the pair is not having the translation — `check-translation-language` found 9 documents whose `.md` is written in Spanish, which is what `GAP-011` and `GAP-017` are about. | 🟡 MEDIUM | 🟡 MEDIUM | | 10 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | | 11 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | | 12 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | @@ -348,7 +348,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-013 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs From a5f719c558d29e97a979966882c8c1a0c1674075 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:31:23 -0500 Subject: [PATCH 09/40] =?UTF-8?q?docs(audit):=20close=20COH-009=20?= =?UTF-8?q?=E2=80=94=20BR-003=20conflation=20already=20split=20into=20BR-0?= =?UTF-8?q?10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The row asks for one business-rule id carrying two rules to be split. The business-rule table already carries the split, and credits this row for it: BR-010, CFR Quality Threshold, described as escindida de BR-003 por COH-009; BR-003 es solo la firma humana. Verified across the repository rather than from that one line: every BR-003 occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half is cited as BR-010 by reference/specs/qa, by the test strategy against PhaseGateEvaluator, and by the Re-Do flow design. This is the eighth row found describing work already done. Its claim is not machine-falsifiable (it is about meaning, not presence), so it is NOT added to falsifiable-claims.json: that file takes only what a probe can refute without judgement, and a regex over prose is the failure mode it exists to avoid. --- .codex/config.toml | 10 ++++++++++ docs/audit/tracker-gaps-opportunities-tracking.md | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 .codex/config.toml diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 00000000..8b5006a4 --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,10 @@ +[mcp_servers.nx] +command = "npx" +args = [ + "-y", + "nx-mcp@latest", + "/Users/beyondnet/Source/evolith_tracker/src", + "--minimal", + "false", + "--disableTelemetry", +] diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index fa759805..0fa75929 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -31,8 +31,8 @@ This document is the only operational gap register in this repository. The maste | 4 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | | 5 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | | 6 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 7 | 🟡 OPEN | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 8 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 7 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 8 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | | 9 | 🟢 RESOLVED | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | REFUTED and MEASURED 2026-08-01. The row says 14 technical design documents lack a Spanish version. `reference/specs/design/` holds **20** documents and **every one** has its `.es.md` — zero missing. Repository-wide, 19 `.md` files have no Spanish pair, and **9 of them are under `docs/audit/`**: audit reports, corpus triages and this register itself, which are working documents rather than product documentation. The other ten are READMEs and task notes (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). None is a technical design document. **A related defect DOES survive and is tracked elsewhere:** having the pair is not having the translation — `check-translation-language` found 9 documents whose `.md` is written in Spanish, which is what `GAP-011` and `GAP-017` are about. | 🟡 MEDIUM | 🟡 MEDIUM | | 10 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | | 11 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | @@ -513,7 +513,7 @@ This document is the only operational gap register in this repository. The maste ### Detail COH-009 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** INCO (Source incoherence) - **Component:** Backend - **Module:** Release From 17adc223c1805e15ec78a079c241c3f3fd6a4666 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:40:21 -0500 Subject: [PATCH 10/40] =?UTF-8?q?docs(i18n):=20translate=20C4=20topology?= =?UTF-8?q?=20and=20Discovery=20Canvas=20=E2=80=94=20close=20GAP-011,=20GA?= =?UTF-8?q?P-017?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both rows were TRUE, and both had been marked DONE on the other board while the defect was still there. c4-macro-topology-phase1.md carried the banner English (this document) and 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. DISCOVERY_CANVAS.md was 23 of 24. Both passed check-bilingual-parity, which compares that the pair exists and that the headers match, and can see neither language nor content. Both are now genuinely English — prose, mermaid node descriptions and relationship labels — and their entries are removed from untranslated-allowlist.json, which drops from 9 declared to 7. That file is a list of promises, so shrinking it is the point. Verified after translating that no line still identical to the Spanish file contains Spanish prose: the remaining overlap is fences, braces and identifiers. --- .../tracker-gaps-opportunities-tracking.md | 18 +-- docs/audit/untranslated-allowlist.json | 8 -- .../architecture/c4-macro-topology-phase1.md | 120 +++++++++--------- reference/specs/discovery/DISCOVERY_CANVAS.md | 56 ++++---- 4 files changed, 97 insertions(+), 105 deletions(-) diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 0fa75929..58e3e50d 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,13 +25,13 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | CONFIRMED and MEASURED 2026-08-01. The row is right, and the file EXISTS — that is the trap. `X.md` is present, labelled «English (this document)», and written in Spanish, so `check-bilingual-parity` passes it: that guard compares file presence and header counts, neither of which sees language. `check-translation-language` does, and found **9 documents in this state of 143 paired**, including `DECISIONS.md` (128 Spanish markers to 1 English) and `MASTER_INDEX.md`. This row names one of the nine; all nine are declared with a reason in `untranslated-allowlist.json`, so the debt is counted rather than invisible and the tenth fails CI. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 5 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 6 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 7 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 1 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 2 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 3 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | +| 5 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 6 | 🟢 RESOLVED | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | RESOLVED — the row was TRUE and had been mismeasured. `c4-macro-topology-phase1.md` existed, was labelled «English (this document)» and passed `check-bilingual-parity`, but 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. It is now genuinely in English — prose, diagram descriptions and relationship labels — and its entry was removed from `untranslated-allowlist.json`, which drops from 9 declared to 7. Note for the record: the other board, `tracker-gap-tracking.md`, marked this DONE while the file was still Spanish. | 🟡 MEDIUM | 🟡 MEDIUM | +| 7 | 🟢 RESOLVED | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | RESOLVED — same defect and same correction as GAP-011. `DISCOVERY_CANVAS.md` was 23 of 24 non-empty lines identical to `DISCOVERY_CANVAS.es.md`; the English label was the only English in it. Now translated in full and removed from `untranslated-allowlist.json`. Both boards had this backwards on direction — one said the ES version was missing, the other said the EN one was — and what was actually missing was English content behind an English filename. | 🟡 MEDIUM | 🟡 MEDIUM | | 8 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | | 9 | 🟢 RESOLVED | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | REFUTED and MEASURED 2026-08-01. The row says 14 technical design documents lack a Spanish version. `reference/specs/design/` holds **20** documents and **every one** has its `.es.md` — zero missing. Repository-wide, 19 `.md` files have no Spanish pair, and **9 of them are under `docs/audit/`**: audit reports, corpus triages and this register itself, which are working documents rather than product documentation. The other ten are READMEs and task notes (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). None is a technical design document. **A related defect DOES survive and is tracked elsewhere:** having the pair is not having the translation — `check-translation-language` found 9 documents whose `.md` is written in Spanish, which is what `GAP-011` and `GAP-017` are about. | 🟡 MEDIUM | 🟡 MEDIUM | | 10 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | @@ -332,7 +332,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-011 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -396,7 +396,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-017 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs diff --git a/docs/audit/untranslated-allowlist.json b/docs/audit/untranslated-allowlist.json index 16b77586..3bbc3bcb 100644 --- a/docs/audit/untranslated-allowlist.json +++ b/docs/audit/untranslated-allowlist.json @@ -17,14 +17,6 @@ "file": "docs/adrs/T-044-single-tenant-isolation-model.md", "reason": "ADR awaiting PO ratification (its own Status says so). Translating an unratified decision would produce two versions to keep in step while its content may still change." }, - { - "file": "reference/specs/discovery/DISCOVERY_CANVAS.md", - "reason": "This IS `GAP-017` — the row is correct and stays open. Listed so the guard measures it instead of asserting it." - }, - { - "file": "reference/specs/architecture/c4-macro-topology-phase1.md", - "reason": "This IS `GAP-011` — the row is correct and stays open. Listed so the guard measures it instead of asserting it." - }, { "file": "reference/specs/architecture/scale-out-strategy.md", "reason": "Tracked by GAP-013." diff --git a/reference/specs/architecture/c4-macro-topology-phase1.md b/reference/specs/architecture/c4-macro-topology-phase1.md index 6bfdf481..ca80530f 100644 --- a/reference/specs/architecture/c4-macro-topology-phase1.md +++ b/reference/specs/architecture/c4-macro-topology-phase1.md @@ -1,123 +1,123 @@ -# C4 Model: Evolith Tracker (Fase 1 - MVP Topology) +# C4 Model: Evolith Tracker (Phase 1 - MVP Topology) > **Bilingual Navigation:** English (this document) · [Versión en Español](./c4-macro-topology-phase1.es.md) -Este documento detalla la arquitectura a nivel de Contexto y Contenedores para la Fase 1 del producto, alineada con la **Visión de Governed Composition**. Evolith Tracker actúa como el **Governance Control Plane** que orquesta y audita, mientras delega la ejecución técnica a proveedores externos mediante puertos y adaptadores (ACLs). +This document details the Context- and Container-level architecture for Phase 1 of the product, aligned with the **Governed Composition vision**. Evolith Tracker acts as the **Governance Control Plane** that orchestrates and audits, while delegating technical execution to external providers through ports and adapters (ACLs). -**Condición crítica:** El Backend opera como un Monolito de Despliegue Único con separación por esquemas en Base de Datos (convención `tracker_`, ver [T-008](../../../DECISIONS.md)). El Frontend opera como una arquitectura de **Microfrontends** (Module Federation). +**Critical condition:** The backend runs as a Single-Deployment Monolith with schema-level separation in the database (convention `tracker_`, see [T-008](../../../DECISIONS.md)). The frontend runs as a **Microfrontend** architecture (Module Federation). > [!NOTE] -> **Superficie API (Fase 1):** REST + OpenAPI 3.0 es el único estándar de API expuesto. GraphQL queda fuera de alcance en Fase 1 (ver [T-009](../../../DECISIONS.md)). +> **API surface (Phase 1):** REST + OpenAPI 3.0 is the only API standard exposed. GraphQL is out of scope for Phase 1 (see [T-009](../../../DECISIONS.md)). -## Nivel 1: Diagrama de Contexto del Sistema +## Level 1: System Context Diagram -Muestra el panorama general del Evolith Tracker actuando como el plano de control que centraliza decisiones y delega la ejecución a herramientas de mercado. +Shows the overall landscape, with Evolith Tracker acting as the control plane that centralises decisions and delegates execution to market tooling. ```mermaid C4Context title System Context diagram for Evolith Tracker Suite - Person(human_user, "Human Actor", "Gobernanza humana, autorizaciones y excepciones.") - Person(ai_agent, "Autonomous Agents", "Agentes ejecutando tareas acotadas vía MCP/API.") + Person(human_user, "Human Actor", "Human governance, authorisations and exceptions.") + Person(ai_agent, "Autonomous Agents", "Agents executing scoped tasks via MCP/API.") - System(evolith_tracker, "Evolith Tracker", "Governance Control Plane. Centraliza el estado del SDLC, evalúa Gates y mantiene el Grafo de Evidencias.") + System(evolith_tracker, "Evolith Tracker", "Governance Control Plane. Centralises SDLC state, evaluates Gates and maintains the Evidence Graph.") - System_Ext(core, "Evolith Core", "La Constitución. Provee Reglas, Esquemas y ADRs inmutables.") - System_Ext(ums, "UMS (User Management System)", "Identidad corporativa (AuthN/AuthZ).") + System_Ext(core, "Evolith Core", "The Constitution. Provides immutable Rules, Schemas and ADRs.") + System_Ext(ums, "UMS (User Management System)", "Corporate identity (AuthN/AuthZ).") - System_Ext(work_providers, "Work Systems (Jira, etc.)", "Sistemas operativos de tickets y tareas.") - System_Ext(scm_providers, "SCM & CI/CD (GitHub, .harness)", "Repositorios, pipelines y despliegues.") - System_Ext(obs_providers, "Observability & Analytics", "Langfuse, Superset. Trazas, costos y visualización.") + System_Ext(work_providers, "Work Systems (Jira, etc.)", "Operational ticket and task systems.") + System_Ext(scm_providers, "SCM & CI/CD (GitHub, .harness)", "Repositories, pipelines and deployments.") + System_Ext(obs_providers, "Observability & Analytics", "Langfuse, Superset. Traces, cost and visualisation.") - Rel(human_user, evolith_tracker, "Gobierna, aprueba y audita") - Rel(ai_agent, evolith_tracker, "Consume contexto y provee evidencia") + Rel(human_user, evolith_tracker, "Governs, approves and audits") + Rel(ai_agent, evolith_tracker, "Consumes context and supplies evidence") - Rel(core, evolith_tracker, "Provee reglas de negocio") - Rel(evolith_tracker, ums, "Delega AuthN y Roles") + Rel(core, evolith_tracker, "Provides business rules") + Rel(evolith_tracker, ums, "Delegates AuthN and Roles") - Rel(evolith_tracker, work_providers, "Mapea tickets a evidencias (Port & ACL)") - Rel(evolith_tracker, scm_providers, "Recibe resultados de CI/CD (Port & ACL)") - Rel(evolith_tracker, obs_providers, "Consume telemetría (Port & ACL)") + Rel(evolith_tracker, work_providers, "Maps tickets to evidence (Port & ACL)") + Rel(evolith_tracker, scm_providers, "Receives CI/CD results (Port & ACL)") + Rel(evolith_tracker, obs_providers, "Consumes telemetry (Port & ACL)") ``` -## Nivel 2: Diagrama de Contenedores (Fase 1 Topology) +## Level 2: Container Diagram (Phase 1 Topology) -Muestra la vista interna de la arquitectura en su **Fase 1**. Aquí se refleja la separación entre la API, el motor de decisiones (Gate Decision Engine), y los puertos (Provider Registry). +Shows the internal view of the architecture in its **Phase 1** form. It reflects the separation between the API, the decision engine (Gate Decision Engine), and the ports (Provider Registry). ```mermaid C4Container - title Container diagram for Evolith Tracker (Fase 1) + title Container diagram for Evolith Tracker (Phase 1) System_Ext(ums, "UMS SaaS", "AuthN/AuthZ") - Person(user, "User/Agent", "Interactúa con la Suite") + Person(user, "User/Agent", "Interacts with the Suite") System_Boundary(c1, "Evolith Tracker - Frontend Tier (Microfrontends)") { - Container(shell_host, "Shell Host", "React/Vite", "Orquesta la carga de remotes y layout") + Container(shell_host, "Shell Host", "React/Vite", "Orchestrates remote loading and layout") Container(mfe_gates, "SDLC Gates MFEs", "React Remote", "Discovery, Design, Construction, QA, Release") - Container(mfe_governance, "Governance & Metrics MFE", "React Remote", "Dashboards y auditoría") + Container(mfe_governance, "Governance & Metrics MFE", "React Remote", "Dashboards and audit") } System_Boundary(c2, "Evolith Tracker - Edge Tier") { - Container(api_gateway, "Governance API / BFF", "REST/OpenAPI", "Enruta tráfico y actúa como límite de autorización") + Container(api_gateway, "Governance API / BFF", "REST/OpenAPI", "Routes traffic and acts as the authorisation boundary") } System_Boundary(c3, "Evolith Tracker - Backend Tier (Control Plane)") { - Container(process_orch, "Process & Phase Orchestrator", "Service", "Gestiona el ciclo de vida de los procesos SDLC") - Container(gate_engine, "Gate Decision Engine", "Service", "Toma la decisión canónica evaluando evidencias, reglas y aprobaciones") - Container(evidence_graph, "Evidence Graph Service", "Service", "Mantiene la trazabilidad inmutable y el linaje de datos") - Container(provider_acl, "Provider & Adapter ACL", "Service", "Puertos neutrales (Work, SCM, Observability, Analytics) protegiendo el dominio") + Container(process_orch, "Process & Phase Orchestrator", "Service", "Manages the lifecycle of SDLC processes") + Container(gate_engine, "Gate Decision Engine", "Service", "Makes the canonical decision by evaluating evidence, rules and approvals") + Container(evidence_graph, "Evidence Graph Service", "Service", "Maintains immutable traceability and data lineage") + Container(provider_acl, "Provider & Adapter ACL", "Service", "Neutral ports (Work, SCM, Observability, Analytics) shielding the domain") } System_Boundary(c4, "Evolith Tracker - Data Tier") { - ContainerDb(single_db, "Relational Database", "PostgreSQL", "Schemas segregados lógicamente (tracker_discovery, tracker_release, etc.)") + ContainerDb(single_db, "Relational Database", "PostgreSQL", "Logically segregated schemas (tracker_discovery, tracker_release, etc.)") } - Rel(user, shell_host, "Visita", "HTTPS") - Rel(shell_host, mfe_gates, "Carga", "Module Federation") - Rel(shell_host, mfe_governance, "Carga", "Module Federation") + Rel(user, shell_host, "Visits", "HTTPS") + Rel(shell_host, mfe_gates, "Loads", "Module Federation") + Rel(shell_host, mfe_governance, "Loads", "Module Federation") - Rel(shell_host, api_gateway, "Llamadas API", "REST") + Rel(shell_host, api_gateway, "API calls", "REST") - Rel(api_gateway, process_orch, "Solicita transición", "HTTPS/REST") - Rel(api_gateway, ums, "Valida JWT", "HTTPS") + Rel(api_gateway, process_orch, "Requests transition", "HTTPS/REST") + Rel(api_gateway, ums, "Validates JWT", "HTTPS") - Rel(process_orch, gate_engine, "Solicita evaluación de Gate") - Rel(gate_engine, evidence_graph, "Consulta/Guarda Evidencia") - Rel(evidence_graph, provider_acl, "Normaliza datos de proveedores") + Rel(process_orch, gate_engine, "Requests Gate evaluation") + Rel(gate_engine, evidence_graph, "Queries/Stores Evidence") + Rel(evidence_graph, provider_acl, "Normalises provider data") - Rel(process_orch, single_db, "Escribe (schema por contexto)") - Rel(evidence_graph, single_db, "Guarda Linaje") + Rel(process_orch, single_db, "Writes (schema per context)") + Rel(evidence_graph, single_db, "Stores Lineage") ``` -## Nivel 3: Diagrama de Componentes (Control Plane Backend) +## Level 3: Component Diagram (Control Plane Backend) -Muestra los 9 Bounded Contexts lógicos (5 Phase Gates + 4 de soporte) que conforman el Monolito de Fase 1. +Shows the 9 logical Bounded Contexts (5 Phase Gates + 4 supporting) that make up the Phase 1 monolith. ```mermaid C4Component title Component diagram for Tracker Monolith Service Container_Boundary(backend_monolith, "Tracker Control Plane") { - Component(discovery_module, "Discovery Module", "Phase Gate 1", "Ideación, Canvas, validación estratégica (Build vs Compose)") - Component(design_module, "Design Module", "Phase Gate 2", "Contratos, ADRs, blueprints") + Component(discovery_module, "Discovery Module", "Phase Gate 1", "Ideation, Canvas, strategic validation (Build vs Compose)") + Component(design_module, "Design Module", "Phase Gate 2", "Contracts, ADRs, blueprints") Component(construction_module, "Construction Module", "Phase Gate 3", "Tracking, commits, Architecture Drift") - Component(qa_module, "QA Module", "Phase Gate 4", "Pruebas, calidad, CFR") - Component(release_module, "Release Module", "Phase Gate 5", "Despliegues, autorizaciones de release") + Component(qa_module, "QA Module", "Phase Gate 4", "Testing, quality, CFR") + Component(release_module, "Release Module", "Phase Gate 5", "Deployments, release authorisations") - Component(governance_module, "Governance Module", "Soporte", "SDLC execution, orquestación de agentes") - Component(artifacts_module, "Artifacts Module", "Soporte", "Definiciones de artefactos, Evidence Graph") - Component(metrics_module, "Metrics Module", "Soporte", "Scorecards asíncronos (DORA/SPACE)") - Component(integration_module, "Integration Module", "Soporte", "Ports & ACLs (Jira, GitHub, Langfuse)") + Component(governance_module, "Governance Module", "Supporting", "SDLC execution, agent orchestration") + Component(artifacts_module, "Artifacts Module", "Supporting", "Artifact definitions, Evidence Graph") + Component(metrics_module, "Metrics Module", "Supporting", "Asynchronous scorecards (DORA/SPACE)") + Component(integration_module, "Integration Module", "Supporting", "Ports & ACLs (Jira, GitHub, Langfuse)") - Component(event_bus, "Internal Event Bus", "In-Memory", "Comunicación asíncrona entre módulos (CQRS/Eventos)") + Component(event_bus, "Internal Event Bus", "In-Memory", "Asynchronous inter-module communication (CQRS/Events)") } - Container(api_gateway, "Governance API", "Nginx", "Llamadas entrantes (REST)") + Container(api_gateway, "Governance API", "Nginx", "Inbound calls (REST)") ContainerDb(single_db, "Relational Database", "PostgreSQL", "schema-per-context (T-047)") - Rel(api_gateway, discovery_module, "Ruta tráfico", "REST") - Rel(api_gateway, integration_module, "Ruta tráfico", "REST") + Rel(api_gateway, discovery_module, "Routes traffic", "REST") + Rel(api_gateway, integration_module, "Routes traffic", "REST") - Rel(integration_module, event_bus, "Publica eventos (ej. PR Merged)") - Rel(construction_module, event_bus, "Escucha eventos") + Rel(integration_module, event_bus, "Publishes events (e.g. PR Merged)") + Rel(construction_module, event_bus, "Listens for events") ``` diff --git a/reference/specs/discovery/DISCOVERY_CANVAS.md b/reference/specs/discovery/DISCOVERY_CANVAS.md index 588f8942..9b2d1ae3 100644 --- a/reference/specs/discovery/DISCOVERY_CANVAS.md +++ b/reference/specs/discovery/DISCOVERY_CANVAS.md @@ -2,31 +2,31 @@ > **Bilingual Navigation:** English (this document) · [Versión en Español](./DISCOVERY_CANVAS.es.md) -*Este documento es el artefacto oficial de entrada al flujo Spec-Driven. Toda iniciativa debe superar esta compuerta de viabilidad (ROI/KPIs) antes de autorizar el diseño arquitectónico.* - -## 1. Definición del Problema / Oportunidad -- **Problema:** Los ciclos de desarrollo de software tradicionales sufren de "Deriva Arquitectónica", falta de gobernanza en la codificación, y desalineación entre las fechas de negocio (Release Planner) y la calidad real del código (QA/Regresión). -- **Oportunidad:** Construir un SDLC AI-Native (Evolith Tracker) donde la IA genere y verifique código basado en contratos (Spec-as-Source), asegurando que el esfuerzo humano se concentre exclusivamente en el gobierno y orquestación. - -## 2. Propuesta de Valor -Una Suite de Ingeniería E2E que integra Discovery, Arquitectura, Tracking, QA y Release Management en un Monolito Progresivo Multi-Tenant, regido estrictamente por los estándares inmutables de `Evolith Core`. - -## 3. Retorno de Inversión (ROI) Justificado -- **Reducción de Costos:** Disminución del 40% en horas de refactorización por deuda técnica y deriva arquitectónica. -- **Eficiencia Operativa:** Eliminación del trabajo manual en la actualización de cronogramas de despliegue mediante el Motor de Contingencias (Re-Do Flow). -- **Time-to-Market:** Reducción del ciclo de entrega mediante la automatización del diseño técnico y QA por contratos. - -## 4. KPIs y Métricas de Éxito (DORA & SPACE) -- **Deployment Frequency:** Aumentar de despliegues semanales a despliegues diarios (On-Demand) gracias a los Quality Gates automatizados. -- **Lead Time for Changes:** Reducir el tiempo desde la ideación (Discovery) hasta producción en un 50%. -- **Architecture Adherence Index (Nuevo KPI):** Mantener un 100% de correlación entre especificaciones funcionales (Markdown), contratos técnicos (OpenAPI) y código físico. Cero deriva permitida. -- **Change Failure Rate:** Menor al 2% gracias a la integración profunda con `.harness` (Contract Testing). - -## 5. Riesgos y Supuestos (Gate Viability) -- **Riesgo:** Resistencia al cambio por parte de equipos acostumbrados a herramientas tradicionales (Jira, Trello) y desarrollo empírico sin contratos previos. -- **Mitigación:** Gobernanza forzada (System-level lock). Ningún código se despliega si no nace de una Spec y pasa el pipeline de `.harness`. -- **Supuesto:** Disponibilidad y estabilidad del servicio UMS para AuthN/AuthZ. - -## 6. Resolución del Agente PO (Compuerta) -[APROBADO] **ESTADO: APROBADO.** -El retorno de inversión justifica el costo. Los KPIs son medibles asíncronamente mediante CQRS. Se autoriza el avance a la fase de **Architecture Spec-Driven** para la definición de Contratos. +*This document is the official entry artifact into the Spec-Driven flow. Every initiative must clear this viability gate (ROI/KPIs) before architectural design is authorised.* + +## 1. Problem / Opportunity Definition +- **Problem:** Traditional software development cycles suffer from "Architecture Drift", a lack of governance over coding, and misalignment between business dates (Release Planner) and the real quality of the code (QA/Regression). +- **Opportunity:** Build an AI-Native SDLC (Evolith Tracker) where AI generates and verifies code from contracts (Spec-as-Source), ensuring human effort concentrates exclusively on governance and orchestration. + +## 2. Value Proposition +An end-to-end engineering suite integrating Discovery, Architecture, Tracking, QA and Release Management into a Progressive Multi-Tenant Monolith, governed strictly by the immutable standards of `Evolith Core`. + +## 3. Justified Return on Investment (ROI) +- **Cost reduction:** 40% fewer hours spent refactoring technical debt and architecture drift. +- **Operational efficiency:** Elimination of manual work updating deployment schedules, via the Contingency Engine (Re-Do Flow). +- **Time-to-Market:** Shorter delivery cycle through automation of technical design and contract-based QA. + +## 4. KPIs and Success Metrics (DORA & SPACE) +- **Deployment Frequency:** Move from weekly to daily (on-demand) deployments thanks to automated Quality Gates. +- **Lead Time for Changes:** Cut the time from ideation (Discovery) to production by 50%. +- **Architecture Adherence Index (new KPI):** Maintain 100% correlation between functional specifications (Markdown), technical contracts (OpenAPI) and physical code. Zero drift allowed. +- **Change Failure Rate:** Below 2%, thanks to deep integration with `.harness` (Contract Testing). + +## 5. Risks and Assumptions (Gate Viability) +- **Risk:** Resistance to change from teams used to traditional tooling (Jira, Trello) and to empirical development without prior contracts. +- **Mitigation:** Enforced governance (system-level lock). No code deploys unless it originates from a Spec and passes the `.harness` pipeline. +- **Assumption:** Availability and stability of the UMS service for AuthN/AuthZ. + +## 6. PO Agent Resolution (Gate) +[APPROVED] **STATUS: APPROVED.** +The return on investment justifies the cost. The KPIs are measurable asynchronously via CQRS. Advancement to the **Architecture Spec-Driven** phase is authorised for contract definition. From 5870fada27623f9fe58a5981ea138263611fd363 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:51:41 -0500 Subject: [PATCH 11/40] =?UTF-8?q?docs(discovery):=20cover=20Create/Read/Su?= =?UTF-8?q?persede=20in=20Gherkin=20=E2=80=94=20close=20COH-012,=20GAP-016?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit COH-012 asked for the two missing CRUD operations. Nine scenarios added across three Features: Create (type derivation for 0/1/2/7 products against InitiativeScope.Derive, the Initiative.TenantRequired guard, ConsolidateFrom lineage), Read (own-tenant hit; other-tenant read returning exactly what a non-existent id returns) and withdrawal. The row's premise is corrected, not obeyed. There is no Delete in this aggregate and there must not be: an initiative is superseded into another (Supersede -> consolidated, BR-DIS-005) because its lineage is governance evidence. A Scenario: Delete would have satisfied the row, satisfied the probe that was watching for exactly that string, and described a system that does not exist. The COH-012 entry is withdrawn from falsifiable-claims.json with that reason recorded in the file rather than deleted silently — a probe inherits whatever its row assumed, and a row can assume something false. Constants in the scenarios were read from the code, not guessed: TENANT_WIDE, SINGLE_PRODUCT, CROSS_PRODUCT, consolidated, Initiative.TenantRequired, Initiative.NotConsolidatable. GAP-016 was stale. The roadmap has carried Document Status: SUPERSEDED since it was corrected, and the marker cites this row by id. Note on coverage: with COH-012 withdrawn and GAP-022 resolved, the falsifiable-claim guard now probes ZERO claims and says so on every run. That is the guard working as designed, not a pass. --- docs/audit/falsifiable-claims.json | 28 ++----- .../tracker-gaps-opportunities-tracking.md | 14 ++-- docs/design/discovery-functional-specs.md | 77 +++++++++++++++++++ 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/docs/audit/falsifiable-claims.json b/docs/audit/falsifiable-claims.json index ba491e41..8433662a 100644 --- a/docs/audit/falsifiable-claims.json +++ b/docs/audit/falsifiable-claims.json @@ -6,27 +6,6 @@ "notProse": "Probes are DATA, never regular expressions over the row's prose. `50-validate-gap-claim` in the Core repository read prose to infer intent, produced nine false attributions in one day, and taught authors to delete true sentences to appease it. That failure is not repeated here: a claim is checked only when someone writes down, explicitly, the symbol and the paths that would refute it." }, "claims": [ - { - "id": "COH-012", - "claim": "Gherkin covers only Create and Update; Delete and Read are entirely missing.", - "probe": { - "kind": "symbol-absent", - "symbols": [ - "Scenario: Delete", - "Scenario: Read", - "Escenario: Eliminar" - ], - "paths": [ - "docs", - "reference" - ], - "extensions": [ - ".feature", - ".md" - ] - }, - "note": "Refuted the day a Delete or Read scenario appears anywhere in the specs. The row is about spec coverage, so the probe reads specs and not code." - }, { "id": "GAP-022", "claim": "SPACE metrics are not defined anywhere.", @@ -46,5 +25,12 @@ }, "note": "The row claims absence of a definition. Any document that defines the framework refutes it." } + ], + "withdrawn": [ + { + "id": "COH-012", + "probeWas": "symbol-absent on 'Scenario: Delete' / 'Scenario: Read' / 'Escenario: Eliminar'", + "why": "The probe encoded a WRONG PREMISE and would have stayed green forever while rewarding the wrong fix. It asked for a Delete scenario; the Discovery aggregate has no Delete and must not have one — an initiative is superseded into another (Supersede, status consolidated, BR-DIS-005) because its lineage is governance evidence. Adding 'Scenario: Delete' would have turned the probe green by describing a system that does not exist. Recorded rather than quietly removed: the lesson is that a falsifiable probe inherits whatever the row assumed, and a row can assume something false." + } ] } diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 58e3e50d..2d3d2592 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,11 +25,11 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 5 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 1 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 2 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 3 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 4 | 🟢 RESOLVED | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | RESOLVED — stale row. `reference/specs/design/tracker-implementation-roadmap.md` has carried `Document Status: SUPERSEDED — historical NestJS-era draft` since it was corrected, and the marker cites **this row by id**: «SUPERSEDED (GAP-016)». The roadmap planned a NestJS build that was executed in .NET, so «no calendar dates» is moot on a document that describes a plan already carried out under a different stack. The other board, `tracker-gap-tracking.md`, recorded this correctly; this register did not. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟢 RESOLVED | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | RESOLVED — 9 scenarios added to `docs/design/discovery-functional-specs.md`, covering Create (type derivation for 0/1/2/7 products against `InitiativeScope.Derive`, the `Initiative.TenantRequired` guard, and `ConsolidateFrom` lineage), Read (own-tenant hit, and other-tenant read returning exactly what a non-existent id returns — the shape that stops the id being confirmed), and withdrawal. **The row's premise was partly wrong and is corrected rather than obeyed:** there is no Delete in this aggregate and there must not be. An initiative is superseded into another (`Supersede` → `consolidated`, BR-DIS-005) because its lineage is governance evidence. Writing a Delete scenario would have satisfied the row and described a system that does not exist. The COH-012 probe in `falsifiable-claims.json` is therefore withdrawn, with the reason recorded in that file: it had inherited the same false premise. | 🟢 | 🟢 | | 6 | 🟢 RESOLVED | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | RESOLVED — the row was TRUE and had been mismeasured. `c4-macro-topology-phase1.md` existed, was labelled «English (this document)» and passed `check-bilingual-parity`, but 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. It is now genuinely in English — prose, diagram descriptions and relationship labels — and its entry was removed from `untranslated-allowlist.json`, which drops from 9 declared to 7. Note for the record: the other board, `tracker-gap-tracking.md`, marked this DONE while the file was still Spanish. | 🟡 MEDIUM | 🟡 MEDIUM | | 7 | 🟢 RESOLVED | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | RESOLVED — same defect and same correction as GAP-011. `DISCOVERY_CANVAS.md` was 23 of 24 non-empty lines identical to `DISCOVERY_CANVAS.es.md`; the English label was the only English in it. Now translated in full and removed from `untranslated-allowlist.json`. Both boards had this backwards on direction — one said the ES version was missing, the other said the EN one was — and what was actually missing was English content behind an English filename. | 🟡 MEDIUM | 🟡 MEDIUM | | 8 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | @@ -380,7 +380,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-016 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -497,7 +497,7 @@ This document is the only operational gap register in this repository. The maste ### Detail COH-012 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** GAP (Missing capability / corrective gap) - **Component:** Backend - **Module:** Discovery diff --git a/docs/design/discovery-functional-specs.md b/docs/design/discovery-functional-specs.md index 82b96d28..f2949942 100644 --- a/docs/design/discovery-functional-specs.md +++ b/docs/design/discovery-functional-specs.md @@ -44,6 +44,83 @@ La compuerta de aprobación de Discovery es dinámica y se basa en el tipo de in A continuación, se detallan los escenarios base que guían el QA y aseguran la coherencia entre el requerimiento y el modelo de dominio. +> [!NOTE] +> **Sobre "las cuatro operaciones CRUD" (COH-012).** El hallazgo original pedía cubrir Create, Read, Update y Delete. Tres de las cuatro existen en el agregado; **`Delete` no existe y no debe existir**: una iniciativa nunca se borra, se *supersede* (`Supersede` → estado `consolidated`, BR-DIS-005), porque su linaje es evidencia de gobierno y borrarlo rompería la trazabilidad. Escribir un escenario `Delete` habría satisfecho la ficha y descrito un sistema que no es éste. Lo que sigue cubre Create, Read y la operación de retiro que el dominio sí tiene. + +```gherkin +Feature: Initiative Creation & Type Derivation + + Scenario Outline: Type is derived from the size of the product scope + Given a tenant "acme" + When an Initiative is created with Product(s) in its ProductScope + Then its InitiativeType is "" + And a Facet stub exists for each product in the scope + And the Initiative is in "draft" state with TypeFrozen false + + Examples: + | count | type | + | 0 | TENANT_WIDE | + | 1 | SINGLE_PRODUCT | + | 2 | CROSS_PRODUCT | + | 7 | CROSS_PRODUCT | + + Scenario: Creation without a tenant is refused + Given no tenant context + When an Initiative is created with an empty tenant identifier + Then the operation is rejected with error "Initiative.TenantRequired" + And no Initiative is persisted + + Scenario: A consolidating Initiative records the lineage of what it groups + Given three source inputs from Intake + When an Initiative is created via ConsolidateFrom with those three as constituents + Then the Initiative is in "draft" state + And its Constituents list the three sources + And its type is derived from the supplied scope, not from the constituents + +``` + +```gherkin +Feature: Reading an Initiative + + Scenario: An Initiative is readable by its own tenant + Given an Initiative belonging to tenant "acme" + When tenant "acme" requests it by id + Then the Initiative is returned with its scope, facets and approval state + + Scenario: An Initiative of another tenant is indistinguishable from one that does not exist + Given an Initiative belonging to tenant "acme" + When tenant "globex" requests it by the same id + Then nothing is returned + And the response is identical to requesting an id that was never created + + # The two outcomes MUST stay identical. A distinct "forbidden" answer would confirm to + # tenant "globex" that the id exists — which is the leak the null-for-both shape prevents. + +``` + +```gherkin +Feature: Withdrawing an Initiative (Supersede — the domain has no Delete) + + Scenario: A draft Initiative is superseded by a larger one + Given an Initiative in "draft" state + When it is superseded into initiative "INI-042" with reason "grouped into the platform epic" + Then the Initiative transitions to "consolidated" + And its SupersededByInitiativeId is "INI-042" + And the reason is retained in its metadata + And the Initiative is still readable — nothing is deleted + + Scenario: An already-consolidated Initiative cannot be superseded again + Given an Initiative in "consolidated" state + When it is superseded into another initiative + Then the operation is rejected with error "Initiative.NotConsolidatable" + + Scenario: A rejected Initiative cannot be superseded + Given an Initiative in "rejected" state + When it is superseded into another initiative + Then the operation is rejected with error "Initiative.NotConsolidatable" + +``` + ```gherkin Feature: Initiative State Machine & Scope Freezing From f4a5dc7d17a26bc1966d2c798b87cc29feda1309 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:57:45 -0500 Subject: [PATCH 12/40] =?UTF-8?q?chore(audit):=20contrast=20the=20third=20?= =?UTF-8?q?gap=20surface=20=E2=80=94=20reconcile=20GAP-020/023/025,=20file?= =?UTF-8?q?=20COH-016?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This repository keeps THREE gap surfaces sharing one id namespace: the register (tracker-gaps-opportunities-tracking.md), the board (tracker-gap-tracking.md) and the catalog (tracker-gap-reference-catalog.md). check-gap-registry.py kept the last two in step since the day it was written, and never looked at the first. Measured today: 34 ids in common, 5 of them contradicting each other. And neither surface was the trustworthy one — the board claimed GAP-011 and GAP-017 done while both files were still Spanish, and the register kept three rows open that the catalog had closed with evidence in July. Reconciled, each verified against the repository rather than against the other board: GAP-023 -> RESOLVED. The 254-line Re-Do design exists with state model, recalculation algorithm, events and traceability. Its five open items are scheduling decisions awaiting PO ratification, not missing design. GAP-025 -> RESOLVED. bounded-context-map.md names the four supporting contexts and all ten ddd-model.md files exist. GAP-020 -> REOPENED. This corrects my own closure from earlier today. The catalog reopened it by product direction and the reason stands: the Tracker must CONSUME the Core schema references, not merely document them. The guard now compares the two vocabularies on the only thing both state unambiguously — closed or not — because inventing an OPEN->PENDING mapping would be a decision dressed up as a check. Six self-tests; three go red when the comparison is disabled, verified by disabling it. COH-016 records the finding so the next reader does not rediscover it. --- .github/workflows/ci.yml | 8 + .harness/scripts/check-gap-registry.py | 55 ++++ .harness/scripts/check-gap-registry.test.py | 94 +++++++ .../tracker-gaps-opportunities-tracking.md | 237 ++++++++++-------- 4 files changed, 284 insertions(+), 110 deletions(-) create mode 100644 .harness/scripts/check-gap-registry.test.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 21497219..8360f92b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,6 +236,14 @@ jobs: - name: Board y catalogo deben contar lo mismo run: python3 .harness/scripts/check-gap-registry.py + # El paso anterior contrasta ademas el REGISTRO, la tercera superficie, anadida el + # 2026-08-01: board y catalogo llevaban sincronizados desde que existe el guard y + # nadie miraba el registro, que comparte el mismo espacio de ids. De los 34 ids + # comunes, CINCO se contradecian. Estas pruebas son negativas: comprueban que el + # contraste se pone rojo cuando debe, no que exista. + - name: Self-tests for the board/registro contrast + run: python3 .harness/scripts/check-gap-registry.test.py + # Las fichas del board recogen hallazgos de auditoria y nada las vuelve a # contrastar con el codigo, asi que envejecen en silencio mientras siguen # dirigiendo prioridades. El 2026-08-01 se encontraron CINCO reclamando trabajo ya diff --git a/.harness/scripts/check-gap-registry.py b/.harness/scripts/check-gap-registry.py index 8b944765..eaec5b0d 100755 --- a/.harness/scripts/check-gap-registry.py +++ b/.harness/scripts/check-gap-registry.py @@ -24,6 +24,8 @@ RAIZ = Path(__file__).resolve().parent.parent.parent BOARD = RAIZ / "docs/audit/tracker-gap-tracking.md" CATALOGO = RAIZ / "docs/audit/tracker-gap-reference-catalog.md" +# Tercera superficie, añadida el 2026-08-01. Ver `estados_registro`. +REGISTRO = RAIZ / "docs/audit/tracker-gaps-opportunities-tracking.md" # Tolerante a sangrado y a viñeta con `*`: el objetivo es DETECTAR el desorden, no # tropezar con él y reportar un falso "no existe". @@ -57,12 +59,60 @@ def estados_catalogo() -> tuple[dict[str, str], list[str], list[str]]: return estados, dobles, sangradas +def estados_registro() -> dict[str, str]: + """Estados del REGISTRO, la tercera superficie. + + Se añadió el 2026-08-01 después de medir el agujero: board y catálogo llevaban + sincronizados desde que existe esta comprobación, y el registro —que comparte el mismo + espacio de identificadores— no lo miraba nadie. De los 34 ids que las dos superficies + tienen en común, **5 se contradecían**: `COH-012`, `GAP-016`, `GAP-023` y `GAP-025` + figuraban cerrados en el board y abiertos en el registro, y `GAP-020` al revés. En dos + de esos casos el board mentía (los ficheros «traducidos» seguían en español) y en tres + mentía el registro. No es que una superficie sea de fiar y la otra no: es que nada las + obligaba a coincidir. + """ + estados = {} + for linea in REGISTRO.read_text().splitlines(): + if not linea.startswith("|"): + continue + celdas = linea.split("|") + if len(celdas) < 4: + continue + m = re.search(r"\[([A-Z]+-[A-Z0-9/]+)\]", celdas[3]) + if not m: + continue + estado = next( + (s for s in ("BLOCKED", "OPEN", "DEFERRED", "RESOLVED") if s in celdas[2]), None + ) + if estado: + estados[m.group(1)] = estado + return estados + + +# Los dos vocabularios no coinciden y NO se traducen entre sí: inventar un mapa +# `OPEN→PENDING`, `DEFERRED→?` sería una decisión disfrazada de comprobación. Se compara +# sólo lo que ambas superficies afirman sin ambigüedad — si el ítem está cerrado o no — +# que es justo la dimensión en la que se contradecían. +CERRADO_BOARD = {"DONE"} +CERRADO_REGISTRO = {"RESOLVED"} + + def main() -> int: board = estados_board() catalogo, dobles, sangradas = estados_catalogo() + registro = estados_registro() problemas = [] + for gid in sorted(set(board) & set(registro)): + cerrado_b = board[gid] in CERRADO_BOARD + cerrado_r = registro[gid] in CERRADO_REGISTRO + if cerrado_b != cerrado_r: + problemas.append( + f"{gid}: el board dice {board[gid]} y el registro dice {registro[gid]} — " + f"uno lo da por cerrado y el otro no" + ) + desync = [(g, board[g], catalogo[g]) for g in catalogo if g in board and board[g] != catalogo[g]] for gid, b, c in sorted(desync): problemas.append(f"{gid}: el board dice {b} y su ficha dice {c}") @@ -82,8 +132,13 @@ def main() -> int: print(f" · {p}") return 1 + comunes = len(set(board) & set(registro)) print(f"Registro coherente: {len(catalogo)} fichas / {len(board)} filas.") print(f" {dict(Counter(board.values()))}") + # El denominador se imprime siempre. Board y registro comparten espacio de ids pero + # sólo se solapan en una parte: fuera de esos ids nada aquí comprueba nada, y verlo + # escrito evita leer el verde como si cubriera las tres superficies enteras. + print(f" board∩registro: {comunes} id(s) contrastados de {len(registro)} en el registro.") return 0 diff --git a/.harness/scripts/check-gap-registry.test.py b/.harness/scripts/check-gap-registry.test.py new file mode 100644 index 00000000..0e610b7b --- /dev/null +++ b/.harness/scripts/check-gap-registry.test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""Pruebas del contraste board ↔ registro añadido a `check-gap-registry.py`. + +Todas menos una son NEGATIVAS. Un guard que sólo se ha visto pasar es indistinguible de +uno roto, y esa confusión ya costó cara en este repositorio: el board daba por traducidos +dos ficheros que seguían en español, y todo estaba verde. + +La última prueba es la que evita el falso positivo simétrico: board y registro sólo se +solapan en una parte de sus ids, así que un id presente en uno y ausente en el otro NO es +una contradicción y no debe reportarse como tal. +""" +import shutil +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + +GUARD = Path(__file__).resolve().parent / "check-gap-registry.py" + + +def _repo(tmp: Path, filas): + """Monta un repositorio de usar y tirar con las tres superficies coherentes salvo + en lo que cada prueba quiera romper. `filas` = [(id, estado_board, estado_registro)]; + un estado a None omite la fila en esa superficie.""" + (tmp / ".harness/scripts").mkdir(parents=True) + (tmp / "docs/audit").mkdir(parents=True) + shutil.copy(GUARD, tmp / ".harness/scripts" / GUARD.name) + + board = ["| Gap | Qué | Estado |", "|---|---|---|"] + catalogo = ["# Catálogo", ""] + registro = [ + "| # | Status | ID | Type |", + "|---|---|---|---|", + ] + for n, (gid, eb, er) in enumerate(filas, start=1): + if eb is not None: + board.append(f"| [`{gid}`](./cat.md#{gid.lower()}) | algo | `{eb}` |") + catalogo += [f"#### {gid}", "", f"- **Status:** `{eb}`", ""] + if er is not None: + registro.append(f"| {n} | {er} | [{gid}](#detail-{gid.lower()}) | GAP |") + + (tmp / "docs/audit/tracker-gap-tracking.md").write_text("\n".join(board) + "\n") + (tmp / "docs/audit/tracker-gap-reference-catalog.md").write_text("\n".join(catalogo) + "\n") + (tmp / "docs/audit/tracker-gaps-opportunities-tracking.md").write_text("\n".join(registro) + "\n") + return tmp / ".harness/scripts" / GUARD.name + + +def correr(filas): + with tempfile.TemporaryDirectory() as d: + script = _repo(Path(d), filas) + p = subprocess.run([sys.executable, str(script)], capture_output=True, text=True) + return p.returncode, p.stdout + p.stderr + + +class ContrasteBoardRegistro(unittest.TestCase): + def test_de_acuerdo_en_cerrado_pasa(self): + code, _ = correr([("GAP-001", "DONE", "🟢 RESOLVED")]) + self.assertEqual(code, 0) + + def test_de_acuerdo_en_abierto_pasa(self): + code, _ = correr([("GAP-001", "PENDING", "🟡 OPEN")]) + self.assertEqual(code, 0) + + def test_board_cerrado_y_registro_abierto_falla(self): + """La forma exacta de COH-012, GAP-016, GAP-023 y GAP-025 el 2026-08-01.""" + code, salida = correr([("GAP-001", "DONE", "🟡 OPEN")]) + self.assertEqual(code, 1) + self.assertIn("GAP-001", salida) + self.assertIn("uno lo da por cerrado y el otro no", salida) + + def test_registro_cerrado_y_board_abierto_falla(self): + """La forma de GAP-020: cerrada en el registro y reabierta en el catálogo.""" + code, salida = correr([("GAP-001", "PENDING", "🟢 RESOLVED")]) + self.assertEqual(code, 1) + self.assertIn("GAP-001", salida) + + def test_deferred_en_el_registro_no_cuenta_como_cerrado(self): + code, _ = correr([("GAP-001", "DONE", "🟡⏳ DEFERRED")]) + self.assertEqual(code, 1) + + def test_id_en_una_sola_superficie_no_es_contradiccion(self): + """Las dos superficies sólo se solapan en parte. Comparar lo no compartido + convertiría cada id exclusivo en un fallo y haría el guard inservible.""" + code, _ = correr([ + ("GAP-001", "DONE", "🟢 RESOLVED"), + ("GAP-002", "DONE", None), + ("GAP-003", None, "🟡 OPEN"), + ]) + self.assertEqual(code, 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 2d3d2592..6ddaba52 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,113 +25,114 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | -| 4 | 🟢 RESOLVED | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | RESOLVED — stale row. `reference/specs/design/tracker-implementation-roadmap.md` has carried `Document Status: SUPERSEDED — historical NestJS-era draft` since it was corrected, and the marker cites **this row by id**: «SUPERSEDED (GAP-016)». The roadmap planned a NestJS build that was executed in .NET, so «no calendar dates» is moot on a document that describes a plan already carried out under a different stack. The other board, `tracker-gap-tracking.md`, recorded this correctly; this register did not. | 🟡 MEDIUM | 🟡 MEDIUM | -| 5 | 🟢 RESOLVED | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | RESOLVED — 9 scenarios added to `docs/design/discovery-functional-specs.md`, covering Create (type derivation for 0/1/2/7 products against `InitiativeScope.Derive`, the `Initiative.TenantRequired` guard, and `ConsolidateFrom` lineage), Read (own-tenant hit, and other-tenant read returning exactly what a non-existent id returns — the shape that stops the id being confirmed), and withdrawal. **The row's premise was partly wrong and is corrected rather than obeyed:** there is no Delete in this aggregate and there must not be. An initiative is superseded into another (`Supersede` → `consolidated`, BR-DIS-005) because its lineage is governance evidence. Writing a Delete scenario would have satisfied the row and described a system that does not exist. The COH-012 probe in `falsifiable-claims.json` is therefore withdrawn, with the reason recorded in that file: it had inherited the same false premise. | 🟢 | 🟢 | -| 6 | 🟢 RESOLVED | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | RESOLVED — the row was TRUE and had been mismeasured. `c4-macro-topology-phase1.md` existed, was labelled «English (this document)» and passed `check-bilingual-parity`, but 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. It is now genuinely in English — prose, diagram descriptions and relationship labels — and its entry was removed from `untranslated-allowlist.json`, which drops from 9 declared to 7. Note for the record: the other board, `tracker-gap-tracking.md`, marked this DONE while the file was still Spanish. | 🟡 MEDIUM | 🟡 MEDIUM | -| 7 | 🟢 RESOLVED | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | RESOLVED — same defect and same correction as GAP-011. `DISCOVERY_CANVAS.md` was 23 of 24 non-empty lines identical to `DISCOVERY_CANVAS.es.md`; the English label was the only English in it. Now translated in full and removed from `untranslated-allowlist.json`. Both boards had this backwards on direction — one said the ES version was missing, the other said the EN one was — and what was actually missing was English content behind an English filename. | 🟡 MEDIUM | 🟡 MEDIUM | -| 8 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | -| 9 | 🟢 RESOLVED | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | REFUTED and MEASURED 2026-08-01. The row says 14 technical design documents lack a Spanish version. `reference/specs/design/` holds **20** documents and **every one** has its `.es.md` — zero missing. Repository-wide, 19 `.md` files have no Spanish pair, and **9 of them are under `docs/audit/`**: audit reports, corpus triages and this register itself, which are working documents rather than product documentation. The other ten are READMEs and task notes (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). None is a technical design document. **A related defect DOES survive and is tracked elsewhere:** having the pair is not having the translation — `check-translation-language` found 9 documents whose `.md` is written in Spanish, which is what `GAP-011` and `GAP-017` are about. | 🟡 MEDIUM | 🟡 MEDIUM | -| 10 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | -| 11 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | -| 12 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | -| 13 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | -| 14 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | -| 15 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | Resolved 2026-08-01: `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that publish a canonical schema to its `$id`, lists the 3 that are tool output, and names the 7 with none. Upstream `evolith_arch32#378` took coverage from 10 to 17 of 24 and fixed the broken `schemaRef` paths. | 🟡 MEDIUM | 🟡 MEDIUM | -| 16 | 🟢 RESOLVED | [COH-002](#detail-coh-002) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006,007 | Discovery refinement entity has no persisted `status` column. States DRAFT/IN_REFINEMENT/SPLIT referenced in specs cannot be persisted; DDD model also missing the status field. | Resolved / Obsolete: El proceso de partición y refinamiento queda fuera del alcance de Tracker; las iniciativas sólo entran cuando están listas. | 🟢 LOW | 🟢 LOW | -| 17 | 🟢 RESOLVED | [COH-004](#detail-coh-004) | INCO | Source incoherence | Backend | QA | US-QA-001..004,006,008,011 | "TestRun" used in 7 stories but NOT in DDD model. DDD defines TestCycle (container) + TestExecution (atomic). TestCycle Aggregate Root never used by any story. | Resolved: TestCycle/TestExecution es el estándar canónico oficial; TestRun se depreca por ambiguo. Glosario actualizado. Historias asumen TestCycle. | 🔴 | 🔴 | -| 18 | 🟢 RESOLVED | [GAP-019](#detail-gap-019) | Docs | Documentation gap | Docs | Docs | N/A | Discovery requirements not broken down into implementable detail | Resolved: Se creó `docs/design/discovery-functional-specs.md` extrayendo las reglas de negocio, máquina de estados y cadenas de aprobación directamente del modelo DDD (Initiative.cs). | 🔴 HIGH | 🟡 MEDIUM | -| 19 | 🟢 RESOLVED | [GAP-010](#detail-gap-010) | Docs | Documentation gap | Docs | Docs | N/A | PRODUCT_VISION.md No English version | Resolved: PRODUCT_VISION.md ya se encontraba traducido y actualizado en inglés. Registro obsoleto. | 🟢 HIGH | 🟡 MEDIUM | -| 20 | 🟢 RESOLVED | [COH-010](#detail-coh-010) | INCO | Source incoherence | Backend | Construction | US-CON-008 | DDD defines `markAsDone()` but no `reopen()`/`revertStatus()`. Yet story allows DONE→IN_REVIEW regression. Contract breach between spec and domain model. | Resolved: Falsa alarma. La regresión real operaba en PhaseProgression y es estrictamente monótona. | 🟡 | 🟡 | -| 21 | 🟢 RESOLVED | [COH-001](#detail-coh-001) | INCO | Source incoherence | Backend | Discovery | US-DIS-002..005,011 | Status naming: `CANVAS_SUBMITTED` vs DB `submitted`. InitiativeStatus enum undefined in DDD. `under_review` in DB but zero specs. | Resolved: El desajuste se arregló previamente (2026-07-20) extrayendo InitiativeStatus como constantes y aplicando CHECK constraint. | 🟡 | 🟡 | -| 22 | 🟢 RESOLVED | [COH-003](#detail-coh-003) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Violates Small Aggregates pattern: nests child records inside a parent aggregate instead of referencing them by UUID. AGENTS.md mandates UUID refs only. | Resolved: No verificable (la historia US-DIS-006 no existe). El código actual SÍ utiliza referencias UUID correctamente. | 🟡 | 🟡 | -| 23 | 🟢 RESOLVED | [COH-011](#detail-coh-011) | INCO | Source incoherence | Backend | Discovery | US-DIS-003 | "ApprovalChain" aggregate referenced in Gherkin + Tech Reqs, but DDD model only defines `ApprovalGate` VO (0..1 cardinality). No ApprovalChain Aggregate Root exists. | Resolved: El código está bien (implementa ApprovalChain nativamente); el error era documental en una spec antigua. | 🟡 | 🟡 | -| 24 | 🟢 RESOLVED | [COH-006](#detail-coh-006) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-010 | README says "MCP polling/sampling/agent SDK" but 0 of 6 MCP tools exist. | Resolved: Tier 2 BFF (`tracker-gateway`) now exposes 6/6 Tracker MCP tools via SSE and REST. | 🟡 | 🟡 | -| 25 | 🟢 RESOLVED | [COH-007](#detail-coh-007) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-010 | PRD §5.3 defines 6 MCP tools; 0 implemented. BR-009 audit unenforceable via MCP. | Resolved: Tier 2 BFF (`tracker-gateway`) now exposes 6/6 Tracker MCP tools connected to live services. | 🟡 | 🟡 | -| 26 | 🟢 RESOLVED | [COH-300](#detail-coh-300) | GAP | Missing capability / corrective gap | Backend | Construction | US-CON-008 | Architecture Drift blocks DONE transition scenario already present | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 27 | 🟢 RESOLVED | [COH-304](#detail-coh-304) | GAP | Missing capability / corrective gap | Backend | Construction | US-CON-005 | Shell compliance fixed: WFE/IntegrationFabric/TenantConfig injected; seq diagram updated | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 28 | 🟢 RESOLVED | [COH-305](#detail-coh-305) | INCO | Source incoherence | Backend | Construction | US-CON-012 | RefinementLock VO added to Construction DDD model + Ubiquitous Language | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 29 | 🟢 RESOLVED | [COH-201](#detail-coh-201) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-001 | BR-002 enforcement: US-CON-002 rejects linking tasks to DRAFT Blueprint | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 30 | 🟢 RESOLVED | [COH-203](#detail-coh-203) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-011 | DataSchema story created — full CRUD + Core validation for DDD DataSchema AR | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 31 | 🟢 RESOLVED | [COH-204](#detail-coh-204) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-002 | Visual contract designer scenario added to Gherkin + NFRs | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 32 | 🟢 RESOLVED | [COH-205](#detail-coh-205) | INCO | Source incoherence | Backend | Design | US-DES-006 | @evolith/integration-fabric added to dependencies + bounded context | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 33 | 🟢 RESOLVED | [COH-207](#detail-coh-207) | INCO | Source incoherence | Backend | Design | US-DES-007 | VersionEntry VO added to Design DDD model + TechnicalContract.versionHistory | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 34 | 🟢 RESOLVED | [COH-101](#detail-coh-101) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-014 | Discovery Canvas Builder created — guided form enforcing ROI, KPIs, risks | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 35 | 🟢 RESOLVED | [COH-102](#detail-coh-102) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-013 | Point estimate updated from 5→13 to reflect merge engine complexity | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 36 | 🟢 RESOLVED | [COH-106](#detail-coh-106) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-003 | Edge cases (checklist blocking, state guard, Architect estimation, resubmission) confirmed present | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 37 | 🟢 RESOLVED | [COH-202](#detail-coh-202) | GAP | Missing capability / corrective gap | Backend | Governance | AGENTS.md | AGENTS.md §23 already requires RequirementChecklist injection by WorkflowEngine | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 38 | 🟢 RESOLVED | [COH-600](#detail-coh-600) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-010 | Approval chain config story created — all 5 flow types (simple/seq/parallel/hierarchical/mixed) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 39 | 🟢 RESOLVED | [COH-603](#detail-coh-603) | INCO | Source incoherence | Backend | Integration | US-INT-004 | StatusMappingACL added; direct Jira→Evolith status mapping prevented | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 40 | 🟢 RESOLVED | [COH-602](#detail-coh-602) | INCO | Source incoherence | Backend | Metrics | US-MET-003 | DriftAlertEvent removed: Metrics consumes DriftDetectedEvent (Conformist); warning-only | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 41 | 🟢 RESOLVED | [COH-403](#detail-coh-403) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-002 | Automatic .harness trigger scenario added on Construction DONE | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 42 | 🟢 RESOLVED | [COH-404](#detail-coh-404) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-003 | CFR cold-start scenario: insufficient data message + gate blocked | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | -| 43 | 🟢 RESOLVED | [COH-405](#detail-coh-405) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-004 | Root Cleanliness added to QA gate conditions (US-QA-007 violations block gate) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 44 | 🟢 RESOLVED | [COH-406](#detail-coh-406) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-005 | Coverage gate enforcement scenario (below 60% blocks advancement) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 45 | 🟢 RESOLVED | [COH-407](#detail-coh-407) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-010 | ArtifactInstance Core schema validation on QA Report export | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 46 | 🟢 RESOLVED | [COH-500](#detail-coh-500) | INCO | Source incoherence | Backend | Release | US-REL-003 | State naming: RE-DO_SCHEDULED→Replanned, events realigned | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 47 | 🟢 RESOLVED | [COH-501](#detail-coh-501) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-001 | QA gate validation: rejection scenario for non-passed gate prevents Release creation | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 48 | 🟢 RESOLVED | [COH-502/503](#detail-coh-502-503) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-008 | Human authorization + DeploymentRecord status transition on rollback | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 49 | 🟢 RESOLVED | [COH-504](#detail-coh-504) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-009 | Agent deployment execution + report_deployment_status MCP tools | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 50 | 🟢 RESOLVED | [COH-700](#detail-coh-700) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-008 | 4 missing CLI commands added: list, reassign, unassign, mode set | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 51 | 🟢 RESOLVED | [COH-704](#detail-coh-704) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-004 | 3 missing Construction commands added: cycle start, review submit, drift get | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 52 | 🟢 RESOLVED | [COH-705](#detail-coh-705) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-007 | Gate list command added; evaluate/blockers/exception still unresolved | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 53 | 🟢 RESOLVED | [COH-706](#detail-coh-706) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-002 | 2 missing Discovery commands added: initiative init, initiative list | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 54 | 🟢 RESOLVED | [GAP-009](#detail-gap-009) | GAP | Missing capability / corrective gap | CLI | CLI | N/A | BMAD Agent Assignment API Endpoints Missing | Created `reference/specs/design/tracker-agent-assignment-api.md` | 🟠 HIGH | 🟡 MEDIUM | -| 55 | 🟢 RESOLVED | [GAP-005](#detail-gap-005) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | Roadmap subestima 45 puntos (16%) | Corregido: 101 stories/325 pts, Phase 0→M(2w), ~18.5w, R-16 registrado | 🟠 HIGH | 🟢 LOW | -| 56 | 🟢 RESOLVED | [COH-601](#detail-coh-601) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-009 | Audit schema lifecycle story created — tracker_audit bootstrap, append-only trigger, RLS | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | -| 57 | 🟢 RESOLVED | [GAP-002](#detail-gap-002) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | PostgreSQL Schema Names Inconsistent Across Documents | Schema naming `tracker_` adopted | 🟠 HIGH | 🟢 LOW | -| 58 | 🟢 RESOLVED | [GAP-003](#detail-gap-003) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | GraphQL API Status Undefined | REST + OpenAPI 3.0 only in Phase 1 | 🟠 HIGH | 🟢 LOW | -| 59 | 🟢 RESOLVED | [GAP-006](#detail-gap-006) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | Subestimación de puntos no registrada en Risk Register | R-16 añadido a `tracker-risk-register.md` con mitigación y owner | 🟡 MEDIUM | 🟢 LOW | -| 60 | 🟢 RESOLVED | [GAP-007](#detail-gap-007) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | CLI/MCP interbloqueo de fases con feature parity (BR-008) | Roadmap reestructurado: CLI Foundation en Phase 1, CLI distribuido Phase 2-7 | 🟡 MEDIUM | 🔴 HIGH | -| 61 | 🟢 RESOLVED | [COH-821](#detail-coh-821) | INCO | Source incoherence | Backend | Artifacts | US-ART-003 | EvidenceRecord links via ArtifactInstance→PhaseGateState chain. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 62 | 🟢 RESOLVED | [COH-907](#detail-coh-907) | GAP | Missing capability / corrective gap | Backend | Artifacts | N/A | EvidenceChain visualization story created (US-ART-004) — chain traversal + PDF export. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 63 | 🟢 RESOLVED | [COH-808](#detail-coh-808) | GAP | Missing capability / corrective gap | Backend | Construction | All CON | Functional-scope.md references verified — no broken links remain. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 64 | 🟢 RESOLVED | [COH-806](#detail-coh-806) | INCO | Source incoherence | Backend | Design | US-DES-009,010 | C4 Generator + STRIDE Analyzer added to Design DDD ubiquitous language. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 65 | 🟢 RESOLVED | [COH-807](#detail-coh-807) | GAP | Missing capability / corrective gap | Backend | Design | All DES | Tenant scoping added to US-DES-001 (entry point), inherited by remaining Design stories. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 66 | 🟢 RESOLVED | [COH-800](#detail-coh-800) | INCO | Source incoherence | Backend | Discovery | US-DIS-006..013 | All Discovery stories now have Feature:/Scenario: blocks. DIS-006 already had them; DIS-007..013 wrapped. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 67 | 🟢 RESOLVED | [COH-801](#detail-coh-801) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006..013 | MCP execution scenarios added to all 7 stories (DIS-006 already had MCP parity). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 68 | 🟢 RESOLVED | [COH-802](#detail-coh-802) | INCO | Source incoherence | Backend | Discovery | US-DIS-007 | IN_REFINEMENT refinement status defined in Discovery DDD §1. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 69 | 🟢 RESOLVED | [COH-803](#detail-coh-803) | OPP | Improvement opportunity | Backend | Discovery | US-DIS-005 | Scope→phase mapping made tenant-configurable via TenantConfigShell. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 70 | 🟢 RESOLVED | [COH-804](#detail-coh-804) | INCO | Source incoherence | Backend | Discovery | US-DIS-001 | Template field mapping: roiRationale→estimatedRoi fixed in US-DIS-001. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 71 | 🟢 RESOLVED | [COH-805](#detail-coh-805) | INCO | Source incoherence | Backend | Discovery | US-DIS-002,004 | Point delta acknowledged: BusinessCase (external inputs) = 5 vs TJ (internal) = 3. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 72 | 🟢 RESOLVED | [COH-900](#detail-coh-900) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-012 | Trailing template line removed. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 73 | 🟢 RESOLVED | [COH-901](#detail-coh-901) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-011 | Fixed: missing closing `**` after EPIC-005. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 74 | 🟢 RESOLVED | [COH-902](#detail-coh-902) | OPP | Improvement opportunity | Backend | Discovery | US-DIS-001 | Downstream scenario noted for Phase 1 refactoring. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 75 | 🟢 RESOLVED | [COH-816](#detail-coh-816) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-009 | Agent framework selection (bmad/spec-kit/custom) + FrameworkChangedEvent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 76 | 🟢 RESOLVED | [COH-817](#detail-coh-817) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-001 | SatelliteProduct lifecycle: archive(), PENDING_REVALIDATION, status transitions. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 77 | 🟢 RESOLVED | [COH-909](#detail-coh-909) | GAP | Missing capability / corrective gap | Backend | Governance | N/A | Governance 5-gate demo story created (US-GOV-011) — end-to-end gate command trace. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 78 | 🟢 RESOLVED | [COH-822](#detail-coh-822) | INCO | Source incoherence | Backend | Infra | US-INF-008 | Audit/telemetry distinction: permanent (BR-009) vs rotatable logs. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 79 | 🟢 RESOLVED | [COH-818](#detail-coh-818) | GAP | Missing capability / corrective gap | Backend | Integration | US-INT-007 | Health dashboard checks Core, UMS, GitHub, .harness, Jira — all 5 integrations. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 80 | 🟢 RESOLVED | [COH-819](#detail-coh-819) | INCO | Source incoherence | Backend | Integration | US-INT-008 | Gate advancement routed through Governance (AdvanceGateCommand). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 81 | 🟢 RESOLVED | [COH-820](#detail-coh-820) | GAP | Missing capability / corrective gap | Backend | Metrics | N/A | SPACE metrics story created (US-MET-006) with all 5 SPACE dimensions. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 82 | 🟢 RESOLVED | [COH-809](#detail-coh-809) | INCO | Source incoherence | Backend | QA | US-QA-003,004,008 | TestCycle Aggregate Root referenced in all QA stories + caps fixed in QA-008 Gherkin. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 83 | 🟢 RESOLVED | [COH-810](#detail-coh-810) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-006 | Human authorization scenario added: gate blocks until QA Engineer approves. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 84 | 🟢 RESOLVED | [COH-811](#detail-coh-811) | INCO | Source incoherence | Backend | QA | US-QA-008 | CFR displayed as aggregate ratio across all TestCycles, not per-cycle field. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 85 | 🟢 RESOLVED | [COH-903](#detail-coh-903) | INCO | Source incoherence | Backend | QA | US-QA-004 | Persona clarified: QA Engineer runs tests, Release Manager approves gate. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 86 | 🟢 RESOLVED | [COH-904](#detail-coh-904) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-002 | .harness execution is async with callback. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 87 | 🟢 RESOLVED | [COH-812](#detail-coh-812) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-003 | ReDoCycle AR listed in dependencies + persistent audit trail noted. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 88 | 🟢 RESOLVED | [COH-813](#detail-coh-813) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-001 | Calendar collision detection scenario with warning on same date/environment. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 89 | 🟢 RESOLVED | [COH-814](#detail-coh-814) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-006 | SPACE Survey Service story created (US-REL-010) — periodic survey trigger + webhook ingestion. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 90 | 🟢 RESOLVED | [COH-815](#detail-coh-815) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | Authorization-time re-validation scenario + GateConditionChangedEvent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 91 | 🟢 RESOLVED | [COH-905](#detail-coh-905) | INCO | Source incoherence | Backend | Release | US-REL-001 | DDD terminology: ReleasePackage aggregate name consistent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 92 | 🟢 RESOLVED | [COH-906](#detail-coh-906) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | Permission check documented in dependencies. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 93 | 🟢 RESOLVED | [COH-914](#detail-coh-914) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-005 | DORA dashboard threshold noted for Phase 1 statistical review. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 94 | 🟢 RESOLVED | [COH-823](#detail-coh-823) | INCO | Source incoherence | CLI | CLI | Global | CLI README: 11 stories · 37 pts matching actual files. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 95 | 🟢 RESOLVED | [COH-824](#detail-coh-824) | INCO | Source incoherence | CLI | CLI | Global | MCP Tool Suite duplication resolved (US-CLI-010 Phase 5, US-CLI-011 Phase 7). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 96 | 🟢 RESOLVED | [COH-910](#detail-coh-910) | INCO | Source incoherence | CLI | CLI | US-CLI-001 | `--format=json` adopted across all CLI stories per Core ADR 0073. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 97 | 🟢 RESOLVED | [COH-911](#detail-coh-911) | INCO | Source incoherence | CLI | CLI | US-CLI-009 | Title aligned: "MCP Server Bootstrap" in both story and README. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 98 | 🟢 RESOLVED | [COH-912](#detail-coh-912) | INCO | Source incoherence | CLI | CLI | US-CLI-003 | Context flag `--initiative` standardized across CLI stories. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 99 | 🟢 RESOLVED | [COH-913](#detail-coh-913) | GAP | Missing capability / corrective gap | CLI | CLI | Global | Offline-aware CLI story created (US-CLI-012) — queue, sync, conflict resolution. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 100 | 🟢 RESOLVED | [GAP-001](#detail-gap-001) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | README.es.md Missing | Created README.es.md | 🟢 LOW | 🟢 LOW | -| 101 | 🟢 RESOLVED | [GAP-012](#detail-gap-012) | Docs | Documentation gap | Docs | Docs | N/A | MASTER_INDEX.md Carece de Cabecera de Navegación Bilingüe | Added bilingual nav header to MASTER_INDEX.md | 🟢 LOW | 🟢 LOW | -| 102 | 🟢 RESOLVED | [GAP-014](#detail-gap-014) | Docs | Documentation gap | Docs | Docs | N/A | Harness ADR-0002 Applies to .NET Only | Added .NET scope note to ADR-0002 | 🟢 LOW | 🟢 LOW | -| 103 | 🟢 RESOLVED | [GAP-018](#detail-gap-018) | Docs | Documentation gap | Docs | Docs | N/A | TAD Internal Links Broken | Fixed TAD internal links | 🟢 LOW | 🟢 LOW | -| 104 | 🟢 RESOLVED | [GAP-024](#detail-gap-024) | Docs | Documentation gap | Docs | Docs | N/A | No Observability Dashboard or Alert Specification | Created `reference/specs/infrastructure/tracker-observability-spec.md` | 🟢 LOW | 🟢 LOW | -| 105 | 🟢 RESOLVED | [COH-908](#detail-coh-908) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | Secrets management story created (US-INF-010) — Vault + Docker/Helm injection. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | -| 106 | 🟢 RESOLVED | [GAP-008](#detail-gap-008) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | Transactional Outbox Uses Prisma in TypeORM Project | Fixed OutboxProcessor to use TypeORM | 🟢 LOW | 🟢 LOW | -| 107 | 🟢 RESOLVED | [GAP-004](#detail-gap-004) | GAP | Missing capability / corrective gap | API | N/A | N/A | 3 dependencias upstream bloqueadas (Core API, UMS JWKS, UMS Auth Graph) | Resolved via Defensive Isolation (Mocks). | 🔴 CRITICAL | 🔴 HIGH | +| 1 | 🟡 OPEN | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | REOPENED — this is a correction of my own closure earlier today. I closed it on the strength of `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md`, which links each artifact to its canonical `$id`. The catalog then reopened it the same day by product direction, and the reason is not satisfied by that document: the Tracker must CONSUME the Core schema references — persist or cache them tenant-aware, expose them in the phase forms, and validate what people and agents fill in before the Core evaluates. Documenting the links is a prerequisite, not the deliverable. Aligned to the catalog rather than argued with. | 🟡 MEDIUM | 🟡 MEDIUM | +| 2 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 3 | 🟢 RESOLVED | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | RESOLVED — stale row; the evidence was in the catalog and never reached this register. `tracker-gap-reference-catalog.md` closed it on 2026-07-20 with «YA HECHA» and named the artifact. Re-verified here rather than taken on trust: `reference/specs/design/tracker-redo-flow-design.md` is 254 lines with trigger conditions, the state model, the domain model inside the Release context, the recalculation algorithm, impact propagation, the human-authorization gate, domain events and a traceability table. Its §10 lists five scheduling decisions (RD-D1…RD-D5) explicitly registered as proposals awaiting PO ratification — that is a decision pending an owner, not a design that is missing. | 🟡 MEDIUM | 🟡 MEDIUM | +| 4 | 🟢 RESOLVED | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | RESOLVED — stale row, same shape. The catalog closed it on 2026-07-19; this register kept the narrowed half open. Verified directly: `bounded-context-map.md` §2 classifies all nine contexts and names the four supporting ones — Governance, Artifacts, Metrics, Integration — each linked to its own tactical model, and all ten `ddd-model.md` files exist on disk. Both halves of the row are satisfied. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟢 RESOLVED | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | RESOLVED — stale row. `reference/specs/design/tracker-implementation-roadmap.md` has carried `Document Status: SUPERSEDED — historical NestJS-era draft` since it was corrected, and the marker cites **this row by id**: «SUPERSEDED (GAP-016)». The roadmap planned a NestJS build that was executed in .NET, so «no calendar dates» is moot on a document that describes a plan already carried out under a different stack. The other board, `tracker-gap-tracking.md`, recorded this correctly; this register did not. | 🟡 MEDIUM | 🟡 MEDIUM | +| 6 | 🟢 RESOLVED | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | RESOLVED — 9 scenarios added to `docs/design/discovery-functional-specs.md`, covering Create (type derivation for 0/1/2/7 products against `InitiativeScope.Derive`, the `Initiative.TenantRequired` guard, and `ConsolidateFrom` lineage), Read (own-tenant hit, and other-tenant read returning exactly what a non-existent id returns — the shape that stops the id being confirmed), and withdrawal. **The row's premise was partly wrong and is corrected rather than obeyed:** there is no Delete in this aggregate and there must not be. An initiative is superseded into another (`Supersede` → `consolidated`, BR-DIS-005) because its lineage is governance evidence. Writing a Delete scenario would have satisfied the row and described a system that does not exist. The COH-012 probe in `falsifiable-claims.json` is therefore withdrawn, with the reason recorded in that file: it had inherited the same false premise. | 🟢 | 🟢 | +| 7 | 🟢 RESOLVED | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | RESOLVED — the row was TRUE and had been mismeasured. `c4-macro-topology-phase1.md` existed, was labelled «English (this document)» and passed `check-bilingual-parity`, but 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. It is now genuinely in English — prose, diagram descriptions and relationship labels — and its entry was removed from `untranslated-allowlist.json`, which drops from 9 declared to 7. Note for the record: the other board, `tracker-gap-tracking.md`, marked this DONE while the file was still Spanish. | 🟡 MEDIUM | 🟡 MEDIUM | +| 8 | 🟢 RESOLVED | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | RESOLVED — same defect and same correction as GAP-011. `DISCOVERY_CANVAS.md` was 23 of 24 non-empty lines identical to `DISCOVERY_CANVAS.es.md`; the English label was the only English in it. Now translated in full and removed from `untranslated-allowlist.json`. Both boards had this backwards on direction — one said the ES version was missing, the other said the EN one was — and what was actually missing was English content behind an English filename. | 🟡 MEDIUM | 🟡 MEDIUM | +| 9 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | +| 10 | 🟢 RESOLVED | [COH-016](#detail-coh-016) | INCO | Source incoherence | Backend | Release | All REL | Three gap surfaces share one id namespace and only two were kept in step; 5 of the 34 shared ids disagreed. | RESOLVED — found while closing COH-009 and the two translation rows, and recorded here because it explains all of them. This repository keeps THREE gap surfaces sharing one id namespace: this register, `tracker-gap-tracking.md` and `tracker-gap-reference-catalog.md`. `check-gap-registry.py` kept the last two in step and never looked at this one. Measured on 2026-08-01: 34 ids in common, and **5 of them contradicted each other** — COH-012, GAP-016, GAP-023 and GAP-025 closed on the board and open here, GAP-020 the reverse. Neither surface was the reliable one: the board wrongly claimed GAP-011 and GAP-017 done while both files were still Spanish, and this register wrongly kept three closed rows open. Fixed by extending the guard to compare the two vocabularies on the only thing both state unambiguously — closed or not — with six self-tests, three of which go red when the comparison is disabled. | 🟢 | 🟢 | +| 11 | 🟢 RESOLVED | [GAP-013](#detail-gap-013) | Docs | Documentation gap | Docs | Docs | N/A | 14 Technical Design Docs Lack ES Version | REFUTED and MEASURED 2026-08-01. The row says 14 technical design documents lack a Spanish version. `reference/specs/design/` holds **20** documents and **every one** has its `.es.md` — zero missing. Repository-wide, 19 `.md` files have no Spanish pair, and **9 of them are under `docs/audit/`**: audit reports, corpus triages and this register itself, which are working documents rather than product documentation. The other ten are READMEs and task notes (`robosoft/README.md`, `product/infra/helm/README.md`, `Tracker.ArchitectureTests/README.md`, `docs/tasks/*`). None is a technical design document. **A related defect DOES survive and is tracked elsewhere:** having the pair is not having the translation — `check-translation-language` found 9 documents whose `.md` is written in Spanish, which is what `GAP-011` and `GAP-017` are about. | 🟡 MEDIUM | 🟡 MEDIUM | +| 12 | 🟢 RESOLVED | [GAP-015](#detail-gap-015) | Docs | Documentation gap | Docs | Docs | N/A | DECISIONS.md Lacks Description of T-001 Technical Rationale | Resolved 2026-08-01 by writing `docs/adrs/T-001-nx-monorepo-orchestration.md` (+ `.es`). **The row was right and understated it:** the single line T-001 did carry was also WRONG. It said «npm workspaces con Nx», and no `package.json` in this repository declares a `workspaces` field — Nx orchestrates by PROJECT GRAPH (`project.json` plus the `@nx/vite`, `@nx/webpack`, `@nx/eslint` and `@nx/jest` inference plugins in `src/nx.json`). A reader would have looked for a `workspaces` array, not found one, and concluded the monorepo was misconfigured. The ADR records the reason that decided it — `tracker-api` is .NET, and npm workspaces links `node_modules` between npm packages, so it would have covered three projects of four and left the largest outside — and the DECISIONS entry is corrected in both languages. | 🟡 MEDIUM | 🟡 MEDIUM | +| 13 | 🟢 RESOLVED | [GAP-021](#detail-gap-021) | Docs | Documentation gap | Docs | Docs | N/A | Redis in Docker Compose Without Requirement | REFUTED TWICE against the repository 2026-08-01. **The premise is gone:** there is no `docker-compose` file in this repository at all, no Redis in the Helm charts under `product/infra/helm/` — which is the real deployment — and no Redis in application code. **And the requirement it says is missing was decided:** `T-026` («Redis solo para soporte operacional») is recorded in `AdrRegistryEndpoints`, stating «Redis is operational support only (cache/locks/jobs/idempotency); PostgreSQL is the system of record». The row asks for a requirement that exists, about a file that does not. | 🟢 LOW | 🟡 MEDIUM | +| 14 | 🟢 RESOLVED | [GAP-022](#detail-gap-022) | Docs | Documentation gap | Docs | Docs | N/A | SPACE Metrics Not Defined | REFUTED by `check-falsifiable-claims` 2026-08-01: `reference/specs/metrics/prd.md` carries `REQ-MET-03` — «Compute SPACE metrics (Satisfaction, Performance, Activity, Communication, Efficiency)» — with acceptance criteria naming all five scores plus trend, threshold and last-computed timestamp. The framework is defined; the row is stale. | 🟡 MEDIUM | 🟡 MEDIUM | +| 15 | 🟢 RESOLVED | [COH-008](#detail-coh-008) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | DeploymentRecord Aggregate Root NEVER created by any story. UC-005b ("records a DeploymentRecord") cannot be fulfilled. | REFUTED against the code 2026-08-01: the aggregate the row says was never created EXISTS, complete. `Tracker.Domain/Release/DeploymentRecord` ships `Start`, `Finish` and `RollBack`; it persists to `tracker_release.deployment_records`; three endpoints expose it in `ConstructionReleaseEndpoints` (`POST /`, `POST /{id}/finish`, `POST /{id}/rollback`); and `ConstructionReleaseTests` covers it. UC-005b («records a DeploymentRecord») is therefore fulfillable — the row describes a state of the repository that has not held for some time, and nobody moved it. | 🟡 | 🟡 | +| 16 | 🟢 RESOLVED | [COH-005](#detail-coh-005) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-002 | Creates 10 schemas but omits `tracker_audit`. Data design defines 11 schemas; audit trail (BR-009) backbone missing. | Resolved by SUPERSESSION 2026-08-01, and the row simply never moved: `T-047` (Accepted 2026-07-19) ratifies the consolidated four-schema topology, supersedes `T-028` (schema-per-context, 10 schemas) and **names COH-005 among the gaps it closes**. `tracker_audit` was never created ON PURPOSE — the audit aggregates live in `tracker_governance`, where they work: `audit_entries` is queried in production, `GT-603` typed its actor, and `GT-588` wired signed transparency statements on top of it. The data design says so itself: sections 3–12 are «the original 2026-06-07 TARGET design … kept for traceability only … read them as intent, never as a description of the database». Nothing was missing; a document and the code disagreed, and the ADR already decided which one wins. | 🟡 | 🟡 | +| 17 | 🟢 RESOLVED | [COH-002](#detail-coh-002) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006,007 | Discovery refinement entity has no persisted `status` column. States DRAFT/IN_REFINEMENT/SPLIT referenced in specs cannot be persisted; DDD model also missing the status field. | Resolved / Obsolete: El proceso de partición y refinamiento queda fuera del alcance de Tracker; las iniciativas sólo entran cuando están listas. | 🟢 LOW | 🟢 LOW | +| 18 | 🟢 RESOLVED | [COH-004](#detail-coh-004) | INCO | Source incoherence | Backend | QA | US-QA-001..004,006,008,011 | "TestRun" used in 7 stories but NOT in DDD model. DDD defines TestCycle (container) + TestExecution (atomic). TestCycle Aggregate Root never used by any story. | Resolved: TestCycle/TestExecution es el estándar canónico oficial; TestRun se depreca por ambiguo. Glosario actualizado. Historias asumen TestCycle. | 🔴 | 🔴 | +| 19 | 🟢 RESOLVED | [GAP-019](#detail-gap-019) | Docs | Documentation gap | Docs | Docs | N/A | Discovery requirements not broken down into implementable detail | Resolved: Se creó `docs/design/discovery-functional-specs.md` extrayendo las reglas de negocio, máquina de estados y cadenas de aprobación directamente del modelo DDD (Initiative.cs). | 🔴 HIGH | 🟡 MEDIUM | +| 20 | 🟢 RESOLVED | [GAP-010](#detail-gap-010) | Docs | Documentation gap | Docs | Docs | N/A | PRODUCT_VISION.md No English version | Resolved: PRODUCT_VISION.md ya se encontraba traducido y actualizado en inglés. Registro obsoleto. | 🟢 HIGH | 🟡 MEDIUM | +| 21 | 🟢 RESOLVED | [COH-010](#detail-coh-010) | INCO | Source incoherence | Backend | Construction | US-CON-008 | DDD defines `markAsDone()` but no `reopen()`/`revertStatus()`. Yet story allows DONE→IN_REVIEW regression. Contract breach between spec and domain model. | Resolved: Falsa alarma. La regresión real operaba en PhaseProgression y es estrictamente monótona. | 🟡 | 🟡 | +| 22 | 🟢 RESOLVED | [COH-001](#detail-coh-001) | INCO | Source incoherence | Backend | Discovery | US-DIS-002..005,011 | Status naming: `CANVAS_SUBMITTED` vs DB `submitted`. InitiativeStatus enum undefined in DDD. `under_review` in DB but zero specs. | Resolved: El desajuste se arregló previamente (2026-07-20) extrayendo InitiativeStatus como constantes y aplicando CHECK constraint. | 🟡 | 🟡 | +| 23 | 🟢 RESOLVED | [COH-003](#detail-coh-003) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Violates Small Aggregates pattern: nests child records inside a parent aggregate instead of referencing them by UUID. AGENTS.md mandates UUID refs only. | Resolved: No verificable (la historia US-DIS-006 no existe). El código actual SÍ utiliza referencias UUID correctamente. | 🟡 | 🟡 | +| 24 | 🟢 RESOLVED | [COH-011](#detail-coh-011) | INCO | Source incoherence | Backend | Discovery | US-DIS-003 | "ApprovalChain" aggregate referenced in Gherkin + Tech Reqs, but DDD model only defines `ApprovalGate` VO (0..1 cardinality). No ApprovalChain Aggregate Root exists. | Resolved: El código está bien (implementa ApprovalChain nativamente); el error era documental en una spec antigua. | 🟡 | 🟡 | +| 25 | 🟢 RESOLVED | [COH-006](#detail-coh-006) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-010 | README says "MCP polling/sampling/agent SDK" but 0 of 6 MCP tools exist. | Resolved: Tier 2 BFF (`tracker-gateway`) now exposes 6/6 Tracker MCP tools via SSE and REST. | 🟡 | 🟡 | +| 26 | 🟢 RESOLVED | [COH-007](#detail-coh-007) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-010 | PRD §5.3 defines 6 MCP tools; 0 implemented. BR-009 audit unenforceable via MCP. | Resolved: Tier 2 BFF (`tracker-gateway`) now exposes 6/6 Tracker MCP tools connected to live services. | 🟡 | 🟡 | +| 27 | 🟢 RESOLVED | [COH-300](#detail-coh-300) | GAP | Missing capability / corrective gap | Backend | Construction | US-CON-008 | Architecture Drift blocks DONE transition scenario already present | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 28 | 🟢 RESOLVED | [COH-304](#detail-coh-304) | GAP | Missing capability / corrective gap | Backend | Construction | US-CON-005 | Shell compliance fixed: WFE/IntegrationFabric/TenantConfig injected; seq diagram updated | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 29 | 🟢 RESOLVED | [COH-305](#detail-coh-305) | INCO | Source incoherence | Backend | Construction | US-CON-012 | RefinementLock VO added to Construction DDD model + Ubiquitous Language | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 30 | 🟢 RESOLVED | [COH-201](#detail-coh-201) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-001 | BR-002 enforcement: US-CON-002 rejects linking tasks to DRAFT Blueprint | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 31 | 🟢 RESOLVED | [COH-203](#detail-coh-203) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-011 | DataSchema story created — full CRUD + Core validation for DDD DataSchema AR | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 32 | 🟢 RESOLVED | [COH-204](#detail-coh-204) | GAP | Missing capability / corrective gap | Backend | Design | US-DES-002 | Visual contract designer scenario added to Gherkin + NFRs | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 33 | 🟢 RESOLVED | [COH-205](#detail-coh-205) | INCO | Source incoherence | Backend | Design | US-DES-006 | @evolith/integration-fabric added to dependencies + bounded context | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 34 | 🟢 RESOLVED | [COH-207](#detail-coh-207) | INCO | Source incoherence | Backend | Design | US-DES-007 | VersionEntry VO added to Design DDD model + TechnicalContract.versionHistory | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 35 | 🟢 RESOLVED | [COH-101](#detail-coh-101) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-014 | Discovery Canvas Builder created — guided form enforcing ROI, KPIs, risks | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 36 | 🟢 RESOLVED | [COH-102](#detail-coh-102) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-013 | Point estimate updated from 5→13 to reflect merge engine complexity | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 37 | 🟢 RESOLVED | [COH-106](#detail-coh-106) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-003 | Edge cases (checklist blocking, state guard, Architect estimation, resubmission) confirmed present | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 38 | 🟢 RESOLVED | [COH-202](#detail-coh-202) | GAP | Missing capability / corrective gap | Backend | Governance | AGENTS.md | AGENTS.md §23 already requires RequirementChecklist injection by WorkflowEngine | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 39 | 🟢 RESOLVED | [COH-600](#detail-coh-600) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-010 | Approval chain config story created — all 5 flow types (simple/seq/parallel/hierarchical/mixed) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 40 | 🟢 RESOLVED | [COH-603](#detail-coh-603) | INCO | Source incoherence | Backend | Integration | US-INT-004 | StatusMappingACL added; direct Jira→Evolith status mapping prevented | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 41 | 🟢 RESOLVED | [COH-602](#detail-coh-602) | INCO | Source incoherence | Backend | Metrics | US-MET-003 | DriftAlertEvent removed: Metrics consumes DriftDetectedEvent (Conformist); warning-only | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 42 | 🟢 RESOLVED | [COH-403](#detail-coh-403) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-002 | Automatic .harness trigger scenario added on Construction DONE | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 43 | 🟢 RESOLVED | [COH-404](#detail-coh-404) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-003 | CFR cold-start scenario: insufficient data message + gate blocked | Resolved; evidence captured in the description. | 🟠 HIGH | 🟢 LOW | +| 44 | 🟢 RESOLVED | [COH-405](#detail-coh-405) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-004 | Root Cleanliness added to QA gate conditions (US-QA-007 violations block gate) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 45 | 🟢 RESOLVED | [COH-406](#detail-coh-406) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-005 | Coverage gate enforcement scenario (below 60% blocks advancement) | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 46 | 🟢 RESOLVED | [COH-407](#detail-coh-407) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-010 | ArtifactInstance Core schema validation on QA Report export | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 47 | 🟢 RESOLVED | [COH-500](#detail-coh-500) | INCO | Source incoherence | Backend | Release | US-REL-003 | State naming: RE-DO_SCHEDULED→Replanned, events realigned | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 48 | 🟢 RESOLVED | [COH-501](#detail-coh-501) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-001 | QA gate validation: rejection scenario for non-passed gate prevents Release creation | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 49 | 🟢 RESOLVED | [COH-502/503](#detail-coh-502-503) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-008 | Human authorization + DeploymentRecord status transition on rollback | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 50 | 🟢 RESOLVED | [COH-504](#detail-coh-504) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-009 | Agent deployment execution + report_deployment_status MCP tools | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 51 | 🟢 RESOLVED | [COH-700](#detail-coh-700) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-008 | 4 missing CLI commands added: list, reassign, unassign, mode set | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 52 | 🟢 RESOLVED | [COH-704](#detail-coh-704) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-004 | 3 missing Construction commands added: cycle start, review submit, drift get | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 53 | 🟢 RESOLVED | [COH-705](#detail-coh-705) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-007 | Gate list command added; evaluate/blockers/exception still unresolved | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 54 | 🟢 RESOLVED | [COH-706](#detail-coh-706) | GAP | Missing capability / corrective gap | CLI | CLI | US-CLI-002 | 2 missing Discovery commands added: initiative init, initiative list | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 55 | 🟢 RESOLVED | [GAP-009](#detail-gap-009) | GAP | Missing capability / corrective gap | CLI | CLI | N/A | BMAD Agent Assignment API Endpoints Missing | Created `reference/specs/design/tracker-agent-assignment-api.md` | 🟠 HIGH | 🟡 MEDIUM | +| 56 | 🟢 RESOLVED | [GAP-005](#detail-gap-005) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | Roadmap subestima 45 puntos (16%) | Corregido: 101 stories/325 pts, Phase 0→M(2w), ~18.5w, R-16 registrado | 🟠 HIGH | 🟢 LOW | +| 57 | 🟢 RESOLVED | [COH-601](#detail-coh-601) | GAP | Missing capability / corrective gap | Infra | Infra | US-INF-009 | Audit schema lifecycle story created — tracker_audit bootstrap, append-only trigger, RLS | Resolved; evidence captured in the description. | 🟠 HIGH | 🟡 MEDIUM | +| 58 | 🟢 RESOLVED | [GAP-002](#detail-gap-002) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | PostgreSQL Schema Names Inconsistent Across Documents | Schema naming `tracker_` adopted | 🟠 HIGH | 🟢 LOW | +| 59 | 🟢 RESOLVED | [GAP-003](#detail-gap-003) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | GraphQL API Status Undefined | REST + OpenAPI 3.0 only in Phase 1 | 🟠 HIGH | 🟢 LOW | +| 60 | 🟢 RESOLVED | [GAP-006](#detail-gap-006) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | Subestimación de puntos no registrada en Risk Register | R-16 añadido a `tracker-risk-register.md` con mitigación y owner | 🟡 MEDIUM | 🟢 LOW | +| 61 | 🟢 RESOLVED | [GAP-007](#detail-gap-007) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | CLI/MCP interbloqueo de fases con feature parity (BR-008) | Roadmap reestructurado: CLI Foundation en Phase 1, CLI distribuido Phase 2-7 | 🟡 MEDIUM | 🔴 HIGH | +| 62 | 🟢 RESOLVED | [COH-821](#detail-coh-821) | INCO | Source incoherence | Backend | Artifacts | US-ART-003 | EvidenceRecord links via ArtifactInstance→PhaseGateState chain. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 63 | 🟢 RESOLVED | [COH-907](#detail-coh-907) | GAP | Missing capability / corrective gap | Backend | Artifacts | N/A | EvidenceChain visualization story created (US-ART-004) — chain traversal + PDF export. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 64 | 🟢 RESOLVED | [COH-808](#detail-coh-808) | GAP | Missing capability / corrective gap | Backend | Construction | All CON | Functional-scope.md references verified — no broken links remain. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 65 | 🟢 RESOLVED | [COH-806](#detail-coh-806) | INCO | Source incoherence | Backend | Design | US-DES-009,010 | C4 Generator + STRIDE Analyzer added to Design DDD ubiquitous language. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 66 | 🟢 RESOLVED | [COH-807](#detail-coh-807) | GAP | Missing capability / corrective gap | Backend | Design | All DES | Tenant scoping added to US-DES-001 (entry point), inherited by remaining Design stories. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 67 | 🟢 RESOLVED | [COH-800](#detail-coh-800) | INCO | Source incoherence | Backend | Discovery | US-DIS-006..013 | All Discovery stories now have Feature:/Scenario: blocks. DIS-006 already had them; DIS-007..013 wrapped. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 68 | 🟢 RESOLVED | [COH-801](#detail-coh-801) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006..013 | MCP execution scenarios added to all 7 stories (DIS-006 already had MCP parity). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 69 | 🟢 RESOLVED | [COH-802](#detail-coh-802) | INCO | Source incoherence | Backend | Discovery | US-DIS-007 | IN_REFINEMENT refinement status defined in Discovery DDD §1. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 70 | 🟢 RESOLVED | [COH-803](#detail-coh-803) | OPP | Improvement opportunity | Backend | Discovery | US-DIS-005 | Scope→phase mapping made tenant-configurable via TenantConfigShell. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 71 | 🟢 RESOLVED | [COH-804](#detail-coh-804) | INCO | Source incoherence | Backend | Discovery | US-DIS-001 | Template field mapping: roiRationale→estimatedRoi fixed in US-DIS-001. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 72 | 🟢 RESOLVED | [COH-805](#detail-coh-805) | INCO | Source incoherence | Backend | Discovery | US-DIS-002,004 | Point delta acknowledged: BusinessCase (external inputs) = 5 vs TJ (internal) = 3. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 73 | 🟢 RESOLVED | [COH-900](#detail-coh-900) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-012 | Trailing template line removed. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 74 | 🟢 RESOLVED | [COH-901](#detail-coh-901) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-011 | Fixed: missing closing `**` after EPIC-005. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 75 | 🟢 RESOLVED | [COH-902](#detail-coh-902) | OPP | Improvement opportunity | Backend | Discovery | US-DIS-001 | Downstream scenario noted for Phase 1 refactoring. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 76 | 🟢 RESOLVED | [COH-816](#detail-coh-816) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-009 | Agent framework selection (bmad/spec-kit/custom) + FrameworkChangedEvent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 77 | 🟢 RESOLVED | [COH-817](#detail-coh-817) | GAP | Missing capability / corrective gap | Backend | Governance | US-GOV-001 | SatelliteProduct lifecycle: archive(), PENDING_REVALIDATION, status transitions. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 78 | 🟢 RESOLVED | [COH-909](#detail-coh-909) | GAP | Missing capability / corrective gap | Backend | Governance | N/A | Governance 5-gate demo story created (US-GOV-011) — end-to-end gate command trace. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 79 | 🟢 RESOLVED | [COH-822](#detail-coh-822) | INCO | Source incoherence | Backend | Infra | US-INF-008 | Audit/telemetry distinction: permanent (BR-009) vs rotatable logs. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 80 | 🟢 RESOLVED | [COH-818](#detail-coh-818) | GAP | Missing capability / corrective gap | Backend | Integration | US-INT-007 | Health dashboard checks Core, UMS, GitHub, .harness, Jira — all 5 integrations. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 81 | 🟢 RESOLVED | [COH-819](#detail-coh-819) | INCO | Source incoherence | Backend | Integration | US-INT-008 | Gate advancement routed through Governance (AdvanceGateCommand). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 82 | 🟢 RESOLVED | [COH-820](#detail-coh-820) | GAP | Missing capability / corrective gap | Backend | Metrics | N/A | SPACE metrics story created (US-MET-006) with all 5 SPACE dimensions. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 83 | 🟢 RESOLVED | [COH-809](#detail-coh-809) | INCO | Source incoherence | Backend | QA | US-QA-003,004,008 | TestCycle Aggregate Root referenced in all QA stories + caps fixed in QA-008 Gherkin. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 84 | 🟢 RESOLVED | [COH-810](#detail-coh-810) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-006 | Human authorization scenario added: gate blocks until QA Engineer approves. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 85 | 🟢 RESOLVED | [COH-811](#detail-coh-811) | INCO | Source incoherence | Backend | QA | US-QA-008 | CFR displayed as aggregate ratio across all TestCycles, not per-cycle field. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 86 | 🟢 RESOLVED | [COH-903](#detail-coh-903) | INCO | Source incoherence | Backend | QA | US-QA-004 | Persona clarified: QA Engineer runs tests, Release Manager approves gate. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 87 | 🟢 RESOLVED | [COH-904](#detail-coh-904) | GAP | Missing capability / corrective gap | Backend | QA | US-QA-002 | .harness execution is async with callback. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 88 | 🟢 RESOLVED | [COH-812](#detail-coh-812) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-003 | ReDoCycle AR listed in dependencies + persistent audit trail noted. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 89 | 🟢 RESOLVED | [COH-813](#detail-coh-813) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-001 | Calendar collision detection scenario with warning on same date/environment. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 90 | 🟢 RESOLVED | [COH-814](#detail-coh-814) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-006 | SPACE Survey Service story created (US-REL-010) — periodic survey trigger + webhook ingestion. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 91 | 🟢 RESOLVED | [COH-815](#detail-coh-815) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | Authorization-time re-validation scenario + GateConditionChangedEvent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 92 | 🟢 RESOLVED | [COH-905](#detail-coh-905) | INCO | Source incoherence | Backend | Release | US-REL-001 | DDD terminology: ReleasePackage aggregate name consistent. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 93 | 🟢 RESOLVED | [COH-906](#detail-coh-906) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-004 | Permission check documented in dependencies. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 94 | 🟢 RESOLVED | [COH-914](#detail-coh-914) | GAP | Missing capability / corrective gap | Backend | Release | US-REL-005 | DORA dashboard threshold noted for Phase 1 statistical review. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 95 | 🟢 RESOLVED | [COH-823](#detail-coh-823) | INCO | Source incoherence | CLI | CLI | Global | CLI README: 11 stories · 37 pts matching actual files. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 96 | 🟢 RESOLVED | [COH-824](#detail-coh-824) | INCO | Source incoherence | CLI | CLI | Global | MCP Tool Suite duplication resolved (US-CLI-010 Phase 5, US-CLI-011 Phase 7). | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 97 | 🟢 RESOLVED | [COH-910](#detail-coh-910) | INCO | Source incoherence | CLI | CLI | US-CLI-001 | `--format=json` adopted across all CLI stories per Core ADR 0073. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 98 | 🟢 RESOLVED | [COH-911](#detail-coh-911) | INCO | Source incoherence | CLI | CLI | US-CLI-009 | Title aligned: "MCP Server Bootstrap" in both story and README. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 99 | 🟢 RESOLVED | [COH-912](#detail-coh-912) | INCO | Source incoherence | CLI | CLI | US-CLI-003 | Context flag `--initiative` standardized across CLI stories. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 100 | 🟢 RESOLVED | [COH-913](#detail-coh-913) | GAP | Missing capability / corrective gap | CLI | CLI | Global | Offline-aware CLI story created (US-CLI-012) — queue, sync, conflict resolution. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 101 | 🟢 RESOLVED | [GAP-001](#detail-gap-001) | GAP | Missing capability / corrective gap | Docs | Docs | N/A | README.es.md Missing | Created README.es.md | 🟢 LOW | 🟢 LOW | +| 102 | 🟢 RESOLVED | [GAP-012](#detail-gap-012) | Docs | Documentation gap | Docs | Docs | N/A | MASTER_INDEX.md Carece de Cabecera de Navegación Bilingüe | Added bilingual nav header to MASTER_INDEX.md | 🟢 LOW | 🟢 LOW | +| 103 | 🟢 RESOLVED | [GAP-014](#detail-gap-014) | Docs | Documentation gap | Docs | Docs | N/A | Harness ADR-0002 Applies to .NET Only | Added .NET scope note to ADR-0002 | 🟢 LOW | 🟢 LOW | +| 104 | 🟢 RESOLVED | [GAP-018](#detail-gap-018) | Docs | Documentation gap | Docs | Docs | N/A | TAD Internal Links Broken | Fixed TAD internal links | 🟢 LOW | 🟢 LOW | +| 105 | 🟢 RESOLVED | [GAP-024](#detail-gap-024) | Docs | Documentation gap | Docs | Docs | N/A | No Observability Dashboard or Alert Specification | Created `reference/specs/infrastructure/tracker-observability-spec.md` | 🟢 LOW | 🟢 LOW | +| 106 | 🟢 RESOLVED | [COH-908](#detail-coh-908) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | Secrets management story created (US-INF-010) — Vault + Docker/Helm injection. | Resolved; evidence captured in the description. | 🟢 LOW | 🟢 LOW | +| 107 | 🟢 RESOLVED | [GAP-008](#detail-gap-008) | GAP | Missing capability / corrective gap | Infra | Infra | N/A | Transactional Outbox Uses Prisma in TypeORM Project | Fixed OutboxProcessor to use TypeORM | 🟢 LOW | 🟢 LOW | +| 108 | 🟢 RESOLVED | [GAP-004](#detail-gap-004) | GAP | Missing capability / corrective gap | API | N/A | N/A | 3 dependencias upstream bloqueadas (Core API, UMS JWKS, UMS Auth Graph) | Resolved via Defensive Isolation (Mocks). | 🔴 CRITICAL | 🔴 HIGH | @@ -412,7 +413,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-020 -- **Status:** 🟢 RESOLVED +- **Status:** 🟡 OPEN - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -449,7 +450,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-023 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -465,7 +466,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-025 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -493,6 +494,22 @@ This document is the only operational gap register in this repository. The maste [Back to master register](#master-register) + + +### Detail COH-016 + +- **Status:** 🟢 RESOLVED +- **Type:** INCO (Source incoherence) +- **Component:** Docs +- **Module:** Docs +- **Story(ies):** N/A +- **Criticality:** 🟡 MEDIUM +- **Complexity:** 🟢 LOW +- **Description:** Three gap surfaces share one id namespace; the coherence guard covered only two of them. +- **Next Step:** None — `check-gap-registry.py` now contrasts the register too, with self-tests in CI. + +[Back to master register](#master-register) + ### Detail COH-012 From 3b336ab6f3713d16fd38f9369767d063d4c92690 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sun, 2 Aug 2026 00:36:57 -0500 Subject: [PATCH 13/40] =?UTF-8?q?feat(governance):=20consume=20the=20Core?= =?UTF-8?q?=20artifact=20schema=20references=20=E2=80=94=20close=20GAP-020?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The row was reopened by product direction with a precise complaint: a satellite that only DOCUMENTS the link has not consumed it. CORE_ARTIFACT_SCHEMAS.md let a reader find the canonical shape of a PRD; no machine could. The correspondence now lives as data in CoreArtifactSchemaCatalog, and every artifact served by GET /api/phase-artifact-profiles carries a canonicalSchema with the published $id. The artifact-fields screen renders it as a link. provenance has THREE values and not a nullable id, because two of them are different absences: core-schema, tool-output (the Core deliberately publishes none — CI run records, coverage reports) and none (nothing upstream; the tenant's ArtifactFieldSchema is the only authority). Collapsing the last two into null would erase the difference between a gap someone should close and a decision already taken. The mapping is a WRITTEN DECISION, not a slug transformation. A matcher would miss security-scan-result vs Security Scan Report, rollback-plan vs Rollback Procedure and observability-readiness vs Observability Validation, and would miss them silently. So CoreArtifactSchemaCatalogTests parses the markdown table and compares BOTH ways: a documented row nobody wired fails, and a wired entry nobody documented fails too. Verified by breaking it in both directions rather than assuming. adr-registry is deliberately NOT mapped to adr.schema.json: a registry is a list of ADRs and not an ADR, so the mapping would validate green on paper and produce a false negative against the real artifact. DELIBERATELY NOT BUILT: hardwired validation of artifact content against these schemas. The reopen text asks for it, and T-056 — ratified by the user — says content validation is the tenant's configuration and not engine code. The reference is exposed so a tenant's own configuration can point at it; enforcing it here would make the Core the authority over what a tenant may record. Flagged rather than silently skipped. Local: 6/6 new tests, frontend lint+typecheck+build green. The 10 integration failures on this machine are the DB-gated suite that fails by design without PostgreSQL; CI provides it. --- docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md | 37 +++++ docs/artifacts/CORE_ARTIFACT_SCHEMAS.md | 36 +++++ docs/audit/tracker-gap-reference-catalog.md | 3 +- docs/audit/tracker-gap-tracking.md | 2 +- .../tracker-gaps-opportunities-tracking.md | 6 +- .../CoreArtifactSchemaCatalog.cs | 128 ++++++++++++++++ .../IPhaseArtifactProfileSource.cs | 3 + .../PhaseArtifactCatalog.cs | 24 ++- .../CoreArtifactSchemaCatalogTests.cs | 145 ++++++++++++++++++ src/apps/tracker-web/src/api/types.ts | 23 +++ .../screens/md3/FieldSchemaManager.tsx | 55 ++++++- 11 files changed, 448 insertions(+), 14 deletions(-) create mode 100644 src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs create mode 100644 src/apps/tracker-api/Tracker.Tests/Application/Governance/CoreArtifactSchemaCatalogTests.cs diff --git a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md index 212eb420..112c86fd 100644 --- a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md +++ b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md @@ -63,6 +63,43 @@ Tres filas merecen atención en vez de un mapeo silencioso: catálogo del Tracker**. Se listan igualmente, porque quien los busque debe enterarse de que existen en vez de concluir que no. +## Cómo lo consume el Tracker + +Hasta el 2026-08-02 este documento *era* todo GAP-020: una persona podía encontrar la forma +canónica y ninguna máquina podía. La ficha se reabrió por dirección de producto exactamente por eso +— un satélite que sólo documenta el enlace no lo ha consumido. + +La correspondencia vive ahora como **dato** en +`Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs`, y cada +`PhaseArtifactDto` que sirve `GET /api/phase-artifact-profiles` lleva su `canonicalSchema`: + +```json +{ "artifactKind": "prd", "label": "PRD", "required": true, + "canonicalSchema": { "schemaId": "https://evolith.dev/schema/prd.schema.json", + "provenance": "core-schema" } } +``` + +`provenance` tiene tres valores y no un id anulable, porque dos de ellos son *ausencias distintas*: + +| valor | qué significa | qué hacer | +|---|---|---| +| `core-schema` | el Core publica una forma canónica | seguir el `$id` | +| `tool-output` | el Core no publica ninguna, a propósito | leer el formato propio de la herramienta | +| `none` | nada upstream lo cubre | el `ArtifactFieldSchema` del tenant es la única autoridad | + +Juntar `tool-output` y `none` en un `null` borraría la diferencia entre *un hueco que alguien +debería cerrar* y *una decisión ya tomada*. + +La tabla de este documento y la de esa clase se mantienen idénticas mediante +`CoreArtifactSchemaCatalogTests`, que parsea el markdown de arriba y compara en los dos sentidos: +falla una fila de aquí que nadie cableó, y falla también una entrada de allí que nadie documentó. +Se comprobó rompiéndolo en ambas direcciones, no se supuso. + +**Sigue siendo un puntero y no una restricción.** Nada en el Tracker valida el contenido de un +artefacto contra estos esquemas: según [`T-056`](../adrs/T-056-three-layer-separation.md) eso es +configuración del tenant y no código del motor. La referencia se ofrece a quien rellena el +artefacto. + ## Los artefactos que no tienen esquema, y por qué Diez de los veinticuatro no están cubiertos, y se dividen en dos grupos que piden respuestas diff --git a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md index bd18c873..1b747e18 100644 --- a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md +++ b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md @@ -61,6 +61,42 @@ Three rows deserve attention rather than a silent mapping: Tracker's catalog**. They are listed anyway, because a reader looking for them should find out they exist rather than conclude they do not. +## How the Tracker consumes this + +Until 2026-08-02 this document *was* the whole of GAP-020: a reader could find the canonical shape, +and no machine could. The row was reopened by product direction for exactly that reason — a +satellite that only documents the link has not consumed it. + +The correspondence now lives as **data** in +`Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs`, and every +`PhaseArtifactDto` served by `GET /api/phase-artifact-profiles` carries a `canonicalSchema`: + +```json +{ "artifactKind": "prd", "label": "PRD", "required": true, + "canonicalSchema": { "schemaId": "https://evolith.dev/schema/prd.schema.json", + "provenance": "core-schema" } } +``` + +`provenance` has three values and not a nullable id, because two of them are *different absences*: + +| value | meaning | what a reader should do | +|---|---|---| +| `core-schema` | the Core publishes a canonical shape | follow the `$id` | +| `tool-output` | the Core deliberately publishes none | read the tool's own format | +| `none` | nothing upstream covers it | the tenant's `ArtifactFieldSchema` is the only authority | + +Collapsing `tool-output` and `none` into `null` would erase the distinction between *a gap someone +should close* and *a decision already made*. + +The table in this document and the table in that class are kept identical by +`CoreArtifactSchemaCatalogTests`, which parses the markdown above and compares both ways — a row +here that nobody wired fails, and an entry there that nobody documented fails too. This was +verified by breaking it in both directions, not assumed. + +**It remains a pointer and not a constraint.** Nothing in the Tracker validates artifact content +against these schemas: per [`T-056`](../adrs/T-056-three-layer-separation.md) that is the tenant's +configuration, not engine code. The reference is offered to whoever fills the artifact in. + ## The artifacts that have no schema, and why Ten of the twenty-four are not covered, and they split into two groups that call for different diff --git a/docs/audit/tracker-gap-reference-catalog.md b/docs/audit/tracker-gap-reference-catalog.md index 23fab29b..42353a0b 100644 --- a/docs/audit/tracker-gap-reference-catalog.md +++ b/docs/audit/tracker-gap-reference-catalog.md @@ -2945,8 +2945,9 @@ Corregidas las **29 menciones** distinguiendo dos clases que no son lo mismo: la - **Component:** `Docs` · **Module:** Docs · **Type:** Docs - **Criticality:** P2 · **Complexity:** M - **Resolution / Next step:** Consumir desde el Core las URLs o referencias canónicas de schema de cada artefacto, registrarlas en el catálogo tenant-aware del Tracker y usarlas como base para validar los formatos expuestos y llenados. -- **Status:** `PENDING` (2026-08-01) — reabierta por dirección de producto: aunque el Core define la autoridad de los schemas, el Tracker debe materializar su consumo para operar el flujo SDLC completo. +- **Status (superado):** `PENDING` (2026-08-01) — reabierta por dirección de producto: aunque el Core define la autoridad de los schemas, el Tracker debe materializar su consumo para operar el flujo SDLC completo. - **Triaje 2026-08-01 — PENDIENTE.** Las URLs de los esquemas de artefacto siguen siendo autoridad del Core; el Tracker no las inventa ni las redefine. El trabajo pendiente en este repositorio es consumirlas, persistir o cachear sus referencias de forma tenant-aware, exponerlas en los formatos de fase y usarlas para validar los artefactos que personas o agentes llenan antes de la evaluación del Core. +- **Status:** `DONE` — 2026-08-02. El Tracker ya CONSUME las referencias: mapa como dato en `CoreArtifactSchemaCatalog`, `canonicalSchema` en cada artefacto de `/api/phase-artifact-profiles`, enlace en la pantalla de campos, y prueba anti-deriva contra `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` en los dos sentidos. #### GAP-021 diff --git a/docs/audit/tracker-gap-tracking.md b/docs/audit/tracker-gap-tracking.md index 286cfb15..ec4578ca 100644 --- a/docs/audit/tracker-gap-tracking.md +++ b/docs/audit/tracker-gap-tracking.md @@ -30,7 +30,7 @@ This board is the single source of truth for Tracker technical debt, gaps, oppor | [`CP-16`](./tracker-gap-reference-catalog.md#cp-16) | Falta una bitácora SDLC por iniciativa que una artefactos, ediciones, aprobaciones, agentes, evaluaciones Core y decisiones | El seguimiento queda repartido entre pantallas y logs técnicos, sin una línea de tiempo entendible para auditoría o gestión | No hay ledger de negocio que explique el recorrido completo de una iniciativa tenant-aware | `Governance/Audit` | Cross | P1 | M | `PENDING` | | [`CP-03`](./tracker-gap-reference-catalog.md#cp-03) | La experiencia de llenado de artefactos no se genera desde los formatos del Core ni guía a personas y agentes con validación incremental | El usuario ve formularios locales o genéricos en vez de wizards derivados del contrato que luego será evaluado | Los formatos de fase viven en catálogos/stand-ins; no hay renderer común de artifact schema con borrador, validación, recomendaciones y evidencia | `WEB/Artifacts` | Cross | P1 | L | `PENDING` | | [`CP-13`](./tracker-gap-reference-catalog.md#cp-13) | El Tracker no tiene un editor documental avanzado con Markdown canónico y modo visual tipo Word | Editar artefactos complejos sería lento o demasiado técnico, y el formato interno puede perder portabilidad | Se necesita edición Markdown avanzada, WYSIWYG, tablas, referencias, comentarios y guardado interno en MD | `WEB/Artifacts` | Cross | P1 | L | `PENDING` | -| [`GAP-020`](./tracker-gap-reference-catalog.md#gap-020) | Faltan las direcciones de los esquemas de artefactos que publica el núcleo | No hay forma de comprobar automáticamente que un documento entregado tiene la forma correcta | No se registran las URL de esquema de artefacto que provienen del núcleo | `Docs` | Cross | P2 | M | `PENDING` | +| [`GAP-020`](./tracker-gap-reference-catalog.md#gap-020) | Faltan las direcciones de los esquemas de artefactos que publica el núcleo | No hay forma de comprobar automáticamente que un documento entregado tiene la forma correcta | No se registran las URL de esquema de artefacto que provienen del núcleo | `Docs` | Cross | P2 | M | `DONE` | | [`CP-17`](./tracker-gap-reference-catalog.md#cp-17) | No hay generación gobernada de Word y PDF desde el Markdown canónico de los artefactos | El equipo puede aprobar un documento en el Tracker, pero no obtener una versión portable y fiel para comités, contratos o auditorías | Falta pipeline de exportación con branding tenant, anexos, diagramas renderizados y huella de versión | `Artifacts/Export` | Cross | P2 | M | `PENDING` | | [`CP-18`](./tracker-gap-reference-catalog.md#cp-18) | No existe un framework seguro de plugins documentales para Mermaid, diagramas y bloques enriquecidos | Los artefactos necesitan diagramas y gráficos, pero cada capacidad se tendría que improvisar en el editor o rompería la exportación | Mermaid y otros bloques deben renderizarse, validarse, sanitizarse y exportarse de forma consistente | `WEB/Artifacts` | Cross | P2 | M | `PENDING` | | [`CP-09`](./tracker-gap-reference-catalog.md#cp-09) | Las capacidades técnicas de arquitectura, drift, topología, knowledge y upgrade no están modeladas como recomendaciones opcionales dentro del flujo SDLC | El producto puede oscilar entre ignorarlas por completo o tratarlas como bloqueantes impropios | Core ofrece señales de repo facts, drift y operaciones consultivas, pero el Tracker no tiene superficie advisory tenant-configurable para pedirlas y adjuntarlas al expediente | `Architecture/WEB` | Cross | P2 | L | `PENDING` | diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 6ddaba52..7971cfe6 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,8 +25,8 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | REOPENED — this is a correction of my own closure earlier today. I closed it on the strength of `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md`, which links each artifact to its canonical `$id`. The catalog then reopened it the same day by product direction, and the reason is not satisfied by that document: the Tracker must CONSUME the Core schema references — persist or cache them tenant-aware, expose them in the phase forms, and validate what people and agents fill in before the Core evaluates. Documenting the links is a prerequisite, not the deliverable. Aligned to the catalog rather than argued with. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 1 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 2 | 🟢 RESOLVED | [GAP-020](#detail-gap-020) | Docs | Documentation gap | Docs | Docs | N/A | Artifact Schema URLs from Core Missing | RESOLVED — the reopen asked the Tracker to CONSUME the Core schema references rather than document them, and it now does. The correspondence lives as data in `CoreArtifactSchemaCatalog`, and every artifact served by `GET /api/phase-artifact-profiles` carries a `canonicalSchema` with the published `$id`; the artifact-fields screen renders it as a link. `provenance` has THREE values, not a nullable id: `core-schema`, `tool-output` (the Core deliberately publishes none — CI run records, coverage reports) and `none` (nothing upstream; the tenant's `ArtifactFieldSchema` is the only authority). Collapsing the last two into null would erase the difference between a gap someone should close and a decision already taken. The mapping is a WRITTEN DECISION and not a slug transformation — `security-scan-result` ⇄ Security Scan Report, `rollback-plan` ⇄ Rollback Procedure, `observability-readiness` ⇄ Observability Validation would all be missed by a matcher — so `CoreArtifactSchemaCatalogTests` parses the markdown table and compares BOTH ways: a documented row nobody wired fails, and a wired entry nobody documented fails too. Verified by breaking it in both directions. Still a pointer and never a constraint: no content is validated against these schemas here, which is what T-056 requires. | 🟡 MEDIUM | 🟡 MEDIUM | | 3 | 🟢 RESOLVED | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | RESOLVED — stale row; the evidence was in the catalog and never reached this register. `tracker-gap-reference-catalog.md` closed it on 2026-07-20 with «YA HECHA» and named the artifact. Re-verified here rather than taken on trust: `reference/specs/design/tracker-redo-flow-design.md` is 254 lines with trigger conditions, the state model, the domain model inside the Release context, the recalculation algorithm, impact propagation, the human-authorization gate, domain events and a traceability table. Its §10 lists five scheduling decisions (RD-D1…RD-D5) explicitly registered as proposals awaiting PO ratification — that is a decision pending an owner, not a design that is missing. | 🟡 MEDIUM | 🟡 MEDIUM | | 4 | 🟢 RESOLVED | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | RESOLVED — stale row, same shape. The catalog closed it on 2026-07-19; this register kept the narrowed half open. Verified directly: `bounded-context-map.md` §2 classifies all nine contexts and names the four supporting ones — Governance, Artifacts, Metrics, Integration — each linked to its own tactical model, and all ten `ddd-model.md` files exist on disk. Both halves of the row are satisfied. | 🟡 MEDIUM | 🟡 MEDIUM | | 5 | 🟢 RESOLVED | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | RESOLVED — stale row. `reference/specs/design/tracker-implementation-roadmap.md` has carried `Document Status: SUPERSEDED — historical NestJS-era draft` since it was corrected, and the marker cites **this row by id**: «SUPERSEDED (GAP-016)». The roadmap planned a NestJS build that was executed in .NET, so «no calendar dates» is moot on a document that describes a plan already carried out under a different stack. The other board, `tracker-gap-tracking.md`, recorded this correctly; this register did not. | 🟡 MEDIUM | 🟡 MEDIUM | @@ -413,7 +413,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-020 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs diff --git a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs new file mode 100644 index 00000000..426a4616 --- /dev/null +++ b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/CoreArtifactSchemaCatalog.cs @@ -0,0 +1,128 @@ +namespace Tracker.Application.Governance.ArtifactFieldSchema; + +/// +/// Where an artifact's canonical shape comes from — or why it has none. Three states, not a +/// nullable string: «no schema because the Core publishes none» and «no schema because it is a +/// tool's own output» call for opposite answers from a consumer, and collapsing them into `null` +/// makes the difference unrecoverable at the point where it matters. +/// +public static class ArtifactSchemaProvenance +{ + /// Evolith Core publishes a canonical JSON Schema for this artifact. + public const string CoreSchema = "core-schema"; + + /// + /// The artifact IS a tool's native output (CI run record, coverage report). The Core declares + /// producedBy rather than a schema on purpose: a bespoke shape would restate what the + /// tool already publishes and rot the day the tool changes. + /// + public const string ToolOutput = "tool-output"; + + /// + /// Nothing upstream. The shape is whatever the tenant's ArtifactFieldSchema says, and + /// per T-056 nothing here contradicts it. + /// + public const string None = "none"; +} + +/// The canonical shape of an artifact, as far as the Core publishes one. +public sealed record ArtifactCanonicalSchemaDto +{ + /// + /// The schema's published $id, or null when there is none. It is an `$id` and not + /// a repository path deliberately: a path is a fact about where a file sits in one repository + /// at one moment, while the `$id` is the schema's own identity and survives the Core + /// reorganising its tree. Those paths were in fact broken until `evolith_arch32#378`. + /// + public string? SchemaId { get; init; } + + /// See . + public string Provenance { get; init; } = ArtifactSchemaProvenance.None; +} + +/// +/// The correspondence between a Tracker artifact kind and the canonical schema Evolith Core +/// publishes for it (GAP-020). +/// +/// THIS IS A WRITTEN DECISION, NOT A TRANSFORMATION. The two vocabularies agree for some +/// artifacts (prd, release-notes, test-summary-report) and diverge for others: +/// security-scan-result is the Core's *Security Scan Report*, rollback-plan is its +/// *Rollback Procedure*, observability-readiness is its *Observability Validation*. A +/// mapper that matched by slug would silently miss all three. Each entry below is a judgement +/// someone made and can be argued with; none of it is derived. +/// +/// The prose version, with the reasoning for every row, is +/// docs/artifacts/CORE_ARTIFACT_SCHEMAS.md. That document and this table are kept identical +/// by CoreArtifactSchemaCatalogTests, which parses the markdown and compares — because a +/// decision recorded in two places drifts, and this repository has spent the week finding out how +/// quietly. +/// +/// WHAT THIS DOES NOT DO. It does not make the Core the authority over what a tenant may +/// record. Per T-056 content validation is the tenant's configuration and not engine code: +/// the custom fields a tenant adds through ArtifactFieldSchema stay theirs, and this +/// reference is offered to whoever fills an artifact in — never enforced against them here. +/// +public static class CoreArtifactSchemaCatalog +{ + private const string Base = "https://evolith.dev/schema/"; + + /// + /// Tracker kind → published $id. Ten entries: the Core publishes fourteen schemas, but + /// four of them — Discovery Canvas, Ballpark Estimation, Integration Evidence and On-Call + /// Handoff — have no kind in and therefore nothing here to + /// hang off. They are listed in the markdown so a reader looking for them finds out they exist. + /// + private static readonly IReadOnlyDictionary SchemaIdByKind = + new Dictionary + { + ["prd"] = Base + "prd.schema.json", + ["technical-feasibility-canvas"] = Base + "technical-feasibility.schema.json", + ["build-versus-compose-analysis"] = Base + "build-vs-compose.schema.json", + ["bounded-context-map"] = Base + "bounded-context-map.schema.json", + ["definition-of-done-checklist"] = Base + "definition-of-done-checklist.schema.json", + ["test-summary-report"] = Base + "test-summary-report.schema.json", + ["security-scan-result"] = Base + "security-scan-report.schema.json", + ["release-notes"] = Base + "release-notes.schema.json", + ["observability-readiness"] = Base + "observability-validation.schema.json", + ["rollback-plan"] = Base + "rollback-rehearsal.schema.json", + }; + + /// + /// Kinds whose content IS a tool's own output. The Core's third such artifact — Pyramid + /// Distribution — has no Tracker kind. + /// + private static readonly IReadOnlySet ToolOutputKinds = + new HashSet { "ci-pipeline-result", "coverage-report" }; + + /// + /// Note on adr-registry: it is NOT wired to adr.schema.json even though the names + /// invite it. A registry is a *list* of ADRs and not an ADR, so the mapping would produce a + /// validation that fails against the real artifact — coverage on paper, a false negative in + /// practice. + /// + public static ArtifactCanonicalSchemaDto For(string artifactKind) + { + if (SchemaIdByKind.TryGetValue(artifactKind, out var id)) + { + return new ArtifactCanonicalSchemaDto + { + SchemaId = id, + Provenance = ArtifactSchemaProvenance.CoreSchema, + }; + } + + return new ArtifactCanonicalSchemaDto + { + SchemaId = null, + Provenance = ToolOutputKinds.Contains(artifactKind) + ? ArtifactSchemaProvenance.ToolOutput + : ArtifactSchemaProvenance.None, + }; + } + + /// The mapped kinds, for guards that need to compare the table against its source. + public static IReadOnlyDictionary Mappings => SchemaIdByKind; + + /// The tool-output kinds, same purpose. + public static IReadOnlySet ToolOutputs => ToolOutputKinds; +} diff --git a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/IPhaseArtifactProfileSource.cs b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/IPhaseArtifactProfileSource.cs index 878c3830..cbd72f85 100644 --- a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/IPhaseArtifactProfileSource.cs +++ b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/IPhaseArtifactProfileSource.cs @@ -51,6 +51,9 @@ public IReadOnlyList GetProfiles() => ArtifactKind = a.ArtifactKind, Label = a.Label, Required = a.Required, + // GAP-020: el perfil ya no dice sólo QUE hace falta un artefacto, sino + // dónde está su forma canónica — o por qué no la tiene. + CanonicalSchema = CoreArtifactSchemaCatalog.For(a.ArtifactKind), }) .ToList(), }) diff --git a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs index 88d3fd43..92a92999 100644 --- a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs +++ b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs @@ -7,13 +7,14 @@ namespace Tracker.Application.Governance.ArtifactFieldSchema; /// the tenant configures custom fields per artifact (via ArtifactFieldSchema keyed by the /// artifact kind) and — for optional artifacts — their applicability. /// -/// GAP-020 — este catálogo dice que un `prd` es obligatorio y NO dice qué debe contener. La -/// forma canónica, para los 10 de 24 artefactos que la tienen aguas arriba, está enlazada en -/// docs/artifacts/CORE_ARTIFACT_SCHEMAS.md. No se enlaza desde aquí como dato porque los -/// nombres no coinciden mecánicamente (`security-scan-result` ⇄ Security Scan Report, -/// `rollback-plan` ⇄ Rollback Procedure) y la correspondencia es una decisión escrita, no una -/// transformación de cadena — y porque el `schemaRef` que publican los gates del Core es una ruta -/// relativa ROTA: resuelve a un directorio que no existe. +/// GAP-020 — este catálogo dice que un `prd` es obligatorio; QUÉ debe contener lo dice +/// ahora , que cuelga de cada artefacto el `$id` del esquema +/// canónico publicado por el Core, o la razón de que no lo tenga. La correspondencia sigue siendo una +/// DECISIÓN ESCRITA y no una transformación de cadena — `security-scan-result` ⇄ Security Scan Report, +/// `rollback-plan` ⇄ Rollback Procedure — y por eso vive en una tabla explícita contrastada contra +/// `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md`. Se enlaza por `$id` y no por ruta: las rutas relativas +/// que publicaban las compuertas del Core estaban rotas hasta `evolith_arch32#378`, y una ruta es un +/// hecho sobre dónde está un fichero hoy, mientras que el `$id` es la identidad del esquema. /// public static class PhaseArtifactCatalog { @@ -78,6 +79,15 @@ public sealed class PhaseArtifactDto public string ArtifactKind { get; init; } = string.Empty; public string Label { get; init; } = string.Empty; public bool Required { get; init; } + + /// + /// The canonical shape the Core publishes for this artifact, or the reason there is none + /// (GAP-020). Until this field existed a consumer learned that a `prd` is required in discovery + /// and had no way to find out what a PRD is supposed to contain. See + /// — and note that it is a POINTER, not a constraint: + /// per T-056 the tenant's ArtifactFieldSchema stays the authority over content. + /// + public ArtifactCanonicalSchemaDto CanonicalSchema { get; init; } = new(); } public sealed class PhaseArtifactProfileDto diff --git a/src/apps/tracker-api/Tracker.Tests/Application/Governance/CoreArtifactSchemaCatalogTests.cs b/src/apps/tracker-api/Tracker.Tests/Application/Governance/CoreArtifactSchemaCatalogTests.cs new file mode 100644 index 00000000..3a150466 --- /dev/null +++ b/src/apps/tracker-api/Tracker.Tests/Application/Governance/CoreArtifactSchemaCatalogTests.cs @@ -0,0 +1,145 @@ +using System.Text.RegularExpressions; +using Tracker.Application.Governance.ArtifactFieldSchema; + +namespace Tracker.Tests.Application.Governance; + +/// +/// Contrasta la tabla de con su fuente en prosa, +/// docs/artifacts/CORE_ARTIFACT_SCHEMAS.md. +/// +/// POR QUÉ. La correspondencia entre los tipos del Tracker y los artefactos del Core es una +/// decisión escrita, y las decisiones escritas en dos sitios se separan. Esta semana el repositorio +/// encontró la misma avería cuatro veces: dos tableros de gaps que se contradecían en 5 de 34 +/// identificadores, y dos ficheros marcados «traducidos» que eran copias del español. En todos los +/// casos había una comprobación verde al lado que miraba otra cosa. +/// +/// Estas pruebas fallan en las DOS direcciones: una fila en el markdown que nadie cableó, y +/// una entrada en el código que nadie documentó. Una guarda que sólo mira un sentido deja el otro +/// como sitio cómodo donde esconder cosas. +/// +public class CoreArtifactSchemaCatalogTests +{ + private const string Doc = "docs/artifacts/CORE_ARTIFACT_SCHEMAS.md"; + + /// + /// Filas de la tabla con tipo del Tracker. Las que dicen (no catalog kind) se saltan a + /// propósito: son artefactos con esquema en el Core y sin tipo aquí, y están en el documento + /// para que quien los busque descubra que existen. + /// + private static Dictionary FilasDelDocumento() + { + var texto = File.ReadAllText(Path.Combine(RaizDelRepositorio(), Doc)); + var filas = new Dictionary(); + + // | fase | `tipo` | Nombre en el Core | [`fichero`](https://evolith.dev/schema/fichero) | + var patron = new Regex( + @"^\|\s*\w+\s*\|\s*`([a-z0-9-]+)`\s*\|[^|]*\|\s*\[[^\]]*\]\((https://evolith\.dev/schema/[^)]+)\)\s*\|", + RegexOptions.Multiline); + + foreach (System.Text.RegularExpressions.Match m in patron.Matches(texto)) + { + filas[m.Groups[1].Value] = m.Groups[2].Value; + } + + return filas; + } + + [Fact] + public void LaTablaDelCodigoYLaDelDocumentoDicenLoMismo() + { + var doc = FilasDelDocumento(); + + // Una guarda que recorre cero filas pasa siempre. Si el formato del documento cambia y el + // patrón deja de encajar, esto lo dice en vez de dar un verde vacío. + doc.Should().HaveCount(10, + "el documento publica catorce esquemas y diez de ellos tienen tipo en el Tracker; " + + "si este número cambia hay que decidir el mapeo, no ajustar la prueba"); + + CoreArtifactSchemaCatalog.Mappings.Should().BeEquivalentTo(doc, + "la correspondencia es una decisión escrita y vive en dos sitios: el documento explica " + + "el porqué de cada fila y el código la aplica. En cuanto discrepan, uno de los dos " + + "miente y nadie sabe cuál"); + } + + [Fact] + public void LosTiposMapeadosExistenEnElCatalogoDeFases() + { + var conocidos = PhaseArtifactCatalog.ByPhase.Values + .SelectMany(a => a) + .Select(a => a.ArtifactKind) + .ToHashSet(); + + foreach (var tipo in CoreArtifactSchemaCatalog.Mappings.Keys.Concat(CoreArtifactSchemaCatalog.ToolOutputs)) + { + conocidos.Should().Contain(tipo, + $"`{tipo}` tiene esquema o procedencia declarada pero ningún artefacto lo pide: " + + "es un mapeo a la nada, y se lee como cobertura"); + } + } + + [Fact] + public void ElRegistroDeAdrNoSeMapeaAlEsquemaDeUnAdr() + { + // Los nombres invitan al atajo. Un registro es una LISTA de ADRs y no un ADR, así que el + // mapeo daría una validación que falla contra el artefacto real: cobertura sobre el papel + // y un falso negativo en la práctica. + CoreArtifactSchemaCatalog.For("adr-registry").Provenance + .Should().Be(ArtifactSchemaProvenance.None); + } + + [Fact] + public void SinEsquemaYSalidaDeHerramientaNoSeConfunden() + { + // Son dos ausencias distintas y piden respuestas opuestas: a una le falta un esquema que + // habría que escribir; la otra NO debe tenerlo nunca. Colapsarlas en `null` perdería eso. + CoreArtifactSchemaCatalog.For("ci-pipeline-result").Provenance + .Should().Be(ArtifactSchemaProvenance.ToolOutput); + CoreArtifactSchemaCatalog.For("coverage-report").Provenance + .Should().Be(ArtifactSchemaProvenance.ToolOutput); + CoreArtifactSchemaCatalog.For("business-case").Provenance + .Should().Be(ArtifactSchemaProvenance.None); + + CoreArtifactSchemaCatalog.For("ci-pipeline-result").SchemaId.Should().BeNull(); + CoreArtifactSchemaCatalog.For("business-case").SchemaId.Should().BeNull(); + } + + [Fact] + public void LosTresNombresQueNoCoincidenEstanCableadosAMano() + { + // Un mapeador por slug fallaría estos tres, y fallaría en silencio. + CoreArtifactSchemaCatalog.For("security-scan-result").SchemaId + .Should().EndWith("security-scan-report.schema.json"); + CoreArtifactSchemaCatalog.For("rollback-plan").SchemaId + .Should().EndWith("rollback-rehearsal.schema.json"); + CoreArtifactSchemaCatalog.For("observability-readiness").SchemaId + .Should().EndWith("observability-validation.schema.json"); + } + + [Fact] + public void ElPerfilQueSeSirveLlevaLaReferencia() + { + var perfiles = new StandInPhaseArtifactProfileSource().GetProfiles(); + + var prd = perfiles.Single(p => p.Phase == "discovery") + .Artifacts.Single(a => a.ArtifactKind == "prd"); + + prd.CanonicalSchema.Provenance.Should().Be(ArtifactSchemaProvenance.CoreSchema); + prd.CanonicalSchema.SchemaId.Should().Be("https://evolith.dev/schema/prd.schema.json"); + + // Y el que no tiene esquema lo dice, en vez de venir vacío y parecer un fallo de carga. + var caso = perfiles.Single(p => p.Phase == "discovery") + .Artifacts.Single(a => a.ArtifactKind == "business-case"); + caso.CanonicalSchema.Provenance.Should().Be(ArtifactSchemaProvenance.None); + } + + private static string RaizDelRepositorio() + { + var dir = new DirectoryInfo(AppContext.BaseDirectory); + while (dir is not null && !Directory.Exists(Path.Combine(dir.FullName, ".git"))) + { + dir = dir.Parent; + } + dir.Should().NotBeNull("la prueba necesita ubicar la raiz del repositorio"); + return dir!.FullName; + } +} diff --git a/src/apps/tracker-web/src/api/types.ts b/src/apps/tracker-web/src/api/types.ts index 0cfba37e..5613a901 100644 --- a/src/apps/tracker-web/src/api/types.ts +++ b/src/apps/tracker-web/src/api/types.ts @@ -255,11 +255,34 @@ export interface UpsertArtifactFieldSchemaRequest { customFields: CustomFieldDto[]; } +/** + * Where an artifact's canonical shape comes from — or why it has none (GAP-020). + * + * Three states rather than a nullable id, because two of them are different absences and call for + * opposite answers: `tool-output` means the Core deliberately publishes NO schema (the artifact is + * a CI run record or a coverage report, and a bespoke shape would restate what the tool already + * emits), while `none` means nothing upstream covers it and the tenant's own field schema is the + * only authority. Collapsing both into `null` would make the difference unrecoverable in the UI. + */ +export type ArtifactSchemaProvenance = 'core-schema' | 'tool-output' | 'none'; + +export interface ArtifactCanonicalSchemaDto { + /** The schema's published `$id` — not a repository path, which would break when Core moves it. */ + schemaId?: string | null; + provenance: ArtifactSchemaProvenance | string; +} + /** One Core-authoritative base artifact within a phase (read-only for the tenant). */ export interface PhaseArtifactDto { artifactKind: string; label: string; required: boolean; + /** + * The canonical shape Core publishes for this artifact (GAP-020). A pointer, never a constraint: + * per T-056 the tenant's custom fields stay the authority over content. Absent on legacy + * responses. + */ + canonicalSchema?: ArtifactCanonicalSchemaDto | null; } /** GET /api/phase-artifact-profiles — Core base artifacts per phase (PRD required in Discovery, …). */ diff --git a/src/apps/tracker-web/src/components/screens/md3/FieldSchemaManager.tsx b/src/apps/tracker-web/src/components/screens/md3/FieldSchemaManager.tsx index be4a9f15..1f9fb668 100644 --- a/src/apps/tracker-web/src/components/screens/md3/FieldSchemaManager.tsx +++ b/src/apps/tracker-web/src/components/screens/md3/FieldSchemaManager.tsx @@ -12,7 +12,7 @@ import { usePhaseArtifactProfiles, useUpsertArtifactFieldSchema, } from '../../../api'; -import type { CustomFieldDto } from '../../../api'; +import type { ArtifactCanonicalSchemaDto, CustomFieldDto } from '../../../api'; import { Button, Card, @@ -37,10 +37,55 @@ const PHASE_LABEL: Record = { }; /** Per-artifact custom-field editor. The artifact itself is Core-defined; only fields are editable. */ -const ArtifactFieldCard: React.FC<{ artifactKind: string; label: string; required: boolean }> = ({ +/** + * El puntero a la forma canonica de un artefacto (GAP-020). Las tres procedencias se muestran + * distinto A PROPOSITO: un esquema publicado se puede abrir, una salida de herramienta NO tiene + * esquema por decision del Core, y `none` es un hueco de verdad. Un guion para los tres casos + * ocultaria justo la informacion que hace falta para saber si falta trabajo o no. + */ +const CanonicalSchemaHint: React.FC<{ schema?: ArtifactCanonicalSchemaDto | null }> = ({ schema }) => { + const { t } = useTranslation(); + if (!schema) return null; + + if (schema.provenance === 'core-schema' && schema.schemaId) { + return ( + + ); + } + + const texto = + schema.provenance === 'tool-output' + ? t('shape defined by the emitting tool', 'forma definida por la herramienta que lo emite') + : t('no upstream schema — your fields define it', 'sin esquema upstream — lo definen tus campos'); + + return ( +
+ {texto} +
+ ); +}; + +const ArtifactFieldCard: React.FC<{ + artifactKind: string; + label: string; + required: boolean; + canonicalSchema?: ArtifactCanonicalSchemaDto | null; +}> = ({ artifactKind, label, required, + canonicalSchema, }) => { const { t } = useTranslation(); const query = useArtifactFieldSchema(artifactKind); @@ -115,6 +160,11 @@ const ArtifactFieldCard: React.FC<{ artifactKind: string; label: string; require {artifactKind} {count > 0 ? ` · ${count} ${count === 1 ? t('custom field', 'campo personalizado') : t('custom fields', 'campos personalizados')}` : ''} + {/* GAP-020 — hasta aqui la tarjeta decia que un artefacto hace falta y no QUE debe + contener. El enlace apunta a la forma canonica publicada por el Core; es una + referencia y no una restriccion (T-056), por eso se ofrece y no se impone. Las dos + ausencias se distinguen: `tool-output` es deliberada, `none` es un hueco. */} +