The rc.d "rm stale socket on prestart" fix (07e4660) was a band-aid over
two daemon-side defects that surfaced on the live FreeBSD host:
1. colibri-daemon never handled SIGTERM. main.rs awaited only ctrl_c()
(SIGINT), so `service stop`/`restart` — which sends SIGTERM via
daemon(8) to the child — killed it on the default disposition with no
cleanup. The graceful path (socket removal, agent reaping) never ran,
leaking the socket file and orphaning spawned agents across restarts.
Now wait_for_shutdown_signal() selects on SIGTERM or SIGINT, so the
same graceful path runs on a normal service stop. New integration test
(tests/sigterm_shutdown.rs) spawns the binary, sends SIGTERM, and
asserts the socket is removed.
2. Stale-socket cleanup had no liveness check — both the daemon
(socket.rs) and the rc prestart would unconditionally rm the socket
before bind, which could delete a *running* instance's socket if
rc.subr's pid detection misfires and starts a second daemon. Cleanup
now probes first (clear_stale_socket): connect succeeds -> refuse to
start; refused/dead -> remove and bind. Unit-tested for absent, stale,
and live cases.
With the daemon owning safe socket cleanup, the rc prestart no longer
removes the socket (only stale pidfiles), eliminating the restart-time
clobber hazard. This also makes the SIGTERM shutdown described in
ISO-SERVICE-LAYOUT.md (PR #75) actually true.
Gates: cargo fmt --check, clippy -D warnings, cargo test --workspace all
green on Linux; sh -n on the rc script OK. FreeBSD runtime validation
still pending per FREEBSD-BUILD-LANE-HANDOFF.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>