# A policy gate for AI-authored PRs: when a single fail-on threshold stops being enough.

> commitbrief guard evaluates a review against a declarative .commitbrief/policy.yml — per-severity budgets, an optional total, pass or block. And a consume mode that gates a review someone else already ran, with no second provider call.

Published October 8, 2026 by Muhammet Şafak (https://muhammetsafak.com)

Canonical URL: https://commitbrief.com/blog/policy-gate-for-ai-authored-prs/
Tags: ci, policy, governance

---

`--fail-on high` is one number. It says: block if there's anything at or above `high`. For a long time that was enough, because the volume of change flowing through review was human-paced and a single threshold matched how teams actually think about a gate.

The volume changed. When a meaningful share of your PRs are written by an agent, the shape of what you're gating changes with it. You're no longer asking "is there a blocker in this one careful diff?" You're asking "did this machine-authored change stay within the budget I'm willing to accept across *every* severity?" A single threshold can't express a budget. That's the gap `commitbrief guard` fills, and it's the last piece of this arc — [the review as an MCP tool](/blog/mcp-review-gate), [as PR comments](/blog/reviewing-github-prs-from-the-terminal), and now as a hard gate.

## A budget, not a threshold

`commitbrief guard` evaluates a review against a declarative policy file — `.commitbrief/policy.yml` — and exits non-zero if the review breaches it.

```yaml
# .commitbrief/policy.yml
version: 1
thresholds:
  critical: 0    # zero tolerance
  high: 2        # at most two
  medium: 10     # a budget, not a wall
total: 25        # and no more than 25 findings overall
```

```sh
# Run a review and gate it against the policy.
commitbrief guard
```

This says something `--fail-on` can't: *zero criticals, at most two highs, up to ten mediums, twenty-five findings total.* It's a budget with per-severity lines, which is how you actually reason about acceptable risk in a high-throughput codebase — not "any high blocks" but "a couple of highs is the cost of moving fast; three is where I want a human to stop and look." Unknown keys in the file are rejected rather than ignored, because a policy you thought you set but typo'd into oblivion is worse than no policy at all. A load or parse failure blocks the merge too — a gate that fails open is not a gate.

The gate evaluates the **actionable** set — the findings that remain after [baseline and inline suppression](/blog/three-layer-filtering) have done their work. Things you've explicitly accepted don't count against the budget, which is the only way a budget stays meaningful over the life of a real repo.

## Decouple running the review from gating it

The part I'm most pleased with is that `guard` doesn't have to run the review itself. It has a consume mode: hand it the JSON from a review that already happened, and it evaluates the policy with **no provider call at all**.

```sh
# Gate a review the MCP tool or a CI step already produced.
commitbrief --staged --json > review.json
commitbrief guard --from-json review.json

# Or straight off a pipe.
commitbrief --staged --json | commitbrief guard --from-json -
```

This matters because reviewing and gating are two different jobs that shouldn't be welded together. Your agent runs the review once — through [the MCP tool](/blog/mcp-review-gate), or a CI step, or a developer's terminal — and emits schema-v1 JSON. Then any number of gates can evaluate that same JSON against different policies: a lenient budget on a feature branch, a strict one on `main`, a zero-critical wall on a release branch. One review, many gates, one provider call. You're not paying for inference again just to apply a different threshold.

When it blocks, `--json` tells you exactly why:

```json
{
  "passed": false,
  "counts": { "critical": 0, "high": 3, "medium": 4 },
  "total": 7,
  "violations": ["high: 3 exceeds threshold 2"]
}
```

Machine-readable, so the CI step that blocked the merge can also comment *which* line of the budget was breached, not just that something was.

## Why this belongs to you, not the platform

I could have shipped this as server-side branch protection — a bot that enforces the policy in GitHub's settings. I didn't, and it's the same conviction that runs through everything else here: the gate should belong to the person the review is for. `.commitbrief/policy.yml` lives in your repo, version-controlled next to the code, reviewed in the same PRs, owned by the team. The policy is a file you can read, diff, and argue about in a pull request — not a setting buried in a platform dashboard that one admin controls and nobody else can see.

That's the whole posture, stated one more time as this round closes. A review tool earns its place in a workflow by being something you *own* — your trigger, your provider, your rules, your budget — not something that happens *to* your repo. As more of the code arrives machine-written, that ownership stops being a preference and starts being the thing that keeps you in control of your own quality bar. The machine can write the diff and even [run its own review](/blog/mcp-review-gate). The budget it has to clear is still yours to set.