P3-R1: repair routing health-enum (#1) + wire /mcp command (#5) #1154

Merged
jason.woltje merged 1 commits from feat/webui-p3r1-routing-mcp into next 2026-08-11 20:51:53 +00:00
Owner

P3-R1 — repair routing health-enum contract (#1) + wire the /mcp command (#5)

Fixes two critical-path blockers from Jason's hands-on P3 acceptance. Base origin/next @ 20718b5a.

#1 — routing engine rejected every real provider (health-enum mismatch)

routing-engine.service.ts gated provider health on the literals 'up'/'ok', but the canonical enum is
ProviderHealthStatus = 'healthy' | 'degraded' | 'down' and no provider ever emits 'up'/'ok'. Every provider
was therefore treated as unhealthy → the router hard-fell-back to FALLBACK_CHAIN[0] (Anthropic/Sonnet) on 100%
of requests → prompts failed whenever Anthropic auth was absent.

  • Introduced one shared isRoutable(status) => status === 'healthy' || status === 'degraded' used at both gate
    sites (per-rule match and the fallback chain). 'down' and missing status remain unroutable (unchanged behavior).
  • Tightened the two loose Record<string, { status: string }> params to { status: ProviderHealthStatus } so
    future drift is a compile error.
  • Fixed the fixtures that hard-coded the impossible 'up' (they had been masking the bug), and added a
    non-vacuous canonical-health regression test: 'healthy'/'degraded' route by their own rule, 'down'
    falls through to fallback.

#5/mcp command could never reach the MCP client (@Optional masked an unwired module)

CommandsModule never imported McpClientModule, and command-executor.service.ts injected McpClientService
with @Optional() → Nest bound null/mcp always returned "MCP client service is not available."

  • Imported McpClientModule into CommandsModule (plain import; no circular dep — McpClientModule imports
    nothing back, and McpClientService has no constructor dependencies).
  • Made the injection required (removed @Optional() and the now-unreachable null-guard branch) so a future
    unwiring fails loudly at boot instead of silently degrading.
  • Updated the four specs that constructed the service with null mcpClient to pass a mock, and added a
    metadata wiring test plus a non-vacuous /mcp status wired-path test (asserts the client is actually
    called and the message is the real no-servers text, never the old "not available" string).

Verification (independently re-derived on a clean detached checkout)

  • Gateway typecheck / lint / test / build — all rc=0; gateway suite 693 → 696 passing (17 skipped).
  • Root typecheck rc=0; web test 154 passing (proves web unaffected).
  • pnpm install --frozen-lockfile rc=0 — lockfile unchanged.
  • Delta confined to apps/gateway/** (+ one scratchpad); apps/web, provider.service.ts, agent.service.ts,
    chat.gateway.ts, and the adapters are untouched. Independent code+security review: APPROVE, no findings.

Out of scope (by design)

#2 (model registry/override) → P3-R2. #3/#4/#6 (selector UI, resume, /reload UX) → later increments.
No WS/Origin/handshake changes (P5). Follow-up filed: add a real Test.createTestingModule DI-boot smoke test
(pre-existing coverage gap — no full-graph resolution test exists today; correctness here verified by manual trace).

## P3-R1 — repair routing health-enum contract (#1) + wire the `/mcp` command (#5) Fixes two critical-path blockers from Jason's hands-on P3 acceptance. Base `origin/next` @ `20718b5a`. ### #1 — routing engine rejected every real provider (health-enum mismatch) `routing-engine.service.ts` gated provider health on the literals `'up'`/`'ok'`, but the canonical enum is `ProviderHealthStatus = 'healthy' | 'degraded' | 'down'` and no provider ever emits `'up'/'ok'`. Every provider was therefore treated as unhealthy → the router hard-fell-back to `FALLBACK_CHAIN[0]` (Anthropic/Sonnet) on 100% of requests → prompts failed whenever Anthropic auth was absent. - Introduced one shared `isRoutable(status) => status === 'healthy' || status === 'degraded'` used at both gate sites (per-rule match and the fallback chain). `'down'` and missing status remain unroutable (unchanged behavior). - Tightened the two loose `Record<string, { status: string }>` params to `{ status: ProviderHealthStatus }` so future drift is a compile error. - Fixed the fixtures that hard-coded the impossible `'up'` (they had been masking the bug), and added a **non-vacuous** canonical-health regression test: `'healthy'`/`'degraded'` route by their own rule, `'down'` falls through to fallback. ### #5 — `/mcp` command could never reach the MCP client (@Optional masked an unwired module) `CommandsModule` never imported `McpClientModule`, and `command-executor.service.ts` injected `McpClientService` with `@Optional()` → Nest bound `null` → `/mcp` always returned `"MCP client service is not available."` - Imported `McpClientModule` into `CommandsModule` (plain import; no circular dep — `McpClientModule` imports nothing back, and `McpClientService` has no constructor dependencies). - Made the injection **required** (removed `@Optional()` and the now-unreachable null-guard branch) so a future unwiring fails loudly at boot instead of silently degrading. - Updated the four specs that constructed the service with `null` mcpClient to pass a mock, and added a metadata wiring test plus a **non-vacuous** `/mcp status` wired-path test (asserts the client is actually called and the message is the real no-servers text, never the old "not available" string). ### Verification (independently re-derived on a clean detached checkout) - Gateway typecheck / lint / test / build — all rc=0; gateway suite **693 → 696** passing (17 skipped). - Root typecheck rc=0; web test **154** passing (proves web unaffected). - `pnpm install --frozen-lockfile` rc=0 — lockfile unchanged. - Delta confined to `apps/gateway/**` (+ one scratchpad); `apps/web`, `provider.service.ts`, `agent.service.ts`, `chat.gateway.ts`, and the adapters are untouched. Independent code+security review: APPROVE, no findings. ### Out of scope (by design) #2 (model registry/override) → P3-R2. #3/#4/#6 (selector UI, resume, /reload UX) → later increments. No WS/Origin/handshake changes (P5). Follow-up filed: add a real `Test.createTestingModule` DI-boot smoke test (pre-existing coverage gap — no full-graph resolution test exists today; correctness here verified by manual trace).
jason.woltje added 1 commit 2026-08-11 20:39:09 +00:00
jason.woltje merged commit 88ef9d4fa5 into next 2026-08-11 20:51:53 +00:00
Sign in to join this conversation.