feat(kanban): ask the board which columns are deploy states, not a list - #249
Conversation
.github#237 fixed the INSTANCE -- the guard matched the pre-rename "Staging (human review)" while the board's column is "Staging (agent review)", so a card hand-closed there lost its deploy state and kanban-archive.yml hid it. The CLASS survived: a hand-maintained list of six names, duplicated in kanban-reconcile.yml, that the next rename or inserted column reopens silently. @saadqbal made the point on that PR and it is the right one -- the comment's "drop the legacy name in both places" is a manual reminder, not a guard. THE BOARD ALREADY ANSWERS THIS. `$PROJ` carries the Status options in PIPELINE ORDER, so a deploy state is any column at or after "On dev" and at or before "Prod". An inserted column -- exactly how "Staging (agent review)" arrived -- is classified correctly with NO edit here, and a renamed intermediate column keeps working because its POSITION is what matters, not its name. Two anchors instead of six names, and both are written by this same workflow, so .github#247's checker already asserts they exist. UNKNOWN NO LONGER FALLS OPEN, which is the other half of #1846. A column this workflow cannot place used to sail past the `case` and let Done erase a deploy state. It now refuses: a card sitting where it is costs nothing, erasing the fact that it shipped costs the board's meaning. THE TEST READS THE FUNCTION OUT OF THE WORKFLOW rather than copying it -- the shape @saqlainsyed007's e2e#108 review argued for. A copy would let the workflow drift while the test stayed green, which is the same defect class as the list it replaces. Verified: renaming `col_index` makes the test fail loudly ("refuses to fall back to a copy") instead of testing a stale duplicate. 15 cases: every deploy state including the one the old list missed, everything before On dev, both terminal columns (the `<= Prod` bound is what keeps Cancelled reachable), a NEWLY inserted column between the anchors, unknown and empty columns, and a board missing an anchor. ruff and house-rules clean. Refs tracebloc/backend#1846
shujaatTracebloc
left a comment
There was a problem hiding this comment.
Approve. Replaces the hand-maintained six-column deploy-state list (which had already rotted once — carried "Staging (human review)" not the board's "Staging (agent review)", .github#237) with a position-based classification asked of the board: a deploy state is any column between the "On dev" and "Prod" anchors, so an inserted or renamed intermediate column is handled with no edit. Correctly fails closed — missing anchors → exit 1, unknown current column → refuse rather than overwrite Done (the other half of backend#1846). New offline selftest extracts col_index() out of the workflow rather than copying it, so it can't go green against a stale duplicate. CI green, Bugbot clean.
Non-blocking follow-up: kanban-reconcile.yml still carries the duplicated hand-maintained list this PR removes here — same rot risk remains there until it's migrated to the same board-derived approach.
Refs tracebloc/backend#1846 · epic tracebloc/backend#1646 · follow-up to #237, #245, #247
The instance was fixed. The class wasn't.
#237 fixed the guard that was matching the pre-rename
Staging (human review)while the board's column isStaging (agent review)— a card hand-closed there lost its deploy state andkanban-archive.ymlthen hid it.What survived was a hand-maintained list of six column names, duplicated in
kanban-reconcile.yml, which the next rename or inserted column reopens silently. @saadqbal made exactly this point on #237:The board already answers the question
$PROJcarries the Status options in pipeline order, so a deploy state is any column at or afterOn devand at or beforeProd.An inserted column is exactly how
Staging (agent review)arrived. Both anchors are written by this same workflow, so #247's checker already asserts they exist on the board.Unknown no longer falls open
The other half of #1846. A column this workflow cannot place used to sail past the
caseand letDoneerase a deploy state. It now refuses — a card sitting where it is costs nothing; erasing the fact that it shipped costs the board its meaning.The test reads the function out of the workflow
This is the shape @saqlainsyed007 argued for on e2e#108: a copy of the logic in the test would let the workflow drift while the test stayed green — the same defect class as the list it replaces.
Verified by renaming
col_index:15 cases: every deploy state including the one the old list missed · everything before
On dev· both terminal columns (the<= Prodbound is what keepsCancelledreachable) · a newly inserted column between the anchors · unknown and empty columns · a board missing an anchor.ruffandhouse-rulesclean.Not in scope
kanban-reconcile.yml's copy of the list. It runs in a different context with different variables, and one self-contained change reviews better — filed as the remaining half on backend#1846.🤖 Generated with Claude Code
Note
Medium Risk
Changes when hand-closed issues get Done vs stay parked—wrong bounds could still erase deploy state or block legitimate closes—but behavior is fail-closed on unknown columns and covered by a selftest tied to the live workflow shell logic.
Overview
Hand-closed issues in deploy columns no longer rely on a fixed list of six Status names (and the stale
Staging (human review)entry). When routing would set Done, the router now treats a column as a deploy state if its position on the board falls between On dev and Prod, using Status option order from the same$PROJpayload.Fail-closed behavior is tightened: missing On dev / Prod anchors aborts the update with an error; a current column the board does not recognize skips Done instead of falling through and overwriting deploy state. The existing issue comment when Done is refused in a deploy column is unchanged.
Regression coverage adds
kanban-deploy-state-selftest(GitHub Action +scripts/tests/kanban-deploy-state-selftest.py), which parsescol_index()out ofkanban-closure-router.ymland runs offline cases (deploy columns, pre-dev columns, terminals, inserted columns, unknown/missing anchors).kanban-reconcile.yml’s copy of the old list is explicitly out of scope.Reviewed by Cursor Bugbot for commit b11b7e2. Bugbot is set up for automated code reviews on this repo. Configure here.