What
agent-computer/src/env.ts:23-33 numberFromEnv does Number(raw) + isFinite + > 0, with no integer check and no upper bound / port range.
So PORT=80.5, PORT=99999, NAVIGATION_TIMEOUT_MS=0.5, ACTION_TIMEOUT_MS=0.1, COMPUTER_MAX_BROWSERS=2.5, COMPUTER_BROWSER_IDLE_MS=0.5 all pass and are returned verbatim. Existing tests (agent-computer/tests/number-from-env.test.ts) cover empty/non-numeric/zero/negative/Infinity but never fractions or ranges.
Downstream: Bun.serve({port: 80.5 | 99999}) throws/misbinds at boot (a deployment failure instead of the documented fallback); a 0.5ms Playwright timeout makes every action fail as a 502 that reads as a broken computer; chooseEvictions gets a fractional cap.
Siblings already do the strict thing: supervisor/src/listen-port.ts (trim + /^\d+\$/ + 1..65535) and supervisor/src/computer-memory-bytes.ts (/^\d+\$/).
Repro
PORT=80.5 bun run ... → 80.5 returned instead of fallback; serve misbinds.
PORT=99999 → returned instead of fallback.
COMPUTER_MAX_BROWSERS=2.5 → 2.5 reaches eviction math.
Expected: fractions, non-integers and out-of-range values take the fallback; plain integers (with surrounding whitespace) still pass; zero semantics (zeroSwitchesItOff) unchanged.
Where it runs
The computer process at boot/env read. Per-process pure function of env; same fallback on every replica. No shared state, no fan-out.
Fix sketch
Strict integer path mirroring listenPort: trim → /^\d+\$/ → parseInt → range check (port 1..65535 for PORT; integer > 0 / >= 0 elsewhere). Keep empty→fallback and zero semantics. Extend number-from-env.test.ts with fractional/range cases.
What
agent-computer/src/env.ts:23-33 numberFromEnvdoesNumber(raw)+isFinite+> 0, with no integer check and no upper bound / port range.So
PORT=80.5,PORT=99999,NAVIGATION_TIMEOUT_MS=0.5,ACTION_TIMEOUT_MS=0.1,COMPUTER_MAX_BROWSERS=2.5,COMPUTER_BROWSER_IDLE_MS=0.5all pass and are returned verbatim. Existing tests (agent-computer/tests/number-from-env.test.ts) cover empty/non-numeric/zero/negative/Infinity but never fractions or ranges.Downstream:
Bun.serve({port: 80.5 | 99999})throws/misbinds at boot (a deployment failure instead of the documented fallback); a 0.5ms Playwright timeout makes every action fail as a 502 that reads as a broken computer;chooseEvictionsgets a fractional cap.Siblings already do the strict thing:
supervisor/src/listen-port.ts(trim +/^\d+\$/+ 1..65535) andsupervisor/src/computer-memory-bytes.ts(/^\d+\$/).Repro
PORT=80.5 bun run ...→ 80.5 returned instead of fallback; serve misbinds.PORT=99999→ returned instead of fallback.COMPUTER_MAX_BROWSERS=2.5→ 2.5 reaches eviction math.Expected: fractions, non-integers and out-of-range values take the fallback; plain integers (with surrounding whitespace) still pass; zero semantics (
zeroSwitchesItOff) unchanged.Where it runs
The computer process at boot/env read. Per-process pure function of env; same fallback on every replica. No shared state, no fan-out.
Fix sketch
Strict integer path mirroring
listenPort: trim →/^\d+\$/→ parseInt → range check (port 1..65535 for PORT; integer > 0 / >= 0 elsewhere). Keep empty→fallback and zero semantics. Extendnumber-from-env.test.tswith fractional/range cases.