The mismatch was a port-drift bug: SERVERURL fallbacks in legacy src/tests and several OpenCode/memory-bank doc files still pointed at http://localhost:3000 (the old DuckBrain service), while the mafia server runs on :3004. README test counts had also gone stale (716/195 vs the live suite's 737/216).
The mismatch was a port-drift bug: SERVER_URL fallbacks in legacy src/tests and several OpenCode/memory-bank doc files still pointed at http://localhost:3000 (the old DuckBrain service), while the mafia server runs on :3004. README test counts had also gone stale (716/195 vs the live suite's 737/216).
1. src/tests — SERVER_URL fallbacks (7 occurrences in 6 files). Every test that defaulted to the DuckBrain port was corrected to the mafia server port. One file contained two occurrences; the rest one each:
// src/tests/mafiaGame.test.ts (before)
const SERVER_URL = process.env.SERVER_URL ?? 'http://localhost:3000';
// after
const SERVER_URL = process.env.SERVER_URL ?? 'http://localhost:3004';
// src/tests/api/rounds.test.ts (before) — 2 occurrences (HTTP + websocket variants)
const API_URL = process.env.API_URL ?? 'http://localhost:3000';
const WS_URL = process.env.WS_URL ?? 'ws://localhost:3000';
// after
const API_URL = process.env.API_URL ?? 'http://localhost:3004';
const WS_URL = process.env.WS_URL ?? 'ws://localhost:3004';
2. OpenCode / memory-bank docs (7 occurrences in 5 files). Markdown references to the DuckBrain endpoint were updated so agents don't probe the wrong port:
<!-- docs/opencode/architecture.md (before) -->
- Local server: `http://localhost:3000` (DuckBrain)
<!-- after -->
- Mafia server: `http://localhost:3004`
<!-- memory-bank/runbook.md (before) -->
curl http://localhost:3000/api/health
<!-- after -->
curl http://localhost:3004/api/health
3. README. Stale counts refreshed to match the live suite:
<!-- README.md (before) -->
| Tests | 716 passing / 195 pending |
<!-- after -->
| Tests | 737 passing / 216 pending |
Fix invariant: process.env.SERVER_URL ?? 'http://localhost:3004' — the env override always wins, so CI remains portable; the fallback is now correct for local dev against the mafia server.
Verification was run against the repo after the edits:
rg -n "localhost:3000" src/tests → 0 matches; rg -rn "localhost:3000" . --glob '!node_modules' --glob '!.git' → 0 matches in docs (all :3000 references eliminated, including ws:// and trailing-slash variants like http://localhost:3000/).src/tests files (one file had a duplicated fallback in HTTP + WS consts) and 7 across 5 doc files — matching the pre-fix grep report 1:1.npm test (typescript 5.9.3, production env) completed with 737 passing / 216 pending, matching the updated README numbers exactly — confirming the README was stale, not the suite.SERVER_URL=http://localhost:9999 npm test -- tests/api — the fallback was bypassed correctly, proving ?? semantics intact.ws://localhost:3004 (not just http://), since a half-fixed port with the old scheme would still fail.curl -s http://localhost:3004/api/health returned 200 OK from the mafia server; the same curl against :3000 refused connection, confirming the port switch was load-bearing.:3000 and :3004 — every operative reference now resolves to :3004; zero dangling DuckBrain URLs remain.{"problem_class":"typescript-doc-port-mismatch","model":"deepseek-v4-flash","result":"passed","tests":737}
Solved by Pi Agent (deepseek-v4-flash).