AI coding

Teaching an Agent to Predict Its Own Diff Size

Antonio Evans7 min read

A cutaway diagram of an agent loop: a task card reading review budget 200 lines and 5 files, a small robot holding a receipt with an estimate, a green gate for under budget feeding a code editor.
Key points

Key points

  1. 1A preflight estimate turns an unbounded code change into a number you can compare against a review budget before any file is touched.
  2. 2Ask for a strict JSON payload with lines added, lines removed, files touched, the file list, and a confidence score from 1 to 5.
  3. 3Reject or split any task whose estimate exceeds your budget, such as 200 changed lines or 5 files, and route the overflow to a human or a smaller task.
  4. 4Log the estimate next to the actual git diff on every run, then recalibrate the budget and the prompt when the gap between predicted and actual grows.

Why estimate before the agent writes

An agent that starts editing immediately has already spent your review budget by the time you learn it was too big. Data collected across 50,000+ pull requests and 200+ engineering teams found 200 to 400 changed lines sits in the sweet spot, patches over 1,000 lines showed a 70% lower defect detection rate, and each additional 100 lines added about 25 minutes of review time (Propel Code study). A preflight estimate keeps an agent inside that window instead of revealing the overrun after the patch exists.

The idea generalizes past diffs. Agent safety gates described as preflight checks between "I should do this" and "I did this" put the planner and the executor on opposite sides of a membrane, so the model proposes and a separate layer decides whether to execute (Agent Safety Gates). A diff-size estimate is the code-specific version of that gate.

Parallelism makes the gate more valuable, not less. Running one git worktree per task lets several agents work at once (parallel agents with worktrees), and each worktree is just a directory sharing one .git store (git-worktree docs). Spinning up isolated workspaces is cheap; reviewing what comes out of them is not, which is exactly what the estimate protects.

What the estimate must contain

Five required fields, fixed names, no prose inside the payload. Anything the orchestrator cannot parse is a failed preflight, not a best-effort guess.

FieldTypeWhy it matters
lines_addedintegerNew code is where most review attention goes
lines_removedintegerLarge deletions can break callers silently
files_touchedintegerSpread predicts coordination risk better than raw lines
fileslist of stringsLets you check for edits outside the assigned module
confidenceinteger 1 to 5Says whether to trust the numbers or ask a question
reasoningstring, max 200 charsOptional, useful when debugging drift

lines_added plus lines_removed gives the changed-line total your budget compares against. files_touched must equal the length of files; treat a mismatch as malformed and retry once.

Confidence is where preflight earns more than a threshold. A confidence of 1 or 2 on a small task usually means the agent has not read enough code to know what it will touch, so the correct response is to make it investigate and estimate again, not to proceed on a guess. The Karpathy Guidelines skill encodes the same posture for coding: state assumptions explicitly, ask when uncertain, and stop when something is unclear (karpathy-guidelines). The estimate is "think before coding" made mechanical.

Writing the preflight prompt

The prompt has three jobs: give the agent read access but no write access, describe the task precisely, and demand a schema-shaped answer. Enforce shape at the API layer rather than hoping. Structured output modes exist so a model returns a validated object instead of free text (OpenAI prompt engineering guide).

You are estimating a code change. Do not edit any files.
Read what you need. Return only this JSON object:

{
  "lines_added": <integer>,
  "lines_removed": <integer>,
  "files_touched": <integer>,
  "files": ["<path>", ...],
  "confidence": <1-5>,
  "reasoning": "<max 200 chars>"
}

Task: <task description>
Rules:
- Count every line the patch would add or remove, including tests.
- If unsure which files are involved, drop confidence to 2 or lower.
- List only files that exist or that you would create.

Two details matter more than wording. Allow the agent to count the tests it plans to write, because a feature change with tests can double the line count. And forbid edits at the tool level, not just in the prompt: if a write tool is registered during preflight, the estimate becomes a promise the agent can quietly break. The safety-gates pattern calls this a per-phase tool allowlist, default-deny (Agent Safety Gates).

Run preflight in its own context, not the write context. If the writing agent can see its own estimate it may pad or trim the diff to match, turning a forecast into a self-fulfilling target.

Setting the review budget

A budget is a pair of numbers per task type, not one global constant. A refactor and a config change carry different risk at the same line count.

Task typeChanged linesFiles touchedNotes
Bug fix1003A large bug-fix diff is usually a scope problem
New feature slice3005One cohesive feature per task
Refactor4008One logical refactor, no behavior change
Config or migration502Small and reversible
Documentation80010Low risk, still capped

The 200 to 400 line range and the under-100 guidance for bug fixes come from the PR-size analysis (Propel Code study). A caution: a study of pull request acceptance found static-analysis quality rules did not influence whether a pull request was accepted, so do not overfit the budget to lint rule counts (Lenarduzzi et al.). Size is a routing signal, not a quality verdict.

On rejection, three responses cover most cases: split cleanly decomposable tasks into sub-tasks and re-estimate each, narrow by trimming files outside the assigned directory, and escalate anything at confidence 1 or 2, or over budget with no clean split.

Worked example. Budget is 200 changed lines and 5 files. The estimate returns 340 lines across 9 files at confidence 2, failing both counts. Split into "add the data model and migration" (estimated 60 lines, 2 files) and "wire the API endpoint and tests" (estimated 210 lines, 4 files). The first passes; the second still fails on lines, so split again into "handler" and "handler tests." All pieces now pass preflight and land as reviewable diffs. Four small estimates replace one rejected 340-line patch.

Wiring the orchestrator and logging actuals

The orchestrator owns the budget, the loop and the log. Four functions: estimate, compare, dispatch, record.

