fix(daemon): serve reset-required stores as a typed state - #2263
Conversation
A registered store whose persisted shape this binary does not open no longer stops the daemon. It stays unmounted in a typed reset-required state that status, doctor, and initialize name with the exact reset command; update's restore accepts such a daemon and exits 75 on the named reset instead of wiping the profile itself. Fixes #2230
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 88560a6a78
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Box::pin(attach_reset_required_stores( | ||
| response, | ||
| &engine.store_administration, | ||
| )) |
There was a problem hiding this comment.
Add reset metadata to every initialize route
The reset metadata is attached only in the Unix bootstrap branch. I checked the portable Windows broker and routed RMCP paths: the former writes its bootstrap response without this call, while the latter's decorator adds only route metadata. Because query_daemon_identity_stream treats an absent metadata key as an empty list, update and doctor on Windows can falsely report no pending reset, and cached-project initialize responses omit the advertised reset state on every platform. Apply the reset-store decoration to all successful initialize response paths.
AGENTS.md reference: AGENTS.md:L209-L212
Useful? React with 👍 / 👎.
What was wrong
A daemon from
origin/masterexits at startup over a beta.54-era profile. #2202 moved Git correlation to schema 6. Every registered store that beta.53/54 wrote records schema 5:global.db(profile authority),user-sessions.db(profile sessions), and each project'ssessions.db. Registered-schema admission refuses those stores, and two eager mounts at bootstrap turned that refusal into a process exit: the worker plan reads profile sessions, and the maintenance coordinator reads the profile authority. The account-deletion resume, the remote router, and connection identity binding each also returned the refusal with?.tracedecay updatewaits for the restored daemon to reachRunningEnabled, so it timed out and exited 1 with the daemon down. It never reached its own post-window reset.What changed
Typed state.
StoreResetRequiredV1 { store, authority, found_version, required_version, reason, remedy }lives intracedecay-domain.DaemonSessionRuntimeRegistryV1records it at the one admission point,attach_registered. A refused store stays unmounted, so every open re-runs admission, and a reset store serves on its next open. A successful attach clears the record. The Git correlation refusal is now the versionedProfileResetRequired { component: "git correlation", found_version: Some(5), required_version: 6 }.Daemon stays up. These paths now treat a reset-required store as a typed state instead of exiting:
Automaticselection, the value a reset profile initializes to, and logsprofile_worker_plan_reset_required.retention_degradedand retries.global.dblocation, so requests get a typed answer instead of a closed socket.Reads answer the typed problem.
reset_requiredwith theresetlegal action instead of a retryableunavailable.Stores that admit keep serving. When only a session store is refused, a project keeps its graph/search core. The retained core activates code indexing (
full_upgrade_reset_required). The query-authority waiter now demands the complete generation itself: a restored generation seats only for a reader that asks for it, and a refused full upgrade has no advisory owner to ask.Surfaces.
tracedecay_status(core and full) carriesreset_required_stores, and markdown renders each as a pending operator action.initialize_meta["tracedecay/reset_required_stores"]carries the same list.doctorlists each store with its exact command. It exits 75 when it found no issue but a reset is pending (fix(cli): type host sweep outcomes and exit truthfully #2075's table).DaemonProtocolState::Ready { reset_required_stores }. The restore check accepts such a daemon as restored.updateno longer wipes the profile on the operator's behalf. It prints each pending reset and exits 75. The refusal remedy text drops the claim thatupdateresets.Fail before / pass after
typed_terminal_restart_acceptance::reset_required_serving::reset_required_profile_session_store_is_served_typed_until_its_named_resetruns a physically spawned daemon over an isolated profile. It stampsuser-sessions.dbto Git correlation v5 and restarts, then asserts:tracedecay_statuslists exactly[{"store":"profile sessions","authority":"git correlation","found_version":5,"required_version":6,"reason":"git correlation profile schema 5 is incompatible with required schema 6; reset the profile","remedy":"tracedecay wipe --all --yes"}];tracedecay_lcm_status {storage_scope:user}returnskind: reset_requiredwithlegal_actions: ["reset"];tracedecay_searchon the same project still returnsprobe.It then runs
tracedecay wipe --all --yes, after which the same read serves and status lists[].Same test binary,
TRACEDECAY_TEST_BINpointed at a build oforigin/masterfe6b7fd469:With this branch:
test result: ok. 1 passed; 0 failed.Restore check:
service::update_restore_tests::restore_check_accepts_a_reset_required_daemon_and_returns_its_pending_reset. A fake systemd unit reportsRunningEnabled, and a socket answers initialize with the reset-required_meta. The test assertsrestored_service_matches(...) == trueandReady { reset_required_stores: [<the literal store>] }. On master the probe drops_metaand has no pending-reset state to assert, so the test cannot be expressed there; the behavioral failure on master is the startup exit above.update_with_a_reset_required_store_is_pending_on_the_named_resetpinsPendingOperatorActionand the literal printed line.Journey on the built binary (real beta.54 profile)
v1.0.0-beta.54x86_64-linux release binary, rantracedecay init, and indexed a small repo.global.db,user-sessions.db, andprojects/*/sessions.dball recordgit_correlation|5.systemctlon PATH runs the unit's ExecStart under a cappedsystemd-runscope.On a real beta.54 profile,
global.dbis refused too, so project reads return the typed refusal until the reset. The "code index still answers" case applies when only session stores are refused, which is what the integration test covers.Suites (post-rebase on
e3adbfba17, run under a cappedsystemd-runscope)shutdown_coordination: 2 passed--features test-transport): 330 passed;host_journeys_suite: 35 passedregistered_schema_fail_closed: 1;session_relation_graph: 8domain_suite: 171workflow::test_runner10/10 run serially. Those 4 cargo-fixture tests time out only when run concurrently under load.transport_acceptance_suite typed_terminal_restart_acceptance: 5 passeddaemon::tests::restart_proxy::serve_attaches_during_first_service_start_once_the_record_appears, which fails identically when run alone and exercises only files this PR does not touch (core_proxy.rs, daemon identity).mcp_suite: 571 of 572 passed with 4 threads.retrieve_truncation_test::diff_context_large_response_uses_retrievable_truncation_handlehit "interactive catalog is warming" under load and passes 3/3 alone.status_behavior_testnow also expects thegithub_sourceline fix(configuration): provision the GitHub origin source binding #2221 added.cargo clippy -p tracedecay-domain -p tracedecay-global-db -p tracedecay-store-runtime -p tracedecay-mcp -p tracedecay-daemon-protocol -p tracedecay-daemon-control -p tracedecay -p tracedecay-cli --all-targets -- -D warnings, with and without--features tracedecay-cli/test-transport,tracedecay/test-transport: clean.cargo fmt --all -- --check: clean.pnpm run contracts:check: contracts up to date.Windows:
windows_task.rsonly gains theReady { .. }pattern; not run on Windows (#2081/#2082/#2083/#2105).Fixes #2230