Keep background commands' startup image alive across daemon exits
Fixes the Linux merge-queue failure where a background command never started: sandbox_unavailable: ... openat2 secure walk failed for .../run/aft-pinned-<pid>-<start>: No such file or directory.
Cause. In daemon mode AFT pins its startup executable into <storage>/run/aft-pinned-<pid>-<start>/ and launches sandbox-launch and the gh shim from it (#1151). When the daemon exits on connection loss, its clean-exit path removes that directory. A detached background task whose sandbox-launch was still applying its profile then pointed at a folder that no longer existed. Crash-restart cleanup of dead pins had the same lifetime mismatch, and any background command outliving a restart lost its gh shim.
Fix.
- Each native task hard-links (or byte-copies) the startup image and
ghshim into its own task bundle before either sandbox backend builds its profile, so the profile and the child environment name paths the task owns. A daemon exit or restart can remove its own pin without breaking detached tasks. - A live daemon's pin holds a kernel owner lease, so dead-pin cleanup can't delete it on misleading PID or start-time data.
- A missing daemon pin is rebuilt from the held startup-image handle and logged, never from a replacement binary at the deploy path.
- Explicitly configured binary targets are unchanged.
Tests. scope_end_kill::connection_loss_preserves_pin_until_delayed_sandbox_and_shim_run holds the sandbox start across a daemon exit and failed before the fix. Unit tests cover cleanup against a live process, the lease overriding a mismatched clock, task images outliving the daemon pin, and repair from the held image. Landlock probes ran on the build server's new image, and the Seatbelt delayed-launch window passed on a macOS build machine. A separate test-only commit retries ETXTBSY when the replacement test executes a freshly copied binary (a sibling test's fork can briefly hold the copy open for writing).
Build server (main merged): 215 pin/sandbox/child-env lib tests, 15 scope_end_kill tests, 3 executable-replacement tests three times, formatting and the Windows check passed. No agent-visible text, tool schema or config change.
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes detached background tasks losing their startup executable when the daemon exits or restarts mid-sandbox-start.
- Each native task now hard-links the startup image and
ghshim into its own task bundle before the sandbox profile is built. - Daemon pin cleanup now honors a kernel owner lease, so dead-pin cleanup can't remove a live daemon's pin on misleading PID or start-time data.
- A missing daemon pin is rebuilt from the held startup image handle, never from a replacement binary at the deploy path.
- Adds a test-only start gate that holds
sandbox-launchacross a daemon exit, reproducing the original failure; includes an ETXTBSY retry for the replacement-executable test on Linux.
Migration
None. Explicitly configured binary targets and non-daemon hosts are unchanged.