· 7 min read ·

The One-Way Ratchet in Your Branch Protection Settings

Source: hackernews

Avery Pennarun’s recent post arguing that every review layer makes you 10x slower generated 510 points and the predictable HN debate: is the 10x figure realistic, does review catch real bugs, what about regulated industries. The compounding mechanics of queue latency are worth understanding on their own terms. But there is a dimension of the problem the post doesn’t explore: the specific tooling that made accumulating review gates frictionless while keeping their throughput cost invisible.

Adding a Gate Takes Thirty Seconds

GitHub’s branch protection rules are a useful feature. You can require a minimum number of approvals, specify which teams must approve via CODEOWNERS, block merges on failing status checks, require signed commits, and prevent force pushes. Every one of those controls exists for legitimate reasons.

The problem is the asymmetry between adding and removing them. Adding a required reviewer takes roughly thirty seconds in repository settings. Removing one requires a political process: justifying to a security org, a team lead, or a compliance function why that gate no longer needs to exist, typically without the vivid incident data that justified adding it in the first place. The gate’s cost accumulates invisibly across hundreds of changes over months. The incident that triggered the gate was a concrete, memorable event that people can still name.

This asymmetry is what makes the ratchet one-directional. Individual incidents produce new gates. No individual event ever produces gate removal. The repository settings page reflects this: there is a button to add a required reviewer, and there is no button that says “this gate has increased average time-to-merge by 3.4 days.”

The CODEOWNERS Trajectory

CODEOWNERS is worth examining specifically because it is the primary mechanism by which review chains accumulate without anyone deciding to create a review chain.