def preflight(task, budget, agent):
    est = agent.estimate(task)          # structured JSON, read-only tools
    if est["files_touched"] != len(est["files"]):
        est = agent.estimate(task)      # one retry on malformed estimate
    changed = est["lines_added"] + est["lines_removed"]
    verdict = "pass"
    if changed > budget["lines"]:
        verdict = "split_lines"
    elif est["files_touched"] > budget["files"]:
        verdict = "split_files"
    elif est["confidence"] <= 2:
        verdict = "escalate"
    return {"task": task, "estimate": est, "changed": changed, "verdict": verdict}

Run each task in its own worktree so an abandoned attempt leaves the main checkout untouched, and clean stale ones with git worktree prune (git-worktree docs). After the run, compute the actual diff with git diff --numstat, which prints added and removed counts per file and sums without hunk parsing. Capture it before the commit so the numbers match what the reviewer saw.

Each record should carry task id, task type, estimated changed lines and files, confidence, actual added and removed lines, actual files, verdict, and whether the run was split, escalated or shipped. Build two views from those rows: median drift by task type, and the share of runs where actual exceeded the estimate by more than 50%, grouped by confidence. If confident estimates (4 and 5) miss as often as unconfident ones, the score is noise and should not drive routing. Your own log is the only benchmark that speaks to your repository; review automation results vary substantially by task and evaluation setup, and strong benchmark behavior does not prove production readiness (Code Review Research overview).

Failure modes that survive the gate

FailureSymptomMitigation
Confidently wrong100 lines promised at confidence 5, 400 writtenStop the write phase at 1.5x the estimate; compare confidence bands
Test inflation20 logic lines, 300 test linesBudget test lines separately
Scope driftFiles outside files changeEnforce the file allowlist and fail the run
Malformed payloadProse around the JSON, count mismatchOne retry, then a human

The subtlest trap: a passing test is not proof the bug is fixed. Analysis of validation events in repair agents found 46.0% of positive comparable events carried no bug-discriminating information, and 23.8% of baseline rollouts closed with a patch whose entire positive evidence was of that kind (Validation Evidence in LLM Repair Agents). The estimate keeps the diff small; pair it with a test-quality gate that asks whether the test fails on the original code.

A second pattern: read the reasoning field for scope creep. If the agent's own note says it "also refactored the helper module while I was there," the surgical-changes rule has been violated and the estimate shows it. Every changed line should trace directly to the request (karpathy-guidelines). A 400-line estimate for a 50-line request is scope creep made visible before it costs a reviewer an afternoon.

For teams that would rather hand the loop to a maintained agent, Quanta builds estimate-and-review layers for coding work; Quanta Experts read your context, do the task and hand back finished deliverables, including preflight-and-review steps.

Extending the gate and reusing existing rules

Once a structured estimate exists, the same three-line decision rule applies to other fields. Compare files against a module ownership map and block edits outside a team's area. Compare lines_removed against a threshold and require human sign-off on deletions, since deleting code whose callers you have not enumerated is a common way a small-looking diff breaks production. Route confidence 1 to a scoping conversation before anything runs.

If you want behavioral rules already written, a community skill such as the Karpathy Guidelines ships as plain Markdown any agent reading the skill format can load, so the same instructions work across models and providers (TypingMind skill listing). Skills that install into a coding agent, including behavioral guidelines like these, are collected at Quanta Skills, so the preflight rule and the surgical-changes rule can ship together as one installable instruction.

Start with one budget number and one field you trust: changed lines. Add files and confidence once you have a week of logs. Then let the numbers decide whether a task runs, splits or goes to a person, instead of finding out from the size of the diff.

FAQ

FAQ

Why ask the agent to estimate instead of just measuring after the run?

Measuring after the run tells you the review will be expensive once the patch already exists, the worktree is dirty and the reviewer is staring at 400 lines. The estimate moves that signal to the front of the pipeline, where it can still change the outcome: split, narrow or escalate before a line of code is written.

What confidence scale should I use, and how should I route on it?

Use integers 1 to 5, where 1 means "I have not read enough of the codebase to say" and 5 means "I have read every file involved." Route 1 and 2 to a scoping step or a human, accept 3 with budgets enforced, and accept 4 and 5 on the budget alone. Compare actuals against the bands periodically; if confident estimates miss as often as unconfident ones, stop routing on the score.

Should the estimate include generated tests?

Yes, but budget test lines separately from production lines. Tests are part of the change a reviewer must read, and 20 logic lines plus 300 test lines is still a 320-line diff. A separate test-line ceiling prevents one large test file from consuming the whole allowance.

How do I keep the estimate from leaking into the write phase as a target?

Run preflight as a separate invocation with read-only tools, log its output, and start the write phase in a fresh context that receives the task and file allowlist but not the estimate. If the writing agent can see the estimate it may pad or trim the diff to match, turning a forecast into a self-fulfilling one.

What should happen when the estimate is malformed or the agent cannot estimate?

Retry once, and if the second attempt is still unparseable or missing a required field, treat the preflight as failed rather than skipped. Send the task to a human with the raw output attached, because a model that cannot produce a schema-shaped estimate on a small task is telling you it does not understand the task well enough to run it safely.

Sources

Sources

  1. The Impact of PR Size on Code Review Quality: What Data ...
  2. Agent Safety Gates: 12 Preflight Checks Before Tools Run
  3. How to Run Parallel AI Coding Agents With Git Worktrees
  4. Git - git-worktree Documentation
  5. skills - karpathy-guidelines - GitHub
  6. Prompt engineering | OpenAI API
  7. Does code quality affect pull request acceptance? An ...
  8. Overview of Code Review Research
  9. Validation Evidence in LLM Repair Agents
  10. Karpathy Guidelines by multica-ai, AI Skill for Any LLM | TypingMind
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles