Problem
_run_hook_guard (cli.py) decides staleness per target file: os.stat(fp).st_mtime > gmtime. When the graph predates a batch of recent commits but the file being read hasn't changed since the build, the guard still emits the strict wording:
MANDATORY: graphify-out/graph.json exists. You MUST run `graphify query` ...
Real session: graph built ≤ 2026-09-08; ~21 commits landed in browser-extension/viewer/ after that date (new modules, deleted modules). Every Read in that area got the MANDATORY nudge, so the agent paid graphify query calls on a snapshot that had never seen those modules — queries returned nothing useful and the agent had to fall back to Read/Grep anyway. The stale wording exists (_READ_NUDGE_STALE) but only fires on per-file mtime.
Proposal
When the project is a git repo, also compare repo-level freshness:
head = int(subprocess.run(["git", "log", "-1", "--format=%ct"], ...).stdout or 0)
repo_stale = head > int(gmtime)
If repo_stale, emit the softened wording — e.g.:
graphify-out/graph.json may predate recent commits (last build , latest commit ). For recently changed areas prefer Read/Grep directly; graphify update refreshes the graph.
Fails open as today if git is missing or errors.
Why
The current design already accepts "stale → soften" (#1840b); it just can't see staleness that lives between files, at the commit layer. New/deleted modules are exactly where the graph is most confidently wrong.
Problem
_run_hook_guard(cli.py) decides staleness per target file:os.stat(fp).st_mtime > gmtime. When the graph predates a batch of recent commits but the file being read hasn't changed since the build, the guard still emits the strict wording:Real session: graph built ≤ 2026-09-08; ~21 commits landed in
browser-extension/viewer/after that date (new modules, deleted modules). Every Read in that area got the MANDATORY nudge, so the agent paidgraphify querycalls on a snapshot that had never seen those modules — queries returned nothing useful and the agent had to fall back to Read/Grep anyway. The stale wording exists (_READ_NUDGE_STALE) but only fires on per-file mtime.Proposal
When the project is a git repo, also compare repo-level freshness:
If
repo_stale, emit the softened wording — e.g.:Fails open as today if git is missing or errors.
Why
The current design already accepts "stale → soften" (#1840b); it just can't see staleness that lives between files, at the commit layer. New/deleted modules are exactly where the graph is most confidently wrong.