DEV Community

Emery Yang
Emery Yang

Posted on

Your AI Patch Is Cheap to Write and Expensive to Review: A 90-Minute Review-Cost Ledger

Writing code got cheap. Reviewing it did not. That is the whole problem now.

This post is a 90-minute spike. One hypothesis. One artifact. A ship-or-kill verdict on paper.

The angle comes from a topic signal I keep seeing on DEV this week: AI made coding cheaper, so why is software still expensive? My answer is narrow and testable. The cost moved. It left the editor and landed in your review queue.

The hypothesis, written before the clock starts

A spike without a pre-registered threshold is just browsing.

So write this down first, in a file, with a timestamp:

Agent patches that pass CI cost no more human review minutes than hand-written patches touching the same files.
Kill the workflow if median review minutes per accepted agent patch exceed the hand-written median by more than 50%.

Two rules keep this honest.

  • Fixed sample: five tasks, chosen before you start. Not five tasks you like after.
  • Fixed clock: 90 minutes total. When time is out, you write a verdict, not an extension.

Three numbers, not a dashboard

You only need three measurements per task. Anything more is procrastination with charts.

  1. Patch surface — files touched, lines added, lines deleted.
  2. Review minutes — wall clock from opening the diff to approving or rejecting it.
  3. Rework rounds — how many times the patch came back.

Patch surface is free to collect. Review minutes are not. Start a timer. Be boring about it.

The 90-minute budget

Minutes Activity Output
0–10 Write hypothesis and kill rule HYPOTHESIS.md
10–25 Build the ledger script review_ledger.py
25–60 Run five fixed tasks five patches
60–80 Review each patch, timing yourself reviews.csv
80–90 Compute, compare to threshold, decide VERDICT.md

Note what is missing. No evaluation framework. No prompt library. No leaderboard.

The spike is not about which model is best. It is about whether your review loop absorbs the output at a sane price.

The artifact: one script, standard library only

Save this as review_ledger.py in the repo you are spiking. It reads git patch stats and your timed reviews, then prints a verdict object.

# review_ledger.py — stdlib only, run from the repo root
import json
import statistics
import subprocess


def sh(*args):
    return subprocess.run(args, capture_output=True, text=True, check=True).stdout


def patch_stats(base, head):
    out = sh("git", "diff", "--numstat", f"{base}..{head}").strip()
    files = added = deleted = 0
    for line in out.splitlines():
        a, d, _path = line.split("\t")
        files += 1
        added += int(a) if a.isdigit() else 0
        deleted += int(d) if d.isdigit() else 0
    return {"files": files, "added": added, "deleted": deleted}


def load_reviews(path):
    rows = []
    with open(path) as fh:
        next(fh)  # header: task,kind,minutes,rework
        for line in fh:
            task, kind, minutes, rework = line.strip().split(",")
            rows.append({
                "task": task,
                "kind": kind,          # "agent" or "human"
                "minutes": float(minutes),
                "rework": int(rework),
            })
    return rows


def verdict(rows, max_ratio=1.5):
    agent = [r["minutes"] for r in rows if r["kind"] == "agent"]
    human = [r["minutes"] for r in rows if r["kind"] == "human"]
    if not agent or not human:
        return {"decision": "INCOMPLETE", "why": "need both kinds"}
    a = statistics.median(agent)
    h = statistics.median(human)
    ratio = a / h if h else float("inf")
    return {
        "agent_median_min": a,
        "human_median_min": h,
        "ratio": round(ratio, 2),
        "rework_agent": sum(r["rework"] for r in rows if r["kind"] == "agent"),
        "decision": "SHIP" if ratio <= max_ratio else "KILL",
    }


if __name__ == "__main__":
    rows = load_reviews("reviews.csv")
    print(json.dumps(verdict(rows), indent=2))
Enter fullscreen mode Exit fullscreen mode

And a hard stop, so the clock can actually end you:

#!/usr/bin/env bash
set -euo pipefail
DEADLINE=$(( $(date +%s) + 90*60 ))
while true; do
  left=$(( DEADLINE - $(date +%s) ))
  [ "$left" -le 0 ] && { echo "TIME. Write VERDICT.md now."; exit 0; }
  printf '\r%02d:%02d left ' $((left/60)) $((left%60))
  sleep 15
done
Enter fullscreen mode Exit fullscreen mode

Small note on the script: reviews.csv has four columns, and kind is what makes the comparison possible. Fill it in as you go, not from memory at minute 80.

Where a free tier and a free server fit in this spike

The spike measures your review loop, so the agent host should not be your laptop's variable. Free model access removes the "token budget" excuse, and a free server option removes the "my machine was busy" excuse. Both are exactly the kind of thing a 90-minute experiment needs: zero procurement before minute ten.

MonkeyCode is the open-source project I used for that slot in this workflow. The project advertises free model access and a free server option; at the time of writing the project page also lists a free token allowance of 10M tokens. I did not measure that quota, and terms like that change, so treat the number as project-page information and re-check it before you cite it. What the spike actually needs from the product is unglamorous: a place to run five patches, and a model that does not cost money per attempt.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

Run it on the free server, keep review timing local, and the spike still measures what you care about.

Illustrative ledger output, not a measured result

The block below is a shape example, made up to show the format. Replace it with your own run.

{
  "agent_median_min": 11.0,
  "human_median_min": 9.5,
  "ratio": 1.16,
  "rework_agent": 4,
  "decision": "SHIP"
}
Enter fullscreen mode Exit fullscreen mode

Read the object, not the vibe. Ratio under the threshold and a rework count you can live with means the loop absorbs agent patches. Ratio over it means you are now a full-time diff reader.

The decision table

Use these rows when you write VERDICT.md. Pick one.

Evidence Verdict Next action
Ratio ≤ 1.5, rework ≤ 1 per task Ship narrow Allow agent patches on low-risk files only
Ratio ≤ 1.5, rework high Ship with a review cap Cap diff at one concern per patch
Ratio > 1.5, patch surface small Kill Reviewer overhead is structural, not model-related
Ratio > 1.5, patch surface large Kill and resplit Enforce a file-count ceiling in the prompt
Fewer than three reviews logged Incomplete Do not conclude anything

Last row is the important one. Half a spike is worse than none, because it feels like data.

Limitations, and who should skip this

Be honest about what 90 minutes cannot buy.

  • Five tasks is a smoke test, not a study. Do not generalize to your whole backlog.
  • Review minutes measure your attention, not the patch's correctness. Keep CI as the correctness gate.
  • The ledger says nothing about licensing, security review, or generated-code provenance.
  • A free tier is not a production plan. Plan the migration before the quota matters.
  • Solo one-file bugfixes do not need a ledger. You already know the cost.

Skip this spike entirely if you have no test suite. Without CI, "accepted patch" has no meaning, and the ratio measures nothing. Skip it too if you cannot separate writing time from review time. Your numbers will be fiction with decimals.

Start the clock

One hypothesis, written first. Three numbers, collected five times. One script, ninety minutes, a verdict you can defend to a teammate on Monday.

If you want a low-friction place to run the agent side, the free model access and free server option on MonkeyCode are a reasonable starting slot — verify the current terms on the project page, then let the ledger, not the demo, make the call.

Top comments (0)