feat(helper)!: detach activations, freeze wire - #668
feat(helper)!: detach activations, freeze wire#668Alex Shabalin (alex-sparus) wants to merge 1 commit into
Conversation
This stack of pull requests is managed by jj-ryu. |
🎨 Storybook previewUpdated for 7b637c2
|
📋 PR Overview
🔬 Coverage
|
d71975f to
aedf770
Compare
aedf770 to
feff8d4
Compare
feff8d4 to
ad485a9
Compare
ad485a9 to
f1f2cbb
Compare
f1f2cbb to
9522ed4
Compare
| self.current.lock().unwrap_or_else(PoisonError::into_inner) | ||
| } | ||
|
|
||
| /// The `Status` answer, from live observation: this process's own memory |
There was a problem hiding this comment.
This calculation is surprisingly (to me, at least) complex, and I have general concerns about if there's any way for "status" to get persistently out of sync and therefore block the product behavior -- for example, due to a crash / restart / ungraceful termination of a process.
There was a problem hiding this comment.
With the help of AI:
There's no persisted status anywhere to get out of sync: every Status answer is recomputed live from one kernel flock probe, and the kernel releases a flock on any process death, crash and SIGKILL included. So a dead runner reads Idle on the next probe with zero cleanup code, and a restarted helper only loses the display-only details (it still reports Activating while the runner lives). "Blocked forever" would need the lock held forever, which needs a live process actually holding it — i.e. a real (or genuinely hung) activation, which Busy then reports truthfully.
The complexity that's visible here is one mutex for one narrow race (a status probe's momentary LOCK_SH turning a concurrent admission into a phantom Busy); the flock itself is the simplification — crash-consistency comes from the kernel instead of from code we'd have to get right.
aac483d to
a232b6c
Compare
9522ed4 to
157884e
Compare
Problem: SMAppService unregister kills the helper process, and the helper was the process running the root activation — so replacing the helper on upgrade risked interrupting a root mutation in flight. And whatever wire surface ships is a forever commitment: every future GUI must be able to talk to a helper of any older build. Solution: the helper only authenticates and admits. The activation runs in a forked no_std runner in its own session that survives unregister (the shipped plist gains AbandonProcessGroup, asserted by a test against the real resource), so terminating a helper interrupts nothing. The single activation slot is an exclusive flock on a never-unlinked lock file, shared with the password path's root executor, so "an activation is running" has one source of truth across helper generations and both paths. The cross-build wire is kept minimal — a frozen Status exchange plus three typed refusals, byte-pinned by golden tests — while TryActivate stays same-build-only and free to change. Connections close after the reply.
a232b6c to
93a823b
Compare
157884e to
7b637c2
Compare





Summary
Problem:
SMAppServiceunregister kills the helper process, and the helper was the process running the root activation — so replacing the helper on upgrade risked interrupting a root mutation in flight. And whatever wire surface ships is a forever commitment: every future GUI must be able to talk to a helper of any older build.Solution: the helper only authenticates and admits. The activation runs in a forked
no_stdsupervisor in its own session that survives unregister (the shipped plist gainsAbandonProcessGroup, asserted by a test against the real resource), so terminating a helper interrupts nothing. The single activation slot is an exclusiveflockon a never-unlinked lock file, shared with the password path's root executor, so "an activation is running" has one source of truth across helper generations and both paths. The cross-build wire is kept minimal — a frozenStatusexchange plus three typed refusals, byte-pinned by golden tests — whileTryActivatestays same-build-only and free to change. Connections close after the reply.Stacked on #667.
Test Plan
cargo testgreen: golden wire fixtures, flock admission/release (incl. unwind paths), real fork+supervise integration tests (exit codes, signal deaths, straggler cannot inherit the lock, capped log tail, profile-update warning)unregister,launchctl asuserkeeps working from the orphan, and a full real nix-darwin activation started before unregister ran to completion (exit 0) after itDocs
Prior review
peer_auth.rs(710 lines) is byte-identical to the version Scott approved in #619. Everything else here is the redesign that replaced #619's single-slot state machine — the detached runner, the flock slot, and the shrunken frozen wire — and is the part that needs a real review.