fix(cli): affected and god-nodes refresh the orientation stamp and write the query ledger - #3054
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Makes the CLI affected and god-nodes verbs count as orientation like query/path/explain: a successful run refreshes the strict read guard's freshness stamp via _touch_query_stamp and appends a query-ledger line (affected with the impacted-node count, god_nodes with the returned-hub count). Both querylog.log_query calls are fail-silent and stay opt-in behind the existing GRAPHIFY_QUERY_LOG* gates, so an agent that orients through either verb is no longer denied on its next raw read or left absent from the audit trail.
No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 463 functions depend on the 290 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 122 callees - new:
_stale_graph_sources()— 7 callers, 6 callees - new:
_run_hook_guard()— 4 callers, 7 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 463 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 421 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
· 4 more finding(s) on lines outside this diff (see the check run).
|
Thanks for the automated review — glad it reads clean. To restate the intent for human reviewers: |
…query ledger The strict read guard admits an agent only while the "recently oriented" stamp (graphify-out/cache/last_query_stamp) is fresh, and the query ledger is the audit trail of graph consults. query/path/explain each stamp + log, and PR #12 extended the stamp to the MCP orientation tools — but the CLI affected and god-nodes verbs did neither: an agent orienting through them stayed blind to the guard (next raw read denied) and invisible to the audit trail. Orientation is orientation regardless of door (PR #12): both verbs now mirror the query verb's calls after a successful run — kind="affected" with the impacted-node count, kind="god_nodes" with the returned-hub count — followed by _touch_query_stamp. Both are fail-silent; the ledger stays opt-in behind the GRAPHIFY_QUERY_LOG* gates. The MCP god_nodes tool still does not stamp; widening that set is a deliberate follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4fed5a4 to
912dcd8
Compare
Fixes #3053. Same defect class as #3039 (MCP half: #3042), one door over — this is the CLI half.
Defect
The strict read hook admits an agent only while the "recently oriented" stamp (
graphify-out/cache/last_query_stamp) is fresh, and the opt-in query ledger is the audit trail of graph consults.graphify query/path/explaineach stamp + log on success (e.g.querylog.log_queryat cli.py:1177 and_touch_query_stamp(gp)at cli.py:1187 forquery) — butgraphify affectedandgraphify god-nodes(#2004) do neither. An agent that orients through either verb stays blind to the strict guard (next raw read denied after it already consulted the graph) and invisible to the ledger.Fix
Orientation is orientation regardless of which door it comes through. Both verbs now mirror the query verb's calls on the success path:
affected:querylog.log_query(kind="affected", question=<seed>, corpus=<graph>, nodes_returned=<impacted count>, depth, duration_ms)then_touch_query_stamp(gp), then print. The count is exact: each impacted node renders as exactly one-line and no header line starts with-.god-nodes:querylog.log_query(kind="god_nodes", question="top N", corpus=<graph>, nodes_returned=len(gods))then_touch_query_stamp(gp).Both are fail-silent like the existing call sites (
log_querynever raises;_touch_query_stampswallows); the ledger stays opt-in behind theGRAPHIFY_QUERY_LOG*gates; error paths (missing/corrupt graph) exit before either call, so a failed run stamps and logs nothing. Output bytes of both verbs are unchanged.Not touched here: the MCP tools' stamping is #3042; if both land,
god_nodesover MCP becomes the remaining non-stamping door for the same consult and can be folded into #3042's_ORIENTATION_TOOLSset as a follow-up.Tests
test_affected_cli_stamps_orientation_and_logs— an aged stamp's mtime advances; exactly one ledger line with kindaffected, the exact impacted count, depth, and duration; ledger env-gated viaGRAPHIFY_QUERY_LOGexactly like tests/test_querylog.py; tmp graph fixture, offline.test_god_nodes_cli_stamps_orientation_and_logs— same shape forgod-nodes; the logged count equals the number of hubs actually printed, not the--topceiling.🤖 Generated with Claude Code