go-test-port-collision-stray-daemon
Solution written to ~/go-test-port-collision-stray-daemon.md (217 lines). Summary:
A previous tick booted a scratch daemon (HOME=~/trbl008-home bin/troubled ...) bound to the fixed dashboard port <ip-address>:7644 and never tore it down. The next tick's TestPreflightBinds* — a port-availability preflight, not the code under test — fails with bind: address already in use. That's a false red, not a regression.
Immediate (prove-then-kill, never pkill -f):
PORT=7644
ss -tlnp | grep ":$PORT" # name holder pid -> users:(("troubled",pid=NNNN,...))
ps -o pid=,lstart=,etime=,cmd= -p NNNN # date it; earlier than this tick = not yours
ps -o lstart= -p "$$" # compare to current tick
kill NNNN && sleep 1
ss -tlnp | grep ":$PORT" && kill -9 NNNN
go test ./... -run 'TestPreflightBinds' -count=1
pkill -f troubled matches your own shell/test command — use PID only.
Permanent: bind scratch daemons to an ephemeral port instead of 7644, and reap on every exit path:
- Go tests: reserve net.Listen("tcp","<ip-address>:0"), or start the daemon with --addr <ip-address>:0 and read the chosen port back; register t.Cleanup(d.Stop) so t.Fatal still reaps it.
- Shell scripts: capture DAEMON_PID=$! and trap cleanup EXIT INT TERM, using kill "$DAEMON_PID"; keep a unique scratch HOME per tick.
ss -tlnp | grep ':7644' || echo "OK: port free"
ps -o pid=,cmd= -C troubled 2>/dev/null || echo "OK: no stray daemon"
go test ./... -run 'TestPreflightBinds' -count=5 -v
go test ./... -count=1
ss -tlnp | grep ':7644' || echo "OK: suite released :7644"
On this host right now all checks pass: no listener on :7644, no troubled process, no ~/trbl008-home — confirming the leak is intermittent/cross-tick rather than a standing bug. The full runbook includes a drop-in testutil.FreePort helper, a self-reaping scratch-boot script, and a CI orphan-listener guard.
# Evidence - Problem class: go-test-port-collision-stray-daemon - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-19T12:23:36.692Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Go suite red on TestPreflightBinds* with TROUBLE-LIFECYCLE-003 bind: address already in use on <ip-address>:7644. Diagnosis: an EARLIER tick left a scratch daemon booted from its own HOME (HOME=~/trbl008-home bin/troubled ...) holding the documented dashboard port; the failing test was a port-availability preflight, not the code under test. Probe order that settles it: ss -tlnp | grep <port> to name the holder pid, ps -o lstart on that pid to date it (before this tick = not yours), then kill BY PID (never pkill -f, which matches your own shell) and re-run the suite for a green. Lesson: a per-tick scratch boot must be torn down or bound to a scratch port, otherwise the NEXT tick pays a false-red suite and may misread it as a regression.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-test-port-collision-stray-daemon", "provider": "openrouter", "solved_at": "2026-09-19T12:23:36.692Z", "version": ""}Solution written to ~/go-test-port-collision-stray-daemon.md (217 lines). Summary:
A previous tick booted a scratch daemon (HOME=~/trbl008-home bin/troubled ...) bound to the fixed dashboard port <ip-address>:7644 and never tore it down. The next tick's TestPreflightBinds* — a port-availability preflight, not the code under test — fails with bind: address already in use. That's a false red, not a regression.
Immediate (prove-then-kill, never pkill -f):
PORT=7644
ss -tlnp | grep ":$PORT" # name holder pid -> users:(("troubled",pid=NNNN,...))
ps -o pid=,lstart=,etime=,cmd= -p NNNN # date it; earlier than this tick = not yours
ps -o lstart= -p "$$" # compare to current tick
kill NNNN && sleep 1
ss -tlnp | grep ":$PORT" && kill -9 NNNN
go test ./... -run 'TestPreflightBinds' -count=1
pkill -f troubled matches your own shell/test command — use PID only.
Permanent: bind scratch daemons to an ephemeral port instead of 7644, and reap on every exit path:
- Go tests: reserve net.Listen("tcp","<ip-address>:0"), or start the daemon with --addr <ip-address>:0 and read the chosen port back; register t.Cleanup(d.Stop) so t.Fatal still reaps it.
- Shell scripts: capture DAEMON_PID=$! and trap cleanup EXIT INT TERM, using kill "$DAEMON_PID"; keep a unique scratch HOME per tick.
ss -tlnp | grep ':7644' || echo "OK: port free"
ps -o pid=,cmd= -C troubled 2>/dev/null || echo "OK: no stray daemon"
go test ./... -run 'TestPreflightBinds' -count=5 -v
go test ./... -count=1
ss -tlnp | grep ':7644' || echo "OK: suite released :7644"
On this host right now all checks pass: no listener on :7644, no troubled process, no ~/trbl008-home — confirming the leak is intermittent/cross-tick rather than a standing bug. The full runbook includes a drop-in testutil.FreePort helper, a self-reaping scratch-boot script, and a CI orphan-listener guard.
# Evidence - Problem class: go-test-port-collision-stray-daemon - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-19T12:23:36.692Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Go suite red on TestPreflightBinds* with TROUBLE-LIFECYCLE-003 bind: address already in use on <ip-address>:7644. Diagnosis: an EARLIER tick left a scratch daemon booted from its own HOME (HOME=~/trbl008-home bin/troubled ...) holding the documented dashboard port; the failing test was a port-availability preflight, not the code under test. Probe order that settles it: ss -tlnp | grep <port> to name the holder pid, ps -o lstart on that pid to date it (before this tick = not yours), then kill BY PID (never pkill -f, which matches your own shell) and re-run the suite for a green. Lesson: a per-tick scratch boot must be torn down or bound to a scratch port, otherwise the NEXT tick pays a false-red suite and may misread it as a regression.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-test-port-collision-stray-daemon", "provider": "openrouter", "solved_at": "2026-09-19T12:23:36.692Z", "version": ""}