Skip to content

fix(config): the acknowledgement trailer is refused when it is not in git's trailer block #444

Description

@tpouyer

The refusal lockstep-config / exercised prints tells a person to add a trailer, and a person who
does exactly that can still be refused — because git only reads the last paragraph of a commit
message as the trailer block, and this repository's commits already end with Co-Authored-By:.

How it happened

Writing the first change that actually meets this check (#437), I put the acknowledgement where it
reads best — after the prose, before the sign-off:

No binding changes. The container resolved for Test, Validate and Provision …

Unexercised-Config: this deletes a constant with no caller …

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

git log --format='%(trailers:only,unfold)' sees one trailer: Co-Authored-By. The blank line
makes that the final paragraph, and everything above it is prose — including the acknowledgement.
The check stayed red, correctly by its own rules, while telling me to do the thing I had just done.

Both trailers in one block with no blank line between them works. So does a folded multi-line value.
Neither is discoverable from the message.

Why it matters more than it looks

This repository's own convention guarantees the collision. CLAUDE.md requires every commit to end
with Co-Authored-By:, so an acknowledgement written anywhere except immediately adjacent to that
line is silently not a trailer. The natural place to write it — with the paragraph explaining it — is
the one place that does not work.

And the failure is silent in the direction that matters: the check does not say "a trailer was
found but not in the trailer block"
. It says nothing was found, which reads as "you did not write
one"
.

What would fix it

Either, or both:

  • Say it in the refusal. The message already carries the remedy, which is the reason it is worth
    reading; one more clause — that the trailer must be in the final block, with no blank line before
    Co-Authored-By: — costs nothing and is where somebody is already looking.
  • Notice the near-miss. acknowledgement() asks git for trailers. A second, cheap read of the
    raw message for ^Unexercised-Config: anywhere would let the refusal distinguish "no
    acknowledgement"
    from "an acknowledgement that git does not see as a trailer, because it is not
    in the last paragraph"
    . Those are different sentences and send a person to different places —
    the same argument tdd.not_red and tdd.suite_collected_nothing settled in fix(tdd): a red phase that collected nothing says the staged test passed #435.

The second is the better one and is the shape this repository keeps arriving at: a diagnostic that
cannot tell two causes apart gives a confident, specific, wrong answer.

Acceptance

  • A commit carrying Unexercised-Config: outside git's trailer block is refused with a message that
    says so and says how to move it, distinct from the refusal for no acknowledgement at all.
  • The syntax clause is in the refusal a person actually reads.
  • A test per branch: acknowledged, unacknowledged, and acknowledged-but-not-a-trailer — with the
    third asserting the two refusals differ, because a test that only checks "non-zero exit" would
    pass on the defect.
  • The trailer-block rule is not reimplemented. %(trailers:key=…) is git's parser and stays the
    one that decides; the near-miss read is a separate, clearly-labelled scan for a better error.

Objectives

O2 — onboarding is light, and a control whose remedy does not work when followed is a
configuration project in miniature. O12 — a second engineer meets this refusal exactly once and
should not need to be told by somebody how git parses a commit message.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions