Skip to content

detect_incremental() uses a single global manifest for all subdirectories — --update on one subfolder reports files from the last-graphed folder as deleted #3785

Description

@newwaysai

Bug: detect_incremental() uses a single global manifest for all subdirectories — --update on one subfolder reports every file from the last-graphed folder as deleted

Version: graphifyy 0.3.28

What happened

Running the skill's --update flow on one subdirectory of a large repo (e.g. workflows/) after a previous full run had graphed a different subdirectory (e.g. experts/) causes deleted_files in the incremental-detect result to list hundreds of paths from that unrelated, previously-graphed folder.

Live case: --update on workflows/ (a workspace with ~15 top-level graphed subfolders, each run via /graphify <subfolder>) returned deleted_files containing 230+ paths under experts/rechts-kanzlei/... — none of which are under workflows/ and none of which were actually deleted. The last folder graphed before this run was experts/.

Root cause

In graphify/detect.py, the manifest path is a module-level constant:

_MANIFEST_PATH = "graphify-out/manifest.json"

load_manifest() / save_manifest() both default to this single flat path regardless of which root was passed to detect_incremental(root). Every /graphify <subfolder> --update run in a multi-subfolder workspace reads and writes the same manifest file, so the manifest only ever reflects whichever subfolder was graphed most recently. The comparison in detect_incremental():

current_files = {f for flist in full["files"].values() for f in flist}
deleted_files = [f for f in manifest if f not in current_files]

flags every manifest entry not under the current run's file set as deleted — including entries that were never under root to begin with.

Impact

If the caller (e.g. the skill's --update flow) prunes graph nodes whose source_file is in deleted_files, this can silently remove nodes belonging to an unrelated subfolder's graph, depending on which graph is currently loaded. In our case the prune step happened to target the just-loaded subfolder graph, which contained none of the flagged paths, so the visible symptom was only a wrong "N files deleted" count in the diff report — but the mechanism is a correctness bug regardless of the specific graph layout, and could delete real nodes in a different call pattern (e.g. running --update against the root graph, or against a subfolder whose graph overlaps the previously-graphed one).

Suggested fix

Scope the manifest path to root by default (e.g. graphify-out/<sanitized-root>/manifest.json, falling back to the existing flat path for the root-level . invocation to avoid a migration step for existing single-folder setups). Additionally, filter deleted_files to only include manifest entries that were ever under root, as defense in depth against a stale or manually merged manifest.

Happy to share a patch if useful — we worked around it locally by scoping _MANIFEST_PATH per-root and adding the under-root filter to deleted_files.

Activity

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