Skip to content

update runbook omits kind="ast": incremental update re-extracts the entire corpus semantically #2033

Description

@rohit-tambakhe

The --update runbook in graphify/skills/claude/references/update.md omits the kind= argument on both its detect_incremental() and save_manifest() calls, so both fall back to defaults that are wrong for an AST-only update. Verified on v8 HEAD (file is byte-identical to the copy shipped in graphifyy 0.9.19).

1. detect_incremental() defaults to kind="semantic" → re-extracts the whole corpus

Line 15:

result = detect_incremental(Path('INPUT_PATH'))

The signature defaults to kind="semantic", which reports a file as changed when its semantic_hash is missing. On a graph built without a semantic pass — e.g. installed without the LLM extra, or built purely from AST — no file has ever had a semantic_hash, so every file reports as changed.

On a 629-file corpus this reported new_total: 629 (629/629, 100%) when the real delta was 12 changed source files. Following the runbook literally would then chunk ~620 files into ~29 semantic subagents and spend LLM tokens re-extracting a corpus that had not changed.

The detect_incremental docstring already states the intended mode:

kind="ast": a file is "changed" when its ast_hash is missing or its content has changed. Use this for graphify update.

Passing kind="ast" gives the correct answer (12 files) at zero token cost.

2. save_manifest() defaults to kind="both" → falsely stamps semantic_hash

Line 145:

save_manifest(incremental['files'], root='INPUT_PATH')

This defaults to kind="both", which stamps both hashes. An AST-only update therefore writes a semantic_hash for files that were never semantically extracted. A later detect_incremental(kind="semantic") then considers them already done and skips them — so the semantic pass silently never runs on that corpus.

save_manifest's own docstring describes kind="ast" as the mode "written by graphify update (AST-only rebuild)", so the intent is clear; the runbook just doesn't pass it.

Interaction

The two defects partially mask each other: (2) suppresses future semantic extraction, while (1) forces a full semantic re-extraction whenever the manifest lacks those hashes. Net effect is that the token cost of an incremental update is unpredictable and can be ~50x the real delta.

Suggested fix

In the AST-only path of references/update.md, pass the mode explicitly:

result = detect_incremental(Path('INPUT_PATH'), kind='ast')
...
save_manifest(incremental['files'], root='INPUT_PATH', kind='ast')

The full-pipeline path (graphify extract after a real semantic pass) should keep kind="semantic" / "both" — the fix applies specifically to the code-only branch the runbook labels "Code-only changes detected - skipping semantic extraction (no LLM needed)", which is precisely the branch where a semantic-mode diff is wrong.

Same omission appears in the sibling copies under graphify/skills/*/references/update.md.

Environment

  • graphifyy 0.9.19 (installed via uv tool), file identical to v8 HEAD
  • Python 3.11, Linux

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