diff --git a/docs/LOCAL_DEV_WITH_K8S_CORE.es.md b/docs/LOCAL_DEV_WITH_K8S_CORE.es.md index 643ef97a..4ed01001 100644 --- a/docs/LOCAL_DEV_WITH_K8S_CORE.es.md +++ b/docs/LOCAL_DEV_WITH_K8S_CORE.es.md @@ -88,12 +88,15 @@ dotnet run --project Tracker.Presentation admin con todos los permisos; se niega a arrancar fuera de Development). Postgres (`tracker-ci-pg`) ya está arriba con las credenciales `evolith` / `evolith_tracker` / `localdev` que esta cadena espera. -> **Aviso de `CoreApi__BaseUrl` (gap `LV-18`):** `appsettings.json` trae `.../api/core/api/v1`, -> pero al pegar **directamente al pod** del Core (como hace el port-forward) el prefijo `/api/core` -> no está — el pod sirve `/api/v1`. Tres rutas (`/gates`, `/architecture`, `/reference`) siguen -> dando `404` en la imagen actual del Core de todos modos; solo `/capabilities` existe. Esa -> discrepancia de contrato está registrada como `LV-18` y **no** se resuelve corriendo en local: -> verás fallar esas tres llamadas hasta que se arregle. +> **`CoreApi__BaseUrl` (era el gap `LV-18`):** `appsettings.json` ahora tiene por defecto +> `http://localhost:3001/api/v1` — la superficie **directa** `/api/v1` del Core (el Core del compose +> en `:3001`). El ADR T-038 hace del BFF tracker-api el ÚNICO cliente del Core, llamando `/api/v1` +> directo, nunca el tracker-gateway; el prefijo `/api/core` del gateway es un facade de agregación +> para consumidores externos (ADR T-052) y no existe en el pod del Core. Este runbook reenvía el +> Core de **k8s** a `:8090`, así que el comando de arriba sobrescribe `CoreApi__BaseUrl` a +> `http://localhost:8090/api/v1` — la misma superficie directa `/api/v1`, distinto host:puerto. El +> default roto anterior (`http://localhost:4000/api/core/api/v1`, el prefijo imaginario del gateway) +> está corregido. ## 4. Arrancar tracker-gateway (superficie MCP) en :4000 diff --git a/docs/LOCAL_DEV_WITH_K8S_CORE.md b/docs/LOCAL_DEV_WITH_K8S_CORE.md index b3d9754c..45a74623 100644 --- a/docs/LOCAL_DEV_WITH_K8S_CORE.md +++ b/docs/LOCAL_DEV_WITH_K8S_CORE.md @@ -88,12 +88,14 @@ dotnet run --project Tracker.Presentation full-permission admin; it refuses to start outside Development). Postgres (`tracker-ci-pg`) is already up with the `evolith` / `evolith_tracker` / `localdev` credentials this string expects. -> **`CoreApi__BaseUrl` caveat (gap `LV-18`):** `appsettings.json` ships `.../api/core/api/v1`, -> but hitting the Core **pod directly** (as the port-forward does) the `/api/core` prefix is not -> there — the pod serves `/api/v1`. Three routes (`/gates`, `/architecture`, `/reference`) still -> `404` on the current Core image regardless; only `/capabilities` exists. That contract -> mismatch is tracked as `LV-18` and is **not** solved by running locally — you'll see those -> three tool calls fail until it's resolved. +> **`CoreApi__BaseUrl` (was gap `LV-18`):** `appsettings.json` now defaults to +> `http://localhost:3001/api/v1` — the Core's **direct** `/api/v1` surface (the compose Core on +> `:3001`). ADR T-038 makes the tracker-api BFF the Core's SOLE client, calling `/api/v1` directly, +> never the tracker-gateway; the gateway's `/api/core` prefix is an aggregation facade for external +> consumers (ADR T-052) and does not exist on the Core pod. This runbook port-forwards the **k8s** +> Core to `:8090`, so the run command above overrides `CoreApi__BaseUrl` to +> `http://localhost:8090/api/v1` — same direct `/api/v1` surface, different host:port. The old +> broken default (`http://localhost:4000/api/core/api/v1`, the imaginary gateway prefix) is fixed. ## 4. Run tracker-gateway (MCP surface) on :4000 diff --git a/docs/audit/tracker-gap-reference-catalog.md b/docs/audit/tracker-gap-reference-catalog.md index 43d28f53..d48c2178 100644 --- a/docs/audit/tracker-gap-reference-catalog.md +++ b/docs/audit/tracker-gap-reference-catalog.md @@ -3990,6 +3990,7 @@ La prueba HTTP del bucle completo pasó a la primera, y al mutar la regla de aut - **Status:** `DONE` (2026-07-21 — implementado según [ADR T-051](../adrs/T-051-mcp-gateway-binds-to-bff.md)). **Nota — superado por [T-052](../adrs/T-052-gateway-consumes-core-single-mcp.md):** las 6 tools `tracker_*` se eliminaron (duplicaban el MCP del Core); el problema de rutas 404 queda sin objeto. Evidencia histórica conservada abajo. - **Cierre:** las 6 tools se reenlazaron al BFF `tracker-api`. Smoke en vivo (gateway `nx serve` + BFF stand-in) confirma las rutas exactas golpeadas: `GET /api/v1/gates/{execId}/phase/{phase}`, `GET /api/v1/architecture/topologies`, `GET /api/v1/architecture/reference` (las 3 antes-404), más `GET /api/v1/products`, `POST /api/v1/design/blueprints/{id}/submit-gate`, `POST /api/v1/audit-entries` — **6/6 `success:true`**. Guarda `mcp.contract.spec.ts` (4 asserts) + build verde. **Residual (no revalida el binding):** el smoke E2E contra el `tracker-api` sembrado real devolviendo datos de negocio queda como paso del runbook `LOCAL_DEV_WITH_K8S_CORE.md` / `OPP-003`. +- **Residual de config committeada — CERRADO (2026-07-24, GT-447 Obj-1 bring-up):** el cierre de arriba rebindeó las MCP tools, pero **el default propio del cliente Core del BFF nunca se corrigió**: `CoreApi:BaseUrl` en `src/apps/tracker-api/Tracker.Presentation/appsettings.json` seguía apuntando al path imaginario `http://localhost:4000/api/core/api/v1` — manifestación **hermana** de la misma causa raíz («`/api/core` inexistente en el Core»). Pasó desapercibido porque el compose full-stack y los Helm values lo **sobrescriben por env** (`CoreApi__BaseUrl=http://core-api:3000/api/v1` / DNS de clúster), así que sólo mordía a quien corriera el BFF con la config committeada apuntando al gateway. El cliente (`CoreEvaluationGateway`) fija `BaseAddress = BaseUrl+"/"` y hace `PostAsJsonAsync("evaluate", …)` → `…/api/core/api/v1/evaluate`, que cae al catch-all `@All('*')` del gateway (404). **Fix:** `BaseUrl` → `http://localhost:3001/api/v1` (directo al Core, ADR **T-038**: el BFF es el único cliente del Core; el `/api/core` es facade de agregación para consumidores externos, ADR **T-052**). Alineado con el default del código (`CoreEvaluationOptions.cs`), `evolith.satellite.json`, todos los Helm values, el `docker-compose.fullstack.yml` y los defaults de los tests en vivo. **Verificado e2e contra el stack vivo:** `POST :5100/api/v1/core/evaluate` → `200`, `provenance=core`, `coreEndpoint=/api/v1/evaluate`, `status=COMPLETED`; el path viejo `POST :4000/api/core/api/v1/evaluate` → `404`; `POST :3001/api/core/evaluate` en el Core → `404` («Cannot POST /api/core/evaluate»). Docs alineados: `evolith.satellite.json` (nota corregida) + `LOCAL_DEV_WITH_K8S_CORE.md`/`.es.md` (caveats). - **Purpose / hallazgo:** Tres de las seis tools pegan a endpoints que el Core real **no expone**: `tracker_get_gate_status`→`/api/v1/gates`, `tracker_get_upstream_constraints`→`/api/v1/architecture`, `tracker_read_spec`→`/api/v1/reference`. Sondeados en vivo devuelven **HTTP 404**; sólo `/api/v1/capabilities` responde (401, existe). Aun corrigiendo despliegue (`LV-16`) y URLs (`LV-17`), la mitad del catálogo fallaría: el contrato Core nunca se verificó contra el servicio real. - **Evidence:** `kubectl exec` (core-api pod) `curl -o /dev/null -w '%{http_code}'` → `/api/v1/gates` 404, `/api/v1/architecture` 404, `/api/v1/reference` 404, `/api/v1/capabilities` 401. - **Component:** `Contracts/Integration` · **Module:** tracker-gateway MCP · **Type:** LV diff --git a/docs/audit/tracker-gap-tracking.md b/docs/audit/tracker-gap-tracking.md index a51f4f97..a8ac5a6d 100644 --- a/docs/audit/tracker-gap-tracking.md +++ b/docs/audit/tracker-gap-tracking.md @@ -73,7 +73,7 @@ This board is the single source of truth for Tracker technical debt, gaps, oppor | [`LV-15`](./tracker-gap-reference-catalog.md#lv-15) | **Hecho — roll-out de [ADR T-034](../adrs/T-034-config-hub-vs-monitor.md)** (Config-hub vs Monitor) completo. Los **monitores** migrados a solo-lectura con la edición movida a zonas inline en Tenant configuration: Gate policies & criteria, Custom fields / artifact schemas (Gate governance 100% solo-lectura) y Tenant intelligence (`intel` solo-lectura). **Connectors (PPM intake)** y **Products** quedan como pantallas de **registro/gestión** — exentas por diseño (ADR T-034 §2.1: los registros no son monitores); sus cards de Config enlazan a su área de gestión ("Manage …"). | | | `WEB` | Cross | P2 | L | `DONE` | | [`LV-16`](./tracker-gap-reference-catalog.md#lv-16) | El `tracker-gateway` (servidor MCP que reclama COH-006/007) no está desplegado en ningún entorno; sólo corren los servicios del Core | El código de la superficie de agentes existe pero nunca ha corrido: los cierres de COH-006/007 son "code-complete" sin una sola evidencia viva | Desplegado: `Dockerfile` (Node multi-stage) + chart `evolith-tracker-gateway`; corre en `evolith-local` y consume el Core **in-cluster por DNS** (capabilities + 47 MCP tools), sin port-forward | `Infra/Integration` | Cross | P1 | S | `DONE` | | [`LV-17`](./tracker-gap-reference-catalog.md#lv-17) | Las 6 MCP tools del gateway resuelven Core y Tracker-API por `localhost` y nombran la variable del Core distinto que el core-proxy | Desplegado tal cual en clúster, ninguna tool alcanza su upstream: apuntan a hosts que no existen ahí | `mcp.service.ts` usa `CORE_API_BASE_URL` (default `localhost:4000/api/core`) mientras `core-proxy.service.ts` usa `EVOLITH_CORE_API_URL` (default DNS de clúster) para el MISMO Core | `Integration/Config` | Cross | P1 | S | `DONE` | -| [`LV-18`](./tracker-gap-reference-catalog.md#lv-18) | Tres de las seis MCP tools llaman rutas del Core que devuelven 404 en el servicio vivo | Aun corrigiendo despliegue y URLs, la mitad del catálogo choca con endpoints que el Core no expone: el contrato nunca se verificó contra el Core real | `/api/v1/gates`, `/api/v1/architecture` y `/api/v1/reference` → HTTP 404 en vivo; sólo `/api/v1/capabilities` responde (401, existe) | `Contracts/Integration` | Cross | P1 | M | `DONE` | +| [`LV-18`](./tracker-gap-reference-catalog.md#lv-18) | Tres de las seis MCP tools llaman rutas del Core que devuelven 404 en el servicio vivo. **Residual de config cerrado (2026-07-24):** el cierre por T-051/T-052 rebindeó las tools al BFF, pero el default propio del cliente Core del BFF —`CoreApi:BaseUrl` en `appsettings.json`— seguía en el path imaginario `…:4000/api/core/api/v1` (hermano de esta misma causa, tapado por env en compose/Helm); corregido a `http://localhost:3001/api/v1` (directo al Core, ADR T-038), alineado con el default del código, Helm, el compose full-stack y los tests en vivo. Verificado e2e contra el stack: `POST :5100/api/v1/core/evaluate` → 200 `provenance=core`, `coreEndpoint=/api/v1/evaluate`; el path viejo `POST :4000/api/core/api/v1/evaluate` → 404. | Aun corrigiendo despliegue y URLs, la mitad del catálogo choca con endpoints que el Core no expone: el contrato nunca se verificó contra el Core real | `/api/v1/gates`, `/api/v1/architecture` y `/api/v1/reference` → HTTP 404 en vivo; sólo `/api/v1/capabilities` responde (401, existe) | `Contracts/Integration` | Cross | P1 | M | `DONE` | | [`LV-19`](./tracker-gap-reference-catalog.md#lv-19) | ⚠️ **Premisa falsa (corregido 2026-07-21)** — el Tracker SÍ tiene cliente del runtime: `AgentRuntimeGateway` (BFF) llama `POST /v1/agent/converse` vía `/api/v1/assistant/converse`, tenant-scoped y engine-agnóstico, más el puerto gobernado `IAgentExecutionPort` (EAG-16) | El cliente vive en el BFF (correcto per T-051), no en el gateway MCP; el `rg` original miró sólo el `tracker-gateway`, no el `tracker-api` | El residual real —ejercitarlo contra el runtime vivo— es `AR-02`, no un cliente faltante | `Integration` | Cross | P2 | M | `DONE` | | [`LV-20`](./tracker-gap-reference-catalog.md#lv-20) | `COH-006` y `COH-007` siguen `BLOCKED` pese a que su bloqueante `EAG-16` está `DONE` y su código ya existe | El estado del board no refleja la realidad: ni "bloqueado" (el bloqueante cerró) ni "hecho" (sin verificar en vivo); el estado honesto es code-complete-unverified | `COH-006/007` ya no están `BLOCKED` ni pendientes: cerrados `DONE` por [ADR T-052] (la superficie de agentes es el MCP del Core, que el Tracker consume) | `Docs` | Cross | P3 | XS | `DONE` | | [`OPP-003`](./tracker-gap-reference-catalog.md#opp-003) | RoboSoft: flota de agentes de prueba E2E determinísticos contra el stack vivo (Core real) como evidencia reproducible | El entorno vivo ya existe; RoboSoft ejercita REST + MCP tools + `/converse` con round-trips reales al Core, asevera y emite evidencia JSON + exit code para CI | RoboSoft REALIZADO: 7 robots validados en vivo (core-integration 11/13 vs Core real; governance-journey 53/53; provider-connections 19/19; tenant-isolation 10/10; gate-enforcement 25/25; exception-governance 21/21; audit-trail 14/14; intake 12/12; qa-quality-gate 13/13; scorecard 33/33; auth-perimeter 6/6 cierra RS-GAP-2; runtime-approvals 10/10 CD-23 HITL) + gate de CI en cada PR con los 9 tracker-api-only (200/200); seeds e2e arreglados (/api/v1 + CD-19); 3 gaps de cobertura registrados (inmutabilidad-en-reposo=BD, auth real=prod-standup, core-integration=Core-en-CI) | `Infra/Quality` | Cross | P2 | M | `DONE` | diff --git a/evolith.satellite.json b/evolith.satellite.json index 740a027c..7bdb726d 100644 --- a/evolith.satellite.json +++ b/evolith.satellite.json @@ -218,7 +218,7 @@ "baseUrl": "http://localhost:3001/api/v1", "version": "v1 (path-versioned: /api/v1)", "openapi": "http://localhost:3001/api/v1/openapi.json (Core-API Swagger, ADR-0073 envelope); the machine-readable capabilities manifest is served at GET /api/v1/capabilities", - "baseUrlNote": "Default from CoreEvaluationOptions.BaseUrl (src/apps/tracker-api/Tracker.Presentation/Integration/CoreEvaluationOptions.cs). A deployment behind the BFF gateway overrides CoreApi:BaseUrl in appsettings.json (e.g. http://localhost:4000/api/core/api/v1)." + "baseUrlNote": "Default from CoreEvaluationOptions.BaseUrl (src/apps/tracker-api/Tracker.Presentation/Integration/CoreEvaluationOptions.cs). The Tracker BFF is the SOLE Core client (ADR T-038) and calls the Core's /api/v1 surface DIRECTLY, never through the tracker-gateway. A deployment overrides CoreApi:BaseUrl to the Core service DNS (e.g. http://core-api:3000/api/v1 in-network, http://evolith-core-api/api/v1 in-cluster). Do NOT point it at the gateway's /api/core aggregation facade: that prefix is for EXTERNAL consumers (ADR T-052) and 404s from the BFF's Core client — the earlier http://localhost:4000/api/core/api/v1 example was gap LV-18." } }, "canonicalModelRefs": { diff --git a/src/apps/tracker-api/Tracker.Presentation/appsettings.json b/src/apps/tracker-api/Tracker.Presentation/appsettings.json index 261e1113..6a978ac4 100644 --- a/src/apps/tracker-api/Tracker.Presentation/appsettings.json +++ b/src/apps/tracker-api/Tracker.Presentation/appsettings.json @@ -40,7 +40,8 @@ }, "CoreApi": { "//ApiKey": "SERVICE credential the BFF presents to the Core as 'Authorization: Bearer ' (Core's global ApiKeyGuard / EVOLITH_API_KEY). Required for non-mock runs. This does NOT contradict ADR-0080: that contract forbids forwarding USER tokens or tenant identity to the Core (repositoryRef + opaque workspaceRef only); a BFF->Core service key is a separate, allowed transport concern. Keep this key.", - "BaseUrl": "http://localhost:4000/api/core/api/v1", + "//BaseUrl": "The Tracker BFF is the satellite's SOLE Core client (T-038): it calls the Core's REST surface DIRECTLY, never through the tracker-gateway. The Core serves /api/v1/{capabilities,rulesets,evaluate} (ADR-0074/0098) — the /api/core prefix is the gateway's own aggregation facade for EXTERNAL consumers (ADR T-052) and is NOT reachable from the Core pod. Local host: core-api is on :3001 (docker-compose.fullstack.yml maps 3000->3001). In-cluster/compose this is overridden via CoreApi__BaseUrl to the Core service DNS (e.g. http://core-api:3000/api/v1 or http://evolith-core-api/api/v1). Pointing this at the gateway (:4000/api/core/api/v1) 404s — that path is imaginary (gap LV-18).", + "BaseUrl": "http://localhost:3001/api/v1", "ApiKey": "local-dev-key", "TimeoutMs": 8000, "MockFallback": false,