You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since 07-14, six drivers spawned and only ONE got a ledger completion line (a 30s rc=1 run). The other five died ledger-less — the fingerprint of the DAEMON being killed mid-driver: the ledger write is the daemon's last act after a driver exits, so a missing line means the daemon died first and systemd's default KillMode=control-group took the whole cgroup — driver, orchestrator, implementers, reviewers — down with it. setsid does not help: cgroup membership ignores process groups.
Confirmed killers: the 07-14 09:33 CEST service restart (killed the #107 driver post-commit/pre-push → wedge, recovered manually as PR #117), overnight VM downtime 07-15 (01:18Z driver died before scoping), and a ~06:19Z daemon death (killed the #106 driver 13 min into implementation, leaving dirty-worktree debris). The 07-14 tick stream shows a restarted daemon ticking 2 minutes after a driver spawn that should have been blocking it.
Root problem: driver lifetime is coupled to daemon lifetime, and the daemon's environment (WSL2 host: sleep, reboot, wsl --shutdown, service restarts) is not always-on.
Design
Spawn each driver as a transient systemd unit, not a daemon child:
The driver's parent becomes the user manager, so Restart=always bouncing the daemon (or the daemon crashing) no longer kills it; the daemon's systemd-run --wait is just a disposable waiter that blocks and propagates the exit code — run_driver's ledger logic is unchanged.
RuntimeMaxSec replaces the timeout wrapper as the hard ceiling: it is enforced by the user manager, which outlives the daemon. (Today's timeout 90m dies WITH the daemon, so an orphaned driver currently has NO ceiling — the current design is strictly worse.)
Keep the current setsid timeout ... spawn as the fallback when systemd-run is unavailable (legacy-cron path, non-systemd environments).
Ops / halt helper: a daemon restart no longer stops drivers — document the new commands and add loop-halt.sh:
one driver: systemctl --user stop pr-loop-driver-issue106
all drivers: systemctl --user stop 'pr-loop-driver-*'
everything: loop-halt.sh → stops the daemon unit AND all driver units.
Update USAGE.md's daemon + failure-contract sections accordingly (the "restart kills in-flight drivers" caveat documented there flips to "restart is driver-safe" once this lands).
Tests (loop-daemon.test.sh, systemd-run stub on fixture PATH): unit naming derived from the verdict; RuntimeMaxSec passed through from LOOP_DRIVER_TIMEOUT; exit-code propagation into the ledger line; re-attach scenario (stubbed active unit → no new spawn, waits, then ledgers); fallback to setsid+timeout when the systemd-run stub is absent.
Complementary, not overlapping: this issue eliminates the restart-collateral kill class (daemon bounce no longer destroys work in flight). #111's post-exit/startup debris classifier heals what still dies — host reboot, sleep, wsl --shutdown kill everything regardless, and nothing can prevent that. The startup re-attach here is the natural place to invoke #111's verification for drivers that finished while no daemon was watching.
Evidence (2026-07-14 → 2026-07-15)
Since 07-14, six drivers spawned and only ONE got a ledger completion line (a 30s rc=1 run). The other five died ledger-less — the fingerprint of the DAEMON being killed mid-driver: the ledger write is the daemon's last act after a driver exits, so a missing line means the daemon died first and systemd's default
KillMode=control-grouptook the whole cgroup — driver, orchestrator, implementers, reviewers — down with it.setsiddoes not help: cgroup membership ignores process groups.Confirmed killers: the 07-14 09:33 CEST service restart (killed the #107 driver post-commit/pre-push → wedge, recovered manually as PR #117), overnight VM downtime 07-15 (01:18Z driver died before scoping), and a ~06:19Z daemon death (killed the #106 driver 13 min into implementation, leaving dirty-worktree debris). The 07-14 tick stream shows a restarted daemon ticking 2 minutes after a driver spawn that should have been blocking it.
Root problem: driver lifetime is coupled to daemon lifetime, and the daemon's environment (WSL2 host: sleep, reboot,
wsl --shutdown, service restarts) is not always-on.Design
Restart=alwaysbouncing the daemon (or the daemon crashing) no longer kills it; the daemon'ssystemd-run --waitis just a disposable waiter that blocks and propagates the exit code —run_driver's ledger logic is unchanged.RuntimeMaxSecreplaces thetimeoutwrapper as the hard ceiling: it is enforced by the user manager, which outlives the daemon. (Today'stimeout 90mdies WITH the daemon, so an orphaned driver currently has NO ceiling — the current design is strictly worse.)setsid timeout ...spawn as the fallback whensystemd-runis unavailable (legacy-cron path, non-systemd environments).run_once, checksystemctl --user list-units 'pr-loop-driver-*'. If a driver unit is still active, WAIT for it instead of ticking (no duplicate driver, no premature debris classification), then run Loop: driver one-shot contract needs enforcement + tests — background orchestration produced phantom-success drivers and wedged the queue #111's post-exit verification on its outcome. Census additionally must never advance an issue whose driver unit is active.loop-halt.sh:systemctl --user stop pr-loop-driver-issue106systemctl --user stop 'pr-loop-driver-*'loop-halt.sh→ stops the daemon unit AND all driver units.Update USAGE.md's daemon + failure-contract sections accordingly (the "restart kills in-flight drivers" caveat documented there flips to "restart is driver-safe" once this lands).
loop-daemon.test.sh, systemd-run stub on fixture PATH): unit naming derived from the verdict;RuntimeMaxSecpassed through fromLOOP_DRIVER_TIMEOUT; exit-code propagation into the ledger line; re-attach scenario (stubbed active unit → no new spawn, waits, then ledgers); fallback to setsid+timeout when the systemd-run stub is absent.Interaction with #111 / #98
Complementary, not overlapping: this issue eliminates the restart-collateral kill class (daemon bounce no longer destroys work in flight). #111's post-exit/startup debris classifier heals what still dies — host reboot, sleep,
wsl --shutdownkill everything regardless, and nothing can prevent that. The startup re-attach here is the natural place to invoke #111's verification for drivers that finished while no daemon was watching.🤖 Generated with Claude Code