Repository navigation
fix(daemon): upgrade an outdated index before the daemon starts serving it - #330
Merged
Merged
Conversation
…ng it In the default daemon mode nothing upgraded an index an older extraction version built. A cold `serve --mcp` session defers to its daemon, and the daemon's startup gate admits only a current index, so every tool call answered "outdated" until a manual `codegraph sync`. v0.55.0 moved the extraction version from 21 to 22, so every v0.54.0 index hit this. The daemon now upgrades the index before its startup gate, through a new codegraph-watch entry, upgrade_outdated_index_once. Under one exclusive lease it requires an outdated namespace whose authoritative slot records the current phase, no uninitialized tombstone, and the database file, and only then runs the migration `codegraph sync` runs. The state gate classifies every phase an older version wrote as outdated, so without these checks a daemon would rebuild the database an older `uninit --force` removed. Anything else, and a failed upgrade, is left to the unchanged gate, which refuses it as before.
Two tests that started within one clock tick shared a directory, and the first to finish deleted the other's project mid-run, as in the first CI attempt of #325. The name now carries a process-wide sequence, and the directory is created with create_dir, so a collision fails instead of sharing.
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (84.93%) is below the target coverage (95.00%). You can increase the patch coverage or adjust the target coverage. @@ Coverage Diff @@
## main #330 +/- ##
==========================================
- Coverage 95.60% 95.59% -0.01%
==========================================
Files 280 280
Lines 166327 166400 +73
==========================================
+ Hits 159016 159070 +54
- Misses 7311 7330 +19
... and 4 files with indirect coverage changes 🚀 New features to boost your workflow:
|
The upgrade runs the migration `codegraph sync` runs, which publishes `phase=building` before it removes the old database, so a rebuild that fails partway leaves the index `building`, as an interrupted `sync` does, and the daemon refuses it. The upgrade section said only that a later tool call succeeds.
A failed upgrade is a failed migration, and a migration failure must stop. The daemon logged the error and went on to its startup gate. The last step of the rebuild publishes `Current`, and the publisher's directory sync can still fail after that, so the gate could serve an index whose upgrade had just reported an error. The daemon now refuses to start with that error, before the gate, and publishes no pid or socket. A later daemon finds the index as the failure left it, and the gate decides as before. docs/cli.md now says what a failed rebuild can leave: the older index untouched if it fails before it begins replacing it, `building` if it fails later, as an interrupted `sync` does.
Merged
sunerpy
added a commit
that referenced
this pull request
Oct 22, 2026
Release-please PR #331 merged as 44fd8af and tag v0.55.1 was cut there. Release run 39754559422 passed all twelve jobs, and the downloaded release passed the black-box acceptance: an index built by v0.54.0 or v0.53.0 is upgraded by a cold session's daemon, and by a replacement daemon, with no manual sync. A second entry records #330's fix and the pre-existing sync behavior it leaves alone.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In the default daemon mode nothing upgraded an index an older extraction version built. A cold
serve --mcpsession defers to its daemon, and the daemon's startup gate admits only a current index, so every tool call answered "outdated" until a manualcodegraph sync. v0.55.0 moved the extraction version from 21 to 22, so every v0.54.0 index hits this. The v0.55.0 black-box acceptance found it; v0.54.0 behaves the same on a v0.53.0 index.codegraph_watch::upgrade_outdated_index_oncebefore its startup gate. Under one exclusive lease it requires three things before it runs the migrationcodegraph syncruns:outdatednamespace whose authoritative slot records thecurrentphase;uninit --force, an interrupted older build, or a removed database. The state gate classifies every phase an older version wrote asoutdated, so without these checks a daemon would rebuild the database an olderuninit --forceremoved.Current, and the publisher's directory sync can still fail after that, so the gate alone could have served an index whose upgrade had just failed.codegraph sync. A failure before it begins replacing the index leaves the older index untouched. A later failure can leavebuilding, the store's interrupted-build marker. A later daemon then finds that state, and the gate decides as before.plain_outputprojects no longer share a temporary directory when two tests start within one clock tick, which caused the failure in chore: release 0.55.0 #325's first CI attempt.docs/cli.md: the extraction-version upgrade and detached-daemon lifecycle sections describe the new behavior, including that a tool call may wait up to 30 seconds or fail while the daemon upgrades, and what a rebuild that fails partway leaves behind.Tests
New tests in
crates/codegraph-cli/tests/upgrade_from_v054.rs:a_cold_mcp_session_upgrades_a_v0_54_index_through_its_daemoninit, and a later edit becomes searchable through the session. Onb02b563it times out after 60 s while the daemon refuses the outdated index.a_cold_mcp_session_leaves_an_older_uninit_alonea_daemon_whose_upgrade_fails_still_refuses_the_outdated_indexthe_daemon_upgrade_skips_an_interrupted_older_buildthe_daemon_upgrade_skips_an_older_index_with_a_tombstonethe_daemon_upgrade_skips_an_older_index_without_its_databaseNew test in
crates/codegraph-cli/tests/plain_output.rs:projects_created_within_one_clock_tick_get_distinct_directories.Verification:
Mutation checks. Each mutant was applied, its pinned tests were run, and the file was restored and compared. Every mutant failed its tests:
Focused suites. All passed:
codegraph-rsintegration tests (upgrade, cold start,daemon_*,batch_m_*, proxy, home guard, lease), 127 passed;codegraph-rsbin tests, 440 passed;codegraph-watch, 342 passed;codegraph-daemon, 181 passed;cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --check,oxfmt --check,scripts/docs-check.py.make pre-cipassed through the pre-push hook.Manual acceptance. Released v0.54.0 and v0.53.0 binaries built the index, and this branch's binary served it, for both a cold session and a replaced v0.54.0 daemon:
init.The same scripts fail against the released v0.55.0.
Not changed
codegraph-daemon,codegraph-store,codegraph sync, and the direct-mode catch-up.codegraph syncalso sees an older binary'suninit --forceleftovers asoutdatedand would rebuild them. This comes from reading the code path; it was not reproduced.