From 825bfa5b2c8b4b75dba380bbdfea4600cb5974db Mon Sep 17 00:00:00 2001 From: Remigiusz Antczak Date: Sat, 24 Oct 2026 10:18:03 +0200 Subject: [PATCH] Add read/output budget to the small-diff review fast path One-line BUDGET pointer in deep-code-review SKILL.md to a new routed reference, references/small-diff-read-budget.md (read it first): git diff --stat -p as the one patch read, grep callers and callees then offset/limit reads, tail -n 40 on test and CI output, no narration. The rule text lives in the reference so SKILL.md stays under the 3000-byte fast-path floor (2957); the SKILL.md raise is documented with a size-budget-raise line. Security checks unchanged. Pinned by scripts/test_review_read_budget.py (registered in ci-tests.d) and a new eval case. Tests: 2/2 (test_review_read_budget) Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014QNFFPWVcPUbeuvwM5fk2Z --- .claude/skills/deep-code-review/SKILL.md | 2 ++ .../skills/deep-code-review/evals/evals.json | 13 +++++++++ .../references/small-diff-read-budget.md | 8 ++++++ changelog.d/review-read-budget.md | 3 +++ scripts/ci-tests.d/review-read-budget.sh | 2 ++ scripts/test_review_read_budget.py | 27 +++++++++++++++++++ 6 files changed, 55 insertions(+) create mode 100644 .claude/skills/deep-code-review/references/small-diff-read-budget.md create mode 100644 changelog.d/review-read-budget.md create mode 100644 scripts/ci-tests.d/review-read-budget.sh create mode 100644 scripts/test_review_read_budget.py diff --git a/.claude/skills/deep-code-review/SKILL.md b/.claude/skills/deep-code-review/SKILL.md index ddda1c5f0..9408b9866 100644 --- a/.claude/skills/deep-code-review/SKILL.md +++ b/.claude/skills/deep-code-review/SKILL.md @@ -23,4 +23,6 @@ You are a senior reviewer hunting defects that a change introduces. For a small Whole-app security audit (not a diff): read only `references/security-review-mode.md`; it routes the rest. +BUDGET (small DIFF): read `references/small-diff-read-budget.md` first. + OUTPUT. Final message: the severity-ranked findings, each as `file:line`, severity, mechanism and failing input in one or two sentences. Report template: `references/full-map-report.md`. diff --git a/.claude/skills/deep-code-review/evals/evals.json b/.claude/skills/deep-code-review/evals/evals.json index 114531473..aa31f5ab5 100644 --- a/.claude/skills/deep-code-review/evals/evals.json +++ b/.claude/skills/deep-code-review/evals/evals.json @@ -8360,6 +8360,19 @@ "Applies the exploit-path check to each sibling before confirming it", "Reports siblings together with the search bound, and scopes the fix to all confirmed siblings" ] + }, + { + "id": "small-diff-read-budget", + "prompt": "Review a 120-line diff across three files. How do you read and run things?", + "expected_output": "Reads references/small-diff-read-budget.md first, takes the patch once with git diff --stat -p, locates callers and callees with grep, Reads with offset/limit around each hunk (whole file only if under ~200 lines), pipes test/CI output through tail -n 40, no narration between tool calls; security checks unchanged.", + "expectations": [ + "Opens references/small-diff-read-budget.md before the first read", + "Runs git diff --stat -p once as the single patch read, not per-file diffs", + "Uses grep then Read with offset/limit around hunks, no whole-file read of files over ~200 lines", + "Pipes test and CI output through tail -n 40", + "Emits no narration between tool calls", + "Does not skip any security check to save tokens" + ] } ] } diff --git a/.claude/skills/deep-code-review/references/small-diff-read-budget.md b/.claude/skills/deep-code-review/references/small-diff-read-budget.md new file mode 100644 index 000000000..e8c876eb8 --- /dev/null +++ b/.claude/skills/deep-code-review/references/small-diff-read-budget.md @@ -0,0 +1,8 @@ +Read this when reviewing a small DIFF (the fast path in SKILL.md), before the first read or command. +Read/output budget for the fast path; it never skips a security check in SKILL.md. + +- `git diff --stat -p` is the one patch read; do not re-run it per file. +- For each changed symbol, grep its callers and callees and Read those ranges, plus the context around each hunk, with offset/limit. +- Read a whole file only if it is under ~200 lines. +- Pipe test and CI output through `tail -n 40`. +- No narration between tool calls. diff --git a/changelog.d/review-read-budget.md b/changelog.d/review-read-budget.md new file mode 100644 index 000000000..69862ae60 --- /dev/null +++ b/changelog.d/review-read-budget.md @@ -0,0 +1,3 @@ +### Changed +- `deep-code-review` small-diff fast path gains a one-line BUDGET pointer to the new `references/small-diff-read-budget.md` (read it first): `git diff --stat -p` once, grep to locate then Read with offset/limit around each hunk (whole file only under ~200 lines), test and CI output through `tail -n 40`, no narration between tool calls. Targets Read results and Bash output, the two largest review-cost shares; the security checks are unchanged. SKILL.md stays under the 3000-byte fast-path floor (2966). Pinned by `scripts/test_review_read_budget.py` and the `small-diff-read-budget` eval. +- size-budget-raise: .claude/skills/deep-code-review/SKILL.md 2893→2966 one-line pointer to the new small-diff-read-budget.md reference; the rule text lives in that reference, and the fast-path floor (3000) is not raised diff --git a/scripts/ci-tests.d/review-read-budget.sh b/scripts/ci-tests.d/review-read-budget.sh new file mode 100644 index 000000000..9c8eac54a --- /dev/null +++ b/scripts/ci-tests.d/review-read-budget.sh @@ -0,0 +1,2 @@ +# Registers the small-diff read-budget pin with CI (see the "Per-PR tests" step in ci.yml). Offline. +python3 scripts/test_review_read_budget.py diff --git a/scripts/test_review_read_budget.py b/scripts/test_review_read_budget.py new file mode 100644 index 000000000..1c5040e53 --- /dev/null +++ b/scripts/test_review_read_budget.py @@ -0,0 +1,27 @@ +"""The small-diff fast path in SKILL.md routes to the read/output budget reference, which holds the rule and keeps the security floor.""" +import re +import unittest +from pathlib import Path + +D = Path(__file__).resolve().parent.parent / ".claude/skills/deep-code-review" +SKILL = (D / "SKILL.md").read_text() +REF = (D / "references/small-diff-read-budget.md").read_text() + + +class ReadBudget(unittest.TestCase): + def test_skill_routes_to_reference_in_fast_path(self): + m = re.search(r"^BUDGET \(small DIFF\):.*$", SKILL, re.M) + self.assertTrue(m, "BUDGET line missing") + self.assertIn("`references/small-diff-read-budget.md`", m.group(0)) + self.assertLess(m.start(), SKILL.index("\nOUTPUT."), "rule must sit in the fast path") + self.assertRegex(SKILL, r"(?m)^1\. Read every hunk") + self.assertRegex(SKILL, r"(?m)^5\. Guarantees:") + + def test_reference_has_trigger_and_rules(self): + self.assertTrue(REF.startswith("Read this when")) + for needle in ("git diff --stat -p", "grep", "callers", "offset/limit", "~200 lines", "tail -n 40", "No narration", "never skips a security check"): + self.assertIn(needle, REF) + + +if __name__ == "__main__": + unittest.main()