Agent-generated pull requests rarely fail because of syntax errors. They fail in the silent gaps between the lines — swallowed exceptions, off-by-one date boundaries, copy-pasted error handlers, dead branches that only trigger on Tuesdays. CI won't catch those. A code review should.
This post gives you a scripted 15-minute postmortem that turns a diff into a list of suspicious lines, then verifies each one against a clean execution environment. It uses free model access and a free server option from MonkeyCode for the heavy lifting, but the procedure itself is tool-agnostic.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Why a normal review fails on agent code
When a human writes a PR, they carry context from the codebase conversation. An agent carries a context window. It has seen the relevant files, but it has not lived through the bug reports, the logout edge case, the timezone migration. So its code inherits the agent's confidence and the agent's amnesia.
That leads to three recurring defects:
-
Optimistic path only — the happy path works, error paths are stubbed with
passor a genericraise. - Surface-level consistency — variable names match the style guide, but the logic ignores adjacent invariants.
- Self-fulfilling tests — tests assert what the implementation does, not what the spec requires.
A diff review that reads top-to-bottom cannot see these because they live in the interactions with existing code. You need structured questions.
The artifact: pr_autopsy.py
Here's a small script that scans a unified diff and flags the patterns above. It's pure Python, no dependencies:
#!/usr/bin/env python3
"""pr_autopsy.py - scan a unified diff for common agent-generated PR symptoms."""
import re
import sys
from collections import defaultdict
SUSPECT_PATTERNS = {
"bare_except": re.compile(r"^\+\s*except\s*:$", re.MULTILINE),
"pass_on_error": re.compile(r"^\+\s*pass\s*$", re.MULTILINE),
"todo_comment": re.compile(r"^\+\s*#\s*(TODO|FIXME|HACK)", re.MULTILINE),
"magic_number": re.compile(r"^\+\s*.*[=<>]+\s*\d{3,}"),
"time_hardcoded": re.compile(r"^\+\s*.*(?:sleep|timeout|expire).*=\s*\d+"),
"dup_error_handler": re.compile(r"^\+\s*\w+\s*=\s*(\w+)\s*\n(?:^\+\s*\w+\s*=\s*\1\s*\n)+"),
}
def parse_diff(diff_text):
current_file, current_line = None, 0
for line in diff_text.splitlines():
if line.startswith("+++"):
current_file = line[6:].strip()
current_line = 0
elif line.startswith("@@"):
m = re.search(r"\+(\d+)", line)
current_line = int(m.group(1)) if m else 0
elif line.startswith("+") and not line.startswith("+++"):
yield current_file, current_line, line
current_line += 1
elif line.startswith("-") and not line.startswith("---"):
continue
else:
current_line += 1
def main(diff_path):
with open(diff_path, encoding="utf-8") as f:
diff = f.read()
findings = defaultdict(list)
for fname, lineno, line in parse_diff(diff):
for name, pattern in SUSPECT_PATTERNS.items():
if pattern.search(line):
findings[fname].append((lineno, name, line.strip()[:80]))
for fname, hits in findings.items():
print(f"### {fname}")
for lineno, name, snippet in hits:
print(f" {lineno}: [{name}] {snippet}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("usage: pr_autopsy.py <diff-file>")
sys.exit(1)
main(sys.argv[1])
Run it against a saved diff:
git diff main...agent-branch > agent_pr.diff
python3 pr_autopsy.py agent_pr.diff
It is intentionally shallow. The value isn't the matches — it's the trail they lead you to. Each flag is a question, not a sentence.
Applying it to a realistic agent PR
Here's a condensed set of changes from a synthetic agent PR that converts Unix timestamps to dates for a reporting dashboard:
+++ b/report_utils.py
@@ -42,7 +42,7 @@ def build_report(timestamps):
for ts in timestamps:
- d = datetime.utcfromtimestamp(ts)
+ d = datetime.fromtimestamp(ts)
rows.append((d.year, d.month, d.day, compute_metrics(ts)))
+++ b/report_utils.py
@@ -55,13 +55,17 @@ def build_report(timestamps):
metrics = _cached_metrics[ts]
except KeyError:
metrics = compute_metrics(ts)
- _cached_metrics[ts] = metrics
+ pass
return rows
+++ b/tests/test_report.py
@@ -12,7 +12,7 @@ def test_month_break():
ts = date(2026, 2, 28).timestamp()
result = build_report([ts])
- assert result[0].year == 2026
- assert result[0].month == 2
+ assert result[0].year == 2026
+ assert result[0].month == 2 # will this break on a leap year?
Run the autopsy:
python3 pr_autopsy.py agent_pr.diff
You'll see output like:
### report_utils.py
45: [magic_number] datetime.fromtimestamp(ts)
58: [pass_on_error] pass
### tests/test_report.py
15: [todo_comment] # will this break on a leap year?
None of these are fatal alone. Together they tell a story: the agent changed a timezone function, swallowed a cache write, and left a speculative comment in a test. That's exactly the combination that produces a production incident two weeks later.
The free-server verification loop
Now the trustworthy part: don't take the diff's word for it. Spin up a clean environment and exercise the suspicious paths. I used a free server from MonkeyCode for this sandbox — it boots in seconds and gives you a disposable shell, which is all you need.
The loop is three steps:
- Revert the suspicious line — temporarily restore the original code in the sandbox.
- Run the existing test suite — watch for tests that start failing or passing.
- Add a boundary test — for a timezone change, test midnight UTC vs local, a leap day, a timestamp before 1970.
Example boundary test for the timestamp change:
from datetime import datetime, timezone, timedelta
def test_timezone_aware():
local_now = datetime(2026, 9, 2, 12, 0, tzinfo=timezone(timedelta(hours=2)))
ts = local_now.timestamp()
row = build_report([ts])[0]
# previously this returned UTC, now it returns local
assert row.hour == 12 # passes on the agent's machine, fails in UTC CI
This test isn't in the agent's PR. That's the point.
What to trust, revert, and test
After the loop, classify every touched hunk with this decision table:
| Condition | Action |
|---|---|
| Diff matches a stated requirement and tests fail without it | Trust — but require the agent's test, not the assertion rewrite. |
| Diff changes behavior outside the PR description | Revert — or split into a separate PR with its own rationale. |
| Diff fixes a bug but adds no test | Test — ask for a regression test before merging. |
Diff introduces a pass or bare except
|
Revert — these are never necessary in a non-prototype codebase. |
| Diff comment contains "maybe", "probably", or "?" | Test — the comment is a confession of uncertainty. |
The table doesn't remove human judgment. It replaces vibes with an audit trail.
Limitations and who shouldn't use this
This procedure is a triage, not a proof. pr_autopsy.py produces false positives on legitimate code; the patterns are heuristics, not logic errors. And the free server approach gives you a clean environment, not a full staging replica — don't use it for load testing, secrets, or anything that needs persistent state.
Skip this entire workflow if you're reviewing a 10-line dependency bump, or if you already have a formal verification pipeline with property-based tests. For those cases, the review is the diff — you don't need archaeology.
The one thing to take away
Agent PRs deserve the same treatment as any unfamiliar code: verify behavior in a clean environment, not your remembered context. A 15-minute scripted postmortem catches the silent defects that make you regret trusting automation. Run the script, spin up a free box, and decide with evidence.
If you want more concrete patterns like this, I have a longer checklist in a previous post about filtering agent PRs. But this script alone should pay for itself in the first week.
Top comments (0)