typescript-default-port-mismatch
Solution written to ~/MAF-GAP-052-fix.md.
Root cause: The server hard-coded process.env.PORT || 3000, while the CLI's DEFAULT_SERVER_URL targets port 3004. With no PORT set on a fresh machine, the server binds 3000 but the CLI dials 3004 → ECONNREFUSED. This is the 4th re-occurrence of the 3000/3004 drift because the literal 3000 has no shared source of truth and nothing prevents divergence.
The fix (4 parts):
1. src/config.ts exports a single canonical DEFAULT_PORT = 3004.
2. Server becomes const PORT = process.env.PORT || DEFAULT_PORT (imports the config).
3. A unit test asserts the exported default equals the CLI's DEFAULT_SERVER_URL port, locking the whole family and blocking a 5th drift in CI.
4. docker-compose pins PORT: 3000 explicitly so the container-internal port, the 3004:3000 mapping, and the 3000 healthcheck are preserved while the bare default becomes 3004.
Net behavior: direct run binds 3004 (CLI default matches), docker run binds container-3000 reaching localhost:3004 via the mapping — both connectable by the CLI.
The core logic was verified on node 22 (DEFAULT_PORT=3004, no-env → 3004, PORT:3000 override → 3000), and the doc includes a full verification section covering unit tests, fresh-machine direct run, explicit-var override, and the docker healthcheck path.
The repository itself (mafia-ai-benchmark) is not checked out in this environment, so the exact file paths (src/config.ts, src/config.test.ts, etc.) use the same conventions described in the task and should be adjusted to the repo's actual layout when applying.
# Evidence - Problem class: typescript-default-port-mismatch - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-20T00:28:46.751Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Server code default port (process.env.PORT || 3000) mismatches the CLI client default (DEFAULT_SERVER_URL http://localhost:3004): fresh machine direct-run pnpm run server + mafiactl list-games -> ECONNREFUSED. 4th recurrence of the 3000/3004 drift family. Fix: export DEFAULT_PORT=3004 from a config module, PORT = process.env.PORT || DEFAULT_PORT, unit-test the exported default; docker-compose keeps container-internal 3000 via explicit PORT:3000 override (healthcheck + 3004:3000 mapping unaffected).", "environment": "production", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-default-port-mismatch", "provider": "openrouter", "solved_at": "2026-08-20T00:28:46.751Z", "version": "node 22"}Solution written to ~/MAF-GAP-052-fix.md.
Root cause: The server hard-coded process.env.PORT || 3000, while the CLI's DEFAULT_SERVER_URL targets port 3004. With no PORT set on a fresh machine, the server binds 3000 but the CLI dials 3004 → ECONNREFUSED. This is the 4th re-occurrence of the 3000/3004 drift because the literal 3000 has no shared source of truth and nothing prevents divergence.
The fix (4 parts):
1. src/config.ts exports a single canonical DEFAULT_PORT = 3004.
2. Server becomes const PORT = process.env.PORT || DEFAULT_PORT (imports the config).
3. A unit test asserts the exported default equals the CLI's DEFAULT_SERVER_URL port, locking the whole family and blocking a 5th drift in CI.
4. docker-compose pins PORT: 3000 explicitly so the container-internal port, the 3004:3000 mapping, and the 3000 healthcheck are preserved while the bare default becomes 3004.
Net behavior: direct run binds 3004 (CLI default matches), docker run binds container-3000 reaching localhost:3004 via the mapping — both connectable by the CLI.
The core logic was verified on node 22 (DEFAULT_PORT=3004, no-env → 3004, PORT:3000 override → 3000), and the doc includes a full verification section covering unit tests, fresh-machine direct run, explicit-var override, and the docker healthcheck path.
The repository itself (mafia-ai-benchmark) is not checked out in this environment, so the exact file paths (src/config.ts, src/config.test.ts, etc.) use the same conventions described in the task and should be adjusted to the repo's actual layout when applying.
# Evidence - Problem class: typescript-default-port-mismatch - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-20T00:28:46.751Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Server code default port (process.env.PORT || 3000) mismatches the CLI client default (DEFAULT_SERVER_URL http://localhost:3004): fresh machine direct-run pnpm run server + mafiactl list-games -> ECONNREFUSED. 4th recurrence of the 3000/3004 drift family. Fix: export DEFAULT_PORT=3004 from a config module, PORT = process.env.PORT || DEFAULT_PORT, unit-test the exported default; docker-compose keeps container-internal 3000 via explicit PORT:3000 override (healthcheck + 3004:3000 mapping unaffected).", "environment": "production", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-default-port-mismatch", "provider": "openrouter", "solved_at": "2026-08-20T00:28:46.751Z", "version": "node 22"}