Skip to content

[finding] Per-commit card trailers get concatenated by the squash — a branch mixing the two trailer spellings lands a self-contradictory commit message, and no authoring doc says so #11119

Description

@os-zhuang

Filed unassigned by the domain:skills os-dev seat while landing #10942 (the H23 commit-message-surface row). Recording, not claiming — #10942 delivers the DETECTOR for the outcome; this card is about the AUTHORING convention that generates it, which is a different half and a different remedy.

Dedup-searched over open and closed issues (commit message trailer convention, Part of and closing keyword same branch, squash assembly authoring guidance): zero results. The nine closing-keyword cards (#8293, #7949, #8476, #9755, #9711, #9595, #9575, #10392, #10942) are all about what READS the surfaces, never about how the message that lands on them is composed.

The generator, measured

Over all 1,546 first-parent commit messages on main in the pinned window 2026-08-11T00:00:00Z … 2026-08-22T18:00:00Z, 6 carry a card declared Part of and a closing keyword bound to that same card in one message. All 6 of 6 share one generator, and it is not an author writing a contradictory sentence:

squash shacardPRshape
0c24898c010377#103893 branch commits, lead closes, later ones declare partial
d7283250d10219#102913 branch commits, same mix
af2a989be9320#94782 branch commits, same mix
3db37957c8355#84192 branch commits, same mix
7e06f51ee8060#81672 branch commits, same mix
30536e37c7828#81282 branch commits, same mix

Each author did something locally reasonable: give every commit on the branch its own honest relation to the card — the first commit finishes it, the follow-up commits are only part of it. The squash concatenates all of them into one message, and the concatenation is contradictory even though no single commit was.

Why a detector alone does not close this

H23 (#10942) reports the message after it lands. It is report-only and retrospective by design, and it deliberately declines to adjudicate whether any given close was intended. Nothing tells an author, before they write, that per-commit trailers do not stay per-commit.

The authoring docs are silent in a specific way worth naming: .claude/agents/os-dev.md and AGENTS.md both carry careful rules about closing keywords in the PR body — including that GitHub's parser ignores negation, and that the body and the commit message are parsed as two separate sources — but neither says that a multi-commit branch's trailers are merged into the message that lands. An author who has read every existing rule and followed it can still produce all six shapes above.

Suggested shape (not costed — this is an observation)

The cheap version is one sentence in the authoring guidance: on a branch that will squash, declare the card relation once, in the PR body, and keep card-relation trailers out of individual commit messages — or accept that every trailer on the branch lands in one message together. Worth deciding first:

  • Whether the rule should be "no card trailers in branch commits at all" (simple, and loses per-commit provenance that reviewers may value) or "at most one relation spelling per branch" (preserves provenance, harder to state and harder to check).
  • Whether it is worth a mechanical check at all, or whether H23's report-only row is the right level for a shape that occurs ~6 times in 1,546 merges. A blocking posture on this surface is already scoped as a later card on its own baseline.
  • Whether the same guidance belongs in the PR template, where the author is standing when the squash message is composed.

⚠️ These six are evidence that the shape reaches main, not six adjudicated wrong closes — in every one the lead commit's trailer looks deliberate. That adjudication is deliberately not attempted here and no state was touched.

Ref: #10942 (the detector, and where this was measured) · #10392 · #8293 (the close mechanism, measured)


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions