Repository navigation
feat(done-check): key Done on the release, and refuse a Done no tag contains - #398
Conversation
CLOUD-192 The board transitions to Done on merge, not on release — In Review is never occupied
Why. The board is the observability surface, and its states are defined against a trunk-based model: In Review = landed on Measured. PR #103 merged at The end state converged here only because release-plz happened to release promptly. The transition is keyed on the wrong event, so the failure is latent rather than absent:
This also supersedes a recorded observation in Acceptance.
Implementation, 2026-08-13. Re-measured before touching anything. The defect is still live and unchanged from the original CLOUD-168 observation: CLOUD-499's state history reads The two halves have different owners, and only one is code.
So the repo ships the half it can hold: the consequence. The board was corrected rather than grandfathered. Piping the full Done closure (159 issues) exited 1 and named five: CLOUD-404, CLOUD-484, CLOUD-491, CLOUD-495, CLOUD-499 — each landed, each in no tag. All five moved to In Review, Fewer than the 50 unreleased commits would suggest, because an issue is judged by its most-released ref: work carrying several PRs, some shipped, passes. That is CLOUD-468's question and this gate deliberately does not answer it. Notes. If the integration cannot key |
`Done` means released, and the tracker keys it on the merge — a whole release cycle earlier. Measured 2026-08-13: CLOUD-499 went Todo -> In Progress -> Done at merge time, with main 50 commits past v0.0.62. The terminal twin of `landed-check`: both report In Review from opposite sides. It only ever refutes, never confirms — a ref inside a tag is weak evidence (refs come from commit messages), a ref nowhere near one is conclusive. Refs: CLOUD-192
…ith an unjudged one Found by mutation: deleting the released guard left the two passing cases green, because once the tag is cut nothing is unreleased and an issue judged `unlanded` also exits 0. The count separates them. Refs: CLOUD-192
…view The merged event now maps to In Review in the tracker's GitHub integration (a workspace setting — nothing in this tree holds it), so Done has exactly one source left: a release. Retracts two claims in mem:workflow/board-states that the fix falsifies — that the merge lands on Done, and that hand-moving to In Review does not stick. Names done-check as the gate on the last leg. Refs: CLOUD-192
e33f944 to
bd99948
Compare
|
|
/fast-forward |
Measured on #398, the PR that landed the setting change: merged 06:27:05, all checks green, and CLOUD-192 still read In Progress 8m21s later with no In Review entry. The open side fired normally on the same PR, so Linear had the issue and the link and did nothing on merge. The claim this replaces was mine, landed one PR ago, and an agent reading it would wait for a board move that never comes. Closes CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…loses it The merged-event automation fires only for a CLOSING pull request. Measured as a controlled pair on one issue, one variable: #398 `Refs: CLOUD-192` merged 06:27:05 never moved #400 `Closes CLOUD-192` merged 06:59:39 In Review 06:59:41 issue-guard already forces a key onto every PR, so every PR here names its issue and none of them close it — the convention was satisfied and the outcome still wrong. It is invisible when broken: nothing reds, the PR merges, the board is quietly one column behind. DO-NOT-CLOSE opts out, for the several-PRs-per-issue case (CLOUD-186). Refs: CLOUD-192
…does not stop it CLOUD-847's arm I deferred one obligation: write the attachment half beside the closing-key entry the next time anything touches this file. `39dc672` was that change and went in without it, so this lands both halves — and the second one corrects what `39dc672` itself concluded. That entry read "the branch name lost" from CLOUD-860 moving on #635. Re-read from the board, CLOUD-847 — the branch's own row — moved on exactly the same events, and so did both rows on #639's open and merge. Nothing lost; every key a PR carries moves its row on both events, and every one collects the attachment as a union. Three consequences, and none of them was written down: - arm I's starvation prediction does not reproduce. A row cannot end In Review with no PR attached while an unrelated row hoards them, so `graph-check`'s `in-review-no-pr` is not at risk from a branch naming another key. - `DO-NOT-CLOSE` is an exemption from `closing-key-check`, not a hold on the automation. #639 declared it, closed nothing, and moved two rows twice. - a PR OPENING drags a linked row backwards: #639 knocked CLOUD-860 out of the In Review #635 had just given it, back to In Progress, for work that was not its own. The completion half stands unchanged — `Refs:` still does not close, and no row here reached Done. The one tension left is named rather than smoothed over: #398's `Refs:`-only body moved nothing while #639's moved two rows, and the discriminating measurement is written down for whoever needs it. DO-NOT-CLOSE — this corrects a memory entry and completes no row; CLOUD-847's own completion is a release. Refs: CLOUD-847



Doneon this board means released ([dor-dod]), and the tracker's GitHubintegration keyed it on the merge — a whole release cycle early. Re-measured
2026-08-13: CLOUD-499's state history reads
Todo -> In Progress -> DonewithDoneset at 05:13:12, merge time, while the last tag wasv0.0.62andmainstood 50 commits past it. So ~1.5 days of landed work read as released, and
In Review— the post-merge, pre-release column the trunk-based model dependson — was entered only when a human put an issue there by hand.
The two halves have different owners
merge -> In Review is a workspace setting (team -> GitHub integration -> the
status mapped to "pull request merged"). No repo code and no Linear MCP tool can
change it. It has been flipped from
DonetoIn Review.release -> Done has no automation available at all, and no setting reaches
it: per
mise-tasks/released's header, the integration triggers on PR events,and "a release tag now contains this commit" is not one. Performing it needs a
Linear credential this repo deliberately does not have.
So the repo ships the half it can hold — the consequence
mise-tasks/done-checkrefuses aDonethat nov*tag reaches:CLOUD-N Done -> In Review, exit 1. A promotion skipped at release time is nowa failing check rather than silent drift.
It is
landed-check's terminal twin, built to its shape deliberately — bothname In Review from opposite sides, one for a board behind git, one for a board
ahead of the release — and it composes with
releasedrunning the other way.It only ever refutes a Done, never confirms one. Refs are resolved from
commit messages, so a ref inside a tag is weak evidence (a commit can cite or
defer), while a ref nowhere near a tag is conclusive. Two things it therefore
stays quiet about: an issue whose work half-landed and half-shipped (CLOUD-468's
question), and a
Doneno commit names at all, reported asunlandedand notfailed on.
Both preconditions are exit 2 and fail in opposite directions: no
origin/mainmakes every Done look unlanded (false green), no tags makes every Done look
unreleased (false red). A default CI checkout fetches no tags, so the second is
the ordinary way to meet it.
Shown able to fail, on fixtures and on the real board
tests/done-check.bats, 15 cases, mutation-checked three ways — dropping thereleased guard, never reporting, and dropping the no-tags precondition each
redden exactly the cases that own them. The first mutation run found a real gap:
two passing cases were green under the mutant, because once a tag is cut nothing
is unreleased and an issue judged
unlandedalso exits 0. Pinning the countseparated them.
Against the live board, the full
Doneclosure (159 issues) exited 1 and namedfive landed-but-untagged issues; all five moved to In Review (
graph-check-adjudicated on their PR attachments first), and the same closure now exits 0.
Also here
.github/workflows/release-plz.yml— the report step's promotion is now theonly path to Done rather than advice competing with an automation that already
fired.
mem:workflow/board-states— two claims this change falsifies are retractedrather than appended to: that the merge lands on Done, and that hand-moving to
In Review does not stick.
AGENTS.md— the open-issue pointer is dropped and the rule states the source.Refs: CLOUD-192