Summary
A Stacks site's main service could use release-local Bun while its generated scheduler and queues still used the host runtime. Add explicit SiteConfig.backgroundBun selection and bind opted-in workers to their physical release from process launch, including child PATH. Native entries validate the selected runtime before loading application work.
existing target -> drain managed work -> arm cleanup -> reset and stage
activation and health -> reconcile desired services, including empty -> prune
selected worker -> physical release and launch PATH -> application actionSame-ID retries drain before replacing files. Removing the last service still removes stale managed units. A refused stop or disable aborts before unit removal and pruning. Cleanup owns a replacement only after drain admission, while still deleting later failed partial releases. Successful default and Laravel runtime commands remain unchanged; shared stale-unit error handling now propagates refused lifecycle operations.
Evidence
- Before: two real Bun executables reproduced an A worker spawning its later bare Bun child from B after
currentswitched. In-process PATH mutation also failed because default Bun child spawning retains the launch environment. After: actual native scheduler and queue entries retain A, exact argv and child cwd through the switch. - Before: native keep-one pruning removed a live worker's runtime; native same-ID promotion removed its assets before it drained. After: actual SIGTERM/drain, original-generation reads and bare child completion precede same-ID replacement; native pruning still removes the drained old release at the configured count.
- Before: empty desired services skipped cleanup, refused manager operations still removed files, and the early EXIT trap deleted a non-current target after refused draining. After: maintained app/static wiring, actual filesystem refusal/success/sibling controls and real-trap failure controls cover preservation and subsequent owned cleanup.
- Final focused: 154 passing cases, zero failures. Final native full suite: 5,088 passes, 51 skips, two existing template TODOs, zero failures and 14,085 assertions across 375 files. Source and frozen lock hashes remained unchanged before/after qualification.
- Native lint reports zero errors/warnings; types, production package/UI build and 48-page docs build pass. The rendered configuration page includes the new runtime contract. Both independent review axes are clean across all 13 authored paths; earlier findings and original failures remain retained separately.
Refs #197. Exact-head CI passes lint, types and the production-build/full-test job. Native bun run release:patch, public-package qualification and Stacks/Open Farming adoption remain separate gates. Do not close the source issue merely on merging this PR.
Merge Danger
Door: Two-way source/configuration change. Existing-target retries deliberately stop managed background work before replacement; a failed replacement may leave it stopped until recovery deployment.
Blast Radius: Background services. Non-PHP release reconciliation now precedes count pruning, including removal of all services. Stop/disable refusal is fatal instead of silently deleting managed files. Qualification covers generated deployment phases, real finite native processes and owned filesystem effects; it does not claim a deployed systemd service or physical operation. No installed-package patch, production unit rewrite, global runtime replacement or application data migration is included.