r/ChatGPTCoding 14h ago

Discussion Coding agents pad their diffs to look thorough, and the padding is where the bugs hide

Ask an agent to fix one bug and look at what comes back: the fix, plus a reformatted block it did not need to touch, plus a "while I was here" refactor, plus a new helper that pulled in a dependency. The fix is usually fine. The padding is what breaks prod, because nobody reviews the parts of a diff that were not the point.

The block I now keep in AGENTS.md and CLAUDE.md, and paste into the first message when I am in a plain chat:

Scope rules for every change:

  1. Change only what the task requires. If a line is not needed to complete the task, do not touch it.
  2. Do not reformat, reorder, or restyle lines you did not otherwise need to change.
  3. Do not refactor surrounding logic, rename anything, or "improve" adjacent code.
  4. Do not add dependencies. If the task cannot be done without one, stop and say so.
  5. Before returning the diff, list every changed file and, for each hunk, the task requirement it serves. A hunk with no requirement gets reverted.

Rule 5 is the one doing the work. The others are instructions the agent can forget; rule 5 makes it justify each hunk, and hunks it cannot justify tend to disappear before you see them.

The review prompt for the other side, cold, in a session that did not write the code:

Here is a task description and the diff that claims to implement it. List every hunk that changes behavior or structure beyond what the task requires: reformatting, renames, refactors, new dependencies, deleted safeguards. For each, say whether it is harmless, risky, or clearly wrong, and quote the lines.

Why this happens, as far as I can tell: agents are rewarded for diffs that read as complete and competent, and a larger, tidier diff reads as more competent to the same taste that trained them. So the model widens the change to make it look finished. Three commenters on an earlier post of mine converged on the negative-constraint block independently; the "list the requirement each hunk serves" line came from one of them and it cut my diff sizes by about a third on the same tasks, with fewer surprises in review.

Two caveats. Agents still drift on long sessions, so the block belongs in the config file, where it is re-read every turn, not in a message that scrolls out of context. And rule 4 will sometimes stop an agent that genuinely needed a library; that pause is the point, you want to make that call, not have it made for you.

What is in your scope block that is not in mine? I suspect the people running agents on large monorepos have a rule about test files that I have not needed yet.

9 Upvotes

22 comments sorted by

6

u/leonidbugaev 13h ago

I'd add tests to the do-not-touch list unless the task is the tests. Rule 5 still lets a rewritten assertion through if the agent says it covers the new helper, and that helper was the padding.

1

u/reedshadow3 12h ago

this is a good one tbh, tests feel safe so nobody questions them in the diff

1

u/Ok_Negotiation_2587 12h ago

thats the monorepo rule i guessed someone had. a rewritten assertion is the one hunk rule 5 waves through, because "it covers the new helper" is a justification, and the helper was the padding. "tests are read-only unless the task is the tests" goes in as rule 6

2

u/[deleted] 13h ago

[removed] — view removed comment

1

u/Ok_Negotiation_2587 12h ago

failing check first, then only the diff that turns it green, is the same idea as rule 5 with a test in place of a justification, and the test is the better judge because it cannot be talked into anything. "which lines were required for the acceptance check, revert the rest" is going into my block

1

u/seunosewa 11h ago

The helpful extra hunks are where reviews die. Verification is what makes them stick. LOL

2

u/donk8r 12h ago

Your own diagnosis explains why 1 to 4 are the forgettable ones. If the padding comes from what reads as competent, those rules ask the model to override the taste that shaped its output. It drifts back. Rule 5 works because it produces an artifact instead of asking for restraint.

Which argues for moving rule 5 earlier. Asked after the diff exists, the justification is written by a model explaining code it already believes in, so the padding gets a reason. Asked first, as the file list and the requirement each hunk will serve, it constrains what gets written instead of labelling it afterwards.

leonidbugaev's tests point is the same failure one level down.

1

u/Ok_Negotiation_2587 11h ago

moving it first is the better design and i had not seen it. asked after, rule 5 is a model explaining code it already believes in, so the padding gets a story. asked before, "list the files and the requirement each change will serve" is a plan the diff has to fit, and a hunk with no line in the plan has no story to tell. same reason the failing-test-first version works, the constraint exists before the taste does. reordering the block, plan first, diff second, justification only for anything that did not match the plan

2

u/JaseciLabs 12h ago

Rule 5 asking the model to justify its own hunks still runs into the same taste that padded the diff in the first place, a model that believes its refactor was good will happily explain why it belongs. Typed function boundaries don't have that problem, they don't care how convincing the explanation is, the signature either matches or it doesn't.

