Skip to content

feat(helper): service-management adapter and primitives - #620

Closed
Alex Shabalin (alex-sparus) wants to merge 1 commit into
alex/fix-helper-e1afrom
alex/fix-helper-e1b
Closed

feat(helper): service-management adapter and primitives#620
Alex Shabalin (alex-sparus) wants to merge 1 commit into
alex/fix-helper-e1afrom
alex/fix-helper-e1b

Conversation

@alex-sparus

@alex-sparus Alex Shabalin (alex-sparus) commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • prepares primitives for the helper service management
    internal code E1b

Test Plan

  • Manual testing of a CI-build artifact

Docs

  • Docs updated (companion PR in darkmatter/nixmac-web: #___)
  • No docs update needed

@alex-sparus

Alex Shabalin (alex-sparus) commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by jj-ryu.

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

No Linear issue ID found in this PR's title, description, or branch name (expected something like ENG-123). Add one so this work is traceable in Linear, or add #no-linear to the PR description to acknowledge it's intentionally untracked.

⚠️ PR is marked WIP / draft — do not merge until ready for review.
⚠️ ❗ Big PR (1810 lines changed). Consider splitting it into smaller, focused changes.

📋 PR Overview

Lines changed 1810 (+1704 / -106)
Files 1 added, 14 modified, 0 deleted
Draft / WIP yes
Has Test Plan yes
Linear issue no
No Test Plan Needed no
New UI components no
New Storybook stories no
New Rust modules yes (1)
New TS source files no
New tests no
package.json touched no
Cargo.toml touched yes
Infra / CI touched no

🔬 Coverage

Report Lines Statements Functions Branches
apps/native/coverage/coverage-summary.json 35.6% 35.2% 30.5% 29.5%

Generated by 🚫 dangerJS against a21e004

@darkmatter

darkmatter Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🎨 Storybook preview

Open Storybook preview

Updated for a21e004


⚠️ Detected UI changes (5)

These stories' HTML snapshots changed. I've added screenshots + links to the changed stories below. Review them carefully then accept the changes to regenerate baselines and include them in this PR:

Flows/Evolve › Playground

Flows/Evolve › Playground

Flows/Evolve › 1. Begin (idle)

Flows/Evolve › 1. Begin (idle)

Flows/Evolve › 2. Evolving (progress)

Flows/Evolve › 2. Evolving (progress)

Flows/Evolve › Evolving With Error Event

Flows/Evolve › Evolving With Error Event

Flows/Evolve › 3. Review (changes generated)

Flows/Evolve › 3. Review (changes generated)


Accept UI changes

  • Click here to accept these changes

Alternatively, you can run bun run test:update-snapshots locally to re-generate the baselines and then push the changes to this PR.

What does this do?

The screenshots above show UI changes detected by the Storybook
snapshot tests run on this PR. Each image is the rendered output of
a Storybook story from the code in this PR branch; the snapshot
test compared it against the committed baseline in
__snapshots__/ and flagged the difference.

Checking the box tells the darkmatter[bot] to regenerate the
baselines from this PR's current code and commit them directly to
this branch. The new baselines become the source of truth for
future runs — only accept after confirming the visual changes are
intentional.

Comparison baseline: the committed __snapshots__/ files on this
PR branch (carried forward from develop). Accept updates them in
place on this branch.

@alex-sparus
Alex Shabalin (alex-sparus) force-pushed the alex/fix-helper-e1a branch 4 times, most recently from e171392 to a4109c4 Compare August 3, 2026 11:32
@alex-sparus Alex Shabalin (alex-sparus) changed the title feat(helper): add lifecycle drain and agent handoff feat(helper): service-management adapter and primitives Aug 3, 2026
/// A raw value outside this set is an adapter error, never a fifth status:
/// every reconciliation decision is a total match over these four, and a
/// catch-all would let an unreadable registration pass for one of them.
// Only the macOS adapter reads a raw status, so off Apple nothing constructs

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably meant to be a /// comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this is a neat trick: only /// will appear as the documentation and the // part is just a comment about building on non-macOS (allow(dead_code) etc)

@@ -0,0 +1,318 @@
// Observation of the helper socket: is anything listening on it?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explanation from AI:

Four files in this module (protocol.rs, peer_auth.rs, client.rs, helper_runtime.rs) are include!d into the helper and sync-agent binaries, where //! is a hard error (E0753) — see the note at peer_auth.rs:17. socket_probe.rs isn't include!d, so //! would compile here, but keeping one header style across the module means nobody has to work out which files may take it. Only upside would be rustdoc on an internal module.

return Ok(false);
}

adopt_legacy_fields(prefs, |key| store.get(key))?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really be able to quit supporting legacy migration and rip that code out since I think it predates the major launch by a significant amount, especially for newly added preferences. I will enter an issue about this.

Swap the hand-rolled objc SMAppService calls for
objc2-service-management and add the observations and effects a helper
replacement needs. Behavior-preserving: the existing facade keeps its
callers and everything new is caller-less.

- The published wrapper crates offer neither the asynchronous unregister
  nor a typed status. The async form is the point: its completion fires
  only after the running helper has been killed, which is the one signal
  that makes re-registering safe, and the synchronous call returns
  before the process is reaped.
- A replacement refuses a main-thread caller up front. Both calls are
  issued on the main queue, so awaiting them there starves the queue
  that has to make them and reads back as a callback that never
  arrived — a wrong diagnosis of a deadlock we can rule out instead.
- Registering only once the unregister has reported is also Apple's
  workaround for an immediate re-registration failing: the second
  dispatch is unavoidably a later run-loop turn than the first.
- Stamp the build ID into the bundle's Info.plist, because a running GUI
  has to be able to tell that its bundle was replaced underneath it. One
  resolution feeds both the compiled constant and the stamp, so they
  cannot disagree; the tracked plist becomes a template so only the
  stamped copy is merged and one file reaches the bundle.
- The helper preference is tri-state, not a boolean: `unset` is what
  lets an existing registration be adopted as an earlier opt-in without
  that adoption overriding an explicit disable. It is device-local, so
  settings import and the legacy-store migration leave it alone — no
  other machine's file, and no key in the old store, decides whether
  this Mac runs a privileged helper.
- Positive absence is deliberately narrow: a refusal or a missing socket
  across a bounded window, never a timeout or anything else ambiguous.
  It is one of the few observations that authorizes terminating a
  registration, so an unproven absence has to stay unproven.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants