Skip to content

fix: rebuild index when mode adds capabilities - #1263

Open
astandrik wants to merge 5 commits into
DeusData:mainfrom
astandrik:fix/index-mode-capability-rebuild
Open

fix: rebuild index when mode adds capabilities#1263
astandrik wants to merge 5 commits into
DeusData:mainfrom
astandrik:fix/index-mode-capability-rebuild

Conversation

@astandrik

@astandrik astandrik commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1273
Related: #563

  • persist the effective index capability level in the Project node as index_mode
  • force a full rebuild when the requested mode needs capabilities missing from the stored index
  • on downgrades, keep requested discovery/reporting scope separate from the stronger stored extraction scope
  • conservatively rebuild legacy, missing, malformed, or non-exact mode metadata
  • export persistent artifacts exactly once, after atomic database publication
  • keep the implementation focused by sharing manifest indexing and repeated test setup

Why

Incremental routing originally compared stored file hashes and the discovered-file threshold, but not the capability level of the stored index. An unchanged fast -> moderate request could therefore take the no-op route without creating the stronger similarity data.

The inverse transition also needs two distinct concepts. The caller's requested mode determines which files are discovered and reported, while the stored stronger mode determines which extraction passes and capabilities must be preserved. Promoting one mutable mode before discovery widened a full -> fast request back to full discovery. If a stored-only file has changed or disappeared, the pipeline now performs an effective-scope full rediscovery and rebuild so stale stronger-mode graph data cannot survive.

Exact no-op downgrade eligibility compares the requested manifest subset with the stored manifest. Stored extras are accepted only when they remain safe relative, regular, non-symlink files. Duplicate, malformed, or allocation-incomplete comparisons fail closed to a rebuild.

The no-op persistence path also exported the artifact inside staging and then again after publication. Export now has one boundary: after the final database rename.

Mode contract

Stored index Requested mode Behavior
weaker stronger full rebuild and record the stronger effective mode
same same existing incremental/no-op route
stronger weaker, requested subset unchanged requested discovery/reporting with stored stronger extraction capabilities; no database rewrite
stronger weaker, stored-only input changed or missing effective-scope full rebuild, while preserving requested discovery reporting
missing / unknown / malformed / non-exact any one conservative full rebuild

The public MCP API and SQLite schema are unchanged. Existing threshold routing and ADR preservation behavior remain unchanged.

Regression coverage

  • unchanged fast -> moderate rebuilds, creates similarity data, and records index_mode=moderate
  • changed moderate -> fast preserves SIMILAR_TO and the stronger stored mode
  • changed full -> moderate preserves full-only Macro nodes and the stronger stored mode
  • full -> fast no-op discovers/reports only the requested scope while retaining stronger graph capabilities
  • deleting a full-only file during a fast request forces an effective-full rebuild and removes its stale nodes
  • missing legacy metadata and escaped-NUL/non-exact metadata rebuild once and normalize safely
  • explicit and implicit no-op persistence each export exactly once, after the real database rename
  • persistence failure still propagates as a pipeline failure

Verification

Exact branch head: 3959fdf5 on base 49d928be.

Fail-before on the current-main rebase:

  • requested/effective discovery regression: 25 existing focused tests passed; the new contract test failed on the widened discovery report
  • artifact publication regression: 25 existing focused tests passed; the new observer independently measured two exports and one export before publication

Pass-after on the exact published tree:

  • focused semantic-manifest suite: 27 passed
  • broad pipeline suite: 257 passed (one redundant test was removed after its contract was fully subsumed by a stricter test)
  • complete plain local matrix: 7500 passed, 1 failed, 5 skipped across 138 suites; the sole daemon-runtime fixture failure reproduces unchanged with the previous published-head runner and is therefore unrelated to this cleanup
  • production O2 build, parent/worker watchdogs, worker error response, security string allowlist, destructive-ordering gate, lint-no-suppress, lint-format, no-forbidden-skips, and git diff --check: passed
  • Desloppify rescan found no new detector regressions in the changed files; the next reported cleanup target is outside this PR

Exact-head GitHub CI is running. Its clean runners are authoritative for sanitizer and cppcheck coverage: local macOS ASan blocked inside runtime initialization before main, and local cppcheck is not installed.

