Skip to content

Gate the pull request body on AI attribution - #20

Merged
damian1000 merged 2 commits into
mainfrom
add-pull-request-body-scan
Aug 25, 2026
Merged

Gate the pull request body on AI attribution#20
damian1000 merged 2 commits into
mainfrom
add-pull-request-body-scan

Conversation

@damian1000

@damian1000 damian1000 commented Aug 25, 2026

Copy link
Copy Markdown
Member

What

A reusable pr-body-scan.yml that fails when a pull request body carries an AI attribution footer, this repository's caller for it, and a third scan in attribution-scan holding new commit messages to the same bar.

Why

The existing scans read commit messages and authorship. The body was outside every gate in the estate, and it is where a footer arrives without an author writing one — the agent backend appends it at creation, whatever body was supplied, so care in the agent's own output cannot remove it.

The two tiers

History cannot be rewritten. Eight public repositories carry the commit that introduced this action, and its subject names the tool it rejects, so a pattern strict enough to bar a bare mention would fail all eight permanently. The strict pattern is therefore aimed where it can be met:

Surface Bar
History, read with --all attribution artifacts: a footer, a trailer, a tool identity
Commits a pull request adds any mention, CLAUDE.md excepted
The pull request body any mention, because a body is rewritable

Load-bearing decisions

  • Live read, not the event payload. github.event.pull_request.body is frozen at the instant the event fired, so a footer stripped a second after creation would fail a payload read permanently, on a pull request that is already correct.
  • Callers trigger on edited. Correcting a body raises no other event; without that type a corrected body could never clear the check. synchronize is separate — a check run attaches to a commit, so a push must re-report.
  • The range scan is guarded to pull_request. There is no range on a push event, and history is the other tier's job.

Testing

  • actionlint 1.7.12, the version and checksum lint.yml pins — clean.
  • Prettier 3.4.2 over the workflow and markdown targets — clean.
  • Strict pattern exercised against a bare mention, a vendor name, an oblique description and CLAUDE.md — correct on all four.
  • Every repository's full history measured against the strict pattern: eight fail. That measurement is the evidence for tiering rather than tightening the --all scan.
  • Run block simulated against a body carrying a footer, a body describing one, and a null body.
  • This branch's own commits measured against the range scan — clean.

The caller here resolves the scan by local path, so this pull request is gated by the files it adds, and this body is written to pass the rule it introduces.

Not done here

Adoption. Buildable repositories reach shared workflows at @main, so nothing picks up the body scan until this merges, and each then needs its own thin caller — ci.yml cannot host it. The range scan, living inside the action, arrives everywhere the moment this merges. Required-check contexts in estate-infra are a separate decision, with the blast radius document 02 records for 2026-08-13.

The history scan reads commit messages and authorship. Nothing read the
pull request body, which is where an attribution footer arrives without an
author writing one: the agent backend appends it at creation, whatever body
was supplied, so care in the agent's own output cannot remove it.

The scan reads the body live over the API rather than from the event
payload, because the payload is frozen at the instant the event fired and a
body corrected a second later would fail it permanently. Callers trigger on
edited so that the correction is seen, and on synchronize because a check
run attaches to a commit. The pattern is line-anchored for the reason the
message scan is: a body is prose, and this one quotes the footer it looks
for.
The gates matched attribution artifacts because they read every commit,
and history cannot be rewritten: eight public repositories carry the
commit that introduced this action, whose subject names the tool it
rejects. A pattern strict enough to bar a bare mention would fail all
eight permanently.

So the strict pattern is aimed where it can be met. A third scan reads
only the commits a pull request adds, and the body scan rejects any
mention rather than a footer shape, because a body is rewritable. The
filename CLAUDE.md is excepted so a commit can name the file it edits.
@damian1000
damian1000 merged commit 062e648 into main Aug 25, 2026
3 checks passed
@damian1000
damian1000 deleted the add-pull-request-body-scan branch August 25, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant