Skip to content

fix(instructions): graph narrows scope, source verifies, and upgrades actually reach existing users - #886

Merged
tirth8205 merged 6 commits into
mainfrom
docs/graph-guardrails-and-platform-policy
Aug 19, 2026
Merged

fix(instructions): graph narrows scope, source verifies, and upgrades actually reach existing users#886
tirth8205 merged 6 commits into
mainfrom
docs/graph-guardrails-and-platform-policy

Conversation

@tirth8205

Copy link
Copy Markdown
Owner

Fixes #314 and #883, and adds a contribution bar for new platform targets.

1. The instruction text told agents to trust the graph over the source (#314)

The injected section said to ALWAYS use the graph BEFORE Grep/Glob/Read and to fall back to file search ONLY when the graph did not cover the need. In practice models acted on graph summaries, skipped the implementation, and produced shallower work. Several commenters on #314 describe exactly that.

The absolute wording is gone. The section now says to start with the graph to narrow scope, then read the source, and carries six guardrails: do not change code from graph output alone; read the implementation and its tests before a non-trivial change; verify the exact source for behaviour, database, migration, retry, fallback, recovery and compatibility code; when the graph and the source disagree, the source wins; and an empty result can mean "not indexed" or "not statically visible", not "does not exist".

That last line is the instruction-layer half of #884 and #885, which say the same thing at the tool-output layer.

Because this text costs every user tokens in every session, the old intro was tightened to pay for most of the space. _CLAUDE_MD_SECTION goes from 38 to 45 lines, _COPILOT_SECTION from 46 to 52. The intro and guardrails are shared constants, so all nine generated targets stay byte-identical.

2. Those improvements would never have reached anyone (#883)

_inject_instructions was append-only behind a marker guard: if the marker was present it logged "already contains instructions, skipping" and returned without ever comparing content. Once a user had installed, no later release could change that section. Every improvement above would have reached only brand-new installs.

Generated sections now carry a closing marker so they have real boundaries. Older blocks have none, so _upgrade_managed_block matches their full recorded text, longest first, and never guesses where a boundary-less block ends, because guessing is what would eat user content. code_review_graph/_legacy_instructions.py records the 10 past block texts, recovered by walking the git history of skills.py and by scanning the instruction files this repo ships. That second pass mattered: this repo's own CLAUDE.md, AGENTS.md and GEMINI.md carried a block a markdown formatter had reflowed, which the source history alone would never have produced, and those three files would otherwise have been reported as hand-edited.

_inject_instructions now reports created, updated, unchanged or conflict. A hand-edited block is left exactly as the user wrote it and named in the output. Reinstalling an unchanged file does not even touch its mtime. uninstall was the same bug in reverse, refusing to remove a block written by an older release, and now consults the same recorded list.

What an existing user sees on their next install:

Updated graph instructions in: CLAUDE.md
Left edited graph instructions alone in: AGENTS.md. Delete the section between
<!-- code-review-graph MCP tools --> and its closing marker and reinstall to pick up the current text.

This repository's own instruction files were regenerated through that path rather than hand-edited, so the upgrade is proven end to end. Every byte outside the managed block is identical to HEAD.

3. A bar for new platform targets

CONTRIBUTING.md gains an "Adding a Platform Target" section. Every supported tool is permanent maintenance surface, and the ones that break are the ones merged without evidence they ever worked in a released client. New targets need official MCP config documentation, the exact path and schema, an entry through the existing PLATFORMS table, preserved unrelated settings, byte-idempotent reinstall, a working uninstall, lifecycle tests matching the existing ones, and a screenshot or transcript from a real released client showing a CRG tool being invoked. A rendered image of text does not count. Requests no maintainer can install and test may be declined or left open.

Tests

24 new: 5 guardrail assertions across all nine targets, 12 for the install upgrade path (upgrade from each recorded variant, byte-idempotent reinstall, hand-edited block preserved and reported, user content around the block survives, duplicate stale blocks collapsed), and 7 for uninstall including a full install-then-uninstall byte-for-byte round trip.

Full suite 2783 passed, 5 skipped, 2 xpassed. ruff and mypy clean.

tirth8205 and others added 5 commits August 19, 2026 19:47
The generated instruction section told agents to ALWAYS use the graph
before Grep/Glob/Read and to fall back to file search only when the graph
did not cover the need. In practice that made models act on graph
summaries, skip the implementation, and produce shallower work. A zero
result can also mean "not indexed" rather than "does not exist".

Every platform instruction file now carries the same short guardrails:
narrow scope with the graph then read the source, read the implementation
and its tests before a non-trivial change, verify the exact source for
behavior, database, migration, retry, fallback, recovery and compatibility
code, prefer the source when the two disagree, and treat an empty result as
possibly unindexed. The intro and the "fall back only when" line were
tightened to pay for most of the space, so the injected section grows by 6
lines (38 to 44) for CLAUDE.md and 5 lines (46 to 51) for Copilot. The
intro and guardrails are shared constants so all 9 targets stay identical.

The four skill templates no longer say ALWAYS start with
get_minimal_context_tool, and each gained one line about reading the
implementation before changing code. Bundled skills/ regenerated to match.

CONTRIBUTING.md gains a platform target section stating what a new AI-tool
install target must include before review: official MCP config docs, the
exact path and schema, an entry through the existing PLATFORMS table,
preserved unrelated settings, byte-idempotent reinstall, working uninstall,
lifecycle tests matching the existing ones, and evidence from a real
released client. Requests no maintainer can test may be declined.

Fixes #314

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
…he file

_inject_instructions only checked whether the opening marker was present.
Anyone who installed at an earlier version kept that release's text forever
and reinstalling was a no-op, so the guardrails added in the previous commit
would only ever reach brand-new installs. Same upgrade-path failure as #558.

Generated sections now end with <!-- /code-review-graph MCP tools --> so the
managed block has real boundaries. Blocks written before that marker existed
have no closing boundary, so they are found by matching their full recorded
text rather than by guessing where they stop, and only text that exactly
equals a block this project generated is ever rewritten. Anything the user
wrote around the block survives byte for byte, and duplicate stale blocks
from repeat installs collapse to one.

_legacy_instructions.py records the 10 past block texts, recovered by walking
git history twice: an AST evaluation of every past revision of skills.py, and
a scan of the instruction files this repo ships, which caught blocks a
markdown formatter rewrote after generation. The list is append-only.

_inject_instructions now returns created, updated, unchanged or conflict.
Identical content stays a no-op and does not rewrite the file. A block that
matches nothing known was hand-edited: it is left untouched and reported, so
install names the file instead of silently doing nothing. inject_platform_
instructions keeps its list-of-filenames contract; the new
inject_instruction_files carries the outcomes, and the install command and
its dry-run preview both use them.

Refs #314, #558

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
Ran skills.inject_instruction_files against this checkout rather than
hand-editing, so the upgrade path from the previous commit is proven on real
files that have carried the stale wording since before the guardrails existed.

CLAUDE.md, AGENTS.md and GEMINI.md each held the previous generated block with
a markdown formatter's normalized table separator; all three upgraded in place
and every byte outside the block is unchanged.
.github/code-review-graph.instruction.md is a superseded path, so the same run
removed it, taking with it a Copilot variant that told agents to prefer the
graph over #tool:search.
.github/copilot-instructions.md is not owned by the platform table, so it went
through skills._inject_instructions directly with the same marker and section.

The install path also writes .cursorrules, .windsurfrules, CODEBUDDY.md,
QODER.md and the .kiro and .github/instructions files. This repo does not track
those, so they were removed again rather than committed.

Refs #314

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
_remove_instruction matched only the section text the running version
generates. Install can now upgrade a block from any release, so leaving
removal on a single exact text meant a user who asked for the instructions to
go kept whichever wording their original install wrote, reported as "differs
from a known installed section" and silently left in place.

Removal now walks skills._known_instruction_sections(), the same recorded
texts install matches, longest first so a short variant cannot strand the tail
of a longer one that contains it. That covers every past release including the
variant a markdown formatter rewrote in this repo's own files, and clears
duplicate blocks an older release stacked up.

The safety rules are unchanged: exact match only, no end boundary is ever
guessed for a block that has no closing marker, and a section that matches
nothing known is left alone and reported rather than deleted. A file holding
both a generated and a hand-edited block loses only the generated one and is
named in the report.

_join_without_instruction closes the gap. Text on both sides is kept and only
the whitespace at the seam is normalised, so removing a block from the middle
of a file leaves one blank line rather than a pile of them, and removing one
appended at the end restores the file byte for byte.

Refs #314, #558

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012fHfGDiZedoxjpKzanHri3
@github-actions

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.65 (MEDIUM) — 45 changed function(s)/class(es), 0 affected flow(s), 12 test gap(s)

Risk-scored changes

Risk Level Symbol Location Tested
0.65 medium code_review_graph/cli.py::_describe code_review_graph/cli.py:180 no
0.60 medium code_review_graph/cli.py::_instruction_files_to_modify code_review_graph/cli.py:158 no
0.60 medium code_review_graph/cli.py::_handle_init code_review_graph/cli.py:282 yes
0.40 medium code_review_graph/skills.py::_known_instruction_sections code_review_graph/skills.py:1460 yes
0.40 medium code_review_graph/skills.py::_inject_instructions code_review_graph/skills.py:1503 no
0.35 low code_review_graph/uninstall.py::_join_without_instruction code_review_graph/uninstall.py:842 no
0.30 low code_review_graph/skills.py::_upgrade_managed_block code_review_graph/skills.py:1470 no
0.30 low code_review_graph/skills.py::inject_claude_md code_review_graph/skills.py:1544 yes
0.30 low code_review_graph/skills.py::_remove_legacy_instruction_file code_review_graph/skills.py:1577 no
0.30 low code_review_graph/skills.py::inject_platform_instructions code_review_graph/skills.py:1782 yes

Test gaps

  • code_review_graph/cli.py::_instruction_files_to_modify (code_review_graph/cli.py:158)
  • code_review_graph/cli.py::_describe (code_review_graph/cli.py:180)
  • code_review_graph/skills.py::_upgrade_managed_block (code_review_graph/skills.py:1470)
  • code_review_graph/skills.py::_inject_instructions (code_review_graph/skills.py:1503)
  • code_review_graph/skills.py::_remove_legacy_instruction_file (code_review_graph/skills.py:1577)
  • ...and 7 more without direct tests

Token savings: this graph-backed report used ~120,364 fewer tokens (~95%) than reading every changed file in full (estimated, chars/4 approximation).


Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

@tirth8205
tirth8205 merged commit d9c5f04 into main Aug 19, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warning: blindly using code-review-graph can make model faster but noticeably worse at code understanding

1 participant