docs(609): correct the --no-merges rationale — merges are discouraged, not blocked

Review Low x2, both correct and both the stale-comment class:

The claim that prepush-rebase-check.sh forbids merging main into a PR branch is
false. That hook refuses a branch that is BEHIND origin/main; a merge makes
origin/main an ancestor, so the push is allowed. Merging main in is discouraged by
convention only. So --no-merges does cost a real false negative: an author who marks
ONLY a conflict-resolving merge commit gets a legitimate rewrite rejected. Keeping
--no-merges and stating the trade explicitly -- that failure is loud and costs one
extra commit, whereas honoring forge-composed merge bodies disables the guard
silently, which is #609 itself.

The module comment also still claimed a quoted example cannot arm the guard, which
contradicts the residual the decision record now states accurately. Aligned both, and
narrowed the record's Rule line from "some commit" to "some NON-MERGE commit" so the
stated contract matches the implementation.

No logic change -- comments, docstring, record prose and regenerated catalog only.

fixes #609

Decisions-Edit: yes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-25 18:36:07 +02:00
co-authored by Claude Opus 5
parent cc9481f541
commit f00dfde0c5
3 changed files with 21 additions and 9 deletions
+14 -5
View File
@@ -30,8 +30,10 @@ REQUIRED_META = ("key", "status", "since", "supersedes", "superseded_by", "signa
# ersatztv#609: the original `[decisions-edit]` substring test armed on ANY commit message containing
# the literal string — including prose *about* the mechanism, and including a message explaining why
# no token was needed — which silently disabled all three body-diff comparisons while the job still
# reported green. Git recognises a trailer only in a message's final trailer block, so prose can't
# arm it, and neither can a quoted example commit message (which docs commits here routinely carry).
# reported green. Git recognises a trailer only in a message's final trailer block, so discussing the
# marker mid-message which is what actually happened — can no longer arm anything. It is NOT a total
# immunity: a quoted example that IS the final paragraph of a commit message parses as a real trailer
# and does arm. See `ci.decisions-edit-trailer` for that residual, stated rather than papered over.
EDIT_TRAILER = "Decisions-Edit"
_EDIT_TRAILER_AFFIRMATIVE = frozenset({"yes", "true", "1"})
_LEGACY_EDIT_TOKEN = "[decisions-edit]" # noqa: S105 (a commit-message marker, not a credential)
@@ -274,9 +276,16 @@ def _edit_trailer_armed(mb: str, head: str) -> bool:
most needed policing. Failing open here would reintroduce #609 through a different door.
`--no-merges` skips merge commits: on a `pull_request` event `actions/checkout` lands on a
synthetic merge commit whose body is composed by the forge, not by the author, so a trailer
parsed out of it was never a deliberate marker. Merging main into a PR branch is separately
forbidden (`.husky/pre-push` → `prepush-rebase-check.sh`), so no author-written commit is lost.
synthetic merge commit whose body is composed by the forge from the PR description, not by the
author, so a trailer parsed out of it was never a deliberate marker.
This does cost a real (if narrow) false negative, and the trade is deliberate. Merging main into
a PR branch is discouraged by convention but NOT mechanically blocked — `prepush-rebase-check.sh`
only refuses a branch that is BEHIND origin/main, and a merge makes origin/main an ancestor, so
the push is allowed. An author who resolves a rationale conflict in such a merge and puts the
ONLY marker on that merge commit gets their legitimate rewrite rejected. That failure is LOUD and
costs one extra commit carrying the trailer; honoring forge-composed merge bodies would instead
disable the guard SILENTLY, which is the #609 failure itself. Prefer the loud one.
`unfold` joins RFC-822 continuation lines before the value is compared. Without it, a folded
`Decisions-Edit: no\\n yes` yields two lines and the continuation ` yes` arms the exemption on