Repository navigation
Description
Problem
loadConfig (pm-stack/aggregator/src/config.ts:64-69) performs no validation on the aggregator's bind configuration:
port: Number(s(env.PM_AGG_PORT, "4870"))— a bareNumber()with no integer/range check.hostsis split/trimmed/filtered with no non-empty check.
server.ts:807-817 then maps one Bun.serve per host and logs whatever port Bun reports.
Evidence (verified this run, main b2b885b9)
Probe 1 — loadConfig itself (bun, importing the real src/config.ts):
{PM_AGG_PORT:"0"}→port 0{PM_AGG_PORT:"abc"}→port NaN{PM_AGG_PORT:"4870.5"}→port 4870.5{PM_AGG_HOSTS:","}→hosts []{PM_AGG_HOSTS:" , "}→hosts []
Probe 2 — what Bun does with those ports (sandbox bun 1.4.4, Bun.serve on 127.0.0.1):
NaN,99999,-1,4870.5→RangeError [ERR_OUT_OF_RANGE]: The value of "options.port" is out of range…— the process dies at startup with an error that names neitherPM_AGG_PORTnor the accepted range, so an operator typo presents as a Bun internals crash.0→ binds a random ephemeral port (probe got 36279) andserver.tshappily logsaggregator listening on http://127.0.0.1:36279. Every consumer of the aggregator expects 4870, so the service is "up" in systemd terms and unreachable in practice — a silent misconfiguration, worse than a crash.hosts []→serversis an empty array, nothing is bound, nothing is logged, and the process exits 0 immediately — the unit looks like it ran fine while no dashboard exists.
Why it matters
The aggregator is the PM stack's single dashboard URL. Its only two bind knobs can each turn a one-character env typo into either a misleading crash or a silently absent/wrong-port service, and none of the failure modes name the offending variable. Sibling services in this repo already learned this lesson the hard way (the proxy fleet's strict parseProxyPort in bin/proxy-port.mjs exists for exactly this class).
Acceptance criteria
-
loadConfigrejects aPM_AGG_PORTthat is not an integer in 1–65535 (0 included — an ephemeral aggregator port is never useful) with an error namingPM_AGG_PORT, the received value, and the accepted range; the process fails at startup, before binding. -
loadConfigrejects aPM_AGG_HOSTSthat yields zero bind addresses with an error namingPM_AGG_HOSTS. - Valid configurations are unchanged: unset → port 4870, hosts
["127.0.0.1"]; explicit valid port/hosts pass through. - Tests for
loadConfigcover:"abc","0","-1","99999","4870.5"rejected;","/" , "hosts rejected; defaults accepted.
Triage should pin whether validation lives in loadConfig (throwing) or in server.ts before serving, and whether port 0 deserves a deliberate opt-in instead of a rejection.
Activity
developing-today commentedon Oct 29, 2026
CODE-1056
dezren39 commentedon Oct 29, 2026
🤖 Agent note · filed
dezren39 commentedon Oct 30, 2026
agent-note:v1 — design-architect pass 22 (2026-10-30): ADOPTED as Phase 2 of design #2835 (pm-stack services, with #2758/#2172): this issue lands via a per-app config helper in the aggregator's config.ts carrying the design's contract (digits-only, port 1-65535 with 0 invalid, hosts list non-empty after filter, boot failure naming the variable) plus the shared probe matrix as tests — not a one-off patch. Linked as a sub-issue of #2835 (verified in its sub_issues list). Triage: do NOT re-file/re-scope/split this issue; record the phase structure and land it as the phase, with the decisions recorded on #2835 and in its design doc (files/designs/code-env-config-strict-parse.md). This issue keeps its own queued triage packet.
19 remaining items
dezren39 commentedon Nov 2, 2026
agent-note:v1 — done — OpenChamber scheduled lane
bun test test/config.test.tspasses (6 tests, 48 assertions). Full suite has 951 passes and two unrelated failures reproduced on clean main; typecheck diagnostics also reproduce on clean main. PR CI is queued.dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
direct— this lane triages it at current main. Claim labels synced.dezren39 commentedon Nov 3, 2026
🤖 Agent note · triage verdict — already done, closing
443e1d91b). The fix landed as commit378c4d971"fix(aggregator): validate bind configuration" (2026-11-01), merged via PR fix(design-code): repoint :18745 legs to antigravity-direct :18751 (#1413, unblocks opencode#1409) #4626, after this issue's evidence was gathered atb2b885b9:pm-stack/aggregator/src/config.tsparseAggregatorPort: unset/blank → 4870; otherwise the value must match/^\d+$/and be a safe integer in 1–65535, else it throwsInvalid PM_AGG_PORT=<value>; expected a decimal integer in range 1-65535— naming the variable, the received value, and the range, atloadConfigtime (startup, before any bind). Port 0 is rejected; there is no opt-in — that pins the triage question the issue left open.parseAggregatorHosts: unset/blank →["127.0.0.1"]; a value yielding zero hosts (,,,) throwsInvalid PM_AGG_HOSTS=<value>; expected at least one non-empty host.pm-stack/aggregator/test/config.test.ts(added by the same commit) covers defaults, valid pass-through, and rejection of"0","abc","12.5","-1","99999","0x10","1e3","4870oops"and of","/" , , "hosts.bun test test/config.test.ts— 6 pass, 0 fail.already_done; claim labels removed by this lane.developing-today commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03