Skip to content

feat(daemon): Reaper#3087

Open
kriskowal wants to merge 7 commits intokriskowal-daemon-replyfrom
kriskowal-daemon-collector
Open

feat(daemon): Reaper#3087
kriskowal wants to merge 7 commits intokriskowal-daemon-replyfrom
kriskowal-daemon-collector

Conversation

@kriskowal
Copy link
Member

Description

This change introduces a garbage collector to the daemon. The user level requirement is that, if a user deletes every pet name in their local user agent that ultimately retains a formula, we must revoke the corresponding live reference. This is sufficient for purposes of security, but creates an incentive for developers on the platform to create elaborate accommodations for the sudden revocation of live references and the reestablishment of a fresh live reference from "sturdy" paths. To mitigate this, the daemon instead elects to obligate developers to tolerate a restart if a worker is contaminated with a live reference to a revoked capability. So, in this change, we also cancel (deincarnate) any value for which the formula has been collected, and any value that transitively dependended upon a collected formula for its construction, and furthermore reincarnate that value if it is still retained from PINS.

Formula collection is a deterministic garbage collector for the formula graph. Formulas that become unreachable from the root are cancelled, their persistence files deleted, and any CapTP connections or workers still holding references are disconnected or terminated.

The collector uses a union-find structure to group formulas that share identity (agent+handle, promise+resolver) so they are collected atomically. A refcount over the group-level dependency graph drives collection. Pet store writes and removals maintain dynamic edges. Collection runs inside formulaGraphJobs and is triggered in the finally block of every host and guest command, ensuring the graph is consistent before any command returns.

New modules extracted from daemon.js:

  • graph.jsmakeFormulaGraph: union-find, dependency tracking, root set, dirty flag.
  • residence.jsmakeResidenceTracker: CapTP export/import hooks that track which connections retain which formulas, and disconnectRetainersHolding to sever connections to collected values.

Pet store path construction and deletion were consolidated into pet-store.js, removing duplication with daemon-node-powers.js.

Security Considerations

Formula collection introduces a new authority boundary: when a formula is collected, its live value is cancelled and its CapTP connection is severed. The error message intentionally avoids leaking formula internals, stating only that a formula "became unreachable by any pet name path and was collected." Workers hosting collected values are terminated to prevent use-after-free of stale references.

Scaling Considerations

Collection is O(formulas + edges) per pass but runs only when the graph is dirty. The dirty flag avoids redundant passes. Transient roots prevent premature collection during command execution without holding the formula graph lock.

Documentation Considerations

Not yet addressed. This feature will obligate the user interface to provide a tutorial on revocation, for which is not yet sufficient support to write. A user will need to be able to inspect local retention paths to a petnamed capability.

Testing Considerations

Nine new tests in packages/daemon/test/endo.test.js:

  • Collects formulas after pet name removal
  • Terminates worker retaining collected values
  • Terminates worker retaining derived value after dependency collection
  • Recreates counter after collection resets state
  • PINS values survive collection
  • PINS values reincarnate after cancellation
  • Facet group (agent + handle) collects atomically
  • Unnamed eval results are collected
  • Reply and threading tests (reply links to parent, metadata naming)

Compatibility Considerations

No breaking changes. The collector is always active — there is no feature flag. Existing formulas that are reachable from roots are never collected. The endo reply command is additive.

Upgrade Considerations

No migration needed. Existing daemon state is seeded into the formula graph on boot. Unreachable formulas left over from prior sessions will be collected on the first command after upgrade.

@changeset-bot
Copy link

changeset-bot bot commented Feb 13, 2026

⚠️ No Changeset found

Latest commit: 2f0e365

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@kriskowal kriskowal changed the base branch from master to kriskowal-daemon-reply February 13, 2026 13:51
@kriskowal kriskowal marked this pull request as ready for review February 17, 2026 16:23
@rekmarks rekmarks self-requested a review February 20, 2026 04:25
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.

1 participant