Copilot AI review requested due to automatic review settings July 25, 2026 09:11
@astandrik
astandrik requested a review from DeusData as a code owner July 25, 2026 09:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes incremental routing decisions across index mode transitions by persisting the effective index capability level in Project metadata (properties.index_mode), forcing a full rebuild when the requested mode requires capabilities not present in the stored index, and preserving stronger stored capabilities during downgrades (while still honoring the requested mode for discovery/exclusions). It also ensures persistent artifacts are refreshed after reindexing and adds regression coverage for mode upgrades/downgrades and malformed/legacy metadata handling.

Changes:

  • Persist effective capability mode in the Project node (properties.index_mode) and use exact JSON string comparisons when reading it.
  • Route mode upgrades to full rebuilds; keep stored effective mode for incremental changed-file re-extraction on downgrades.
  • Refresh existing artifacts after reindexing (FAST quality unless persistence is explicitly requested) and add end-to-end tests for these transitions.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/test_pipeline.c Adds regression tests covering upgrade/downgrade routing, capability preservation, malformed metadata, and artifact refresh behavior.
src/store/store.h Clarifies that index_mode in coverage metadata is the requested discovery mode; effective capability mode is stored on the Project node.
src/pipeline/pipeline.c Persists Project index_mode, reads stored mode safely via yyjson, routes upgrades to rebuilds, and adjusts post-publish artifact export behavior.
src/pipeline/pipeline_internal.h Exposes cbm_pipeline_mode_name for consistent internal serialization and updates incremental API contract docs/signature.
src/pipeline/pipeline_incremental.c Accepts an effective_mode for changed-file re-extraction, preserves macro extraction capability on downgrades, and propagates persistence failures when required.
src/mcp/mcp.c Updates MCP tool schema description to document artifact refresh behavior when an artifact already exists.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@astandrik
astandrik force-pushed the fix/index-mode-capability-rebuild branch from 17cf892 to 902262e Compare July 26, 2026 08:10
@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Jul 28, 2026
@DeusData DeusData added this to the 0.9.1-rc milestone Jul 28, 2026
@DeusData

DeusData commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Thank you for the contribution and for covering both index mode upgrades and downgrades, including malformed metadata. This is now triaged as a high-priority graph correctness bug for 0.9.1-rc. Our community PR queue is currently quite full, so it may take a little time before we can complete the review and, if approved, merge it. We are doing our best to support community contributions and will return with code-grounded feedback as capacity opens.

@astandrik
astandrik force-pushed the fix/index-mode-capability-rebuild branch from 902262e to 52866c1 Compare August 7, 2026 14:42
@astandrik
astandrik requested a balanced review from Copilot August 7, 2026 14:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/pipeline/pipeline.c:1527

  • Assigning the stored mode to p->mode here also changes discovery, because cbm_pipeline_run_staged later passes p->mode to cbm_discover_ex2. A full → fast downgrade therefore still scans full-only directories/files instead of using the requested discovery scope, contradicting the stated requested/effective-mode separation and defeating the fast-mode workaround for large repositories. Keep the requested discovery mode separate and use the stored mode only for effective extraction/post-passes and persisted capability metadata.
        p->mode = stored_mode;

src/pipeline/pipeline_incremental.c:2426

  • This exports the artifact during the inner staged run, but the successful return is then marked incremental and export_after_publish exports it again (BEST quality for explicit persistence, FAST for an existing artifact). Thus every exact no-op that needs an artifact performs compression/VACUUM twice, with the first export occurring before final publication. Let the existing post-publication path perform the single export.
            return cbm_pipeline_refresh_artifact(p, db_path);

@astandrik
astandrik force-pushed the fix/index-mode-capability-rebuild branch 2 times, most recently from 5545555 to cb0dfa6 Compare August 13, 2026 19:35
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
Signed-off-by: Anton Standrik <astandrik@yandex-team.ru>
Signed-off-by: astandrik <astandrik@yandex-team.ru>
Keep caller-requested discovery separate from the stronger stored capability used for extraction and full rebuilds. Defer exact-noop artifact export to the single post-publication boundary and cover downgrade deletion plus explicit and implicit artifact refresh paths.

Signed-off-by: astandrik <astandrik@yandex-team.ru>
@astandrik
astandrik force-pushed the fix/index-mode-capability-rebuild branch from cb0dfa6 to 75000eb Compare August 16, 2026 10:43
Signed-off-by: astandrik <astandrik@yandex-team.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mode upgrade silently keeps weaker graph: incremental routing ignores stored index capability level

3 participants