# 15.8 Checks that block (/building-ai-workers/code-review/checks-that-block)

---
type: Document
title: "15.8 Checks that block"
description: "A check that fails the merge against a check that only advises, and how required checks, branch protection and a pull request template make the right checks block."
status: stable
order: 315.08
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-02T18:33:52Z
chapter: "15"
part: III
expert_status: builder-only
concepts: [ "15.8" ]
last_verified: 2026-10-31
sources:
  - id: anthropic-team-review
    title: "How the Claude Code team does code review (Anthropic, October 15, 2026, accessed 2026-10-31)"
    resource: https://claude.dev/blog/solving-code-review-at-anthropic/
  - id: github-protected-branches
    title: "About protected branches (GitHub, accessed 2026-10-31)"
    resource: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches
  - id: github-rulesets
    title: "About rulesets (GitHub, accessed 2026-10-31)"
    resource: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets
  - id: github-events
    title: "Events that trigger workflows (GitHub, accessed 2026-10-31)"
    resource: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows
  - id: github-secrets
    title: "Using secrets in GitHub Actions (GitHub, accessed 2026-10-31)"
    resource: https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions
generated:
  at: 2026-11-02T18:33:52Z
  by: esl-rewrite/1.2.0+ksor.1
trust_tier: unverified
build_id: sha256:e1fbcb7d9a8f8b9b7cb96875022325c02c9ba4be94cef13b301cbd39a9edad85
dirty: true
ksor_version: 0.0.60
---

**In everyday life.** A smoke detector beeps. A circuit breaker cuts the power. Both notice a problem, but only one stops anything. Each is right for its job. The mistake is to believe the beeper is a breaker.

**What you will learn.** The difference between a check that stops a merge and one that only reports, and how to make the right ones stop it.

**Why it matters.** A gate is a check that can really stop a merge. A team that mistakes a report for a gate has no gate.

### Which checks stop a merge?

Only the ones the repository requires. Every check on a pull request is one of two kinds.

- An **advisory check** is one that only reports. It may post findings, but the merge button still works.
- A **blocking check** is one that stops the merge. The pull request cannot join `main` until it passes.

A check blocks only when the repository says so. **Branch protection**, or a **ruleset**, its newer and more flexible form, is a set of rules on a branch such as `main`. The rules that matter here:[^github-rulesets]

| Rule | What it stops |
| --- | --- |
| Require a pull request before merging | Anyone pushing straight to `main`, including an agent |
| Require status checks to pass before merging | A merge while a **required check** has failed or not finished |
| Require conversation resolution | A merge while a review thread is still open |
| Require approvals, and review from code owners[^github-protected-branches] | A merge without the people [15.9](approval-scaled-by-risk.md) names |
| Dismiss stale approvals when new commits are pushed | A merge of code nobody approved |

### What does a workflow do?

It runs the checks. A **workflow** is a file in `.github/workflows/` that tells the host which checks to run, and when. An **event**, such as a new pull request, starts it. It is made of **jobs**, and each job is a list of steps that run in order. A job stops at its first failing step, so a later step in the same job never runs. Each job shows on the pull request as one check. Marking a check **required in branch protection** turns it from advisory into blocking. Running checks like this on every change is called **continuous integration**, or CI.

### What are Brightline's required checks?

One workflow runs everything a machine can check every time, in three jobs, so a failing test cannot hide a weakened test or a printed key:

| Job | What it runs |
| --- | --- |
| `checks` | Both type checks, both test suites, the linter |
| `tests-unchanged` | A script that fails if a change removes or edits a line in an existing test, or adds a line that switches a test off, such as `.skip(`, `.only(` or a bare `return`. The label `tests-changed`, a tag someone adds to the pull request, lets a removed or edited line through, and the team's rules pair that label with a written reason and approval from a named owner |
| `no-secrets` | A script that fails if a logging or print call names a key, token, secret or password on the same line |

Each script **fails closed**: if it cannot do its job, because it cannot find the base branch, the one the pull request merges into, or a folder it should search, it fails instead of passing. A check that passes when it cannot see is worse than none, because it looks like protection.

### What do these checks miss?

A lot, on purpose. Each script catches one common mistake, cheaply, on every change. Neither proves more than that. The test check cannot tell whether a new test checks anything useful, or whether the test runner's settings were changed to skip tests. The secret check misses a logging call split over two lines, or a key in a variable whose name looks harmless. Review covers what they miss. A check is only as strong as the files that run it. So the check scripts, the workflow, `package.json` and the type checkers' settings all have a named owner ([15.9](approval-scaled-by-risk.md)). Here is part of the workflow:

```yaml
permissions:
  contents: read          # the workflow token can read the code, nothing else
jobs:
  checks:                 # the type checks and tests
    steps:
      - run: npm run typecheck
      - run: npm test
  tests-unchanged:        # a separate job, so a failing test cannot hide it
    steps:
      - run: bash scripts/check-tests-unchanged.sh "origin/${{ github.base_ref }}"
```

![On the left, one job with four steps in order: the type check passes, the tests fail on the cutoff test, and the test comparison and the secret check are skipped. On the right, three independent jobs for the same change, each failing on its own. The checks job fails on the cutoff test, tests-unchanged on four removed test lines, and no-secrets on key logging at line 14.](img/jobs-and-steps.png)

*Figure 15.13. One job stops at the first failure. One job per check lets every problem report.*

### Can an AI review block a merge?

Only through the repository. An AI review is advisory by default. It never approves or blocks on its own ([15.7](ai-review-on-every-pr.md)). If you want open findings to stop a merge, choose one way to make the repository enforce it. Require conversation resolution, so an unresolved finding's thread blocks the merge. Or add a required job that reads the review's result and fails on an Important finding. Or run a security review inside your own workflow, with your own step that fails when it reports findings. A review in a workflow is the same agent outside the app that you met in [12.8](../agentic-coding/outside-the-app.md): one task, run headless, with read-only access and nobody watching. The rule is the same in every case: the repository's settings do the blocking, not the reviewer.

### What does the pull request template do?

A file, `.github/pull_request_template.md`, fills every new description with the questions a reviewer needs answered. They ask what and why, how it was tested, with the commands and their output, the level of risk, and how to undo it. It costs the author a minute and saves the reviewer from guessing.

### How do I keep a workflow safe?

A workflow runs code from the pull request, so treat it as running untrusted code. Give its token, the key it uses to act on the repository, read-only permissions. Keep keys in **repository secrets**, which the host stores and gives to workflows.[^github-secrets] Never commit them to a file. The host gives no secrets to workflows triggered by a **fork**, an outside copy of the repository. Never use a trigger that runs with your secrets, such as `pull_request_target`, to build or run a pull request's code.[^github-events] And when a check reads labels, such as `tests-changed`, make the workflow run on the `labeled` and `unlabeled` events too, or adding the label changes nothing until the next push.

**In the case study.** No pull request merges while a finding from the bug review or the security review is open. Lint, type checks, tests and builds are required. The template asks how a change was tested and how to undo it.[^anthropic-team-review]

**At work.** Ana makes all three jobs required on `main`, with conversation resolution on. The `agent-speedup` pull request shows three red marks, one per job. The tests fail on the cutoff case. The test comparison fails on the edited expected value. The secret check fails on the debug line that prints the key. The merge button is gray. Nobody had to read the diff to stop it, though someone still will, to learn why an agent did this.

**The operating rule:** make every check a machine can run a required check, and never mistake an advisory report for a gate.

![Advisory feedback, such as AI review findings, comments and summaries, helps people judge. Enforced requirements, set by the repository's rules, control the merge gate. They are required checks, which cover tests, types, the test comparison and the secret check, then required approvals and conversation resolution. A note says a comment is not a merge rule, and AI feedback blocks only when it is connected to an enforced requirement.](img/advisory-and-blocking.png)

*Figure 15.14. Advisory feedback and merge requirements. Only enforced requirements control the merge gate, and the repository's settings decide what they are.*

**Practice it.** [Practice: checks that block](both-ai-vendors.md#practice-checks-that-block), in your own tool, fifteen minutes.

[^github-rulesets]: About rulesets, GitHub.
[^github-protected-branches]: About protected branches, GitHub.
[^github-secrets]: Using secrets in GitHub Actions, GitHub.
[^github-events]: Events that trigger workflows, GitHub.
[^anthropic-team-review]: How the Claude Code team does code review, Anthropic.
