Skip to content

feat(done-check): key Done on the release, and refuse a Done no tag contains - #398

Merged
wenzowski merged 3 commits into
mainfrom
claude/cloud-192-implementation-9l6mcg
Aug 13, 2026
Merged

wenzowski merged 3 commits into
mainfrom
claude/cloud-192-implementation-9l6mcg

Conversation

@wenzowski

Copy link
Copy Markdown
Contributor

Done on this board means released ([dor-dod]), and the tracker's GitHub
integration keyed it on the merge — a whole release cycle early. Re-measured
2026-08-13: CLOUD-499's state history reads Todo -> In Progress -> Done with
Done set at 05:13:12, merge time, while the last tag was v0.0.62 and main
stood 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 depends
on — 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 Done to In 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-check refuses a Done that no v* tag reaches:
CLOUD-N Done -> In Review, exit 1. A promotion skipped at release time is now
a failing check rather than silent drift.

It is landed-check's terminal twin, built to its shape deliberately — both
name In Review from opposite sides, one for a board behind git, one for a board
ahead of the release — and it composes with released running 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 Done no commit names at all, reported as unlanded and not
failed on.

Both preconditions are exit 2 and fail in opposite directions: no origin/main
makes 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 the
released 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 unlanded also exits 0. Pinning the count
separated them.

Against the live board, the full Done closure (159 issues) exited 1 and named
five 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 the
    only path to Done rather than advice competing with an automation that already
    fired.
  • mem:workflow/board-states — two claims this change falsifies are retracted
    rather 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

@linear-code

linear-code Bot commented Aug 13, 2026 •

Copy link
Copy Markdown
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 main, under post-merge review, pre-release; Done = released. Observed on CLOUD-168, the integration collapses both into one transition fired by the merge.

Measured. PR #103 merged at 19:29; CLOUD-168's state history is Backlog -> In Progress -> Done with Done set at 19:29:03 — merge time. The release (v0.0.15, which does contain the commit) was not cut until 19:31:56, ~3 minutes later. So the issue read Done for three minutes while unreleased, and In Review was never occupied at any point.

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:

  • A release that fails, is delayed, or is held leaves issues sitting in Done while unreleased — the exact "done means landed-and-verified" drift Batten exists to prevent, on Batten's own board.
  • In Review having no occupants means the post-merge review window the trunk-based model depends on has no board representation. Per AGENTS.md we review after merge, before release; a column that is structurally never entered cannot surface that work.

This also supersedes a recorded observation in mem:workflow/board-states, which states "the merge-side transition did not fire" (measured when #100 merged and CLOUD-178 stayed In Progress). It now fires — and overshoots. That memory needs correcting either way, since an agent reading it today will expect to hand-move a landed issue that the integration has already moved.

Acceptance.

  • Merging a PR moves its issue to In Review, not Done.
  • Done is set by the release, not the merge — an issue whose commit is on main but not in any published release is never Done.
  • A test or documented probe demonstrates the two-step path on a real issue (state history shows In Progress -> In Review -> Done).
  • mem:workflow/board-states is updated to record the current, measured behaviour, replacing the "did not fire" note.

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 Todo -> In Progress -> Done, with Done set at 05:13:12 — merge time. Last tag v0.0.62, main 50 commits past it, so ~1.5 days of landed work read as released.

The two halves have different owners, and only one is code.

  • merge -> In Review is a workspace setting — the team's GitHub integration maps the merged event to a status. No repo code and no Linear MCP tool can change it, so nothing in the tree can hold it. This is the one open item; it needs a human to flip it.
  • release -> Done has no automation available at all, and this is not a gap that a setting closes. 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 the repo deliberately does not have.

So the repo ships the half it can hold: the consequence. mise-tasks/done-check refuses a Done that no v* tag reaches — CLOUD-N Done -> In Review, exit 1. It is landed-check's terminal twin (both name In Review, one for a board behind git, one for a board ahead of the release) and composes with released running the other way. It only ever refutes a Done, never confirms one: refs come from commit messages, so a ref inside a tag is weak evidence while a ref nowhere near one is conclusive. A skipped promotion is now a failing check rather than silent drift.

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, graph-check-adjudicated on their PR attachments first. The same closure now exits 0 (27 not judged, the unlanded channel). That before/after pair is the gate demonstrating it can fail on real data, not only on fixtures.

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 on a release event, the fallback is to stop it at In Review and let the release step promote — a correct-but-manual last transition beats an automatic wrong one, since graph-check already gates In Review => a linked PR attachment.

Review in Linear

claude added 3 commits August 13, 2026 06:12
`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
@wenzowski
wenzowski marked this pull request as ready for review August 13, 2026 06:16
@wenzowski
wenzowski force-pushed the claude/cloud-192-implementation-9l6mcg branch from e33f944 to bd99948 Compare August 13, 2026 06:16
@sonarqubecloud

Copy link
Copy Markdown

@wenzowski

Copy link
Copy Markdown
Contributor Author

/fast-forward

@wenzowski
wenzowski merged commit bd99948 into main Aug 13, 2026
9 checks passed
@wenzowski
wenzowski deleted the claude/cloud-192-implementation-9l6mcg branch August 13, 2026 06:27
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski pushed a commit that referenced this pull request Aug 13, 2026
…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
wenzowski added a commit that referenced this pull request Aug 22, 2026
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants