You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
graphify --update: ghost-node pruning silently no-ops when node source_file is relative (deleted_files is absolute) #2012
The --update incremental-merge flow's ghost-node pruning step compares each existing node's source_file against detect_incremental()['deleted_files'] with a plain membership check:
deleted_files is always a list of absolute filesystem paths (confirmed via graphify.detect.detect_incremental — deleted_files is built from manifest keys re-anchored to absolute form via load_manifest(manifest_path, root=root), then compared against full["files"], which are also absolute).
However, the extraction subagent prompt template in SKILL.md (the semantic-extraction schema dispatched to Claude subagents) explicitly instructs source_file to be a path relative to the corpus root:
Node ID format: ...
"source_file": "relative/path"
So on any corpus where nodes were extracted per the documented schema, d.get('source_file') is relative and deleted contains only absolute paths. The in check can never match. The pruning step then reports something like:
56 file(s) deleted since last run, but no ghost nodes were present - no drift.
...even when the deleted files' nodes are genuinely still present in the graph as ghosts.
Repro
Run a full /graphify pass on a corpus (nodes get relative source_file, per the documented schema).
Delete a folder of files that were part of that corpus.
Run /graphify --update.
Observe: deleted_files correctly lists the deleted files (absolute paths). The pruning step reports "no ghost nodes... no drift." The nodes for the deleted files are still present in graph.json.
Verified this by manually diffing node IDs between the pre- and post-update graph.json: 42 nodes whose source files had been deleted were still present after --update reported no drift. Re-running the exact same prune logic with paths normalized to relative-to-root before the membership check correctly identified and removed all 42.
Suggested fix
Normalize both sides to the same path form before the membership check in the --update pruning snippet, e.g.:
(or, alternatively, standardize on absolute source_file everywhere and update the extraction prompt schema/docs accordingly — either direction works, but the two need to agree.)
Fixed in v0.9.21: build_merge now prunes a deleted file's nodes/edges/hyperedges regardless of stored path form (raw / normalized-relative / absolute-identity), and graphify extract records the .graphify_root marker so a later update relativizes correctly even under a custom --out. https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.21
Activity
fix(build): form-insensitive prune + scan-root marker (#2012)
chore: changelog for 0.9.21 data-integrity fixes (#2051/#2056/#2014/#…
safishamsi commentedon Jul 20, 2026
Fixed in v0.9.21:
build_mergenow prunes a deleted file's nodes/edges/hyperedges regardless of stored path form (raw / normalized-relative / absolute-identity), andgraphify extractrecords the.graphify_rootmarker so a later update relativizes correctly even under a custom--out. https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.21fix(build): form-insensitive prune + scan-root marker (Graphify-Labs#…
chore: changelog for 0.9.21 data-integrity fixes (Graphify-Labs#2051/G…