test(middleware): run channelApi suites in-process (#564) - #613
Conversation
Merge prep + independent blast-radius verificationI merged The merge is a no-op for the diff, which is the good news. The four Verification on the merged base (fresh
Note this is better than the "404 pre-existing failures" in the test plan above — those were build-dependent and clear once the workspaces are built. Mutation-checked the new transport, because a test helper that isn't load-bearing makes the suites weaker while looking green:
So the transport is genuinely threaded through to its consumers, not decorative. I also probed one hypothesis and want to record that it was refuted, so nobody re-litigates it: Two findings — neither is a merge blocker1. 2. There are now two in-process HTTP test helpers. To be clear, I think the second one is justified — they are not redundant:
That reasoning just isn't written down anywhere, and "second helper, no explanation, different directory convention" is the kind of thing that costs a review round-trip. Either fold the rationale into the PR body, or migrate the 2 Minor: |
Resolves five conflicts against main (#550 MCP waves 0-6, #624, #613): - mcpClient.ts: keep BOTH the new pool-lifetime members (entries map, idleTtlMs, MCP_POOL_IDLE_TTL_MS, mcpPoolScopeMatches) and main's structuredSink / pendingInput options and outputSchemas cache. - src/index.ts: keep the runtimeMcpManager handle alongside main's structured-sink wiring and the W2-1 (#544) input replayer. - routes/agentBuilder.ts: keep main's W0-1 ownership check on DELETE /mcp-servers/:id/token (404/403 fail-closed) and invalidate the pooled connection after the token row is deleted. - docs/adr: main landed 0007-mcp-client-id-metadata-documents (2026-07-30) first, so this ADR is renumbered 0007 -> 0008 and every reference updated. - CHANGELOG: both Unreleased entries retained. Also fixes the mcpPool fixture: serverRow() predates #550 and omitted the required `delegation` field, so resolveMcpUserKey failed closed and the token-revocation test got 403 instead of 204. Verified on the merge result: lint, typecheck and the core-decoupling ratchet pass, and `npm test` is green 3/3 (6075 pass, 0 fail, ~35-49s) -- the parallelism failures documented in the PR body are resolved by #613, now on main. Both new behaviours mutation-checked: disabling onMcpServerChanged turns 3 tests red, weakening the '#' pool-key separator turns 2 red.
What
Harden the
channelApirouter test suites against parallelism (Closes #564, follow-up to #550). The three suites (adminKeysRouter,chatRouter,chatRouterPrivacyIntegration) no longer bind a real Express server on an ephemeral port + make loopbackfetchcalls; they run through a shared in-process transport (test/support/inProcessHttp.ts) instead.Why
node --testforks a worker per file acrossavailableParallelism() - 1workers with no--test-concurrencycap, so the port bind + TCP accept + round-trips these suites paid stretched under a loaded runner — the failure mode #564 traces (disjoint failures, one 301107 ms hang). This attacks that cost directly rather than masking it: a realhttp.Serverthat is neverlisten()ed, fed a synthetic in-memory socket pair and driven by Node's own HTTP client (so responses are parsed by Node, not by hand). No port, no handshake, nothing to contend for.--test-concurrencyis deliberately left unset — bounding parallelism hides the fragility instead of removing it.Test plan
npx tsc --noEmit(middleware) — 0 errorseslinton the new/changed files — cleannpm run test: same 404 pre-existing failures as cleanmain(build/Postgres-dependent), +6 passing, 0 new failuresRisk / blast radius
Test-only. No schema, no public API, no CI/release tooling, no new env-var. Assertions and per-suite test counts (30) unchanged — streaming (NDJSON,
flushHeaders) and mid-turn throws run the same code path. New filetest/support/inProcessHttp.tsis a test helper; not shipped.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.