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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ Este catálogo explica cada gap: problema, propósito, evidencia, criterios de c
- **Criticality:** P2 · **Complexity:** M
- **Proposed fix:** Parser del subconjunto enforce-able del DSL Structurizr/C4 + mapeo a reglas `enforce:` compiladas por GT-516, con trazabilidad al elemento de modelo de origen.
- **Acceptance criteria:**
- [ ] Un modelo Structurizr/C4 de ejemplo produce al menos una regla `enforce:` verificable contra el código.
- [ ] Cada regla generada traza al elemento de modelo/ADR de origen.
- [x] Un modelo Structurizr/C4 de ejemplo produce al menos una regla verificable contra el código. _(`compileC4ToBoundaryRules` → `EditBoundaryRule` de GT-526; probado end-to-end: bloquea un edit domain→infra)_
- [x] Cada regla generada traza al elemento de modelo/ADR de origen. _(`ruleId` `C4-<id>` + `adrRef` del elemento)_
- **Dependencies:** GT-516.
- **Status:** `PENDING`
- **Status:** `IN-PROGRESS`

#### GT-529

Expand Down
6 changes: 3 additions & 3 deletions reference/core/control-center/gaps/gap-reference-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ This catalog explains each gap: problem, purpose, evidence, closure criteria, an
- **Criticality:** P2 · **Complexity:** M
- **Proposed fix:** Parser for the enforceable subset of the Structurizr/C4 DSL + mapping to `enforce:` rules compiled by GT-516, with traceability to the source model element.
- **Acceptance criteria:**
- [ ] A sample Structurizr/C4 model yields at least one `enforce:` rule verifiable against code.
- [ ] Each generated rule traces to its source model element/ADR.
- [x] A sample Structurizr/C4 model yields at least one rule verifiable against code. _(`compileC4ToBoundaryRules` → GT-526 `EditBoundaryRule`; verified end-to-end: blocks a domain→infra edit)_
- [x] Each generated rule traces to its source model element/ADR. _(`ruleId` `C4-<id>` + the element's `adrRef`)_
- **Dependencies:** GT-516.
- **Status:** `PENDING`
- **Status:** `IN-PROGRESS`

#### GT-529

Expand Down
4 changes: 2 additions & 2 deletions reference/core/control-center/gaps/gap-tracking.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida
| [`GT-525`](./gap-reference-catalog.es.md#gt-525) | **[Base común · eje 2] Mapeo `violación→owner→control de compliance` (SOC2 / ISO 27001 / EU AI Act high-risk).** Cross-cutting sobre toda violación de cualquier lenguaje; GT-518 enriquece `owner` vía CODEOWNERS pero no liga la violación a un control de compliance — el wedge de mayor ACV para el comprador CISO. Extiende GT-518. Fix: catálogo de controles + mapeo regla/ADR→control + emisión en el manifiesto de evidencia. Análisis §12 (P1 wedge). **COMPLETADO (`57b2cc09`):** `domain/compliance.ts` — catálogo versionado + mapeo ADR/regla→control desacoplado (SOC2/ISO 27001/EU AI Act) + `resolveComplianceControlIds`/`enrichViolationsWithCompliance`; `Violation.complianceControls?` (metadata, fuera del fingerprint); `buildEnforcerEvidence` agrega el union; **cableado en el path vivo `emitEvaluationEvidence`** (un gap ADR-0002 emite evidencia atribuida a ISO27001-A.14.2.5 + SOC2-CC8.1, por-violación y a nivel manifiesto). Verificado: core-domain 910/910 (+12), tsc limpio. Sin gate de infra. | `Evolith Core` | Cross | P1 | S | `COMPLETADO` |
| [`GT-526`](./gap-reference-catalog.es.md#gt-526) | **[Superficie de control · eje 2] Enforcement `edit-time` — hook cross-agente.** La 3ª de las tres superficies READ→CONTROL (§14.1): pre-generación (MCP, parcial GT-520) y PR/CI (GT-518) existen, pero falta el hook que bloquea el cambio infractor al vuelo mientras el agente escribe. Sin incumbente en el mercado. Fix: hook cross-agente (Claude Code/Cursor/Copilot) que consulta el contrato de arquitectura y rechaza el edit no conforme. Análisis §14. **EN-PROGRESO (`edit-gate.ts`):** aterrizó el núcleo verificable — `evaluateEdit(edit, rules)` decide **allow/block al vuelo** con un chequeo rápido de un solo archivo (sin toolchain; el PR/CI de GT-518 sigue siendo el gate autoritativo): `extractImports` (TS/JS `import`/`export from`/`require` + C# `using`) + reglas de frontera `EditBoundaryRule` (`appliesTo`/`forbiddenImports`), emite `Violation` canónicas (tool `edit-gate`, reusables por evidencia/compliance), `allow=false` solo ante severidad `error`. Agent-neutral (función pura). Verificado: core-domain 917/917 (+7), tsc limpio. **Pendiente (integración):** el adapter por-agente (hook PreToolUse de Claude Code / extensión Cursor) que alimenta el edit y aplica la decisión. | `Evolith CLI` | Cross | P1 | M | `EN-PROGRESO` |
| [`GT-527`](./gap-reference-catalog.es.md#gt-527) | **[Wedge · eje 2] Conectores de ingesta de ownership sin lock-in: Port / Cortex / OpsLevel + Backstage.** Ingerir blueprints de IDP y `catalog-info.yaml` como fuente de ownership/servicios para enriquecer violaciones y ADRs sin depender del proveedor; Evolith bloquea donde ellos solo miden (§13.2). Fix: conectores read-only vía ACL que normalizan a la forma canónica de ownership. **EN-PROGRESO (`domain/ownership.ts`):** aterrizó el núcleo puro de normalización — `OwnershipEntry` canónico, `parseBackstageCatalog` (`catalog-info.yaml` kind Component → owner + pathPrefix vía anotación `evolith.io/path`/`source-location` relativo; descarta no-Components/incompletos), `parseBlueprintOwnership` (genérico Port/Cortex/OpsLevel: `component`\|`identifier` + `owner`\|`team`), `resolveOwner` (file→owner por longest-prefix) y `enrichViolationsWithOwner` (puebla `owner` sin sobrescribir, fuera del fingerprint). **Completa la cadena violación→owner→compliance** (compone con GT-525). Verificado: core-domain 925/925 (+8), tsc limpio. **Pendiente (conector/infra):** leer el `catalog-info.yaml` del repo (vía el port de config-parser) y el fetch read-only de las APIs Port/Cortex. | `Evolith Core` | Cross | P2 | L | `EN-PROGRESO` |
| [`GT-528`](./gap-reference-catalog.es.md#gt-528) | **[Wedge · eje 2] Ingesta de DSL Structurizr / C4 → ADR ejecutable.** Convertir modelos Structurizr/C4 (intención de arquitectura, hoy prosa/diagrama) en reglas `enforce:` verificables contra el código real (§13.2). Fix: parser del DSL + mapeo a `NormalizedRule.enforce`; complementa GT-516. | `Evolith Core` | Cross | P2 | M | `PENDIENTE` |
| [`GT-528`](./gap-reference-catalog.es.md#gt-528) | **[Wedge · eje 2] Ingesta de DSL Structurizr / C4 → ADR ejecutable.** Convertir modelos Structurizr/C4 (intención de arquitectura, hoy prosa/diagrama) en reglas `enforce:` verificables contra el código real (§13.2). Fix: parser del DSL + mapeo a `NormalizedRule.enforce`; complementa GT-516. **EN-PROGRESO (`c4-compiler.ts`):** aterrizó el compilador — `compileC4ToBoundaryRules(model)` transforma un `C4Model` normalizado (elementos con `path`/`importPrefix` + relaciones permitidas) en `EditBoundaryRule` de GT-526, derivando el denylist desde el allowlist del modelo (un elemento solo puede depender de lo que declara; el resto queda prohibido), con `ruleId` `C4-<id>`, ADR y severidad. **El diagrama C4 se vuelve ejecutable** y se enchufa al gate edit-time (GT-526) y al PR/CI. Verificado end-to-end: un edit de `src/domain` que importa `src/infrastructure` → bloqueado; core-domain 933/933 (+5), tsc limpio. **Pendiente (ingesta):** parsear el `.dsl` crudo de Structurizr (o su export JSON) al `C4Model` normalizado. | `Evolith Core` | Cross | P2 | M | `EN-PROGRESO` |
| [`GT-529`](./gap-reference-catalog.es.md#gt-529) | **[Surround · eje 1] Contrato ACL + referencia de integración Jira Enterprise.** Mapear ideas/epics/stories/aprobaciones/releases de Jira a artefactos Evolith preservando origen/identidad/timestamps/linaje, con salvaguardas de transición (completar un workflow de Jira no autoriza una transición de fase). §8.3 / §12. Fix: ACL de sistemas de trabajo externos + guía de integración. | `Evolith Core` | Cross | P1 | L | `PENDIENTE` |
| [`GT-530`](./gap-reference-catalog.es.md#gt-530) | **[Surround · eje 1] Adaptador Langfuse → evidencia canónica.** Mapear traces/evaluaciones/costo/latencia/versión-de-prompt/tool-calls de Langfuse al modelo de evidencia de Evolith, para no reconstruir una plataforma de telemetría LLM. §8.1 / §12. Fix: `LangfuseEvidenceAdapter` vía puerto de observabilidad. | `Evolith Core` | Cross | P2 | L | `PENDIENTE` |
| [`GT-531`](./gap-reference-catalog.es.md#gt-531) | **[Surround · eje 1] Adaptador Cowork/Claude como ejecutor gobernado acotado.** Ejecutor de actividades con permisos/planes/aprobaciones/captura de evidencia, tratando a Claude como uno de varios ejecutores reemplazables (§8.2, §9). Extiende el épico agent-runtime GT-383…394 (HITL GT-441 / adapters GT-438). | `agent-runtime` | Cross | P2 | M | `PENDIENTE` |
Expand Down Expand Up @@ -547,7 +547,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida
| [`GT-246`](./gap-reference-catalog.es.md#gt-246) | Implementar experimentos Chaos Mesh/Litmus | `QA` | Cross | P3 | L | `COMPLETADO` |


**Progreso:** 496 / 532 completados · 16 en progreso · 18 pendientes · 2 diferido
**Progreso:** 496 / 532 completados · 17 en progreso · 17 pendientes · 2 diferido

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

Expand Down
4 changes: 2 additions & 2 deletions reference/core/control-center/gaps/gap-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This board is the single source of truth for technical debt, gaps, opportunities
| [`GT-525`](./gap-reference-catalog.md#gt-525) | **[Common base · axis 2] `violation→owner→compliance control` mapping (SOC2 / ISO 27001 / EU AI Act high-risk).** Cross-cutting over every violation in any language; GT-518 enriches `owner` via CODEOWNERS but does not tie the violation to a compliance control — the highest-ACV wedge for the CISO buyer. Extends GT-518. Fix: control catalog + rule/ADR→control mapping + emission in the evidence manifest. Analysis §12 (P1 wedge). **DONE (`57b2cc09`):** `domain/compliance.ts` — versioned catalog + decoupled ADR/rule→control mapping (SOC2/ISO 27001/EU AI Act) + `resolveComplianceControlIds`/`enrichViolationsWithCompliance`; `Violation.complianceControls?` (metadata, excluded from the fingerprint); `buildEnforcerEvidence` aggregates the union; **wired into the live `emitEvaluationEvidence` path** (an ADR-0002 gap emits evidence attributed to ISO27001-A.14.2.5 + SOC2-CC8.1, per-violation and at manifest level). Verified: core-domain 910/910 (+12), tsc clean. No infra gate. | `Evolith Core` | Cross | P1 | S | `DONE` |
| [`GT-526`](./gap-reference-catalog.md#gt-526) | **[Control surface · axis 2] `edit-time` enforcement — cross-agent hook.** The 3rd of the three READ→CONTROL surfaces (§14.1): pre-generation (MCP, partial GT-520) and PR/CI (GT-518) exist, but the hook that blocks the offending change in-flight as the agent writes is missing. No market incumbent. Fix: cross-agent hook (Claude Code/Cursor/Copilot) that queries the architecture contract and rejects the non-conforming edit. Analysis §14. **IN-PROGRESS (`edit-gate.ts`):** landed the verifiable core — `evaluateEdit(edit, rules)` decides **allow/block in-flight** with a fast single-file check (no toolchain; GT-518's PR/CI stays the authoritative gate): `extractImports` (TS/JS `import`/`export from`/`require` + C# `using`) + `EditBoundaryRule` boundary rules (`appliesTo`/`forbiddenImports`), emits canonical `Violation`s (tool `edit-gate`, reusable by evidence/compliance), `allow=false` only on `error` severity. Agent-neutral (pure function). Verified: core-domain 917/917 (+7), tsc clean. **Remaining (integration):** the per-agent adapter (Claude Code PreToolUse hook / Cursor extension) that feeds the edit and enforces the decision. | `Evolith CLI` | Cross | P1 | M | `IN-PROGRESS` |
| [`GT-527`](./gap-reference-catalog.md#gt-527) | **[Wedge · axis 2] Lock-in-free ownership ingestion connectors: Port / Cortex / OpsLevel + Backstage.** Ingest IDP blueprints and `catalog-info.yaml` as an ownership/service source to enrich violations and ADRs without vendor lock-in; Evolith blocks where they only measure (§13.2). Fix: read-only connectors via ACL normalizing to the canonical ownership shape. **IN-PROGRESS (`domain/ownership.ts`):** landed the pure normalization core — canonical `OwnershipEntry`, `parseBackstageCatalog` (`catalog-info.yaml` kind Component → owner + pathPrefix via `evolith.io/path`/relative `source-location`; drops non-Components/incomplete), `parseBlueprintOwnership` (generic Port/Cortex/OpsLevel: `component`\|`identifier` + `owner`\|`team`), `resolveOwner` (file→owner longest-prefix) and `enrichViolationsWithOwner` (fills `owner` without overwriting, excluded from the fingerprint). **Completes the violation→owner→compliance chain** (composes with GT-525). Verified: core-domain 925/925 (+8), tsc clean. **Remaining (connector/infra):** reading the repo's `catalog-info.yaml` (via the config-parser port) and the read-only Port/Cortex API fetch. | `Evolith Core` | Cross | P2 | L | `IN-PROGRESS` |
| [`GT-528`](./gap-reference-catalog.md#gt-528) | **[Wedge · axis 2] Structurizr / C4 DSL ingestion → executable ADR.** Turn Structurizr/C4 models (architecture intent, today prose/diagram) into `enforce:` rules verifiable against real code (§13.2). Fix: DSL parser + mapping to `NormalizedRule.enforce`; complements GT-516. | `Evolith Core` | Cross | P2 | M | `PENDING` |
| [`GT-528`](./gap-reference-catalog.md#gt-528) | **[Wedge · axis 2] Structurizr / C4 DSL ingestion → executable ADR.** Turn Structurizr/C4 models (architecture intent, today prose/diagram) into `enforce:` rules verifiable against real code (§13.2). Fix: DSL parser + mapping to `NormalizedRule.enforce`; complements GT-516. **IN-PROGRESS (`c4-compiler.ts`):** landed the compiler — `compileC4ToBoundaryRules(model)` turns a normalized `C4Model` (elements with `path`/`importPrefix` + allowed relationships) into GT-526 `EditBoundaryRule`s, deriving the denylist from the model's allowlist (an element may only depend on what it declares; everything else is forbidden), with `ruleId` `C4-<id>`, ADR and severity. **The C4 diagram becomes executable** and feeds the edit-time gate (GT-526) and PR/CI. Verified end-to-end: a `src/domain` edit importing `src/infrastructure` → blocked; core-domain 933/933 (+5), tsc clean. **Remaining (ingestion):** parse the raw Structurizr `.dsl` (or its JSON export) into the normalized `C4Model`. | `Evolith Core` | Cross | P2 | M | `IN-PROGRESS` |
| [`GT-529`](./gap-reference-catalog.md#gt-529) | **[Surround · axis 1] ACL contract + Jira Enterprise integration reference.** Map Jira ideas/epics/stories/approvals/releases to Evolith artifacts preserving origin/identity/timestamps/lineage, with transition safeguards (completing a Jira workflow does not authorize a phase transition). §8.3 / §12. Fix: external work-system ACL + integration guide. | `Evolith Core` | Cross | P1 | L | `PENDING` |
| [`GT-530`](./gap-reference-catalog.md#gt-530) | **[Surround · axis 1] Langfuse adapter → canonical evidence.** Map Langfuse traces/evaluations/cost/latency/prompt-version/tool-calls to Evolith's evidence model, to avoid rebuilding an LLM telemetry platform. §8.1 / §12. Fix: `LangfuseEvidenceAdapter` via the observability port. | `Evolith Core` | Cross | P2 | L | `PENDING` |
| [`GT-531`](./gap-reference-catalog.md#gt-531) | **[Surround · axis 1] Cowork/Claude adapter as a bounded governed executor.** Activity executor with permissions/plans/approvals/evidence capture, treating Claude as one of several replaceable executors (§8.2, §9). Extends the agent-runtime epic GT-383…394 (HITL GT-441 / adapters GT-438). | `agent-runtime` | Cross | P2 | M | `PENDING` |
Expand Down Expand Up @@ -547,7 +547,7 @@ This board is the single source of truth for technical debt, gaps, opportunities
| [`GT-246`](./gap-reference-catalog.md#gt-246) | Implement Chaos Mesh/Litmus experiments | `QA` | Cross | P3 | L | `DONE` |


**Progress:** 496 / 532 done · 16 in progress · 18 pending · 2 deferred
**Progress:** 496 / 532 done · 17 in progress · 17 pending · 2 deferred

**Wave 2026-06-23 (Winston deep audit III):** Added 14 new gaps `GT-212`…`GT-225` from the Winston Audit Playbook covering: ADR status hygiene (GT-212), topology manifest metadata + operational budgets + guidance corpus (GT-213, GT-217, GT-219), REST controller observability + OpenAPI (GT-214, GT-215), OPA input-schema parity + per-topology test density (GT-216, GT-222), SDLC Phase 05 rollback + on-call templates (GT-218), CLI branch coverage + envelope format coverage + skip-list cleanup (GT-220, GT-224, GT-225), MCP HTTP audit logging (GT-221), and cross-surface parity e2e tests (GT-223).

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { compileC4ToBoundaryRules, type C4Model } from './c4-compiler';
import { evaluateEdit } from './edit-gate';

// A hexagonal C4 model: application may use domain + infrastructure; domain may use nothing.
const MODEL: C4Model = {
elements: [
{ id: 'domain', name: 'Domain', path: 'src/domain', importPrefix: 'src/domain', adrRef: 'ADR-0002' },
{ id: 'app', name: 'Application', path: 'src/application', importPrefix: 'src/application' },
{ id: 'infra', name: 'Infrastructure', path: 'src/infrastructure', importPrefix: 'src/infrastructure' },
],
relationships: [
{ source: 'app', destination: 'domain' },
{ source: 'app', destination: 'infra' },
{ source: 'infra', destination: 'domain' },
],
};

describe('compileC4ToBoundaryRules (GT-528 — model → executable boundary rules)', () => {
it('forbids, for each element, the imports it did not declare a relationship to', () => {
const rules = compileC4ToBoundaryRules(MODEL);
const byApplies = Object.fromEntries(rules.map((r) => [r.appliesTo, r]));
// domain declared no relationships → may not import application or infrastructure.
expect(byApplies['src/domain'].forbiddenImports).toEqual(['src/application', 'src/infrastructure']);
// application declared domain + infra → only its own... nothing else exists → no rule OR empty.
expect(byApplies['src/application']).toBeUndefined();
// infrastructure declared domain → may not import application.
expect(byApplies['src/infrastructure'].forbiddenImports).toEqual(['src/application']);
});

it('carries the element ADR and a C4-prefixed rule id, and honours the severity option', () => {
const [rule] = compileC4ToBoundaryRules(MODEL).filter((r) => r.appliesTo === 'src/domain');
expect(rule.ruleId).toBe('C4-domain');
expect(rule.adrRef).toBe('ADR-0002');
expect(compileC4ToBoundaryRules(MODEL, { severity: 'warning' })[0].severity).toBe('warning');
});

it('skips abstract elements with no code path', () => {
const rules = compileC4ToBoundaryRules({
elements: [{ id: 'ext', name: 'External System' }, ...MODEL.elements],
relationships: MODEL.relationships,
});
expect(rules.some((r) => r.ruleId === 'C4-ext')).toBe(false);
});

it('end-to-end: compiled rules BLOCK a domain edit that imports infrastructure (GT-528 → GT-526)', () => {
const rules = compileC4ToBoundaryRules(MODEL);
const decision = evaluateEdit(
{ filePath: 'src/domain/order.ts', content: "import { Db } from 'src/infrastructure/db';" },
rules,
);
expect(decision.allow).toBe(false);
expect(decision.violations[0].ruleId).toBe('C4-domain');
});

it('end-to-end: an application edit importing domain is allowed (declared relationship)', () => {
const rules = compileC4ToBoundaryRules(MODEL);
const decision = evaluateEdit(
{ filePath: 'src/application/use-case.ts', content: "import { Order } from 'src/domain/order';" },
rules,
);
expect(decision.allow).toBe(true);
});
});
Loading