✨ fix(release): reject literal-emoji commit subjects and close the ### Other blind spot (D-168) - #117
Merged
Merged
Conversation
…s (REDMAIN-N1/N2) The INBOX filed N1 (nothing rejects a literal-emoji subject at commit time) and N2 (changelog_gate_test.sh §8's `### Other` detector requires an ASCII shortcode, so it is fail-open for exactly that shape) as two halves of ONE defect that one lane must own. This is that spec: five REQs, the narrow rule and why it is narrow, and the two things deliberately out of scope — re-filing the rendered entry (needs cliff.toml, filed as REDMAIN-N3) and a 22nd `task check` stage (CHECK_STAGES asserts equality with the Taskfile list).
… them (D-168) Half B: hack/release/commit_subject_gate.sh rejects a commit subject whose first character is not ASCII — the narrow rule, so Dependabot's `build(deps):` and GitHub's `Merge pull request …` stay legal. Published history is exempted by full SHA and each exemption must itself still BE a detection, so it cannot rot into a blanket escape. Reachable as an UNGUARDED verify: step (a PR is the last moment a subject can be reworded) and, locally, through the existing release-changelog-gate-test stage — no new `task check` stage. Half A: §8's `### Other` detector now takes an OPTIONAL gitmoji prefix in two spellings, so a fileable type is seen behind a shortcode, behind a literal emoji, or behind nothing. §8b pins the regression by running the pre-fix pattern over the same probe and showing it miss the literal-emoji line. The `### Other` exemption is read from the gate's own SHA list, so the two halves cannot drift, and it reds as dead scaffolding once cliff.toml files the entry.
…s and its hand-off Why the rule is "first character must be ASCII" and not the whole convention; why there is no 22nd `task check` stage; why the verify: step is deliberately NOT guarded off pull_request while the drift gate beside it still is; how the SHA exemption is kept honest and made self-retiring into REDMAIN-N3; and the incidental finding that AGENTS.md/CLAUDE.md are untracked, so GUIDELINES.md is the authority a gate can actually cite.
…green state (D-168) Review simulated REDMAIN-N3 landing and found the self-retire hand-off named a remedy nobody could execute. Deriving §8's `### Other` exemption from `LEGACY_ALLOW_SHAS` coupled two facts that decouple at exactly that moment: the commit SUBJECT stays a literal emoji forever, while the RENDERED ENTRY stops being mis-filed. Coupled, there was no green allowlist state after N3 — keep it and §8 reds as stale, drop it and both gates red. §8 now keeps its own OTHER_EXEMPT_SHAS, which may be EMPTY (the post-N3 steady state, where every Other line is checked — strictly stronger), linked to the gate only by the one-way invariant OTHER_EXEMPT_SHAS subset-of LEGACY_ALLOW_SHAS, which the empty set satisfies. The retire message now names the one line to delete, and says which list not to touch. Also: pin the allowlist's exact content from §9d, because all three in-gate self-checks pass for a SHA appended in the same PR as the commit it excuses; widen OTHER_MAPPABLE_RE, which accepted exactly one non-ASCII token and exactly one space and so missed three more mis-filing spellings; and point the shallow-clone messages at the cause they actually have.
…or the allowlist pin REQ-REDMAIN-N2-02 said the exemption was derived from one authority and would "red the moment it stops being needed" — true, but the state it redirected to was unreachable. It now states the two predicates, why they diverge at N3, the one-way subset invariant, and the Given/When/Then that ends green. REQ-N1-04 is new and records the allowlist-growth hole review found. The backlog N3 row carries the exact one-line hand-off, and neither doc quotes a commit count any more — a self-dating denominator rots.
…ng instinct here The row claimed the two halves share one authority "so they cannot drift apart". They were never meant to stay equal: one fact is permanent and the other retires at REDMAIN-N3, and coupling them left no green state. Recorded as a correction with the mechanism, not silently rewritten. (e) now carries the executable remedy and the end-to-end proof; (c) carries the second-file size pin; the "893 commits" figure is gone from both this row and the spec.
…ave; file REDMAIN-N4 The Test:/Verify: line named the subset invariant, the empty-list path and the retire message as if running changelog_gate_test.sh exercised them. It does not: on the real tree the subset grep always passes, the empty-list branch is never taken and the retire message is never emitted. They were proved by one-off scratch-clone simulation — evidence produced once, not a probe that re-runs — which is weaker than the standing controls §8a/§8b/§9b/§9d carry. The line now says what running the script actually covers and names the gap in those words. REDMAIN-N4 is the tracked OPEN residual for the missing §8c, on its own row, carrying the three fail-closed P3s the reviewer found.
… at REDMAIN-N4 The row implied (d) and (e) were held by the gate. They are held by a simulation this lane ran once; the gate has no standing control for any of the three. Recorded as a bounded claim with the follow-up named, not narrowed into vagueness.
…re and the x/mod bump (D-168)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this closes
mainwas RED for four days on a changelog-integrity defect with two halves, filed by theREDMAIN-F01 reviewer as REDMAIN-N1 and REDMAIN-N2. The INBOX states they are two halves of one
defect and must land together, so they do.
cliff.toml's classifier (everyparser keys on the ASCII shortcode), and nothing rejected such a subject at commit time. New
hack/release/commit_subject_gate.shscans every subject and rejects a non-ASCII-leading one.It is reachable on
pull_requestas averify:step and locally through the existingrelease-changelog-gate-teststage — no newtask checkstage, soCHECK_STAGESinhack/audit/exitgate_test.shstays at 21.changelog_gate_test.sh§8's### Otherdetector required an ASCII shortcode,so it was fail-open for exactly the literal-emoji shape that causes the mis-filing it exists to
catch. The detector now matches a fileable type behind a shortcode, behind a literal emoji, or
behind no prefix; §8b pins the regression by showing the pre-fix pattern miss the same probe.
The two exemption lists are decoupled (
:bug: fix(release)) so that REDMAIN-N3 — the remainingcliff.tomlparser entry that re-filesdfdae69out of### Other— has a green state to landinto. When it lands, §8's SHA exemption stops matching and the gate reds telling you to delete it;
that red is the hand-off, by design (REQ-REDMAIN-N2-02).
Decision row: D-168. Spec:
openspec/specs/p5-redmain-changelog-integrity/spec.md.Local pre-merge evidence
Both AUD gates are SKIPPED on
pull_request, so a green PR alone proves nothing about changelogdrift. Run locally on the rebased head:
task check— EXIT=0, 21 stages, matchingCHECK_STAGESexactly.task coverage— 91.1% against the 91% floor.hack/release/commit_subject_gate.sh— 914 subjects scanned, all ASCII-leading; the singlepublished-history exemption verified to still be a real detection. This includes every commit on
this branch, so the lane's own new gate passes on its own rebase.
CHANGELOG.mdwas regenerated once withtask changelog-writeafter the rebase and neverhand-edited. All eight lane commits classify correctly; the
👷 ci(docs)entry remains under### Otherbecause that is REDMAIN-N3, still open by design.Rebase notes
Rebased from
20c80cbonto8ec54b8, then re-rebased onto00c429ewhenmainmoved again(the
golang.org/x/modv0.40.0 bump, PR #115). The first rebase hit four conflicts, all thekeep-both adjacency shape:
openspec/specs/backlog.mdonce (main's P5-DOCSNAV/D-170 section vs the lane's REDMAIN-N section,appended at the same tail position) and
docs/decisions/decisions.mdthree times (the lane addsD-168; main now carries D-170 and D-171 — no ID collision). Every one resolved by keeping both
sides' rows; no decision ID was renumbered. The three pure mechanical
CHANGELOG.mdregenerationcommits were dropped and the file regenerated once at the end, so no known-wrong
CHANGELOG.mdexists anywhere in the history. The second rebase onto
00c429ewas conflict-free; because itrewrote already-pushed commits, this PR is opened from
lane/emoji-subject-r3and supersedes #116(no force-push).
Note that
mainat00c429ewas itself in changelog drift — thex/modbump merged without aCHANGELOG.mdregeneration — so the regeneration commit here carries that entry too and repairsit. That is the recurring D-163 shape, not something this lane introduced.
Unblocks
Taskfile.ymland.github/workflows/verify.yamlare free again once this lands: DOCTRUTH,DOCSNAV-R02 and COUNT1-F01 all need them.
Carried follow-ups (P3)
Both filed to the INBOX rather than fixed here — neither is a defect in the shipped gate:
REDMAIN-N4backlog row says the three §8 mechanisms "have no standing control … so runningchangelog_gate_test.shexercises none of them". The subset invariant does execute live onevery run (fail-closed); what is missing is a negative control proving it can red. That row
should say "no negative control". The spec file itself is correctly worded.
backlog.md:822; it is at:825(a 3-line section-introinsertion shifted it). The row is correct — only the citation was stale.