diff --git a/.harness/scripts/ci/rag-eval.mjs b/.harness/scripts/ci/rag-eval.mjs index 3e27777ec..c81ce1dd8 100644 Binary files a/.harness/scripts/ci/rag-eval.mjs and b/.harness/scripts/ci/rag-eval.mjs differ diff --git a/.harness/scripts/lib/guard-classification.mjs b/.harness/scripts/lib/guard-classification.mjs index 6d6c0fabe..242220541 100644 --- a/.harness/scripts/lib/guard-classification.mjs +++ b/.harness/scripts/lib/guard-classification.mjs @@ -155,6 +155,7 @@ export const NOT_A_SCANNER = [ { file: 'rag-port.mjs', reason: 'library: RAG port interface' }, { file: 'rag-pgvector.mjs', reason: 'library: pgvector adapter' }, { file: 'rag-embed-qwen3.mjs', reason: 'library: embedding adapter, needs a model endpoint' }, + { file: 'rag-eval-record.mjs', reason: 'recorder/generator: requires a live embedding sidecar and writes the frozen RAG eval fixtures consumed by rag-eval.mjs' }, { file: 'rag-sync.mjs', reason: 'library: RAG sync driver behind 14/15' }, { file: 'agentic/review-input.mjs', reason: 'library: builds the review payload' }, { file: 'agentic/review-provider.mjs', reason: 'library: LLM provider adapter' }, diff --git a/reference/core/control-center/gaps/gap-tracking.es.md b/reference/core/control-center/gaps/gap-tracking.es.md index 8281714fe..90ef896c2 100644 --- a/reference/core/control-center/gaps/gap-tracking.es.md +++ b/reference/core/control-center/gaps/gap-tracking.es.md @@ -79,7 +79,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida | [`GT-582`](./gap-reference-catalog.es.md#gt-582) | Verificado directamente contra la especificación viva el 2026-07-26, no tomado de una fuente secundaria. La revisión **actual** del protocolo es `2025-11-25`; el **draft** elimina las sesiones a nivel de protocolo y la cabecera `Mcp-Session-Id` (SEP-2567), elimina el handshake `initialize`/`notifications/initialized` en favor de `_meta` por petición (SEP-2575), hace obligatorio `server/discover` (SEP-2575), sustituye las peticiones iniciadas por el servidor con el patrón **MRTR** — `InputRequiredResult`, un `resultType` obligatorio, e `inputResponses` en un reintento de la petición original (SEP-2322) —, deprecia Roots/Sampling/Logging (SEP-2577) y deprecia el Dynamic Client Registration en favor de Client ID Metadata Documents. En este repositorio: SDK `1.29.0`, **7 sitios con `sessionId`** bajo `src/packages/mcp-server/src`, y `grep -rn "well-known\\|oauth-protected-resource" src` devuelve 2 coincidencias no relacionadas, así que tampoco se sirve documento de metadatos de recurso protegido. MRTR importa más allá de la conformidad: es *la aprobación como protocolo*, y es la única forma en que el gate HITL sobrevive a la desaparición de las sesiones. **La "corrección" anterior registrada aquí quedó a su vez refutada, y se reemplaza en vez de borrarse:** esta fila decía antes que la etiqueta `2026-07-28` "no pudo confirmarse" y que la página de versionado "sigue nombrando `2025-11-25` como actual". Verificado contra la especificación viva el 2026-07-31: **`2026-07-28` ES la revisión actual.** La página de versionado lo dice con esas palabras, describe la negociación como una clave `io.modelcontextprotocol/protocolVersion` por request dentro de `_meta` en vez de durante `initialize`, vuelve `server/discover` un RPC obligatorio, y remite a los clientes de la era del handshake (`2025-11-25` y anteriores) a una sección de compatibilidad hacia atrás. El contenido técnico estaba bien; la duda sobre la fecha estaba mal, y estaba mal en la dirección que habría diferido el trabajo. **CERRADO el 2026-07-31 en los tres criterios** — `protocol-revisions.ts` exporta ambas revisiones y `stateless-rpc.ts` las sirve en paralelo, MRTR es real (`mrtr-request-state.ts`, `requestState` sellado, reintento sin sesión), y se sirven los metadatos de recurso protegido RFC 9728 en `/.well-known/oauth-protected-resource` con puntero `WWW-Authenticate`. | `MCP Server` | Cross | P1 | L | `COMPLETADO` | | [`GT-583`](./gap-reference-catalog.es.md#gt-583) | `TOOL_SCHEMAS` es un mapa escrito a mano en `src/sdk/cli/src/commands/api/api.catalog.ts:81`, las tools MCP declaran sus propios input schemas inline en código, y `buildCapabilityManifest` (GT-513) publica solo `evaluationKinds`, `engines`, `surfaces`, `supportedConsumers` y un `sha256` — **ningún esquema de entrada o salida por operación**. Así que "un registro genera las tres superficies" se afirma en prosa y se mantiene a mano. Aparte, **los 154 ficheros `*.schema.json` declaran `http://json-schema.org/draft-07/schema#`**, mientras el draft de MCP espera keywords de 2020-12 en los esquemas de tool — lo que convierte el pin en un bloqueo para GT-581 y no en una elección neutral. Fix: extender el manifiesto con `inputSchema`/`outputSchema` por operación, generar `TOOL_SCHEMAS` y los registros MCP desde él, y migrar el meta-esquema a 2020-12 compilando con el entry point 2020 de ajv. **OLA 2026-07-31 — un criterio de tres, y la fila queda abierta a propósito (#320, `b5545f31`).** CUMPLIDO: el manifiesto lleva ya `inputSchema` y `outputSchema` para las 50 operaciones, generados por `.harness/scripts/generate-capability-operations.mjs` desde `ToolRegistryService.operationProjection()`, y el `TOOL_SCHEMAS` escrito a mano de tres entradas — con clave `gate-evaluate` para un tool llamado `evolith-gate-evaluate`, y nombrando una operación (`agent-create`) que no existe — queda borrado y generado desde el manifiesto. **NO CUMPLIDO, criterio 2:** el criterio pide que `TOOL_SCHEMAS` *y los registros de tools MCP* se generen desde el manifiesto. Solo la primera mitad es cierta. La dirección está invertida por diseño — el registro MCP es la FUENTE de la que se deriva el manifiesto — así que cada fichero de tool sigue escribiendo su `inputSchema` inline a mano. Puede que sea la mejor arquitectura, pero no es lo que dice el criterio, y reescribir el criterio para que calce con la implementación es como un board empieza a felicitarse a sí mismo; el criterio queda sin marcar hasta que el owner decida cuál de los dos está mal. **NO CUMPLIDO, criterio 3:** el guard de drift existe y los esquemas generados sí compilan con el entry point 2020-12 de ajv, pero la migración del meta-esquema que nombra esta fila está intacta. **El conteo de esta fila también está mal y se corrige aquí:** dice "los 154 ficheros `*.schema.json` declaran draft-07"; medido en `develop`, hay **88 `*.schema.json` en draft-07 y 1 en 2020-12**, de los cuales **77 ficheros draft-07 están bajo `src/rulesets/`**. La rama no cambió ninguno. | `Evolith Core` | Cross | P1 | L | `EN-PROGRESO` | | [`GT-584`](./gap-reference-catalog.es.md#gt-584) | La costura de ADR-0111 está viva — `quality-signal-provider.port.ts`, `quality-signal-registry.ts` y dos providers reales (`lighthouse-evidence.provider.ts`, `structural-review-provider.ts`) — y `Evidence` ya lleva `determinism` y `provenance{collectedBy, adapterVersion, artifactHash, timestamp}`. Lo que falta es el gate encima: `grep -rniE "confusion.matrix\|true.positive.rate\|cohen\|kappa\|false.block"` sobre `src` y `.harness` devuelve **0**. Nada lee `determinism` como condición para bloquear, así que el día en que un provider no determinista apunte a algo que importe, su hallazgo será admisible por defecto y sin medir. Fix: `probabilistic-evidence-admissibility.rules.json` con paridad `.rego`/`.test.rego` — la evidencia probabilística solo puede bloquear mientras `tpr ≥ θ₁ ∧ tnr ≥ θ₂ ∧ antigüedad ≤ θ₃`, y si no degrada a advisory — más los campos de calibración en `Evidence` que la regla lee. Ola 2: se encontró y cerró un camino real de heurística a veredicto bloqueante (`detectDependencyInversionIssues` y `detectLayerViolations` emitían MUST bloqueante y mcp-server copiaba la bandera literalmente). Dos defectos concretos detrás de la tasa de error no medida: la comprobación de framework casaba subcadenas desnudas, y la comparación de capas estaba INVERTIDA — todo import legal `application → domain` bloqueaba mientras toda inversión real `domain → infrastructure` pasaba. **Ningún criterio cumplido en su ubicación declarada:** AC1 pide un par ruleset/Rego bajo `src/rulesets/**`, AC2 pide los campos de calibración en el propio `Evidence`. Los umbrales son política declarada, no mediciones — GT-585 es lo que los vuelve reales. | `core-domain` | Cross | P1 | M | `COMPLETADO` | -| [`GT-585`](./gap-reference-catalog.es.md#gt-585) | 167 rulesets y 45 políticas deciden `blocking`, y ninguno se ha medido nunca: todo el vocabulario de calibración (`matriz de confusión`, TPR/TNR, κ de Cohen, falso bloqueo) aparece **0 veces** en `src` y `.harness`. La fuente de etiquetas que esa medición necesita — un humano revocando una decisión de gate — vive en el Tracker, y según GT-435/GT-448 nada ha corrido nunca en producción, así que **todavía no existe corpus orgánico de etiquetas y esta fila no puede cerrarse solo con código**. Lo que sí está disponible hoy, y es el sentido de registrarla ya: un set etiquetado a mano desde la propia historia de este repositorio, más el arnés (un comando estilo `judge:validate` que reporte matriz de confusión, κ e intervalo de Wilson dentro del envelope ADR-0073), de modo que en el momento en que existan etiquetas la cifra sea derivable y no reconstruida a posteriori. | `Governance` | Cross | P1 | L | `PENDIENTE` | +| [`GT-585`](./gap-reference-catalog.es.md#gt-585) | 167 rulesets y 45 políticas deciden `blocking`, y ninguno se ha medido nunca: todo el vocabulario de calibración (`matriz de confusión`, TPR/TNR, κ de Cohen, falso bloqueo) aparece **0 veces** en `src` y `.harness`. La fuente de etiquetas que esa medición necesita — un humano revocando una decisión de gate — vive en el Tracker, y según GT-435/GT-448 nada ha corrido nunca en producción, así que **todavía no existe corpus orgánico de etiquetas y esta fila no puede cerrarse solo con código**. Lo que sí está disponible hoy, y es el sentido de registrarla ya: un set etiquetado a mano desde la propia historia de este repositorio, más el arnés (un comando estilo `judge:validate` que reporte matriz de confusión, κ e intervalo de Wilson dentro del envelope ADR-0073), de modo que en el momento en que existan etiquetas la cifra sea derivable y no reconstruida a posteriori. | `Governance` | Cross | P1 | L | `DIFERIDO` | | [`GT-586`](./gap-reference-catalog.es.md#gt-586) | `EvaluationContext` lleva más de 30 miembros opcionales, entre ellos `executionMode: 'manual' \| 'hybrid' \| 'agentic'` y, por ítem de evidencia, `EvidenceContext.producer.actorType` — pero **no lleva identidad del solicitante ni revisión de código**: sobre `evaluation-context.ts`, `grep -nE "actor\|revision\|commit"` solo coincide con `ExecutionMode` y ese `producer` anidado. `EvaluationResult` refleja `evaluatedAt` y `versions{core, ruleset, rulesetVersion, policy, blueprint}` — otra vez sin revisión. Así que el motor no puede atribuir un veredicto a un humano o a un agente (`executionMode` describe el modo de operación, no la identidad de quien pide, y no lleva ni modelo ni sesión), y dos veredictos sobre el mismo repositorio no pueden ordenarse contra el código que juzgaron. Fix: `requester{actorType, actorId, modelRef?, sessionId?}` y `repositoryRevision` opcionales y aditivos en el contexto, reflejados en el resultado. Solo aditivo, así que el congelamiento de contrato de GT-388 se mantiene. Ola 2: `requester` y `repositoryRevision` se aceptan, se reflejan en el resultado y se proyectan al input de OPA, todo de forma aditiva. Nada se deriva — si no entra, no sale, porque un sha inventado en una traza de auditoría es peor que uno ausente. **Pendiente:** AC3, cobertura de fixtures en `@beyondnet/evolith-contracts`. **CERRADO el 2026-07-28.** Aterrizó el tercer criterio: `@beyondnet/evolith-contracts` publica ahora `EVALUATE_INLINE_ATTRIBUTED_REQUEST` y `EVALUATION_RESULT_ATTRIBUTION_FIXTURE` desde el índice del paquete — no solo desde el módulo de fixtures, que es lo que pide el criterio y lo que un consumidor puede fijar de verdad. Cuatro tests: el requester tipado y la revisión viajan, el resultado los refleja LITERALMENTE (nada derivado — un sha inventado en una traza de auditoría es peor que uno ausente), un veredicto SIN ellos sigue validando y sigue resolviendo a `PASSED`, y un llamador que no aporta revisión no recibe ninguna. Esa mitad aditiva es lo que hace seguro el cambio en un paquete publicado. | `core-domain` | Cross | P1 | S | `COMPLETADO` | | [`GT-587`](./gap-reference-catalog.es.md#gt-587) | `grep -rn "gen_ai" src` devuelve **0**. El tracing existe (`src/packages/mcp-server/src/tracing.ts`) y GT-546 emite métricas `evolith_*`, así que la fontanería está puesta y solo el vocabulario es privado. Las convenciones semánticas GenAI de OpenTelemetry definen `gen_ai.evaluation.result` — que es exactamente la forma de una señal de calidad de ADR-0111 — más un namespace `mcp.*`; el draft de MCP además documenta la propagación de trace context por `_meta` (`traceparent`, `tracestate`, `baggage`, SEP-414). Fix: emitir los atributos de semconv junto a `evolith.*`, y pinnear la versión de semconv, porque ese registro sigue en estado Development. **Cierre 2026-07-31 (#308).** Semconv GenAI/`mcp.*` emitidos JUNTO a `evolith.*`, con la revisión pinneada a 1.41.1 y el guard `51-validate-semconv-pin` leyendo el LOCKFILE, no `node_modules`. Observado en rojo por tres causas independientes (versión, rename de atributo, símbolo sin pinnear) y falsificado de nuevo en la integración subiendo el pin: exit 1 nombrando la deriva, restaurado exit 0. El contexto de traza se levanta de `_meta`, y solo las tres claves W3C — `_meta` es un mapa abierto y copiarlo entero dejaría inyectar claves de propagación arbitrarias. | `Evolith Core` | Cross | P2 | M | `COMPLETADO` | | [`GT-588`](./gap-reference-catalog.es.md#gt-588) | `Provenance{collectedBy, adapterVersion, artifactHash, timestamp}` es obligatorio en cada `Evidence` — y está completamente sin firmar: `grep -rniE "scitt\|cose_sign\|transparency"` sobre `src` devuelve una única coincidencia no relacionada. GT-576 ya degradó la afirmación del Pilar 1 sobre "rastros de auditoría inmutables" de `Validated` a `Designed` por exactamente este motivo. Un `artifactHash` que el productor calcula sobre su propia salida no es evidencia de no-manipulación. Fix: un statement firmado más recibo por decisión en la forma que define RFC 9943 (SCITT) con recibos COSE, un `evolith-cli audit verify` que los compruebe, y — la parte que hace el ledger portante y no ornamental — una regla de gobernanza que FALLE cuando los recibos no verifican. **OLA 2026-07-31 — un criterio de tres, y la fila queda abierta (#319, `a92ce7e5`).** CUMPLIDO, criterio 2: `evolith audit verify` existe (`src/sdk/cli/src/commands/audit/audit.command.ts`), verifica una cadena de recibos con `verifyReceiptChain` y BLOQUEA con exit 2 ante una decisión editada después de firmar; el ser offline se asevera en vez de suponerse ("no necesita red, reloj ni operador de log") a lo largo de 11 casos de manipulación. **NO CUMPLIDO, criterio 1 — y es el criterio que importa:** la costura de firma existe pero nada en producción está conectado a ella. `AuditService` recibe el recorder como parámetro OPCIONAL del constructor y emite solo `if (this.transparency)`; ningún módulo Nest provee `TransparencyRecorderService`, así que toda construcción de producción es `new AuditService(auditRepo)` y no emite nada. Debajo está el bloqueo real, que es custodia y no cableado: la única ruta de clave ejecutable es `createDevelopmentSigningKey()`, un `generateKeyPairSync('ed25519')` efímero en proceso que rechaza `NODE_ENV=production` y va etiquetado `urn:evolith:development-key:NOT-A-PRODUCTION-IDENTITY:`. **Un statement que el productor firma con una clave que él mismo generó sobre su propia salida es una autoatestación, que es justo lo que ya era un `artifactHash`** — no es no-repudio, y esta fila existe precisamente porque la integridad autocalculada no es evidencia de no-manipulación. `externalSigningKey()` es la única ruta honesta y recibe un `KeyObject` de un KMS/HSM que nadie provee. El código lo dice: `AUD-TRANSP-04` falla ante la identidad de desarrollo aunque todos los recibos verifiquen. **NO CUMPLIDO, criterio 3:** la regla (`audit-transparency.rule.ts`, `AUD-TRANSP-01…04`) y sus tests negativos existen, pero `grep -rn "AUD-TRANSP" src/rulesets .harness .github` devuelve **0** y ningún workflow corre `evolith audit verify` — su único llamador es el comando del CLI. Una regla que CI nunca ejecuta es el ornamento que esta fila se abrió para reemplazar. | `Governance` | Cross | P2 | L | `EN-PROGRESO` | @@ -192,8 +192,8 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida | [`GT-465`](./gap-reference-catalog.es.md#gt-465) | **Hecho:** `kind-cluster.yaml` con `disableDefaultCNI:true` (kindnet off → Cilium aplica la política; el README añade el paso de instalación de Cilium); `deploy/kubernetes/network-policies.yaml` (22 políticas) codifica el modelo §7 — default-deny por ns de producto + allows DNS/broker/Core/OTLP/ingress/intra-ns, con el invariante estructural de que `evolith-core` NO tiene ruta al :5672. **kindnet no aplica NetworkPolicy → el modelo default-deny quedaba sin efecto.** Follow-on: aserciones allow/deny en G1. Riesgo §15 #13 (bajo). | `Infra` | Release | P2 | M | `COMPLETADO` | | [`GT-464`](./gap-reference-catalog.es.md#gt-464) | Tres productos dependen de un único bus de mensajes compartido, así que una caída los alcanza a los tres a la vez **Qué significa:** Las tres aplicaciones se pasan novedades por una misma oficina de correos. Si se cae, las tres dejan de enterarse al mismo tiempo, aunque no se pierde nada: los mensajes se acumulan y llegan tarde **Ejemplo:** Todavía no existen las alertas que avisarían al operador de que el bus está caído o de que los datos van con retraso | `Infra` | Cross | P2 | S | `DIFERIDO` | | [`GT-447`](./gap-reference-catalog.es.md#gt-447) | El stack completo aún no levanta en local: el motor arranca, la aplicación compañera y la interfaz no **Qué significa:** Cualquiera del equipo debería poder levantar el producto entero en su máquina con un solo comando y navegarlo. Hoy solo arranca el motor; lo que una persona realmente mira, no **Ejemplo:** Los tres servicios del motor levantan sanos en un clúster local y responden una petición gobernada completa, pero no hay ninguna pantalla que abrir contra ellos. **Cierre (`0b387b44`):** `product/infra/docker-compose.fullstack.yml` levanta el stack completo sano con un solo comando (8/8 servicios), y el chain del navegador está verificado end-to-end — una evaluación gobernada fluye tracker-web → tracker-api → core-api `evaluate()` y de vuelta (HTTP 200, `provenance:core`, un veredicto arquitectónico FAIL real, persistido en Postgres), y la UI (Control Tower) renderiza contra URLs locales con cada llamada de datos en 200. Dos derivas de build corregidas cross-repo en `evolith_tracker` (rama `feature/gt-447-fullstack-local`, `f8b68f2`): un `.dockerignore` de build ausente (663 MB de `node_modules` en el context) y una base `/api` stale horneada en tracker-web (→ `/api/v1`, que rompía el login con un 404). Los 7 hijos ya estaban COMPLETADOS. | `Cross` | Cross | P0 | L | `COMPLETADO` | -| [`GT-448`](./gap-reference-catalog.es.md#gt-448) | Nada corre en producción: el stack nunca se ha promovido al servidor al que llegarían los clientes **Qué significa:** El producto no existe en ningún lugar donde un cliente real pueda usarlo. Todo vive por ahora en máquinas de desarrollo **Ejemplo:** El servidor de producción y sus herramientas de despliegue ya están preparados, pero ninguna parte del producto se ha instalado nunca allí | `Cross` | Cross | P1 | XL | `PENDIENTE` | -| [`GT-435`](./gap-reference-catalog.es.md#gt-435) | El camino completo desde el código hasta un producto en uso real no está desplegado ni validado **Qué significa:** Es el ítem paraguas para llevar el producto de algo que funciona en máquinas de desarrollo a algo que usa gente real. Sigue abierto hasta que se cierre todo lo que cuelga de él **Ejemplo:** Una evaluación situó al motor cerca del noventa y cinco por ciento de preparación mientras todo lo que lo rodea —empaquetado, despliegue, aplicación compañera— no lo estaba | `Cross` | Cross | P0 | XL | `PENDIENTE` | +| [`GT-448`](./gap-reference-catalog.es.md#gt-448) | Nada corre en producción: el stack nunca se ha promovido al servidor al que llegarían los clientes **Qué significa:** El producto no existe en ningún lugar donde un cliente real pueda usarlo. Todo vive por ahora en máquinas de desarrollo **Ejemplo:** El servidor de producción y sus herramientas de despliegue ya están preparados, pero ninguna parte del producto se ha instalado nunca allí | `Cross` | Cross | P1 | XL | `DIFERIDO` | +| [`GT-435`](./gap-reference-catalog.es.md#gt-435) | El camino completo desde el código hasta un producto en uso real no está desplegado ni validado **Qué significa:** Es el ítem paraguas para llevar el producto de algo que funciona en máquinas de desarrollo a algo que usa gente real. Sigue abierto hasta que se cierre todo lo que cuelga de él **Ejemplo:** Una evaluación situó al motor cerca del noventa y cinco por ciento de preparación mientras todo lo que lo rodea —empaquetado, despliegue, aplicación compañera— no lo estaba | `Cross` | Cross | P0 | XL | `DIFERIDO` | | [`GT-436`](./gap-reference-catalog.es.md#gt-436) | Publicar los paquetes npm. El scope viejo `@evolith/*` estaba contaminado con historial publicado (1.0.x/1.1.x/2.0.0-beta/tombstones) que bloqueaba un 1.0.0 limpio, así que se renombró toda la familia a un scope nuevo unificado. **HECHO (0edaa22b): los 7 libs publicados a `1.0.0` limpio bajo `@beyondnet/evolith-*` (core-domain, infra-providers, core, agent-runtime, sdk, mcp, cli — todos HTTP 200 en el registry). Viejos `@evolith/*` deprecados apuntando a los nuevos (4 quedaron en estado 404 corrupto del registry, inservibles de todos modos).** Follow-on: barrido de docs `@evolith/*` → `@beyondnet/evolith-*`. | `CLI` | Cross | P0 | M | `COMPLETADO` | | [`GT-437`](./gap-reference-catalog.es.md#gt-437) | Añadir `agent-runtime-api` al CI/CD (docker build+push a GHCR + deploy Coolify) — hoy tiene Dockerfile pero NINGÚN workflow lo buildea/testea/despliega. **Cierre (`1ddbe25b`):** la premisa estaba en parte stale — agent-runtime YA se buildeaba/testeaba en `ci-cd.yml` (3 builds de workspace). El hueco real: faltaba en el matrix `docker-services` (solo core-api + mcp-server) y no tenía step de deploy Coolify, así que **en main nunca se imageaba ni desplegaba** (`docker-images.yml` lo cubría solo en tags/`workflow_dispatch`). Arreglado: matrix + `agent-runtime` → `ghcr.io//evolith-agent-runtime` (contexto raíz del repo, `./src/apps/agent-runtime-api/Dockerfile`, nombre de imagen igual al de `docker-images.yml`), y un step `Trigger Coolify deploy (agent-runtime)` con el contrato fail-soft establecido (hook sin setear ⇒ warn + exit 0, nunca rompe el CD). agent-runtime-api queda en la misma postura CI/CD que sus dos hermanos. Verificado: `ci-cd.yml` parsea como YAML resolviendo 3 servicios en matrix + 3 steps de deploy; el Dockerfile referenciado existe. **Owner-gated (delegado a [`GT-324`](./gap-reference-catalog.es.md#gt-324)):** aprovisionar `COOLIFY_AGENTRUNTIME_DEPLOY_HOOK`/`COOLIFY_API_TOKEN`; el primer build+deploy vivo corre en el próximo merge a main (el job es solo main/tag, no ejercitable desde develop). | `Infra` | Cross | P1 | M | `COMPLETADO` | | [`GT-438`](./gap-reference-catalog.es.md#gt-438) | Cableado de adapters de producción para `agent-runtime-api`: el bootstrap por defecto usa `StubCoreEvaluationAdapter` + `StubAgentEngineAdapter` + estado in-memory; cablear Core-eval real (HTTP), engine (Hermes/routing), memoria durable + scheduler por defecto/env en prod. **Avance (kind local):** el `HttpCoreEvaluationAdapter` real ya está en la factory (por env); cableado + **verificado en el cluster kind** — `values-local` del agent-runtime setea `AGENT_RUNTIME_CORE_ENDPOINT` al servicio `core-api` in-cluster, y un `POST /v1/agent/handle` produjo un `POST /api/v1/evaluate` real al core-api (SecurityAudit: `200 ALLOW 569ms`, desde el pod del runtime). El runtime ya gobierna sobre el Core REAL, no el stub. **Pendiente:** agent-engine real (gated GT-385), estado durable, y ensamblar un contexto de workspace real (hoy el Core evalúa un contexto vacío → 39 findings correctos tipo GOV-000). **Cierre (`ff57cec6`):** aterrizó la última pieza no-gated — el ensamblado de contexto de workspace real. El runtime ahora ensambla el workspace y lo pasa **inline** como `evaluationInput.files` (el shape de ingestión inline `OverlayFileSystem` que el Core API ya consume), así el Core deja de evaluar un contexto vacío. Nuevo `IWorkspaceContextPort` + `FsWorkspaceContextAdapter` (walk determinista acotado: budgets de archivos/bytes, dirs excluidos, claves relativas-posix, `fsImpl` inyectable); `InlineEvaluationInput`/`RuntimeEvaluationContext` aditivos; `context-mapper` adjunta archivos solo si hay; una caída del workspace degrada al flujo previo (nunca falla la corrida); `runtime.factory` lo cablea desde `AGENT_RUNTIME_WORKSPACE_CONTEXT_ROOT` (sin setear ⇒ comportamiento previo). Surface-freeze GT-388 actualizado (aditivo/minor). Verificado: agent-runtime 131/131 (+8), agent-runtime-api 80/80 (+3), tsc limpio. **Sigue gated (por diseño):** motor de razonamiento real (GT-385/Hermes) + memoria/scheduler durable con servicios externos; un ensamblador guiado por el Tracker es un adapter hermano futuro tras el mismo puerto. | `Agent Runtime` | Cross | P1 | M | `COMPLETADO` | @@ -660,7 +660,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:** 621 / 645 completados · 9 en progreso · 11 pendientes · 4 diferidos +**Progreso:** 621 / 645 completados · 9 en progreso · 8 pendientes · 7 diferidos **Oleada 2026-06-23 (auditoría profunda de Winston III):** Añadidos 14 gaps nuevos `GT-212`…`GT-225` del Winston Audit Playbook que cubren: higiene de estado ADR (GT-212), metadata + presupuestos operativos + corpus de guías por topología (GT-213, GT-217, GT-219), observabilidad + OpenAPI en controladores REST (GT-214, GT-215), paridad de input-schemas OPA + densidad de tests por topología (GT-216, GT-222), plantillas de rollback + on-call de Fase 05 (GT-218), cobertura de ramas CLI + paridad de envelope --format + limpieza de skip-list (GT-220, GT-224, GT-225), audit logging HTTP de MCP (GT-221), y tests e2e de paridad cross-surface (GT-223). diff --git a/reference/core/control-center/gaps/gap-tracking.md b/reference/core/control-center/gaps/gap-tracking.md index 8bdd79438..c241c79a0 100644 --- a/reference/core/control-center/gaps/gap-tracking.md +++ b/reference/core/control-center/gaps/gap-tracking.md @@ -79,7 +79,7 @@ This board is the single source of truth for technical debt, gaps, opportunities | [`GT-582`](./gap-reference-catalog.md#gt-582) | Verified directly against the live specification on 2026-07-26, not taken from a secondary source. The **current** protocol revision is `2025-11-25`; the **draft** removes protocol-level sessions and the `Mcp-Session-Id` header (SEP-2567), removes the `initialize`/`notifications/initialized` handshake in favour of per-request `_meta` (SEP-2575), makes `server/discover` mandatory (SEP-2575), replaces server-initiated requests with the **MRTR** pattern — `InputRequiredResult`, a required `resultType`, and `inputResponses` on a retry of the original request (SEP-2322) — deprecates Roots/Sampling/Logging (SEP-2577) and deprecates Dynamic Client Registration in favour of Client ID Metadata Documents. In this repository: SDK `1.29.0`, **7 `sessionId` sites** under `src/packages/mcp-server/src`, and `grep -rn "well-known\\|oauth-protected-resource" src` returns 2 unrelated matches, so no protected-resource metadata document is served either. MRTR matters beyond conformance: it is *approval as a protocol*, and it is the only way the HITL gate survives the removal of sessions. **The earlier "correction" recorded here has itself been refuted, and is replaced rather than deleted:** this row previously said the `2026-07-28` label "could not be confirmed" and that the spec's versioning page "still names `2025-11-25` as current". Re-checked against the live specification on 2026-07-31: **`2026-07-28` IS the current revision.** The versioning page states it in those words, describes negotiation as a per-request `io.modelcontextprotocol/protocolVersion` key in `_meta` rather than during `initialize`, makes `server/discover` a mandatory RPC, and points handshake-era clients (`2025-11-25` and earlier) at a backward-compatibility section. The technical content was right; the doubt about the date was wrong, and it was wrong in the direction that would have deferred the work. **CLOSED 2026-07-31 on all three criteria** — `protocol-revisions.ts` exports both revisions and `stateless-rpc.ts` serves them side by side, MRTR is real (`mrtr-request-state.ts`, sealed `requestState`, retry without a session), and RFC 9728 protected-resource metadata is served at `/.well-known/oauth-protected-resource` with a `WWW-Authenticate` pointer. | `MCP Server` | Cross | P1 | L | `DONE` | | [`GT-583`](./gap-reference-catalog.md#gt-583) | `TOOL_SCHEMAS` is a hand-written map at `src/sdk/cli/src/commands/api/api.catalog.ts:81`, the MCP tools declare their own input schemas inline in code, and `buildCapabilityManifest` (GT-513) publishes only `evaluationKinds`, `engines`, `surfaces`, `supportedConsumers` and a `sha256` — **no per-operation input or output schema at all**. So "one registry generates the three surfaces" is asserted in prose and maintained by hand. Separately, **all 154 `*.schema.json` files declare `http://json-schema.org/draft-07/schema#`**, while the MCP draft expects 2020-12 keywords in tool schemas — which makes the pin a blocker for GT-581 rather than a neutral choice. Fix: extend the manifest with per-operation `inputSchema`/`outputSchema`, generate `TOOL_SCHEMAS` and the MCP registrations from it, and migrate the meta-schema to 2020-12 compiling under ajv's 2020 entry point. **WAVE 2026-07-31 — one criterion of three, and the row stays open on purpose (#320, `b5545f31`).** MET: the manifest now carries `inputSchema` and `outputSchema` for all 50 operations, generated by `.harness/scripts/generate-capability-operations.mjs` from `ToolRegistryService.operationProjection()`, and the three-entry hand-written `TOOL_SCHEMAS` — keyed `gate-evaluate` for a tool called `evolith-gate-evaluate`, and naming one operation (`agent-create`) that does not exist — is deleted and generated from the manifest instead. **NOT MET, criterion 2:** the criterion asks that `TOOL_SCHEMAS` *and the MCP tool registrations* be generated from the manifest. Only the first half is true. The direction is inverted by design — the MCP registry is the SOURCE the manifest is derived from — so every tool file still hand-writes its `inputSchema` inline. That may well be the better architecture, but it is not what the criterion says, and rewriting the criterion to match the implementation is how a board starts congratulating itself; the criterion stays unticked until the owner decides which of the two is wrong. **NOT MET, criterion 3:** the drift guard exists and the generated schemas do compile under ajv's 2020-12 entry point, but the meta-schema migration named in this row is untouched. **The count in this row is also wrong and is corrected here:** it says "all 154 `*.schema.json` files declare draft-07"; measured on `develop`, there are **88 `*.schema.json` on draft-07 and 1 on 2020-12**, of which **77 draft-07 files sit under `src/rulesets/`**. The branch changed zero of them. | `Evolith Core` | Cross | P1 | L | `IN-PROGRESS` | | [`GT-584`](./gap-reference-catalog.md#gt-584) | The ADR-0111 seam is live — `quality-signal-provider.port.ts`, `quality-signal-registry.ts` and two real providers (`lighthouse-evidence.provider.ts`, `structural-review-provider.ts`) — and `Evidence` already carries `determinism` and `provenance{collectedBy, adapterVersion, artifactHash, timestamp}`. What is missing is the gate on top of it: `grep -rniE "confusion.matrix\|true.positive.rate\|cohen\|kappa\|false.block"` across `src` and `.harness` returns **0**. Nothing reads `determinism` as a condition for blocking, so the day a non-deterministic provider is pointed at something that matters, its finding is admissible by default and unmeasured. Fix: `probabilistic-evidence-admissibility.rules.json` with `.rego`/`.test.rego` parity — probabilistic evidence may block only while `tpr ≥ θ₁ ∧ tnr ≥ θ₂ ∧ age ≤ θ₃`, and degrades to advisory otherwise — plus the calibration fields on `Evidence` that the rule reads. Wave 2: found and closed a real heuristic→blocking path (`detectDependencyInversionIssues`, `detectLayerViolations` emitted blocking MUST and mcp-server copied the flag verbatim). Two concrete defects behind the unmeasured error rate: the framework check matched naked substrings, and the layer comparison was INVERTED — every legal `application → domain` import blocked while every real `domain → infrastructure` inversion passed. **No criterion met in its stated location:** AC1 wants a ruleset/Rego pair under `src/rulesets/**`, AC2 wants the calibration fields on `Evidence` itself. Thresholds are declared policy, not measurements — GT-585 is what makes them real. | `core-domain` | Cross | P1 | M | `DONE` | -| [`GT-585`](./gap-reference-catalog.md#gt-585) | 167 rulesets and 45 policies decide `blocking`, and not one of them has ever been measured: the entire calibration vocabulary (`confusion matrix`, TPR/TNR, Cohen's κ, false block) appears **0 times** across `src` and `.harness`. The label source such a measurement needs — a human overriding a gate decision — lives in the Tracker, and per GT-435/GT-448 nothing has ever run in production, so **there is no organic label corpus yet and this row cannot be closed by code alone**. What is available today, and is the whole point of registering it now: a hand-labelled set drawn from this repository's own history, plus the harness (a `judge:validate`-style command reporting a confusion matrix, κ and a Wilson interval inside the ADR-0073 envelope), so that the moment labels exist the figure is derivable rather than retrofitted. | `Governance` | Cross | P1 | L | `PENDING` | +| [`GT-585`](./gap-reference-catalog.md#gt-585) | 167 rulesets and 45 policies decide `blocking`, and not one of them has ever been measured: the entire calibration vocabulary (`confusion matrix`, TPR/TNR, Cohen's κ, false block) appears **0 times** across `src` and `.harness`. The label source such a measurement needs — a human overriding a gate decision — lives in the Tracker, and per GT-435/GT-448 nothing has ever run in production, so **there is no organic label corpus yet and this row cannot be closed by code alone**. What is available today, and is the whole point of registering it now: a hand-labelled set drawn from this repository's own history, plus the harness (a `judge:validate`-style command reporting a confusion matrix, κ and a Wilson interval inside the ADR-0073 envelope), so that the moment labels exist the figure is derivable rather than retrofitted. | `Governance` | Cross | P1 | L | `DEFERRED` | | [`GT-586`](./gap-reference-catalog.md#gt-586) | `EvaluationContext` carries 30+ optional members including `executionMode: 'manual' \| 'hybrid' \| 'agentic'` and, per evidence item, `EvidenceContext.producer.actorType` — but it has **no requester identity and no code revision**: over `evaluation-context.ts`, `grep -nE "actor\|revision\|commit"` matches only `ExecutionMode` and that nested `producer`. `EvaluationResult` echoes `evaluatedAt` and `versions{core, ruleset, rulesetVersion, policy, blueprint}` — again no revision. So the engine cannot attribute a verdict to a human or an agent (`executionMode` describes the mode of operation, not the identity of the requester, and carries neither model nor session), and two verdicts over the same repository cannot be ordered against the code they judged. Fix: additive optional `requester{actorType, actorId, modelRef?, sessionId?}` and `repositoryRevision` on the context, echoed into the result. Additive only, so the GT-388 contract freeze holds. Wave 2: `requester` and `repositoryRevision` accepted, echoed onto the result and projected into the OPA input, all additively. Nothing is derived — absent in, absent out, because an invented commit sha in an audit trail is worse than an absent one. **Remaining:** AC3, fixture coverage in `@beyondnet/evolith-contracts`. **CLOSED 2026-07-28.** The third criterion landed: `@beyondnet/evolith-contracts` now publishes `EVALUATE_INLINE_ATTRIBUTED_REQUEST` and `EVALUATION_RESULT_ATTRIBUTION_FIXTURE` from its package index — not merely from the fixtures module, which is what the criterion asks for and what a consumer can actually pin. Four tests: the typed requester and revision are carried, the result echoes both VERBATIM (nothing derived — an invented commit sha in an audit trail is worse than an absent one), a verdict WITHOUT them still validates and still resolves to `PASSED`, and a caller that supplies no revision gets none back. That additive half is what makes the change safe to ship in a published package. | `core-domain` | Cross | P1 | S | `DONE` | | [`GT-587`](./gap-reference-catalog.md#gt-587) | `grep -rn "gen_ai" src` returns **0**. Tracing exists (`src/packages/mcp-server/src/tracing.ts`) and GT-546 emits `evolith_*` metrics, so the plumbing is in place and only the vocabulary is private. The OpenTelemetry GenAI semantic conventions define `gen_ai.evaluation.result` — which is the exact shape of an ADR-0111 quality signal — plus an `mcp.*` namespace; the MCP draft additionally documents trace-context propagation through `_meta` (`traceparent`, `tracestate`, `baggage`, SEP-414). Fix: emit the semconv attributes alongside `evolith.*`, and pin the semconv version, since that registry is still Development status. **Closure 2026-07-31 (#308).** GenAI/`mcp.*` semconv emitted ALONGSIDE `evolith.*`, revision pinned at 1.41.1, and `51-validate-semconv-pin` reads the LOCKFILE rather than `node_modules`. Observed red on three independent causes (version, attribute rename, unpinned symbol) and falsified again at integration by bumping the pin: exit 1 naming the drift, restored exit 0. Trace context is lifted from `_meta`, and only the three W3C keys — `_meta` is an open map and copying it wholesale would let a caller inject arbitrary propagation keys. | `Evolith Core` | Cross | P2 | M | `DONE` | | [`GT-588`](./gap-reference-catalog.md#gt-588) | `Provenance{collectedBy, adapterVersion, artifactHash, timestamp}` is mandatory on every `Evidence` — and entirely unsigned: `grep -rniE "scitt\|cose_sign\|transparency"` over `src` returns a single unrelated match. GT-576 already downgraded the Pillar 1 claim of "immutable audit trails" from `Validated` to `Designed` for exactly this reason. An `artifactHash` that a producer computes about its own output is not tamper-evidence. Fix: a signed statement plus receipt per decision in the shape RFC 9943 (SCITT) defines with COSE receipts, an `evolith-cli audit verify` to check them, and — the part that makes the ledger load-bearing rather than ornamental — a governance rule that FAILS when receipts do not verify. **WAVE 2026-07-31 — one criterion of three, and the row stays open (#319, `a92ce7e5`).** MET, criterion 2: `evolith audit verify` exists (`src/sdk/cli/src/commands/audit/audit.command.ts`), verifies a receipt chain with `verifyReceiptChain` and BLOCKS with exit 2 on a decision edited after signing; offline-ness is asserted rather than assumed ("needs no network, clock or log operator") across 11 tamper cases. **NOT MET, criterion 1 — and this is the criterion that matters:** the signing seam exists but nothing in production is wired to it. `AuditService` takes the recorder as an OPTIONAL constructor parameter and emits only `if (this.transparency)`; no Nest module provides `TransparencyRecorderService`, so every production construction is `new AuditService(auditRepo)` and emits nothing. Beneath that is the real blocker, which is custody, not wiring: the only runnable key path is `createDevelopmentSigningKey()`, an ephemeral in-process `generateKeyPairSync('ed25519')` that refuses `NODE_ENV=production` and is tagged `urn:evolith:development-key:NOT-A-PRODUCTION-IDENTITY:`. **A statement a producer signs with a key it generated about its own output is a self-attestation, which is what an `artifactHash` already was** — it is not non-repudiation, and this row exists precisely because self-computed integrity is not tamper-evidence. `externalSigningKey()` is the only honest path and takes a `KeyObject` from a KMS/HSM that nobody supplies. The code agrees: `AUD-TRANSP-04` fails on the development identity even when every receipt verifies. **NOT MET, criterion 3:** the rule (`audit-transparency.rule.ts`, `AUD-TRANSP-01…04`) and its negative tests exist, but `grep -rn "AUD-TRANSP" src/rulesets .harness .github` returns **0** and no workflow runs `evolith audit verify` — its only caller is the CLI command. A rule CI never runs is the ornament this row was opened to replace. | `Governance` | Cross | P2 | L | `IN-PROGRESS` | @@ -192,8 +192,8 @@ This board is the single source of truth for technical debt, gaps, opportunities | [`GT-465`](./gap-reference-catalog.md#gt-465) | **Done:** `kind-cluster.yaml` sets `disableDefaultCNI:true` (kindnet off → Cilium enforces policy; README adds the Cilium install step); `deploy/kubernetes/network-policies.yaml` (22 policies) codifies the §7 model — default-deny per product ns + DNS/broker/Core/OTLP/ingress/intra-ns allows, with the structural invariant that `evolith-core` has NO path to :5672. **kindnet doesn't enforce NetworkPolicy → the default-deny model was silently ineffective.** Follow-on: allow/deny assertions in G1. Risk §15 #13 (low). | `Infra` | Release | P2 | M | `DONE` | | [`GT-464`](./gap-reference-catalog.md#gt-464) | Three products depend on a single shared message broker, so one broker outage reaches all of them at once **What it means:** The three applications pass news to each other through one shared post office. If it goes down they all stop hearing from each other at the same time, though nothing is lost -- messages queue up and arrive late **Example:** The alerts that would tell an operator the broker is down, or that data is falling behind, do not exist yet | `Infra` | Cross | P2 | S | `DEFERRED` | | [`GT-447`](./gap-reference-catalog.md#gt-447) | The whole stack does not come up locally yet: the engine starts, the companion app and the interface do not **What it means:** Anyone on the team should be able to start the entire product on their own machine with one command and click through it. Today only the engine starts; the parts a person actually looks at do not **Example:** The three engine services come up healthy on a local cluster and answer a full governed request, but there is no screen to open against them. **Closure (`0b387b44`):** `product/infra/docker-compose.fullstack.yml` brings the whole stack up healthy with one command (8/8 services), and the browser chain is verified end-to-end — a governed evaluation flows tracker-web → tracker-api → core-api `evaluate()` and back (HTTP 200, `provenance:core`, a real architectural FAIL verdict, persisted in Postgres), and the UI (Control Tower) renders against local URLs with every data call 200. Two build drifts fixed cross-repo in `evolith_tracker` (branch `feature/gt-447-fullstack-local`, `f8b68f2`): a missing build `.dockerignore` (663 MB `node_modules` in context) and a stale `/api` SPA base baked into tracker-web (→ `/api/v1`, which broke login with a 404). All 7 child gaps were already DONE. | `Cross` | Cross | P0 | L | `DONE` | -| [`GT-448`](./gap-reference-catalog.md#gt-448) | Nothing runs in production: the stack has never been promoted to the server that customers would reach **What it means:** The product does not exist anywhere a real customer could use it. Everything so far lives on developer machines **Example:** The production server and its deployment tooling are already set up, but no part of the product has ever been installed on them | `Cross` | Cross | P1 | XL | `PENDING` | -| [`GT-435`](./gap-reference-catalog.md#gt-435) | The end-to-end path from code to a running product in real use is not deployed or validated **What it means:** This is the umbrella item for taking the product from something that works on developer machines to something real people use. It stays open until every piece under it is finished **Example:** An assessment put the engine at roughly ninety-five percent ready while everything around it -- packaging, deployment, the companion app -- was not | `Cross` | Cross | P0 | XL | `PENDING` | +| [`GT-448`](./gap-reference-catalog.md#gt-448) | Nothing runs in production: the stack has never been promoted to the server that customers would reach **What it means:** The product does not exist anywhere a real customer could use it. Everything so far lives on developer machines **Example:** The production server and its deployment tooling are already set up, but no part of the product has ever been installed on them | `Cross` | Cross | P1 | XL | `DEFERRED` | +| [`GT-435`](./gap-reference-catalog.md#gt-435) | The end-to-end path from code to a running product in real use is not deployed or validated **What it means:** This is the umbrella item for taking the product from something that works on developer machines to something real people use. It stays open until every piece under it is finished **Example:** An assessment put the engine at roughly ninety-five percent ready while everything around it -- packaging, deployment, the companion app -- was not | `Cross` | Cross | P0 | XL | `DEFERRED` | | [`GT-436`](./gap-reference-catalog.md#gt-436) | Ship the npm packages. The old `@evolith/*` scope was polluted with published history (1.0.x/1.1.x/2.0.0-beta/tombstones) that blocked a clean 1.0.0, so the whole library family was renamed to a fresh unified scope. **Closure (0edaa22b): all 7 libs published at a clean `1.0.0` under `@beyondnet/evolith-*` (core-domain, infra-providers, core, agent-runtime, sdk, mcp, cli — all HTTP 200 on the registry). Old `@evolith/*` deprecated pointing to the new names (4 are in a broken 404 registry state and unusable anyway).** Follow-on: sweep the docs from `@evolith/*` → `@beyondnet/evolith-*`. | `CLI` | Cross | P0 | M | `DONE` | | [`GT-437`](./gap-reference-catalog.md#gt-437) | Add `agent-runtime-api` to CI/CD (docker build+push to GHCR + Coolify deploy) — today it has a Dockerfile but is NOT built/tested/deployed by any workflow. **Closure (`1ddbe25b`):** the premise was partly stale — agent-runtime WAS already built/tested by `ci-cd.yml` (3 workspace builds). The genuine hole: it was absent from the `docker-services` matrix (only core-api + mcp-server) and had no Coolify deploy step, so **on main it was never imaged or deployed** (`docker-images.yml` covered it only on tags/`workflow_dispatch`). Fixed: matrix + `agent-runtime` → `ghcr.io//evolith-agent-runtime` (repo-root context, `./src/apps/agent-runtime-api/Dockerfile`, image name matching `docker-images.yml`), and a `Trigger Coolify deploy (agent-runtime)` step on the established fail-soft contract (unset hook ⇒ warn + exit 0, never fails CD). agent-runtime-api now sits in the same CI/CD posture as its two siblings. Verified: `ci-cd.yml` parses as YAML, resolving to 3 matrix services + 3 deploy steps; the referenced Dockerfile exists. **Owner-gated (delegated to [`GT-324`](./gap-reference-catalog.md#gt-324)):** provisioning `COOLIFY_AGENTRUNTIME_DEPLOY_HOOK`/`COOLIFY_API_TOKEN`; the first live build+deploy runs on the next merge to main (the job is main/tag-only, not exercisable from develop). | `Infra` | Cross | P1 | M | `DONE` | | [`GT-438`](./gap-reference-catalog.md#gt-438) | Production adapter wiring for `agent-runtime-api`: default bootstrap uses `StubCoreEvaluationAdapter` + `StubAgentEngineAdapter` + in-memory state; wire real Core-eval (HTTP), engine (Hermes/routing), durable memory + scheduler by default/env in prod. **Progress (local kind):** the real `HttpCoreEvaluationAdapter` is already in the factory (env-driven); wired + **verified in the kind cluster** — the agent-runtime `values-local` sets `AGENT_RUNTIME_CORE_ENDPOINT` to the in-cluster `core-api` service, and a `POST /v1/agent/handle` produced a real `POST /api/v1/evaluate` to core-api (SecurityAudit: `200 ALLOW 569ms`, from the runtime pod). The runtime now governs over the REAL Core, not the stub. **Remaining:** real agent-engine (GT-385-gated), durable state, and assembling a real workspace context (today the Core evaluates an empty context → 39 correct GOV-000-style findings). **Closure (`ff57cec6`):** the last non-gated piece — real workspace-context assembly — landed. The runtime now assembles the workspace and passes it **inline** as `evaluationInput.files` (the `OverlayFileSystem` inline-ingestion shape the Core API already consumes), so the Core no longer evaluates an empty context. New `IWorkspaceContextPort` + `FsWorkspaceContextAdapter` (bounded deterministic walk: file/byte budgets, excluded dirs, relative-posix keys, injectable `fsImpl`); additive `InlineEvaluationInput`/`RuntimeEvaluationContext`; `context-mapper` attaches files only when non-empty; a workspace outage degrades to the prior flow (never fails a run); `runtime.factory` wires it from `AGENT_RUNTIME_WORKSPACE_CONTEXT_ROOT` (unset ⇒ prior behavior). GT-388 surface-freeze updated (additive/minor). Verified: agent-runtime 131/131 (+8), agent-runtime-api 80/80 (+3), tsc clean. **Still gated (as designed):** real reasoning engine (GT-385/Hermes) + durable memory/scheduler needing external services; a Tracker-driven context assembler is a future sibling adapter behind the same port. | `Agent Runtime` | Cross | P1 | M | `DONE` | @@ -660,7 +660,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:** 621 / 645 done · 9 in progress · 11 pending · 4 deferred +**Progress:** 621 / 645 done · 9 in progress · 8 pending · 7 deferred **Wave 2026-06-23 (Winston deep audit III):** Added 14 new gaps `GT-212`…`GT-225` from the Winston Audit Playbook covering: ADR status hygiene (GT-212), topology manifest metadata + operational budgets + guidance corpus (GT-213, GT-217, GT-219), REST controller observability + OpenAPI (GT-214, GT-215), OPA input-schema parity + per-topology test density (GT-216, GT-222), SDLC Phase 05 rollback + on-call templates (GT-218), CLI branch coverage + envelope format coverage + skip-list cleanup (GT-220, GT-224, GT-225), MCP HTTP audit logging (GT-221), and cross-surface parity e2e tests (GT-223). diff --git a/reference/core/control-center/maturity-reports/maturity-reconciliation.json b/reference/core/control-center/maturity-reports/maturity-reconciliation.json index 3ce0e9433..f6bde5e2f 100644 --- a/reference/core/control-center/maturity-reports/maturity-reconciliation.json +++ b/reference/core/control-center/maturity-reports/maturity-reconciliation.json @@ -5,9 +5,9 @@ "gaps": { "total": 645, "done": 621, - "pending": 11, + "pending": 8, "inProgress": 9, - "deferred": 4 + "deferred": 7 }, "evidence": { "closureRecords": 603, diff --git a/reference/core/sdlc/assets/master-view.svg b/reference/core/sdlc/assets/master-view.svg index 3eede9dcc..c4f86c078 100644 --- a/reference/core/sdlc/assets/master-view.svg +++ b/reference/core/sdlc/assets/master-view.svg @@ -1,4 +1,4 @@ - +