Skip to content

fix(daemon): publish the Git transaction owner with authority - #2817

Merged
ScriptedAlchemy merged 1 commit into
masterfrom
fleet/audit-leftovers-daemon-owner-order
Oct 1, 2026
Merged

ScriptedAlchemy merged 1 commit into
masterfrom
fleet/audit-leftovers-daemon-owner-order

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Refs #2612

Root cause

Project open published each Git transaction owner when ensure started its service, and installed the owner's authority later in register_project_open_production_owners. The authority slot was therefore an Option, and #2612 had to hide an authority-less owner in for_repository_root (!entry.authority.installed()) so requests in that window answered mounting instead of a policy denial. Shutdown cleared the same Option, so a request that had already resolved an owner saw PolicyDenied. Git reads concealed it as not_found_or_not_authorized instead of reporting that the daemon was going away.

Change

  • DaemonGitIndexTransactionServiceRegistry::mount constructs the production authority first. It then starts the service around it and inserts the entry in one step under the creation gate. Remounting the same identity reuses the started service and replaces its authority in place. A second identity at the same root is refused before any service starts, so no orphaned authority-less entry is left behind.
  • The slot is Installed(source) | Revoked; there is no empty state. Shutdown revokes it, and a revoked owner answers DaemonUnavailable.
  • Git reads map authority errors through map_git_port_problem instead of concealing them all, so a revoked owner reports git_index.unavailable. PolicyDenied is still concealed as not_found_or_not_authorized.
  • Deleted: ensure, ensure_with, existing, install_authority, DaemonGitAuthoritySlot::{installed, clear}, the engine wrapper ensure_git_index_transactions_for_mutation_owners (with its fabricated map_or(0)/unwrap_or(i64::MAX) clock), the git_transactions_ready phase, and the PendingFullServerOwners.session_db field that existed only to feed it. Durable Git transaction recovery still runs before the source-edit mutation lane opens: mount sits immediately before source_edit_mutation.mark_ready().

Fails on origin/master

The owner resolved before shutdown must report the daemon going away. On origin/master (d4835ab), using the master API (ensure + install_authority):

thread 'git_transactions::tests::daemon_owner_resolved_before_shutdown_reports_unavailable_not_denied' panicked at crates/tracedecay-code-index-runtime/src/git_transactions/tests.rs:980:5:
assertion `left == right` failed: a request already routed to the owner must see the daemon shutting down, not an authority-missing policy denial
  left: Some(PolicyDenied)
 right: Some(DaemonUnavailable)
test result: FAILED. 4 passed; 1 failed

On this branch the same assertion lives in daemon_owner_shutdown_fences_admission_clears_services_and_joins_store_actor and passes.

daemon_owner_racing_a_cold_mount_is_absent_until_published_with_authority drives the cold-mount race deterministically. The store open inside mount blocks on a release channel the test holds. While it is held, for_repository_root returns None (callers answer application.runtime.mounting). After release, the resolved owner is the mounted service (Arc::ptr_eq) and carries the literal installed authority (policy_revision 7, digest('1')). On master the same window was already hidden by the installed() guard. This test guards the new ordering; the shutdown assertion above is the one that fails on master.

Runtime journey (built tracedecay debug CLI, isolated HOME, ZeroFS clone, daemon under systemd-run --user --scope -p MemoryMax=6G -p MemorySwapMax=1G)

$ tracedecay init
initialized .../scratch/p1/corpus; daemon code-index reconciliation requested
$ tracedecay tool tracedecay_git_status --args '{}'      # issued during and right after the open
## git\_status
    "query": "status", ... "head": { "branch": "develop", "commit": "922cbcf94f65c2ffd2ca575aef0894e2fd3e0bb1", "state": "attac...

Verification

  • cargo test -p tracedecay-code-index-runtime --lib git_transactions::: 45 passed.
  • cargo test -p tracedecay-code-index-runtime -p tracedecay-daemon-service -p tracedecay --lib --features tracedecay/test-helpers,tracedecay/test-transport -- git: 123 + 7 + 24 passed. This includes daemon::tests::socket::socket_git_preview_apply_replay_and_pre_admission_problems_are_canonical, daemon::tests::bootstrap::shutdown_fences_git_index_transactions_and_joins_store_actors (a real project open mounts exactly one owner), and daemon::project_open_owners::git_catalog_tests::git_owner_uses_explicit_canonical_catalog_and_rechecks_authorization (remount replaces the authority; revoked and expired grants deny).
  • cargo clippy -p tracedecay-code-index-runtime -p tracedecay-daemon-service -p tracedecay --all-targets --features tracedecay/test-helpers,tracedecay/test-transport -- -D warnings: clean.
  • cargo fmt --all -- --check: clean.
  • cargo check --workspace --all-targets --target x86_64-pc-windows-gnu --features tracedecay/test-transport,tracedecay/test-helpers,tracedecay-cli/test-transport: exit 0.
  • ripwire --quality-delta=HEAD: I fixed the duplicated test preamble by folding the revoked-owner assertion into the existing shutdown test. The remaining duplication rows match struct-constructor token shapes in unrelated crates, with nothing to share.

Re-verified after rebase on 964c3d7 (lane recovered after the 2026-10-01 restart)

  • cargo test -p tracedecay-code-index-runtime -p tracedecay-daemon-service -p tracedecay --lib --features tracedecay/test-helpers,tracedecay/test-transport -- git: 122 + 7 + 24 passed.
  • clippy -D warnings (same crates, --all-targets) and cargo fmt --all -- --check: clean.

Project open published each Git transaction owner when it started the
service and installed the owner's authority later, so the slot held an
Option and every lookup had to hide an authority-less owner as still
mounting. Shutdown cleared the same Option, so a request that had
already resolved an owner saw a policy denial instead of the daemon
going away.

`mount` now starts the service around an authority it has already
constructed and inserts the entry in one step; remounting the same
identity replaces the authority in place. The slot is `Installed` or
`Revoked`, and a revoked owner answers `DaemonUnavailable`, which Git
reads now map through the typed port problem instead of concealing it.
The engine-side `ensure` wrapper, `install_authority`, the `installed`
guard, and the session database threaded only to feed them are gone.

Refs #2612
@changeset-bot

changeset-bot Bot commented Oct 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8348a3d

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.

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

@ScriptedAlchemy ScriptedAlchemy changed the title fix(daemon): publish the Git transaction owner with its authority fix(daemon): publish the Git transaction owner with authority Oct 1, 2026
@ScriptedAlchemy
ScriptedAlchemy merged commit d40430b into master Oct 1, 2026
14 of 23 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the fleet/audit-leftovers-daemon-owner-order branch October 1, 2026 22:21
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