Summary
save_manifest() in graphify/detect.py rebuilds the manifest only from the files passed to it. On an incremental extract/update run that processes a small subset of the corpus, every other file's entry is dropped from the manifest.
The next detect_incremental() then sees those files as missing from the manifest and flags the entire corpus as new — forcing a full, expensive re-extraction.
Where
graphify/detect.py, save_manifest() (currently ~line 843 on v8):
existing = load_manifest(manifest_path)
manifest: dict[str, dict] = {} # <-- starts empty
for file_list in files.values():
for f in file_list:
...
manifest[f] = entry # <-- only this run's files land here
existing is loaded but used solely for per-file prev lookups; it never seeds the output manifest.
Reproduce
- Run a full build so the manifest has the whole corpus.
- Run an incremental update touching only a few files.
- Run
detect_incremental() again — it reports the whole corpus as new.
Fix
Seed manifest from the existing on-disk manifest (pruned to files that still exist) before the loop. Deleted files are still dropped, so deletions self-heal. PR attached.
Summary
save_manifest()ingraphify/detect.pyrebuilds the manifest only from thefilespassed to it. On an incrementalextract/updaterun that processes a small subset of the corpus, every other file's entry is dropped from the manifest.The next
detect_incremental()then sees those files as missing from the manifest and flags the entire corpus as new — forcing a full, expensive re-extraction.Where
graphify/detect.py,save_manifest()(currently ~line 843 onv8):existingis loaded but used solely for per-fileprevlookups; it never seeds the outputmanifest.Reproduce
detect_incremental()again — it reports the whole corpus as new.Fix
Seed
manifestfrom the existing on-disk manifest (pruned to files that still exist) before the loop. Deleted files are still dropped, so deletions self-heal. PR attached.