Logic errors are loud. Churn is quiet. Most AI-assisted refactors fail review for the second reason, not the first.
The patch renames a variable and reformats a dict. It touches four files and 180 lines. Your one intended edit is buried inside.
Two commits fix this. Commit A pins behavior and touches tests only. Commit B makes the smallest semantic change and stays inside a line budget. A short script enforces both rules.
Everything below is a proposed workflow. The script is an illustrative sketch and was not executed against any repository. Treat the numbers as starting points you tune per codebase.
1. Why churn defeats the review
Reviewers have finite attention per diff. Every unrelated hunk spends some of it. Past a certain size, review becomes skim and approve.
A model has no reason to minimize diff size. It has a reason to produce a plausible full file. Those two goals diverge on legacy code.
The gate below does not try to make the model careful. It makes the diff small enough that carelessness is visible.
2. Prerequisites
- A test runner that already works on the untouched branch.
- Fixtures small enough to commit, or input capture you are allowed to store.
- Agreement that a refactor may be split across two commits.
If the second item is a privacy problem, stop here. Do not paste production payloads into a repo to satisfy a workflow.
3. Step 1 — Pin one symbol, in tests only
Pick one function. Pin its observable output, not its internals. Then commit with production code untouched.
git switch -c refactor/price-tier
# add fixtures + assertions for the single target symbol
pytest tests/ -q # must pass on unmodified source
git add tests/
git commit -m "pin: observable output of price_tier()"
If the pin cannot pass on unmodified source, you have learned something useful. The behavior is already unstable or the fixture is wrong.
Do not proceed to editing. Diagnose first.
4. Step 2 — Reject a pin commit that touches production
The rule is easy to state and easy to violate. Enforce it with a diff check, not with intent.
# illustrative sketch, not executed
import fnmatch, os, subprocess, sys
TEST_GLOBS = ["tests/*", "test/*", "test_*.py", "*_test.py"]
LINE_BUDGET = 40 # proposed default, tune per repo
def changed(ref):
out = subprocess.run(["git", "diff", "--numstat", ref],
capture_output=True, text=True, check=True).stdout
for row in out.splitlines():
added, removed, path = row.split("\t")
if added == "-":
yield path, None # binary, not reviewable by line count
else:
yield path, int(added) + int(removed)
def is_test(path):
base = os.path.basename(path)
return any(fnmatch.fnmatch(path, g) or fnmatch.fnmatch(base, g)
for g in TEST_GLOBS)
def check_pin(ref):
bad = [p for p, _ in changed(ref) if not is_test(p)]
if bad:
return False, f"pin commit touches production: {bad}"
return True, "pin commit is tests only"
def check_change(ref):
rows = [(p, n) for p, n in changed(ref) if not is_test(p)]
if len(rows) > 1:
return False, f"change commit spans {len(rows)} production files"
for path, n in rows:
if n is None:
return False, f"binary file changed: {path}"
if n > LINE_BUDGET:
return False, f"{path} churns {n} lines, budget {LINE_BUDGET}"
return True, "change commit is inside budget"
if __name__ == "__main__":
mode, ref = sys.argv[1], sys.argv[2]
ok, msg = {"pin": check_pin, "change": check_change}[mode](ref)
print(msg)
sys.exit(0 if ok else 1)
Run each mode against the commit you just made:
python tools/diff_budget.py pin HEAD~1..HEAD
python tools/diff_budget.py change HEAD~1..HEAD
The script is deliberately blunt. It does not understand intent, renames, or generated files. That bluntness is the point: a rule you can state in one sentence survives a busy week.
5. Step 3 — The change commit gets a budget
Now make the smallest semantic edit that satisfies the request. Keep it to one production file if you can.
If the model proposes a rewrite, revert to your branch and regenerate. Do not hand-edit 200 churned lines back into 12 useful ones.
Formatting goes in its own commit, before the pin. It inflates every later diff otherwise. Add generated paths to the script's ignore list, not to the budget.
6. Step 4 — Prove the pin can actually fail
A pin that never fails is documentation, not a test. Break the behavior on a scratch copy and run the suite.
git switch -c scratch/break-pin
git switch refactor/price-tier
# comment out the guard line in price_tier(), then:
pytest tests/ -q # expect failure
# restore the line, or drop the scratch branch
git branch -D scratch/break-pin
This is a manual check. Log the result in the commit message so the next reviewer does not repeat it.
7. When to split, shrink, or stop
| Situation | Action |
|---|---|
| Pin fails on unmodified source | Capture more fixtures first; do not edit yet |
| Change needs two production files | Split into two refactors with their own pins |
| Churn is mostly reformatting | Reformat in a separate prior commit |
| Pin still passes after an intentional break | Weak pin; assert a specific field or byte, not a shape |
| Output contains time or randomness | Normalize in the test only; leave production alone |
| Fixtures need production payloads you cannot store | Abandon the pin; use a different review strategy |
8. Where a shared AI workbench fits
The gate lives in the repository, not in the assistant. That matters when a team uses a shared tool.
MonkeyAI, described in the current README of the open-source repo, is a team AI workbench for office, coding and design work. The README lists shared team resources, configurable models, MCP integrations, access management and self-hosting. It also carries README.monkeycode.md, which documents the historical MonkeyCode AI development platform. Those are two different descriptions; do not assume identical features or service terms.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
A workbench can keep the convention text and repo tooling in one place for the whole team. It cannot decide your line budget, and it cannot make a weak pin strong. Enforcement stays local, in a script a reviewer can read in thirty seconds.
Self-hosting does not by itself mean data stays inside your network. If a configured external model provider is part of your setup, data may reach that provider. Verify the actual configuration rather than assuming.
9. Limitations and who should not use this
The two-commit split costs a review cycle. On a one-file prototype, that cost is not worth paying.
The gate assumes a stable test runner and committed fixtures. Repos with flaky timing tests will fail the pin step for reasons unrelated to the refactor.
Line budgets punish generated code and vendored files. Scope the script to hand-written paths, or it will block legitimate commits.
Teams without commit-splitting discipline will see the pin commit and the change commit merged by habit. The script catches that only if it runs before merge.
If your change is genuinely cross-cutting, skip the budget and review it by design. A gate that lies is worse than no gate.
10. Start with one symbol
Pick the ugliest function you avoid touching. Pin it. Split the commits. Add the check to CI once, not in five places.
The repository is at github.com/chaitin/MonkeyCode. Read the README first, then decide whether a shared workbench changes your review process or just your prompt storage.
Top comments (0)