You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
---------
Co-authored-by: Claude <noreply@anthropic.com>
That is the ninth such trailer on main, after the eight scripts/no-claude-coauthor-trailers.py documents. Like those, it cannot be removed — CLAUDE.md §Git workflow makes main append-only. I caused it and am filing it rather than leaving it to be rediscovered.
trailers.yml was green on the merged commit, correctly. It is not broken; it is aimed at a different source.
Why the guard did not see it
The script's model, stated in its own header, is that the trailer "entered on the branch, not at the merge button" — so it checks two things: every commit message in the PR range, and the PR body. Both were clean here:
$ git log 2cd8366d..776ebb71 --format='%h %s|%(trailers:key=Co-authored-by)'
776ebb71 fix(tests): count a warn attribute as re-opening the gate| (none)
a8a49a98 fix(tests): scan all of src, and require rejection … | (none)
1b61bdd0 fix(tests): parse the manifest as TOML instead of scanning it| (none)
91fa0826 fix(tests): parse whole attributes and inline-table lint entries| (none)
d6cffec2 ci: gate the steel-detailer-lookup crate, and fix what it had drifted into| (none)
The trailer came from a third source the script does not model — commit author identity:
$ git log 2cd8366d..776ebb71 --format='%h %an <%ae>'
776ebb71 Claude <noreply@anthropic.com>
… all five identical
When GitHub squashes, it synthesises a Co-authored-by: trailer for every commit author that differs from the account performing the merge. No message anywhere has to contain the string. So the rule can be broken by a branch whose commit messages are all clean, which is exactly what happened — and what makes this worth a gate rather than a note.
Two things to fix
Extend the guard to authorship.no-claude-coauthor-trailers.py should also fail when a commit in the range is authored by Claude <noreply@anthropic.com> (or any name/email the squash would turn into a Claude co-author), not only when a message or the PR body contains the trailer. Its "What this does not reach" section should gain this case either way — that section is what makes the gate honest about its own reach, and right now it omits the source that actually landed ci: gate the steel-detailer-lookup crate, and fix what it had drifted into #408.
Pass an explicit squash body when merging. The merge that landed this supplied only a commit title and accepted GitHub's generated body, which is where the trailer was appended. Supplying the body explicitly (--body / the API's commit_message) keeps the trailer out regardless of authorship, and is the cheaper half of the fix. This is the part that was mine to get right and I did not.
The underlying cause of the authorship is environmental — the agent sessions that produce routine/* branches commit as Claude <noreply@anthropic.com> — so (1) will keep firing until either that identity changes or the squash body is always supplied. Worth deciding which of those is the intended answer.
The PR's own content is sound and independently verified: 20-agents/aeco/engineering/steel-detailer-lookup is now gated in CI (fmt + clippy + test on the pinned toolchain), its six non-test unwrap()s are gone, and CI is green on main at 0789633b including the new step. This issue is strictly about the trailer on the squash commit and the gap that let it through.
Also still open from #408, unrelated to the above: cli/tests/lint_gates.rs has the four manifest-parsing holes and the warn-attribute hole that #408 fixed in its own copy. Porting the fixed version back is the natural follow-up.
mainat0789633b(the squash of #408) ends:That is the ninth such trailer on
main, after the eightscripts/no-claude-coauthor-trailers.pydocuments. Like those, it cannot be removed — CLAUDE.md §Git workflow makesmainappend-only. I caused it and am filing it rather than leaving it to be rediscovered.trailers.ymlwas green on the merged commit, correctly. It is not broken; it is aimed at a different source.Why the guard did not see it
The script's model, stated in its own header, is that the trailer "entered on the branch, not at the merge button" — so it checks two things: every commit message in the PR range, and the PR body. Both were clean here:
The trailer came from a third source the script does not model — commit author identity:
When GitHub squashes, it synthesises a
Co-authored-by:trailer for every commit author that differs from the account performing the merge. No message anywhere has to contain the string. So the rule can be broken by a branch whose commit messages are all clean, which is exactly what happened — and what makes this worth a gate rather than a note.Two things to fix
Extend the guard to authorship.
no-claude-coauthor-trailers.pyshould also fail when a commit in the range is authored byClaude <noreply@anthropic.com>(or any name/email the squash would turn into a Claude co-author), not only when a message or the PR body contains the trailer. Its "What this does not reach" section should gain this case either way — that section is what makes the gate honest about its own reach, and right now it omits the source that actually landed ci: gate the steel-detailer-lookup crate, and fix what it had drifted into #408.Pass an explicit squash body when merging. The merge that landed this supplied only a commit title and accepted GitHub's generated body, which is where the trailer was appended. Supplying the body explicitly (
--body/ the API'scommit_message) keeps the trailer out regardless of authorship, and is the cheaper half of the fix. This is the part that was mine to get right and I did not.The underlying cause of the authorship is environmental — the agent sessions that produce
routine/*branches commit asClaude <noreply@anthropic.com>— so (1) will keep firing until either that identity changes or the squash body is always supplied. Worth deciding which of those is the intended answer.Not a regression in what #408 shipped
The PR's own content is sound and independently verified:
20-agents/aeco/engineering/steel-detailer-lookupis now gated in CI (fmt + clippy + test on the pinned toolchain), its six non-testunwrap()s are gone, and CI is green onmainat0789633bincluding the new step. This issue is strictly about the trailer on the squash commit and the gap that let it through.Also still open from #408, unrelated to the above:
cli/tests/lint_gates.rshas the four manifest-parsing holes and thewarn-attribute hole that #408 fixed in its own copy. Porting the fixed version back is the natural follow-up.