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:
- Ticking the checkbox (
- [x] **Item name** — …), or - 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/andchangelog.d/do not count beside another one); - touches
core/src/,core/include/,core/tools/,core/meson_options.txt,python/test/orffmpeg-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):
Opt-out (item explicitly skipped):
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¶
- ADR-0108 — the six-deliverable rule.
- ADR-0435 — the decision to wire this as a pre-push hook.
- pr-body-validator.md — implementation internals (parser shape, shim design, caveat on local-vs-CI divergence).
scripts/ci/deliverables-check.sh— the single source of truth parser..github/PULL_REQUEST_TEMPLATE.md— the template that carries the checklist.