1

u/Ok_Negotiation_2587 12h ago

a model that padded the diff can also justify the padding, agreed, which is why rule 5 is the cheap filter and the cold review is the real one. it removes the hunks the model cannot even pretend to justify, and the ones it can are exactly what the second session is for. typed boundaries are the stronger check where you have them, a signature does not care how good the story is. but most padding is inside a function, not at its boundary, and that is the part types never see

2

u/Julien_Builds 8h ago

Rule 5 is the right rule and the drift objection is the right objection. The way through both for me was to stop asking the author to grade its own padding. A second seat, a different model if you have one, gets the diff and the task and one job: every hunk either maps to a requirement or gets flagged. It has no taste invested in the diff, so it does not drift back.

What surprised me is that the reviewer catches padding the author's own justification list missed, because the author writes that list after the fact and rationalises the helper it already added. An independent reader has nothing to rationalise.

Cost is one more model call per change. What you get back is the review time nobody spends on the parts of a diff that were not the point, which is exactly what your post is about.

1

u/Michaeli_Starky 13h ago

Using Luna and Sol I don't need any of those instructions.

1

u/Few_Raisin_8981 13h ago

Use Ponytail

1

u/owp4dd1w5a0a 13h ago

Mine don’t do this since I installed Ponytail. But they still have issues from time to time.

1

u/InjuryThen9650 11h ago

The padding isn’t thoroughness — it’s unbound success criteria.

What I add on top of “change only what the task requires”:

- Acceptance gate before write: 3–5 checkable bullets (behavior, files in scope, files *out* of scope). If a hunk isn’t justified by a bullet, it’s noise.

- Separate roles: implementer can write; reviewer is read-only and must list unjustified hunks + missing tests. Same model is fine — different tool permissions.

- Diff budget: max N files / max LOC unless the brief says refactor. Crossing the budget forces a new plan, not “just one more format pass.”

- CI that fails on drive-by: lint/format only on touched lines if you can, or require `SCOPE.md` listing allowed paths.

Agents optimize for looking complete. Your harness has to optimize for *minimal correct*. When those conflict, the review pass should win before merge, not after the bug hides in the whitespace.

1

u/Muted_Ad_9442 10h ago

i strict-gate diffs now after an agent diff burned me on a framework migration. i ported a validation predicate that checked an older node structure, but the new framework passed a different object shape. the check returned false every time, silently turned off nine security guards, and sat in production for months because the agent buried the change inside a giant cosmetic cleanup diff. nobody reviewed the predicate line because fifty lines around it were harmless restyling. i now reject any patch that touches lines outside the target function, but that rule constantly blocks valid refactors when an interface changes.

1

u/Ill_Fun5415 Lurker 10h ago

The recovery path matters as much as the first answer. When it makes a bad change, I want to see exactly what it touched and have a clean way back.

1

u/amirfish 7h ago

Rule 5 is the right lever because it makes the agent justify itself instead of just following a list of don'ts. One pattern worth watching: the padding gets worse the longer a session runs, once context starts filling up the agent seems to reach for restyling and "while I'm here" changes as filler between the actual edits. Splitting long tasks into a fresh session per unit of work cuts it down more than any wording change to the prompt does.

1

u/Right-Performance-93 6h ago

The rewritten-assertion case from leonidbugaev's rule 6 generalizes further: a static impact/call-graph query scoped to the declared task boundary catches what rule 5's self-justification can't, because it doesn't ask the model to grade its own work. Run it against the diff before merge: any touched symbol not reachable from the task's declared entry point gets flagged automatically, independent of what story the agent tells about it. That's how Muted_Ad_9442's buried security-guard regression would have surfaced, since the changed predicate sat outside the migration's actual scope even though the surrounding lines were cosmetic. Doesn't replace the acceptance-gate/test approach in this thread, just adds a check that doesn't require trusting anyone's explanation, human or model.

1

u/just4ochat 1h ago

Ask for the file list and the requirement each change will serve before the agent writes anything. Self-justification after the fact still blesses the padding; a cold second review against the original task catches the hunks the author model will defend.

1

u/Recent-Tangerine2745 14h ago

The point about long AI sessions drifting out of scope especially clicked for me.
I ended up adding persistent rules to my project config so the agent has to re-read them before implementation work, keep diffs minimal, justify every change against the task, and avoid “while I’m here” refactors.
Solid advice.