Skip to content

manage_adr data loss: ADRs in project_summaries are deleted during graph re-indexing #516

Closed

Description

@vikrant82

Version

0.8.1

Platform

macOS (Apple Silicon)

Install channel

npm

Binary variant

standard

What happened, and what did you expect?

Description

There is a data-loss bug in how the database dump pipeline handles the project_summaries table. When an Architecture Decision Record (ADR) is stored using the manage_adr tool, it correctly saves to the project_summaries table. However, any subsequent indexing operation (index_repository / pipeline execution) completely overwrites the SQLite database file and fails to preserve the project_summaries table, permanently deleting the ADR.

Root Cause Analysis

The issue stems from the custom SQLite writer implementation used to dump the graph buffer to disk.

  • In src/pipeline/pipeline.c (and internal/cbm/sqlite_writer.c), when the pipeline finishes, it opens the target .db file using fopen(path, "wb"), truncating the existing database.
  • The monolithic cbm_writer_finalize (and write_metadata_tables) explicitly writes an empty B-tree for the summaries_root:
    // internal/cbm/sqlite_writer.c
    *summaries_root = write_table_btree(w->fp, &w->next_page, NULL, NULL, NULL, 0, false);
  • While the incremental pipeline attempts to preserve file_hashes by reopening the new DB and re-inserting them, no such preservation logic exists for project_summaries.

Expected Behavior

The database dump pipeline should migrate or preserve the contents of the project_summaries table across re-indexing operations, ensuring that ADRs persist indefinitely across sessions as designed.

Actual Behavior

The project_summaries table is wiped clean on every full dump, resulting in silent data loss.

Reproduction

Steps to Reproduce

  1. Index a repository to create the initial database.
  2. Use the MCP tool to store an ADR:
    manage_adr(project="<project_name>", mode="update", content="# My ADR...")
  3. Verify the ADR was stored:
    manage_adr(project="<project_name>", mode="get") (Returns the expected content).
  4. Trigger a graph re-index (e.g., via index_repository).
  5. Attempt to retrieve the ADR again:
    manage_adr(project="<project_name>", mode="get") (Returns no_adr).

Logs


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

  1. RithvikReddy0-0 commented on Jun 20, 2026

    @RithvikReddy0-0
    Contributor

    Reproduced this on a build from source, and confirmed your root-cause analysis is correct with one refinement on the trigger that matters for the fix.

    The loss only happens on the full dump path, not every re-index:

    • Re-index with no file changes → routes through cbm_pipeline_run_incremental, the DB isn't rewritten, ADR survives.
    • Re-index after a file changes or a new file is added → dump_and_persist_hashes deletes the old .db and rebuilds it from the graph buffer, ADR is wiped → manage_adr(mode="get") returns no_adr.

    I confirmed it directly: store an ADR, change a source file, re-index, and the row in project_summaries is gone.

    The asymmetry you spotted is exactly the cause. In dump_and_persist_hashes (pipeline.c), after cbm_gbuf_dump_to_sqlite writes a fresh DB (with an empty project_summaries, per the summaries_root btree in sqlite_writer.c), the code reopens the DB and explicitly re-persists file_hashes delete then re-upsert but there's no equivalent step for project_summaries. So hashes carry across a full re-index and ADRs don't.

    The fix mirrors the file_hashes handling: read the existing project_summaries rows before the old DB is unlinked, then re-insert them after reopening the rebuilt DB. (Reading after the dump won't work the file's already been truncated/replaced by then, so the rows have to be captured up front and carried through.)

    Happy to put up a PR along those lines if it's wanted.

  2. DeusData commented on Jun 21, 2026

    @DeusData
    Owner

    Hey, thx, will review ASAP

  3. yasku commented on Jun 25, 2026

    @yasku

    Opened #623 with a fix.

    One refinement from tracing the pipeline: the loss happens at two dump sites, not one. The full path (dump_and_persist_hashes in pipeline.c) was correctly identified here, but the incremental path loses the ADR too — when a file changed/was added, cbm_pipeline_run_incremental reaches dump_and_persist (pipeline_incremental.c), which also rewrites the DB with an empty project_summaries. Only the no-change incremental case early-returns without a dump, so the ADR survives there. Fixing just the full path would leave the bug live on any single-file edit.

    The fix mirrors the existing file_hashes preservation: capture the ADR from the old DB before it is rewritten (in try_incremental_or_delete_db, the single point that opens the old DB for both paths) and re-insert it via cbm_store_adr_store after each dump. Regression tests cover both the full and incremental paths.

  4. added a commit that references this issue on Jun 25, 2026
  5. added a commit that references this issue on Oct 22, 2026
    001fbe2
  6. DeusData commented on Oct 31, 2026

    @DeusData
    Owner

    A fix for the reindex-swap race is now on main in 7be2bec (PR #2315 by @0xb007ab1e): a manage_adr write that lands while a reindex swaps in the new database is carried across the swap instead of being lost. Thank you for the report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions