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).
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).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
P3-R1 — repair routing health-enum contract (#1) + wire the
/mcpcommand (#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.tsgated provider health on the literals'up'/'ok', but the canonical enum isProviderHealthStatus = 'healthy' | 'degraded' | 'down'and no provider ever emits'up'/'ok'. Every providerwas 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.
isRoutable(status) => status === 'healthy' || status === 'degraded'used at both gatesites (per-rule match and the fallback chain).
'down'and missing status remain unroutable (unchanged behavior).Record<string, { status: string }>params to{ status: ProviderHealthStatus }sofuture drift is a compile error.
'up'(they had been masking the bug), and added anon-vacuous canonical-health regression test:
'healthy'/'degraded'route by their own rule,'down'falls through to fallback.
#5 —
/mcpcommand could never reach the MCP client (@Optional masked an unwired module)CommandsModulenever importedMcpClientModule, andcommand-executor.service.tsinjectedMcpClientServicewith
@Optional()→ Nest boundnull→/mcpalways returned"MCP client service is not available."McpClientModuleintoCommandsModule(plain import; no circular dep —McpClientModuleimportsnothing back, and
McpClientServicehas no constructor dependencies).@Optional()and the now-unreachable null-guard branch) so a futureunwiring fails loudly at boot instead of silently degrading.
nullmcpClient to pass a mock, and added ametadata wiring test plus a non-vacuous
/mcp statuswired-path test (asserts the client is actuallycalled and the message is the real no-servers text, never the old "not available" string).
Verification (independently re-derived on a clean detached checkout)
pnpm install --frozen-lockfilerc=0 — lockfile unchanged.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.createTestingModuleDI-boot smoke test(pre-existing coverage gap — no full-graph resolution test exists today; correctness here verified by manual trace).