A backend team received an agent-generated pull request on Tuesday morning. The subject line claimed a quiet session-cookie expiry fix. A green CI badge sat under a 240-line TypeScript diff.
The human reviewer had eighteen minutes before standup. The agent summary sounded complete, confident, and specific. That mix is how silent regressions reach production traffic.
This article walks through a hunk-level triage method. Each change is marked trust, revert, or test. The workflow stays useful without any hosted model.
The scene inside PR 418
The constructed example below is not a production incident. It mirrors patterns that show up in agent patches.
Auth middleware, cookie flags, and a retry helper collide. The agent also rewrote error handling for supposed clarity.
It added a shared sleep helper that already existed. It relaxed a cookie Secure flag inside a test fixture. It then copied that fixture into the main runtime path.
Those three moves look unrelated in GitHub's file view. They form one failure mode during a careful review. The agent optimized for a passing demo, not the contract.
What agent PRs hide from reviewers
Agent patches often compile, format, and lint without noise. A tidy diff can still change a public contract.
Cheap agent patches raise review load, not design quality. Technical debt arrives as extra helpers and quiet defaults.
Common failure classes appear together in one branch. The numbered list below is a short memory aid.
- Scope creep appears beside the stated bug fix.
- Duplicate helpers that drift from existing utilities.
- Swallowed errors wrapped in silent retry loops.
- Test fixtures leaking into runtime cookie paths.
- Comments that describe code the model never wrote.
None of these patterns require malice from the model. They require a slower pass than the agent used.
The three-bin review
Every hunk goes into exactly one review bin. Mixed hunks should be split before any merge.
Trust
The change is local, named, and already covered. Types match the surrounding module without new I/O. No new network calls and no new default values.
Revert
The change is unexplained, broad, or security-adjacent. Public signatures, cookie flags, and auth paths start here. Timeouts and retry wrappers belong here until proven.
Test
The change might be correct and remains observable. Reviewers write or extend a test before keeping it.
The three bins are ordered on purpose for safety. Reviewers revert first, then test, then trust leftovers.
Decision table
The table is only a starting filter for tired reviewers. It does not replace reading the full unified diff.
| Signal in the hunk | Bin | First action |
|---|---|---|
| Cookie, CORS, CSRF, or auth header | Revert | Restore prior flags |
| New retry, timeout, or sleep | Revert | Drop unless a test names it |
| Duplicate util already in the repo | Revert | Call the existing helper |
| Pure rename with identical types | Trust | Keep if grep is clean |
| New branch in an existing function | Test | Add a focused unit test |
| Snapshot-only test update | Revert | Demand a behavior assertion |
| Lockfile or CI config churn | Revert | Cut it from this PR |
Error swallow via any or empty catch
|
Revert | Restore typed failures |
Apply the table before arguing about style. Style is not the merge risk here.
Numbered triage on a local checkout
Reviewers should work from a local git checkout. Browser-only review hides rename noise and binary hunks.
- Fetch the review branch and ignore the agent summary.
- List changed files, then open tests before production code.
- Walk the diff in hunks, not in whole-file mode.
- Mark each hunk as trust, revert, or test.
- Revert every revert-bin hunk before running the suite.
- Write focused tests for every remaining test-bin hunk.
- Keep trust-bin hunks only after those tests pass.
Commands for that checkout follow the seven steps. Paste them into a normal developer shell.
git fetch origin pull/418/head:review-418
git switch review-418
git diff main...HEAD --stat
git diff main...HEAD -- test src
git log --oneline main..HEAD
Read the test diff before any production file. Agents often rewrite snapshots to match a new bug.
git diff main...HEAD -- '*.test.ts' '*.spec.ts' '__snapshots__'
rg -n "toMatchSnapshot|secure:\s*false|catch \(" src test
Constructed production snippet
The agent touched cookie flags and error handling together. The TypeScript below is a labeled example, not shipped code.
// example only — agent-generated middleware fragment
export function attachSession(req: Request, res: Response, next: NextFunction) {
const raw = req.headers.cookie ?? "";
const token = parseSession(raw);
retry(
async () => {
try {
await hydrateUser(token);
} catch (err) {
return null; // swallow
}
},
{ times: 3, waitMs: 200 }
).catch(() => next());
res.cookie("sid", token, {
httpOnly: true,
secure: false, // copied from a test fixture
sameSite: "lax",
});
}
Three revert signals sit inside those twenty lines. Swallowed errors hide authentication failure from operators.
A retry turns a 401 response into extra latency. A false Secure flag is a production defect immediately.
A reviewer should not negotiate those three hunks. Revert them in one commit against the main branch.
git checkout main -- src/auth/session.ts
git commit -m "revert: restore session middleware from main"
Keep a legitimate parser fix in a separate file only. Do not re-introduce the retry wrapper during that split.
What to test after the revert
The remaining change, if any, needs a behavior test. Do not accept a snapshot update as proof of correctness. Assert status codes and cookie attributes in plain code.
// example only — review-added tests, not executed here
import { attachSession } from "../src/auth/session";
test("sets Secure cookies on https", () => {
const res = mockResponse();
attachSession(mockRequest({ secure: true }), res, () => {});
const cookie = String(res.headers["set-cookie"]);
expect(cookie).toMatch(/Secure/i);
expect(cookie).toMatch(/HttpOnly/i);
});
test("does not retry on 401 from hydrateUser", async () => {
hydrateUser.mockRejectedValueOnce({ status: 401 });
const next = jest.fn();
await attachSession(mockRequest(), mockResponse(), next);
expect(hydrateUser).toHaveBeenCalledTimes(1);
});
If the agent cannot satisfy those tests, reject the PR. Close it and file a smaller, single-purpose task instead.
A hunk classifier you can run locally
The script below is a mechanical aid for tired eyes. It does not approve code and does not merge branches. It prints a suggested bin from path and diff keywords.
Save it as scripts/triage-diff.mjs in the repo. Run it against a unified diff from git.
#!/usr/bin/env node
import { createInterface } from "node:readline";
const REVERT_PATH = /(auth|session|cookie|csrf|cors|oauth|jwt|password)/i;
const REVERT_HUNK =
/\b(secure\s*:\s*false|sameSite\s*:\s*['"]none|catch\s*\([^)]*\)\s*\{\s*return null|retries?\s*:|setTimeout|sleep\(|\bany\b|@ts-ignore)/i;
const TEST_HUNK = /\b(if\s*\(|switch\s*\(|\bnew |TODO|FIXME)\b/;
const files = [];
let current = null;
const rl = createInterface({ input: process.stdin });
for await (const line of rl) {
if (line.startsWith("diff --git")) {
if (current) files.push(current);
current = { file: line, path: "", bin: "trust", notes: [] };
continue;
}
if (!current) continue;
if (line.startsWith("+++ b/")) current.path = line.slice(6);
if (REVERT_PATH.test(current.path) || REVERT_HUNK.test(line)) {
current.bin = "revert";
current.notes.push(line.slice(0, 120));
} else if (current.bin !== "revert" && TEST_HUNK.test(line)) {
current.bin = "test";
}
}
if (current) files.push(current);
for (const f of files) {
console.log(`${f.bin.toUpperCase()}\t${f.path || f.file}`);
for (const n of f.notes.slice(0, 3)) console.log(` ${n}`);
}
Wire a shell alias so the classifier stays in the review path. Keep the output next to the decision table.
chmod +x scripts/triage-diff.mjs
git diff main...HEAD | node scripts/triage-diff.mjs
Treat every TRUST line as a hypothesis for humans. Humans still read authentication files line by line.
Optional second pass on a free server
A hosted model can draft the same bins from a redacted diff. It must never merge, approve, or rewrite git history.
Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option.
A reviewer pastes a redacted unified diff on that server. The request asks for a trust, revert, and test table. The output is a checklist, never a merge verdict.
Strip secrets before any paste leaves the laptop. Do not send production cookies, tokens, or customer records.
A short prompt shape follows for that optional pass. It is a proposal, not a measured benchmark.
Classify each hunk in this unified diff.
Bins: TRUST, REVERT, TEST.
Rules: auth, cookies, retries, swallowed errors, lockfiles -> REVERT.
New branches and pure logic -> TEST.
Renames with identical types -> TRUST.
Return a markdown table: path, bin, reason, test to add.
Do not praise the patch. Do not invent files.
Compare the model table with the local classifier output. Conflicts go to revert without further debate. Agreement still needs a human read on security paths.
This second pass stays optional for every team. The local script and decision table already finish the review.
Limitations
The classifier uses keywords and simple path checks. It will miss clever breakage in plain helpers. It will flag docs that merely mention cookies.
The method assumes a test runner already exists. A repo with no tests cannot use the test bin. Those teams should revert agent hunks by default.
Do not use this workflow to auto-merge agent PRs. Do not use it on regulated code without a named human owner. Do not send a hosted model any diff that still contains secrets.
The free server and free model access are convenience layers. They do not replace CI, threat review, or on-call judgment. This article does not claim quotas, model names, or hardware.
Who should skip this
Skip the model pass when the diff includes credentials. Skip the whole method when the team cannot revert freely.
Skip it for binary assets, generated protobufs, and huge lockfile-only PRs. Those reviews need different tools and owners.
Staff engineers who already review auth by hand may take only the decision table. That smaller slice still changes the merge order.
Close
Agent PRs fail in clusters, not in single lines. Revert the unsafe cluster first, then test what remains. Trust only the leftover after those two bins.
The eighteen-minute review becomes a fixed sequence. Fetch, classify, revert, test, then read. The agent can wait for that sequence.
Teams on a small machine can add a free hosted model pass. The merge button stays under human control either way.
Top comments (0)