ADR-0435: PR-body pre-push validation hook¶
- Status: Accepted
- Date: 2026-05-15
- Deciders: Lusoris, Claude (Anthropic)
- Tags:
ci,agents,hooks,docs
Context¶
The fork's rule-enforcement.yml workflow runs a deep-dive deliverables checklist gate (ADR-0108) on every non-draft PR. Audit slice G (.workingdir/audit-2026-05-15/G-agents-hooks-skills.md) found that 22 of 200 Rule Enforcement runs (11%) failed due to PR-body format errors, consuming approximately 44 runner-hours of CI capacity. The dominant failure mode was agent-generated PR bodies using prose bullet form (- Research digest: docs/research/foo.md) instead of the required checkbox form (- [x] **Research digest** — docs/research/foo.md).
scripts/ci/validate-pr-body.sh and scripts/ci/deliverables-check.sh already existed and implemented the parser correctly. However, neither was wired into any local hook. Contributors (and agents) had no mechanism to catch format failures before pushing, so every malformed body triggered a full CI cycle: Rule Enforcement itself takes 30–45 s, but the Required Checks Aggregator polls for 90 minutes, making each failure cost roughly 120 minutes of CI wall time before the contributor could push a corrected body.
Decision¶
Wire scripts/ci/validate-pr-body.sh as a pre-push hook via three complementary mechanisms:
-
scripts/git-hooks/pre-push-pr-body-lint.sh— a standalone, single-purpose script that implements the PR-body check. Referenced directly from.pre-commit-config.yamlas astages: [pre-push]hook so thatpre-commit run --hook-stage pre-pushexercises it without running the omnibuspre-pushscript. -
.pre-commit-config.yamlentry —id: validate-pr-body,stages: [pre-push],always_run: true,pass_filenames: false. This integrates with the existing pre-commit infrastructure (make hooks-installalready installs pre-commit hooks). -
make pr-checktarget — already present in the Makefile; the ADR documents it as the canonical local run command for aftergh pr create. The existing target is unmodified.
Additionally:
-
scripts/ci/deliverables-check.shis extended with anti-pattern detection: when the body contains prose bullet deliverable lines (- Research digest: …) without the corresponding checkbox form, a::warning::is emitted before the error so contributors (and agents) understand the format mismatch. -
.github/PULL_REQUEST_TEMPLATE.mdreceives a visible banner in the Deep-dive deliverables section explaining the checkbox requirement and opt-out syntax. -
docs/development/pr-body-sentinel-guide.mddocuments the six opt-out sentinel forms, ticked-file-reference checks, and the prose-vs-checkbox failure mode.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| A — Pre-push hook + pre-commit (chosen) | Catches failures locally in <5 s before any CI cycle; composable with existing pre-commit infrastructure; no new dependencies | Requires gh CLI on PATH; drafts and no-PR pushes skip silently | Best total cost |
B — make pr-check only | Zero-friction manual invocation | Requires contributor to remember to run it; does not block a push | Does not prevent the 44-runner-hour CI waste; contributors forget manual checks |
C — check-pr-body skill | Could draft AND validate body before PR opens | Adds a skill file; relies on Claude Code context, not git hooks; does not catch non-Claude agent pushes | Incomplete coverage; hook covers all push paths including non-Claude agents |
Consequences¶
- Positive: PR-body format failures are caught locally in under 5 seconds, before any CI cycle starts. The 44 runner-hours of annual CI waste from prose-bullet bodies is eliminated for all contributors who have
make hooks-installapplied. - Positive: The anti-pattern warning in
deliverables-check.shgives agents a clear, actionable message explaining why the gate is failing, reducing re-push iterations. - Positive: The PR template banner makes the checkbox requirement visible to agents that generate bodies from the template without reading the surrounding documentation.
- Negative: Contributors without
ghCLI installed skip the hook silently. CI remains the authoritative gate for those contributors. - Neutral: The hook skips draft PRs, matching CI's
pull_request.draft == falsepredicate, so it never blocks a draft-to-ready promotion push. - Neutral:
make hooks-installmust be re-run by any contributor who cloned before this PR landed. Thepre-commithooks are auto-installed for new clones via the existingmake hooks-installdocumentation indocs/development/contributing.md.
References¶
- Audit slice G:
.workingdir/audit-2026-05-15/G-agents-hooks-skills.md(§G.6, §G.7, §G.10, §G.11). - ADR-0108:
docs/adr/0108-deep-dive-deliverables-rule.md. - ADR-0124:
docs/adr/0124-automated-rule-enforcement.md. - Related PRs that tripped the gate: #461, #438, #470, #473, #486, #511, #468, #526.