Measuring Review in Human Minutes: A Risk-Tier Gate for Agent Pull Requests in .NET A .NET developer ran a ten-pull-request experiment testing a risk-tier gate that assigns each kind of agent-generated code change a required number of human review minutes, after concluding that speed-reading diffs from AI agents is "a ritual that makes me feel responsible" rather than review. The experiment was prompted by Anthropic's October 15, 2026 post "How the Claude Code team does code review" by Addy Osmani, Morgan Westlee Lunt and Qing Wang, which reported Anthropic-internal figures including changes landing per day rising from roughly 2,500 to 30,000+ in the Anthropic monorepo between May and September, merged PRs more than doubling in the Claude Code repo from June to September, the share of merged PRs reverted falling more than 40% relative, internal PRs with substantive review comments rising from 16% to 54%, and mean reviews to pass falling from 2.08 to 1.32. The author said he took no numbers from two JIN System Architect rewrites of the Anthropic post (items 124 and 154) and went to the original, noting Anthropic publishes no denominators and that the figures cover different scopes. For most of this year my review habit has been the same as it was in 2019: open the PR, read the diff top to bottom, approve. That habit quietly broke once agents started opening PRs for me. Not because the code got worse, but because there was more of it than I had attention for, and I noticed I was approving the boring ones faster and faster. Speed-reading a diff is not review. It is a ritual that makes me feel responsible. So I set myself a narrower question: if I stop reading every line, what replaces it, and how many human minutes does each kind of change really need? I wanted a number, not a vibe. This post is the answer I got from a small experiment on a .NET repo. It is ten PRs. Keep that in mind the whole way through. The post that pushed me into this was Anthropic’s “How the Claude Code team does code review” by Addy Osmani, Morgan Westlee Lunt and Qing Wang, published October 15, 2026 the URL slug is solving-code-review-at-anthropic : https://claude.dev/blog/solving-code-review-at-anthropic/ https://claude.dev/blog/solving-code-review-at-anthropic/ I first met it secondhand. Two rewrites by the JIN System Architect publication showed up in my weekly digest items 124 and 154 . Both retell the same post, add little beyond it, and both had the tells that make me stop trusting a rewrite: a garbled disclosure paragraph, and in one of them the phrase “The material reports” left in the body, which reads like a summarizer’s scaffolding that nobody removed. I did not take a single number from them. I went to the original. Here are the figures from the original, with the scope each one actually has. All of them are Anthropic’s own internal numbers. I can’t verify any of them, and the post doesn’t publish denominators. +-----------------------------------------------+----------------------+-------------------------------+| Metric Anthropic-reported | Before - After | Scope |+-----------------------------------------------+----------------------+-------------------------------+| Changes landing per day | ~2,500 - 30,000+ | Anthropic monorepo, May- Sep || Merged PRs | more than doubled | Claude Code repo, Jun- Sep || Share of merged PRs reverted | down 40% relative | Claude Code repo, Jun- Sep || Internal PRs with substantive review comments | 16% - 54% | at Code Review preview launch || Pass after one review-and-fix round | 65% - 78% | internal PRs, convergence fix || Need five or more rounds | 8.9% - 1.5% | internal PRs, convergence fix || Mean reviews to pass | 2.08 - 1.32 | internal PRs, convergence fix |+-----------------------------------------------+----------------------+-------------------------------+ The scope column matters. The monorepo number is about Anthropic’s monorepo, which the post says is separate from the Claude Code repo. The revert figure is about the Claude Code codebase. The review-comment and convergence figures are about internal PRs. It is easy to blur these into one “agents made review better” headline, and the post itself doesn’t do that. The numbers were not what changed my mind, though. These ideas were: None of this needs Anthropic’s tooling. That was the point of trying it on my own repo. My digest that week had a cluster of related pieces. I’m separating what I read in a primary source from what I only saw described, and what I actually tried. Uber, four narrow agents. The newsletter description was that Uber split review into four narrow agents instead of one generalist. I did not verify the “four”. What I did read is Uber’s own uReview post, which describes a multi-stage pipeline that decides which files are eligible, generates comments, then validates them before posting, and it names false positives as the main challenge: hallucinated comments, and comments that are technically valid but don’t matter in context. That second category is the one I underestimated. Tried: no, it’s internal to Uber. Borrowed: the idea that the filter after generation matters as much as the generator. Lauren Tan’s verification skill. As described in write-ups of her talk, the idea is that the agent gets a project-local skill that launches the real app, drives it like a user, and captures evidence screenshots, transcripts, logs so the PR arrives with proof instead of “Done.” The PR counts quoted for her talk differ between sources one write-up says about 2,000 a month, a post title elsewhere says 2,500 , so I’m not repeating either as fact. Tried: the idea, not her code. My gate refuses medium and high PRs that don’t carry pasted test output, and refuses high PRs without a recorded run. kunchenguid’s no-mistakes. A local git proxy: you git push no-mistakes instead of origin, it runs a review, test, docs and lint pipeline in a disposable worktree, and only forwards the branch and opens the PR once everything is green. The README install is a curl | sh line: Don't pipe this straight into sh. Download it, read it, then run it.curl -fsSL https://raw.githubusercontent.com/kunchenguid/no-mistakes/main/docs/install.sh -o no-mistakes-install.shless no-mistakes-install.shsh no-mistakes-install.sh I read the script before running it, and I’d ask you to do the same with any installer, including mine. Tried: yes, on the demo repo. It does what it says. I kept my gate on the server side anyway, for one reason: a pre-push gate only runs if the pusher goes through it, and an agent with push rights can push to origin directly. A pre-push gate is a nice first filter. It is not the gate. The Code’s Saturday special: CODEOWNERS plus a PR template. The newsletter described pairing CODEOWNERS with a PR template so ownership and evidence are both structural instead of social. Tried: yes, it’s the base of everything below. One thing the newsletter version skipped: CODEOWNERS decides who must review, it cannot say how many . Branch protection’s approval count is repo-wide. So “two people for auth” needs a check of its own. Jaroslaw Wasowski on brownfield specs. His piece on a “preservation contract” argues that a change spec for legacy code should start with what must not change. His opening example which he says is constructed for the article is an agent “cleaning up” a shared fetch function and dropping a visibility filter that the export path silently depended on. Keep that example in mind for section 5. His companion piece on missing spec decisions, with a two-implementations technique and a decision register, is on my list; I haven’t worked through it, so I won’t summarize it. The repo is a demo ASP.NET Core 8 orders API with EF Core: Orders.Api, Orders.Application, Orders.Domain, Orders.Infrastructure, and tests. The org and team names below orders-demo, orders-team, platform-leads are that demo repo's real names, so the files work as-is if you mirror the layout. Here’s the shape of it: agent pushes branch | v+------------------+ +-----------------------------+| pr-checks.yml | | pr-gate.yml || pull request | | pull request target + || | | pull request review || build, test, | | base-branch code only: || upload .trx | | 1. classify tier || | | 2. label risk:low/med/high || optional: | | 3. check proof in body || local Ollama | | 4. count human approvals || first pass | | on the head commit || advisory | | 0 / 1 / 2 by tier |+------------------+ +-----------------------------+ | | +--------------+--------------+ v branch protection: both required, CODEOWNERS review required, stale approvals dismissed on push I wrote the rules down before writing code, because the post’s advice to “start strict and loosen with evidence” only works if the starting point is explicit. +--------+--------------------------------------------+----------------------+------------------+| Tier | Triggered by | Human approvals | Proof required |+--------+--------------------------------------------+----------------------+------------------+| low | only docs/, .md, tests/, Experimental/ | 0 CI + proof green | template filled || | and under 300 lines / 15 files | | || medium | any other src/ or appsettings .json, | 1 | dotnet test || | unknown paths, 300 lines or 15 files, | | output pasted || | or tests shrank by 20 lines | | || high | Auth/, Migrations/, Program.cs, prod | 2 | test output + || | settings, package versions, .github/, | | recorded run || | the gate tool itself, or 800 lines | | |+--------+--------------------------------------------+----------------------+------------------+ Two rules I added after thinking about how agents fail rather than how humans fail. Unknown paths are never low, because a new top-level folder is exactly where an agent puts something you didn’t expect. And if tests shrink, the PR is at least medium, because “fix the red build” sometimes gets solved by deleting the red. .github/risk-tiers.json: { "high": "src/Orders.Api/Auth/ ", "src/Orders.Infrastructure/Persistence/Migrations/ ", "src/Orders.Api/Program.cs", " /appsettings.Production.json", "Directory.Packages.props", ".github/workflows/ ", ".github/CODEOWNERS", ".github/risk-tiers.json", "tools/RiskGate/ " , "medium": "src/ ", " /appsettings .json", " .sln", " / .csproj" , "low": "docs/ ", " / .md", "tests/ ", "src/Orders.Api/Experimental/ " , "mediumLines": 300, "highLines": 800, "mediumFiles": 15, "testShrinkLines": 20} Experimental/ is low because everything in it is behind a feature flag and auto-mapped by a startup hook that was itself reviewed as high. If your flagged code isn't isolated like that, don't copy this line. .github/CODEOWNERS: Three tiers. CODEOWNERS decides WHO must look; the pr-gate workflow decides HOW MANY. Last matching pattern wins, so the broad rules come first and the strict ones last. Tier 1, low: docs, tests and flagged experiments./docs/ @orders-demo/everyone/tests/ @orders-demo/everyone/src/Orders.Api/Experimental/ @orders-demo/everyone Tier 2, medium: ordinary product code. One person from the owning team./src/ @orders-demo/orders-team Tier 3, high: auth, migrations, startup, CI and the gate itself./src/Orders.Api/Auth/ @orders-demo/platform-leads/src/Orders.Infrastructure/Persistence/Migrations/ @orders-demo/platform-leads/src/Orders.Api/Program.cs @orders-demo/platform-leads/Directory.Packages.props @orders-demo/platform-leads/.github/ @orders-demo/platform-leads/tools/RiskGate/ @orders-demo/platform-leads A subtlety: /src/Orders.Api/Experimental/ comes before /src/, so /src/ wins for experimental files and the orders team owns them. That's what I want for ownership. The count still comes from the tier, which says zero for experimental-only PRs. Ownership and approval count are different questions, which is exactly why the count can't live in CODEOWNERS. .github/pull request template.md: What and why< -- One paragraph. Link the issue. If an agent wrote this, name the agent and who directed it. -- Testing< -- Paste the real output, not a summary. Medium and high tiers need the dotnet test summary line, e.g.The checker strips HTML comments before deciding a section is filled, so an agent can’t pass by leaving the hints in place. One console app, three subcommands: classify reads a numstat diff and prints a tier, proof checks the PR body against the tier, and review asks a local Ollama model for a first pass. No NuGet packages, just the BCL, so it restores fast in CI. tools/RiskGate/RiskGate.csproj: