Skip to content

PR body sentinel guide

The fork's rule-enforcement.yml workflow runs a deep-dive deliverables checklist gate (ADR-0108) on every non-draft PR. The parser is strict: a tick that does not match the documented checkbox shape, or an opt-out that uses the wrong sentinel word, fails the gate. Each retry costs a 3–10 minute CI cycle.

To check a body before pushing, use the Quick start commands below. The pre-push hook (scripts/git-hooks/pre-push-pr-body-lint.sh, wired by make hooks-install) and the standalone validator (scripts/ci/validate-pr-body.sh) run the same parser locally.

Quick start

# Install the pre-push hook (idempotent):
make hooks-install

# Run the validator manually against an open PR:
make pr-check PR=<number>

# Run against a local body file:
make pr-check BODY=pr-body.md

# Run the raw validator:
gh pr view <number> --json body -q .body \
  | scripts/ci/validate-pr-body.sh

Hook behaviour and exemptions

The hook bounds gh lookup time, falls back to the repository's public pull-request pages when local credentials are unavailable, and blocks the push if neither source can establish the PR state and body.

Like the CI gate, the hook skips the machine-generated release-please PR (ADR-1151). It asks scripts/ci/release-pr-exempt.sh whether the PR's head ref is release-please--... and its author is a bot, using the author that gh reports. The head ref must also be the branch being pushed. A human PR on a release-please-- branch is still validated, and a PR found only through the public-page fallback, which carries no author identity, is never exempted.

The six deliverables and their opt-out forms

Every fork-local PR body must address each of the six deliverables below. Each item may be addressed either by:

  1. Ticking the checkbox (- [x] **Item name** — …), or
  2. Opting out with a sentinel sentence anywhere in the body.

Upstream-port PRs (/port-upstream-commit) and pure upstream syncs are exempt from the entire section.

Deliverable Required checkbox label Opt-out sentinel key Example opt-out
Research digest Research digest digest no digest needed: trivial change
Decision matrix Decision matrix alternatives no alternatives: only-one-way fix
AGENTS.md invariant note AGENTS.md invariant note rebase-sensitive or AGENTS no rebase-sensitive invariants
Reproducer / smoke-test command Reproducer / smoke-test command reproducer or smoke no smoke-test needed: doc-only
CHANGELOG fragment CHANGELOG fragment changelog no changelog needed: internal refactor
Rebase note Rebase note rebase no rebase impact: docs-only

Small pull requests (ADR-2461)

A small pull request may put the marker small PR (ADR-2461) anywhere in the body instead of addressing four of the six items. The marker waives the research digest, decision matrix, AGENTS.md note and rebase note; the reproducer and the changelog fragment are still required in the forms above. The gate reads the diff and refuses the marker, with an ADR-2461 small PR error per reason, when the pull request:

  • changes more than 100 lines (changelog and rebase-note fragments, ADR index fragments and lock files are not counted);
  • touches more than one top-level directory (docs/ and changelog.d/ do not count beside another one);
  • touches core/src/, core/include/, core/tools/, core/meson_options.txt, python/test/ or ffmpeg-patches/;
  • adds a file under docs/adr/.

Whether a change adds a user-discoverable surface elsewhere stays a reviewer's judgement. A body without the marker is parsed exactly as before.

Exact syntax

Ticked checkbox (item addressed):

- [x] **Research digest** — docs/research/0435-foo.md written.

Opt-out (item explicitly skipped):

- [ ] **Research digest** — no digest needed: trivial change.

The sentinel phrase (no digest needed:) may appear anywhere in the body — inside the checkbox line or as a standalone sentence. The parser strips markdown emphasis characters (backticks, asterisks, underscores) before matching, so label wrapping does not affect detection.

Ticked-file-reference checks

When an item is ticked, the parser also verifies that the corresponding file type appears in the PR diff. Missing the file after ticking the box fails the gate even if the checkbox shape is correct.

Ticked item Required diff entry
Research digest docs/research/NNNN-*.md (any file matching ^docs/research/[0-9]+-)
CHANGELOG fragment CHANGELOG.md OR changelog.d/<section>/<topic>.md
Rebase note docs/rebase-notes.md

If you tick "Research digest" but do not add a docs/research/NNNN-*.md file, the gate fails with:

::error title=ADR-0108 research digest::Checkbox ticked but no
docs/research/NNNN-*.md added in this PR.

Fix: either add the digest file, or untick the box and write no digest needed: <reason> instead.

The prose-bullet failure mode (most common agent mistake)

The parser requires checkbox syntax (- [x]). Prose bullets and numbered lists are not recognised.

Format Parser result
- [x] **Research digest** — docs/research/0435-foo.md PASS
- [ ] **Research digest** — no digest needed: trivial PASS (opt-out)
- Research digest: docs/research/0435-foo.md FAIL — prose bullet
1. **Research digest** — docs/research/0435-foo.md FAIL — numbered list
**Research digest**: docs/research/0435-foo.md FAIL — no checkbox

When the gate detects a prose bullet, it emits a warning before the error line:

::warning title=ADR-0108 prose-bullet format::One or more deliverables
  appear to be in prose bullet format (e.g. '- Research digest: ...').
  The parser requires the checkbox form: '- [x] **Research digest** ...'

Exit codes

The validator behind make pr-check and scripts/ci/validate-pr-body.sh exits with:

Code Meaning
0 PR body would pass the deliverables gate
1 PR body would fail (same ::error lines as CI emits)
2 Usage error — missing body, unreadable diff file, etc.

For these two deliverables entry points, exit 2 also covers every shape where stdin cannot carry a body at all: a terminal, a closed fd 0, or /dev/null. The other two body-reading gates (ffmpeg-patches-surface-check.sh, ADR-0409, and state-md-touch-check.sh, ADR-0165) answer an absent body from the diff instead. The classification rules are in pr-body-validator.md.

Metadata lookup failures

A locked keyring or broken gh authentication must not hang the push and must not turn validation off. After the bounded authenticated lookup, the hook reads the public pull-request list and page for this public repository. If both paths are unavailable or GitHub's page shape cannot be validated, the hook fails closed. Restore connectivity or credentials and retry; do not skip the hook (AGENTS.md operational rule 6).

See also