Skip to content

Incremental extract() false-positives unchanged files as "deleted", silently pruning valid nodes #2210

Closed

Description

@jkomilanowicz-lab

Summary

graphify extract's incremental scan can false-positive a source file as "deleted" — pruning its nodes from the graph — even though the file is unchanged and still present on disk.

Environment

  • graphifyy 0.9.26, installed via uv tool install graphifyy
  • macOS
  • Corpus: a mixed code+markdown project, previously extracted successfully, no files intentionally deleted between runs

What happened

Running graphify extract . (headless, Gemini backend) on a project that had been extracted once before produced:

[graphify] Pruned 224 node(s) from 171 deleted source file(s).
[graphify] Pruned 28 edge(s) from deleted source file(s).
[graphify extract] incremental scan of <project>
[graphify extract] 0 code, 0 docs, 0 papers, 0 images changed; 560 unchanged; 31 deleted; 54 excluded

I then manually verified specific files graphify reported as sourcing pruned nodes — e.g. a markdown file whose nodes were pruned — and confirmed the file still exists on disk, with unchanged content, at its original path. It was not renamed, moved, or deleted between the two extraction runs. Yet the incremental scan classified it (and apparently ~170 others) as deleted, and its nodes were silently removed from the graph.

Impact

This is silent, incorrect data loss in the knowledge graph: real, still-valid content disappears from graph.json on a routine incremental re-run, with no error surfaced — just a log line that reads like expected housekeeping ("Pruned N nodes from deleted source files"). A user relying on incremental extraction to keep a graph current would have no way to notice unless they happened to cross-check specific nodes against the filesystem, as I did here.

Suspected cause

Possibly related to path/root-anchoring bugs referenced inline in the shipped Claude Code skill's own reference docs (comments mention issue numbers #1417, #1991, #1392 around root=/cache_root= mismatches between the corpus root and the output directory in save_manifest/save_semantic_cache). If the incremental scan's manifest-comparison step resolves file paths against the wrong base directory, files that do exist would fail an existence check and get treated as deleted.

Repro suggestion

Run graphify extract <path> twice in a row on the same unchanged corpus (no --update flag needed — this happened via the standard headless extract command). Diff nodes/links counts in graph.json between the two runs, or watch for a non-zero "Pruned N node(s) from M deleted source file(s)" line when nothing was actually deleted. Cross-check a few of the pruned nodes' source_file values against the filesystem to confirm they still exist.

Ask

Would appreciate a look at the incremental-scan path resolution / manifest comparison logic — this seems like it could cause silent graph degradation for anyone running graphify extract repeatedly (which is the expected, recommended usage pattern for keeping a graph current).

Activity

  1. safishamsi commented on Jul 27, 2026

    @safishamsi
    Member

    Fixed in v0.9.28. The stale-source check now compares paths NFC-normalized on both sides and is fail-closed: a source missing from the scan is pruned only when its exclusion is provable, so alive files (macOS NFD paths, legacy basename spellings) are no longer pruned as deleted. https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.28

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions