diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-28 21:28:29 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-28 21:28:29 -0500 |
| commit | 80624606b8a60d97d8c7600882ddc35f5225469f (patch) | |
| tree | 4c4e56089c1293ab75863fe50bafefcf5084565e /claude-rules | |
| parent | 3a933a26c12b6350fa46faf89bf86e99bfab0f30 (diff) | |
| download | rulesets-80624606b8a60d97d8c7600882ddc35f5225469f.tar.gz rulesets-80624606b8a60d97d8c7600882ddc35f5225469f.zip | |
feat(publish): isolate the pre-commit review and loop it to approval
The review already ran before every commit. It ran in the context that wrote the diff, which is the part that didn't work. A self-review checks the change against the author's own model of it and can't check the model, so the errors that survive are the ones that were never in the diff: a scope inherited from whoever reported the problem, a blast radius estimated instead of measured.
So the reviewer is now a subagent, on every commit including a one-line one. It gets the diff, a one-line claim of what the change does, and the ticket where one exists. It doesn't get the conversation or my reasoning, because those are the model it exists not to hold. The ticket stays in for the opposite reason: it was written before the work and is the only thing that can contradict my claim about my own diff.
Findings loop back to the same reviewer until it approves, rather than to a fresh one that can't tell an addressed finding from one that never existed. Three rounds, or a finding that recurs after being reported fixed, and it stops for a human instead. The unattended callers park the task rather than wait for an answer nobody is awake to give.
I gave the stance a substantiation floor. An agent told to attack will manufacture findings to satisfy the instruction, and a manufactured finding costs a round and teaches the author to discount the next review.
subagents.md said three separate times not to dispatch work this small, so it now carries an Isolation Override: the size heuristics assume the main thread could do the job equally well, and they lapse when its own context is what makes its answer untrustworthy. Field 2 of the Prompt Contract inverts there. Paste your context in and you hand over the very model you spawned the agent to escape.
I wrote it by running it on itself: three rounds and thirteen findings. Two were things I'd have shipped. Withholding the ticket made my own claim self-certifying, and the override reaffirmed the contract field that would have destroyed the isolation.
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/subagents.md | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/claude-rules/subagents.md b/claude-rules/subagents.md index 8578dea..e52d906 100644 --- a/claude-rules/subagents.md +++ b/claude-rules/subagents.md @@ -34,6 +34,66 @@ This is the same boundary the "Don't Subagent At All" section and the "Subagenting trivial work" anti-pattern draw; treat it as an explicit gate at dispatch time. +Every size-based rule in this file — the cost gate here, "Don't Subagent At +All", the trivial-work anti-pattern — is subject to the isolation override +below. + +## Isolation Override — When Size Doesn't Gate + +Every size heuristic in this file rests on one assumption: that the main +thread could do the task itself just as well, so the only question is +whether delegating is worth the overhead. When that assumption fails, the +heuristics don't apply, and a five-line task can require a subagent that a +five-hundred-line one wouldn't. + +The assumption fails whenever **the main thread is structurally disqualified +from the task** — not slower at it, disqualified. The test: would the main +thread's own context make its answer *less* trustworthy? If holding the +context is what corrupts the judgment, then doing it inline doesn't save the +overhead, it destroys the result. The isolation *is* the deliverable, and +"it's only a small diff" is not an argument against it. + +**The standing instance is the pre-commit code review** (`publish` skill, +Step 1). The author cannot review their own change, because a self-review +checks the diff against the author's own model of it and cannot check the +model. Errors that survive a self-review are the ones that were never in the +diff — an inherited scope, an estimated blast radius, a fix correct for the +case in mind and wrong for the one never considered. So that review is +dispatched on *every* commit including a one-line one, and the ~10-tool-call +floor, the single-function rule, and the trivial-work anti-pattern are all +overridden there by design. + +Other cases with the same shape: verifying a claim the main thread already +committed to in conversation, and any second opinion where the first opinion +is already in context. If you find yourself reasoning "I already know the +answer, so a subagent is wasteful," check whether already knowing it is the +problem. + +This override widens *what* gets dispatched. Scope, constraints, and output +format are still required, and arguably matter more here, since an isolated +agent can't fall back on shared context to fill a gap. + +**Field 2 of the Prompt Contract inverts under this override, and the +inversion is the whole point.** Normally field 2 says to paste the relevant +output verbatim and include what you learned in earlier turns. Do that for an +isolation dispatch and you hand over the very model you spawned the agent to +escape — a reviewer given your findings reviews your findings. So for an +isolation dispatch, field 2 is *the artifact under test and the independent +record of what was asked, and nothing else*: the diff, a one-line claim of +what it does, and the ticket or plan where one exists. The conversation, the +rationale, and the dead ends are withheld on purpose. + +Keep the requirement source in. A ticket is not your model of the change; it +was written before the work, usually by someone else, and it is the only +thing that can contradict your claim about your own diff. + +**The output is a judgment, so the review gate resolves differently.** The +Review-Gate Cadence below says subagent output is a claim to be verified +before moving on, which is right when the deliverable is *work*. When the +deliverable is *a judgment about your work*, verifying it against your own +reading reinstates exactly the bias the dispatch removed. Disagreement goes +to the user to adjudicate, not back to the author's own judgment. + ## When to Spawn a Subagent ### Parallel-safe (spawn multiple in parallel) @@ -63,11 +123,15 @@ at dispatch time. ### Don't Subagent At All +Unless the Isolation Override applies — these are efficiency rules, and they +lapse when the main thread's own context is what makes its answer untrustworthy. + - **The target is already known** and the work fits in under ~10 tool calls. - **Single-function logic** — one Read + one Edit is faster than briefing an agent. - **You can see the answer from context** — don't spawn a researcher for - something already on screen. + something already on screen. (The inverse of this one is the override's + clearest case: when *having* seen it is the disqualification, dispatch.) ## Prompt Contract @@ -138,7 +202,11 @@ fix), then dispatch the fix with a specific contract. - **Retrying a failed subagent task in the orchestrator** — pollutes context. Dispatch a fix agent instead. - **Subagenting trivial work** — one Read + one Edit doesn't need an - agent; spawn overhead exceeds benefit. + agent; spawn overhead exceeds benefit. Except under the Isolation + Override, where a one-line diff still gets its own reviewer. +- **Reviewing your own change inline** — the mirror-image failure, and the + more expensive one. Skipping a dispatch to save overhead on a small diff + costs a review that could only have come from outside your context. - **Skipping review between tasks** — compounding bugs are much harder to unwind than any single bug. - **Letting the agent decide scope** — "figure out what needs changing" |