Consider the typical trajectory. A repository starts with a single CODEOWNERS entry assigning the core team. A security incident in auth code prompts the security team to require approval on /src/auth/**. A platform stability issue leads the SRE team to add themselves to infrastructure paths. A compliance audit produces a requirement that a designated reviewer sign off on anything touching external APIs. Eighteen months later:

# .github/CODEOWNERS
/src/auth/**          @security-team
/src/payments/**      @payments-team @security-team
/src/api/**           @platform-team @api-team
/src/config/**        @sre-team @platform-team @security-team
/src/**               @senior-engineers

A config file change now requires approval from five distinct groups. None of those additions were irrational at the time. All of them were locally justified by real incidents or requirements. The CODEOWNERS file has no field for estimated cycle time cost and no expiry date on any entry.

The file also has no representation of the combinatorial review problem. If the security team and the platform team give conflicting feedback on a change that touches both /src/api/ and /src/auth/, the author has to mediate that conflict, resubmit to both, and wait for both to re-engage. Neither reviewer sees that cost; they see only their own review queue.

What the Platform Measures and What It Doesn’t

GitHub’s native analytics do not surface the information needed to understand review overhead. On most plans you can see number of open PRs, time to first review, and comment volume. What the platform does not show by default: average time from PR open to merge broken down by approval chain depth, how many PRs were abandoned mid-review, what percentage of changes required multiple revision cycles, or how often a change was simplified below its original scope to avoid triggering additional review gates.

This reflects what the platform was optimized to facilitate. GitHub was built to make review happen, and the implicit design assumption is that more review is better. The engagement metrics it surfaces, reviews given, comments made, approvals granted, reward activity in the review process, not efficient flow through it.

This gap is precisely why third-party tooling like LinearB, Swarmia, and Cortex exists. These tools pull from GitHub’s API and surface the DORA metrics that connect process structure to delivery outcomes: lead time for changes, deployment frequency, change failure rate, time to restore service. The underlying data is in GitHub; the platform simply does not present it in a way that would connect approval gate depth to cycle time. Teams that want that picture have to buy a separate tool.

What Open Source Projects Learned First

The throughput cost of review latency shows up most clearly in open source, where contributors are volunteers with finite patience. A contributor who submits a patch and waits three weeks for a first response has usually moved on, not just from that patch but from the project. Open source sustainability researchers have documented the relationship between response latency and contributor retention repeatedly; it is one of the most consistent findings in that literature.

High-activity open source projects have developed tooling specifically to address merge queue management, because async multi-reviewer approval on high-velocity repositories produces merge conflicts faster than humans can handle them. Bors and Mergify both developed years before GitHub shipped its own merge queue feature in 2023. They exist because the PR model created a throughput problem that required external automation to manage. GitHub’s merge queue is a reasonable fix for one specific symptom; it does not address the underlying gate accumulation problem.

The projects that handle review load most effectively tend to have explicit reviewer response time norms, distributed review authority so no single person is a bottleneck, and small change sizes as a cultural practice. CPython’s core developer model spreads review authority deliberately. The Rust project tracks PR aging and has public policies about response times. These are organizational practices, not GitHub settings, and they required sustained effort to establish precisely because the platform defaults point in the opposite direction.

The PR Model Was Not Inevitable

The fork-and-PR workflow became the standard for software collaboration not because it was demonstrably optimal but because GitHub won. Before GitHub normalized the PR model, review worked differently across different communities.

Google’s internal Critique tool, built on a Gerrit foundation, evolved within a culture that emphasizes small changes and rapid iteration. Reviewers are expected to respond quickly; the tooling and cultural norms both push toward throughput. The Google Engineering Practices documentation on code review explicitly addresses reviewer speed as a core obligation, not a courtesy.

Facebook’s Phabricator emphasized differential revisions and rapid revision cycles. Arcanist, the command-line client, made submitting and revising changes faster than a web-based PR flow, and the surrounding culture reflected that design priority.

Email-based patch submission, still used for the Linux kernel and git itself, has its own friction, but it produces a different social dynamic. There are no required reviewers in a config file. Approval chains are implicit and cultural, which means they can shift as norms evolve without a CODEOWNERS entry blocking merges.

The async-blocking-PR model that GitHub standardized has genuine advantages: full visibility into proposed changes, integration with CI status checks, searchable history. It also made treating review as a hard deployment gate the path of least resistance, and the tooling that developed around it made adding gates easier and measuring their cost harder.

What Instrumented Teams Find

Organizations that have instrumented their pipelines using DORA metrics consistently find that lead time for changes correlates inversely with the number of blocking approval steps. This is the core empirical finding behind Pennarun’s post, and it has been replicated across the DORA dataset covering tens of thousands of organizations over more than a decade.

The teams that reduced review friction without increasing incident rates did so through a combination of comprehensive automated testing, feature flags for incremental rollout, fast automated rollback, and a cultural practice of smaller changes. When automated testing handles defect detection reliably and fast rollback handles consequence mitigation, human review can focus on the changes where it adds genuine value rather than serving as a mandatory gate on everything. The review overhead drops because the surface area of each change is smaller and the cost of being wrong is lower.

None of this requires eliminating review. It requires making review non-blocking for the large majority of changes that don’t need it, which is a different decision than the one most teams’ CODEOWNERS files reflect.

Why the Ratchet Persists

Pennarun’s post is partly a critique of the organizational dynamic that produces review accumulation: incidents create gates, no one removes them, velocity degrades slowly enough that causation is invisible. That dynamic is real and well-described. The part that compounds it is the tooling.

If adding a required reviewer to branch protection settings required filling in an estimated cycle time cost alongside the team name, teams would have the data to weigh the trade-off. If GitHub’s repository insights surfaced average time-to-merge alongside each active review requirement, the connection between gate depth and shipping velocity would be visible to the people making process decisions. Instead, the platform shows you how many reviews happened and how many comments were left. It rewards more review activity and provides no measurement of what that activity costs.

This is not a conspiracy. It reflects design priorities and the assumptions baked into them. But the result is that the platform used by most engineering teams makes it trivially easy to add a layer of required review and offers no native tooling to understand what that layer is costing. The ratchet clicks one way because the interface was designed for adding, not for measuring.

Pennarun’s 10x figure is a provocation calibrated to cut through the usual defenses. The underlying mechanism, queue latency compounding through sequential dependencies, is well-understood in queuing theory and well-validated by the DORA research. The question worth sitting with is not whether 10x is literally accurate. It is why, knowing this, approval chains keep growing. Part of the answer is organizational psychology. A significant part is that the tooling makes the cost of adding a gate invisible, and the default metrics reward you for doing it.

Was this interesting?