Claim
main is PR-only and squash-only. GitHub composes a squash commit's message from the PR title and body — not from the branch's commits. So the FOLLOWING_AGENTS_PROTOCOL line and the three trailers that AGENTS.md requires on every commit survive only if the PR body itself ends with them. Nothing checks that before merge, and check-commit-trailers.py runs against branch commits, which are discarded by the squash.
Measured over the last 40 commits on origin/main:
with trailers: 33 WITHOUT: 7
All seven are squash merges (subject ends in (#N)):
bc570da0d MODEL-NEMOTRON-H: the WEIGHT LOADER ... (#752)
6e6bba63d ... reporting the pass (#776) (#853)
b5a5f3b18 ... things already had (#672) (#831)
ca01719e6 ... them UBSan cannot see (#815)
6680aab68 ... evidence is absent (#726) (#802)
be4a3edf1 ... the C++ compile (#774) (#795)
5da1d7f2f ... contributor's trailers (#773) (#782)
Note 5da1d7f2f: a commit about contributor trailers that carries none itself.
Reproduce:
for S in $(git log origin/main --format=%H -40); do
M=$(git log -1 --format=%B "$S")
echo "$M" | grep -qx 'FOLLOWING_AGENTS_PROTOCOL' &&
echo "$M" | grep -q '^Assisted-by:' || git log -1 --oneline "$S"
done
Why the branch-side gate cannot catch it
The obligation is enforced on commits that never reach main. An implementer can have every branch commit perfectly trailered, pass check-commit-trailers.py locally and in CI, and still land a trailer-less commit — because the squash throws those messages away and uses the PR body.
This compounds with #841, where agent-preflight.sh skips the trailer gate entirely on branches that have not merged main. Between the two, the trailer requirement is enforced on an artifact that is discarded and skipped on the artifact that is kept.
Also observed
The squash commit gains Co-authored-by: Ettore Di Giacinto <mudler@localai.io> — the human submitter, added by the forge rather than by any AI tool. AGENTS.md accepts a forge-generated Co-authored-by for the submitting account, but names the @users.noreply.github.com form specifically; this is the plain address form. Worth an explicit ruling in this row so it stops being re-litigated per PR.
What done looks like
- A checker that validates the PR body carries the required block before merge, since that is the text that becomes the commit. It can run in CI on
pull_request and read the body from the event payload.
- Or: make the trailer block part of the PR template, so the default path produces it.
- Either way,
check-commit-trailers.py should gain a mode that checks a merge-base range on main and reports the landed reality, not only the branch's discarded history.
- Decide what to do about the seven already landed. History on
main cannot be rewritten, so this is a record-the-debt decision, not a repair.
- Rule explicitly on the plain-address
Co-authored-by form the forge adds.
Found while landing #752. Related: #841 (preflight skips the trailer gate on un-merged branches).
Claim
mainis PR-only and squash-only. GitHub composes a squash commit's message from the PR title and body — not from the branch's commits. So theFOLLOWING_AGENTS_PROTOCOLline and the three trailers that AGENTS.md requires on every commit survive only if the PR body itself ends with them. Nothing checks that before merge, andcheck-commit-trailers.pyruns against branch commits, which are discarded by the squash.Measured over the last 40 commits on
origin/main:All seven are squash merges (subject ends in
(#N)):Note
5da1d7f2f: a commit about contributor trailers that carries none itself.Reproduce:
Why the branch-side gate cannot catch it
The obligation is enforced on commits that never reach
main. An implementer can have every branch commit perfectly trailered, passcheck-commit-trailers.pylocally and in CI, and still land a trailer-less commit — because the squash throws those messages away and uses the PR body.This compounds with #841, where
agent-preflight.shskips the trailer gate entirely on branches that have not mergedmain. Between the two, the trailer requirement is enforced on an artifact that is discarded and skipped on the artifact that is kept.Also observed
The squash commit gains
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>— the human submitter, added by the forge rather than by any AI tool. AGENTS.md accepts a forge-generatedCo-authored-byfor the submitting account, but names the@users.noreply.github.comform specifically; this is the plain address form. Worth an explicit ruling in this row so it stops being re-litigated per PR.What done looks like
pull_requestand read the body from the event payload.check-commit-trailers.pyshould gain a mode that checks a merge-base range onmainand reports the landed reality, not only the branch's discarded history.maincannot be rewritten, so this is a record-the-debt decision, not a repair.Co-authored-byform the forge adds.Found while landing #752. Related: #841 (preflight skips the trailer gate on un-merged branches).