Gate the pull request body on AI attribution - #20
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A reusable
pr-body-scan.ymlthat fails when a pull request body carries an AI attribution footer, this repository's caller for it, and a third scan inattribution-scanholding 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:
--allCLAUDE.mdexceptedLoad-bearing decisions
github.event.pull_request.bodyis 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.edited. Correcting a body raises no other event; without that type a corrected body could never clear the check.synchronizeis separate — a check run attaches to a commit, so a push must re-report.pull_request. There is no range on a push event, and history is the other tier's job.Testing
lint.ymlpins — clean.CLAUDE.md— correct on all four.--allscan.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.ymlcannot host it. The range scan, living inside the action, arrives everywhere the moment this merges. Required-check contexts inestate-infraare a separate decision, with the blast radius document 02 records for 2026-08-13.