Uh oh!
There was an error while loading. Please reload this page.
feat(kanban): resolve "Staging (human review)", fall back to "FR on staging" (backend#1592 step 1) - #187
Merged
Conversation
…taging" (backend#1592 step 1) Step 1 of the three-step rename. Nothing changes behaviourally: this teaches all five reusables to prefer the NEW column name and accept the OLD one, so they work on both sides of the rename instant. Step 2 is the UI rename (Lukas), step 3 removes the fallback. WHY A FALLBACK RATHER THAN A SWAP. A rename cannot be done reads-before-writes. Adding a column can - teach everything to read the new name, then start writing it - but a rename makes the old name stop existing at a single instant, with no period where both are present. Every `select(.name=="FR on staging")` would resolve to null on the far side of that instant, and null resolution in these workflows means "abort" or, worse, "skip silently". So each resolver asks for the new name and falls back to the old, and each comparator accepts both. WHY THE UI, NOT THE API - and this is measured, not cautious. The ticket records that `updateProjectV2Field` replaces the whole option set and re-mints every ID: on 2026-08-05, adding ONE option preserved 0 of 11 option IDs and blanked 625 of 625 items, recoverable only because a name-keyed backup existed (#1576). The UI renames in place, preserving the option ID and every item's value. Step 2 is therefore deliberately a human action. Changed, by kind rather than by file: RESOLVERS (name -> option id), given a new->old fallback: advance-deploy-env.yml, kanban-closure-router.yml, kanban-reconcile.yml (via a new opt_either helper) COMPARATORS (status name read back from the board), now accepting both: advance-deploy-env.yml override map + rank(), fr-gate.yml rank(), kanban-reconcile.yml x3, kanban-closure-router.yml, fr-pass-comment.yml WRITE SITES, now naming the new column: kanban-closure-router.yml staging branch, advance-deploy-env.yml staging EXISTENCE PROBE: fr-pass-comment.yml resolves whichever staging-review column exists and keeps its loud failure for the case where NEITHER does - which is what that block was written for, and its comment already anticipated this rename. Both rank() functions score the two names identically, so the monotonic never-demote guard cannot see a rename as a backwards move. VERIFIED against live board data in both states, not just reasoned about: today (only the old name exists): opt_either -> d3caf1d4 after rename (name swapped): opt_either -> d3caf1d4 live id of "FR on staging": d3caf1d4 Same id either way, which is exactly what the in-place UI rename preserves. 18 literal references remain in comments and user-facing message strings. Those are correct as they stand today and become wrong only after step 2, so they are step 3's work rather than a partial edit now.
saadqbal
approved these changes
Aug 10, 2026
Uh oh!
There was an error while loading. Please reload this page.
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.
Step 1 of the three-step rename in backend#1592. Nothing changes behaviourally — this teaches all five reusables to prefer the new column name and accept the old one, so they work on both sides of the rename instant.
Why a fallback rather than a swap
A rename cannot be done reads-before-writes. Adding a column can — teach everything to read the new name, then start writing it. A rename makes the old name stop existing at a single instant with no period where both are present. Every
select(.name=="FR on staging")would resolve to null on the far side of that instant, and null resolution in these workflows means abort or, worse, skip silently.So each resolver asks for the new name and falls back to the old; each comparator accepts both.
Verified against live board data, in both states
Same option id either way — which is exactly what the in-place UI rename preserves, and why step 2 must be the UI.
What changed, by kind rather than by file
advance-deploy-env,kanban-closure-router,kanban-reconcile(newopt_eitherhelper)advance-deploy-envoverride map +rank(),fr-gaterank(),kanban-reconcile×3,kanban-closure-router,fr-pass-commentkanban-closure-routerstaging branch,advance-deploy-envstagingfr-pass-commentresolves whichever staging-review column exists, keeping its loud failure for the case where neither doesBoth
rank()functions score the two names identically, so the monotonic never-demote guard cannot read a rename as a backwards move.fr-pass-comment's probe already carried a comment anticipating exactly this: "this board has been renamed before … so the next rename fails loudly here instead of reporting 'wrong column' for every card." That intent is preserved.Deliberately not in this PR
18 literal references remain in comments and user-facing message strings. They are correct today and become wrong only after step 2, so changing them now would make the files describe a board that does not exist yet. They are step 3's work.
After this merges — and this order matters
main(callers pin@main, so nothing takes effect until it does).updateProjectV2Fieldreplaces the whole option set and re-mints every ID — measured 2026-08-05, adding one option preserved 0 of 11 option IDs and blanked 625 of 625 items, recovered only because a name-keyed backup existed (#1576).kanban-reconcilewithdry-run=trueand confirm green.Parent backend#1592 → #1552.
Note
Medium Risk
Changes sit on promotion gates, deploy advancement, and board writes, but they are additive aliases and fallbacks meant to keep behavior identical across the rename instant; a mistake could still break status resolution or monotonic guards until step 3 cleans up.
Overview
Step 1 of backend#1592 prepares five reusable kanban workflows for renaming the staging functional-review column from FR on staging to Staging (human review) without changing behavior until the board is renamed in the UI.
Resolvers resolve Status option IDs by trying the new name first, then falling back to the old (
advance-deploy-env,kanban-closure-router,kanban-reconcilevia newopt_either).Comparators treat both names as the same pipeline stage:
rank()inadvance-deploy-envandfr-gate, column lists and deploy-state guards inkanban-reconcileandkanban-closure-router, and/fr-passcolumn checks infr-pass-comment(including a probe for which staging-review option exists).Write paths for staging merges now emit Staging (human review);
.kanban.ymloverrides map both names to the staging deploy environment. Fallback logic is documented as temporary until step 3 removes it.Reviewed by Cursor Bugbot for commit 731481f. Bugbot is set up for automated code reviews on this repo. Configure here.