Uh oh!
There was an error while loading. Please reload this page.
fix(kanban): finish #1592 step 3 — writers first, then the fallback - #245
Merged
Conversation
promote: develop -> main (D30 self-signoff relaxation)
chore(promote): develop → main — fr-pass exit codes, fail-closed mutators, caller comment (backend#1412, #1413)
chore(promote): develop → main — wire the Done column, and give the closer lookup a token (backend#1411)
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
release-train: develop -> staging
release-train: develop -> staging
release-train: develop -> staging
release-train: staging -> main
Three sites still WROTE `Staging (human review)`, a column that no longer exists on the board, and two fallbacks quietly translated it to `FR on staging`. Behaviour today is correct because of those fallbacks -- and both are labelled "removed in step 3 of #1592". So step 3 as written is an outage: delete the fallbacks while three writers still emit the dead name and every staging promotion fails its option lookup and exits 1. The order is the whole fix. Writers emit the live name; only then is the fallback dead code, and it goes in the same change so nothing is left half-done. kanban-closure-router.yml:71 pull_request writer kanban-closure-router.yml:156 issue-closure writer advance-deploy-env.yml:71 push writer Found by @shujaatTracebloc reviewing .github#237, which fixed the same stale-string class on the GUARD path. This is the WRITE path. WHAT THIS DELIBERATELY DOES NOT DO: it does not start writing `Staging (agent review)`. Nothing writes that column anywhere, by design -- fr-gate ranks it 7 and says so ("READ-ONLY for now; nothing writes this value yet, #1578 does that in a LATER hop"). A card landing in `FR on staging` on a staging merge is the documented transition, not a skipped stage. Writing the agent column here would move cards into a column nothing advances, which is backend#1846's dead end, created on purpose. READERS are left alone. `case` arms that accept both names match values read FROM the board, which can never be the dead one -- that is tolerance, not a dependency, and it costs nothing. `fr-pass-comment.yml` needs no change either: it resolves the column by PROBING the board and fails loudly when neither name exists, which is the shape the other two should have had. Verified: both files parse as YAML, every embedded `run:` block parses under `bash -n`, house-rules clean, and no writer of the dead name remains. Refs tracebloc/backend#1592
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka added a commit
that referenced
this pull request
Aug 13, 2026
…it (#247) * feat(kanban): assert the board has every Status column the writers emit The board's column names and the workflows that write them are two systems that must agree, and nothing checked that they did. #1592 carried the `FR on staging` rename by hand across three PRs; in between, the writers emitted a column the board did not have and only a fallback made it work. That gap is exactly what .github#243 reported and what #245 closed by hand. This makes it un-driftable instead of remembered. The failure it prevents is a silent one. A written name that does not resolve means the card is not moved -- and until #246 that was a `::warning::` on a green run, so a frozen board and a working board looked identical. SCOPE IS DELIBERATELY NARROW: * WRITERS are asserted. A name that is written must exist or the write cannot land. `advance-deploy-env.yml` and `kanban-closure-router.yml`, listed rather than globbed -- `STATUS=` is a common shell variable and other workflows use it for "ok"/"absent"/"unreadable", which are not column names. * RESOLVERS are NOT asserted. They ask for names on both sides of a rename on purpose: `opt_either("Staging (human review)", "FR on staging")` is the #1592 shim and its first argument is SUPPOSED to be absent today. Enforcing there would make the tolerance impossible to express. * `STATUS_NAME="$OVERRIDE"` is skipped: a per-repo .kanban.yml value cannot be known here. Runs on PRs touching the writers, and DAILY -- the board can be renamed in the UI at any time with no PR to hang a check on, which is the failure this is really for. Fails closed throughout: an unreadable board, an unparseable response, zero options returned, or a literal pattern that matches nothing are all errors. The last one matters most -- a stale regex would make the check pass vacuously, which is the failure mode of every guard it is modelled on. Verified: passes on today's board (5 names); reproducing the pre-#245 state (writer emitting "Staging (human review)") fails and names the exact file and value; selftest 6/6 with the board stubbed, covering absent names, a stale name among good ones, and a case near-miss. * fix(kanban): gate the conformance check on the selftest job Bugbot (Medium): the check job ran in parallel with selftest and had no needs: selftest. If the checker failure paths regress while the board still matches, "Selftest the checker" goes red but "Written Status names exist on the board" can still report success -- a conformance-named green from a broken guard. caller-drift + standards-sync gate their audit on selftest for the same reason. Add needs: selftest so the conformance verdict is only trusted once the checker is proven able to fail. .github#247. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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 freeto 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.
Follow-up to #237, found by @shujaatTracebloc's review there. Refs tracebloc/backend#1592.
Step 3, as currently written, is an outage
Three sites still write
Staging (human review)— a column that no longer exists on the board — and two fallbacks quietly translate it toFR on staging. Today's behaviour is correct because of those fallbacks, and both are labelled "removed in step 3 of #1592".Delete them while the writers remain, and every staging promotion fails its option lookup and exits 1.
kanban-closure-router.yml:71kanban-closure-router.yml:156advance-deploy-env.yml:71The order is the fix. Writers emit the live name; only then is the fallback dead code — and it goes in the same change so nothing is left half-done.
What this deliberately does not do
It does not start writing
Staging (agent review).I checked, and nothing writes that column anywhere — by design.
fr-gate.ymlranks it 7 and says so: "READ-ONLY for now — nothing writes this value yet (#1578 does that, in a LATER hop)." So a card landing inFR on stagingon a staging merge is the documented transition, not a skipped stage.That's one correction to the review on #237: the mechanism described there is exactly right, but the impact — "every staging promotion appears to bypass agent review" — reads worse than it is. There is nothing to bypass yet. Writing the agent column here would instead move cards into a column nothing advances, which is backend#1846's dead end, created on purpose.
Two sites left alone, on purpose
Readers.
casearms accepting both names match values read from the board, which can never return the dead one. That is tolerance, not a dependency, and it costs nothing:fr-pass-comment.ymlneeds no change and is worth pointing at as the shape the other two should have had: it resolves the column by probing the board for whichever name exists, and fails loudly when neither does — so it never depended on a hardcoded name at all.Evidence
Both files parse as YAML · every embedded
run:block parses underbash -n·house-rulesclean · no writer of the dead name remains (grepconfirms only the three reader arms above).🤖 Generated with Claude Code
Note
Medium Risk
Touches deploy and closure automation that aborts if Status options do not resolve; wrong timing would break staging promotions, but the change matches the documented live column name.
Overview
Completes backend#1592 step 3 by aligning GitHub Actions writers with the live kanban Status column name and removing rename-window fallbacks that are no longer safe once the old option is gone.
advance-deploy-env.ymlsets staging push status toFR on staginginstead ofStaging (human review), and the GraphQL Status lookup no longer falls back to the old name when the new one is missing.kanban-closure-router.ymlusesFR on stagingwhen a PR merges tostagingor when a completed issue was closed by such a PR; the same fallback block before Status resolution is removed, so a missing option fails the run instead of silently retargeting.Read-side tolerance (e.g. rank/override
casearms that still accept both names) is unchanged on purpose.Reviewed by Cursor Bugbot for commit 631603f. Bugbot is set up for automated code reviews on this repo. Configure here.