Skip to content

ci: teach every rank table to READ the agent column (backend#1577) - #200

Merged
LukasWodka merged 2 commits into
developfrom
ci/1577-rank-tables-read-agent-column
Aug 10, 2026
Merged

ci: teach every rank table to READ the agent column (backend#1577)#200
LukasWodka merged 2 commits into
developfrom
ci/1577-rank-tables-read-agent-column

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Hop 1 of RFC-BACKEND-1552 D5 — reads before writes, in separate hops, because org-github's callers are pinned @main and both old and new callee code are live during a promotion of the reusables.

This was already a live landmine

Staging (agent review)exists on project 2 today (added by the #1592 rename) and no rank table knew it.rank() returned "", the [ -n "$SR" ] guard failed, evaluation fell through to strict equality, and the card would have blocked every prod promotion carrying it — the backend#1411 shape.

Measured: 633 board items scanned, zero currently in that column. Armed and waiting, not yet firing.

Changes

file
fr-gate.ymlrank 7; FR on staging→8, Ready for prod→9, Prod→10, terminals→11
advance-deploy-env.ymlsame table, plus the agent column maps to the staging deploy environment if a card is dragged there by hand
kanban-reconcile.ymlthe agent column joins its sibling post-merge columns, so an open issue drifting there returns to Backlog as it would from On dev

Why renumbering is safe

Every comparison is relativerank(a) >= rank(b), and TARGET_RANK is itself $(rank …). No hardcoded rank literals anywhere. I checked that before touching the numbers.

Caught while renumbering:Prod moved to 10 and collided with the terminals, also 10. Terminals must rank strictly aboveProd or the no-demotion guard weakens. Bumped to 11.

Read-only, deliberately

Nothing writes this Status yet. That is #1578, and it must not land before the agent can produce a verdict — otherwise cards park in a column nothing advances.

Test plan

agent column vs required "On dev" -> PASS
agent column vs required "Ready for prod" -> BLOCKED
an unknown column -> BLOCKED (still fails closed)

actionlint clean on all three; standards selftest 20/20.

🤖 Generated with Claude Code


Note

Medium Risk
Changes shared promotion-gate and monotonic deploy-advancement ordering used on every staging/main promotion; mistakes could block or mis-rank cards, though comparisons are relative-only and the change is intentionally read-only.

Overview
Hop 1 (read-only) for RFC-BACKEND-1552 D5: the board already has Staging (agent review), but workflows treated it as unknown—rank() returned empty and cards there would fail closed on prod promotions. This PR fixes that before anything writes that Status (#1578).

fr-gate.yml and advance-deploy-env.yml add the agent column at rank 7 (between On dev and human FR) and renumber later stages (Staging (human review)/FR on staging → 8, Ready for prod → 9, Prod → 10, Done/Cancelled → 11 so terminals stay strictly above Prod). advance-deploy-env.yml also maps a .kanban.yml override of that Status to the staging deploy environment.

kanban-reconcile.yml includes the agent column in the reconcile sweep and treats it like other post-merge deploy columns: closed-completed issues there are not forced to Done, and open issues drifted there move back to Backlog.

Reviewed by Cursor Bugbot for commit 2657523. Bugbot is set up for automated code reviews on this repo. Configure here.

Hop 1 of RFC-BACKEND-1552 D5: reads before writes, in separate hops, because
org-github's callers are pinned @main and both old and new callee code are live
during a promotion of the reusables.
THIS WAS ALREADY A LIVE LANDMINE. `Staging (agent review)` EXISTS on project 2
today (added by the #1592 rename) and NO rank table knew it. rank() returned "",
the `[ -n "$SR" ]` guard failed, evaluation fell through to strict equality, and
the card would have BLOCKED every prod promotion carrying it -- the backend#1411
shape. Measured: 633 board items scanned, zero currently in that column, so it
was armed and waiting rather than firing.
fr-gate.yml rank 7, FR->8, Ready for prod->9, Prod->10, terminals->11
advance-deploy-env.yml same, plus the agent column maps to the `staging`
deploy environment if a card is dragged there by hand
kanban-reconcile.yml the agent column joins its sibling post-merge columns,
so an OPEN issue drifting there goes back to Backlog
like it would from `On dev`
Renumbering is safe: every comparison is relative (`rank(a) >= rank(b)`, and
TARGET_RANK is itself `$(rank ...)`), with no hardcoded rank literals anywhere.
Checked before touching the numbers.
Caught while renumbering: Prod moved to 10 and collided with the terminals, also
10. Terminals must rank STRICTLY above Prod or the no-demotion guard weakens.
Bumped to 11.
READ ONLY -- nothing writes this Status yet. That is #1578, deliberately a
later hop, and it must not land before the agent can produce a verdict or cards
park in a column nothing advances.
Verified:
agent column vs required "On dev" -> PASS
agent column vs required "Ready for prod" -> BLOCKED
an unknown column -> BLOCKED (still fails closed)
actionlint clean on all three; standards selftest 20/20.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodkaLukasWodka self-assigned this Aug 10, 2026

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d7f44ba. Configure here.

Comment thread.github/workflows/kanban-reconcile.yml
Bugbot (#200): the classify case I added for `Staging (agent review)` was DEAD
CODE. The non-terminal pull filter that populates items.ndjson never listed the
column, so cards there were filtered out before classification ran.
That is the exact shape this whole session has been auditing -- a guard exists,
nothing reaches it -- and I shipped one while writing the audit.
Found by reading rather than reported: a SECOND omission at the closed-completed
case. A closed issue in the agent column fell through to `*)` and was marked
Done, overwriting a deploy state -- precisely what its sibling list exists to
prevent (D8: a deploy state is not Done, follow the PR's stage).
Swept every column list in the file. The one remaining absence is DELIBERATE:
the `CLOSER_BASE` mapping at ~L426 is a WRITER (branch -> destination column),
and hop 1 is read-only. That belongs to #1578.
actionlint clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodka
LukasWodka merged commit 36b9d29 into developAug 10, 2026
9 checks passed
LukasWodka added a commit that referenced this pull request Aug 10, 2026
Same artifact as .github#204, removed on this branch as well. This branch was cut
after #200, so it carries the file; without this, merging #197 after #204 would
put it straight back and the fix would look like it had held.
The .gitignore is identical to #204's, so whichever merges first the other
resolves cleanly.
Selftest: 27 checks, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LukasWodka added a commit that referenced this pull request Aug 10, 2026
`scripts/__pycache__/standards-sync.cpython-314.pyc` was committed by a
`git add -A` in #200 and reached `develop`. It is now riding the
develop -> staging promotion in .github#203, which is how I noticed it.
It is a build artifact and does not belong in the tree: version- and
platform-specific (cpython-314, while CI runs 3.12), regenerated on every local
run of the selftest, and a stale one silently shadows the source it was built
from.
Added a .gitignore covering the whole class rather than the one file that got
caught -- `__pycache__/`, `*.py[cod]`, plus .DS_Store and .pytest_cache, which
the same careless `add -A` would sweep in next.
The file is also present on the #197 branch, which branched after #200; removed
there too, so whichever lands first the artifact is gone and the other cannot
reintroduce it.
Selftest still passes (20 checks on this branch; #197 takes it to 27).
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
saadqbal pushed a commit that referenced this pull request Aug 11, 2026
…tes (backend#1602) (#197)
* fix(standards): retry fresh-branch reads; refresh sha on rejected writes (backend#1602)
Design rule 5: fresh refs are eventually consistent. On run 31373298821
(frontend-app leg) the contents read on a just-created branch transiently
404'd, the 404 was believed, and the sha-less PUT was rejected as
'Invalid request' — one flaky read failed a fleet run. remediate() now
knows whether the base has the file: reads the base proves must succeed
retry with backoff and fail closed if they never do; genuine absence is
confirmed by a re-read; a 409/422-rejected write refreshes the sha and
retries exactly once. Five new offline selftest checks pin the contract
with a scripted gh stub (25 checks total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(standards): a reused sync branch may honestly 404, and say so on a real conflict
Two Bugbot findings on #197.
1. `expect_file` MEANS "a 404 here cannot be true" -- which holds only when the
ref was cut moments ago from a base that has the file. That is the eventual
consistency window the retry exists for.
A REUSED branch (the 422 path) is a different situation: it may have been cut
BEFORE CLAUDE.md existed on the base, so a 404 is honest and permanent.
Passing file_on_base alone made the read retry five times and fail closed, so
the sha-less create could never run and that repo was stuck forever. The old
code read the 404 as absence and created the file, which was right here.
expect_file is now `file_on_base and branch_is_fresh`.
2. The second-rejection message was UNREACHABLE. On attempt 2 the flow fell
through to the generic return inside the loop, so the one failure worth
distinguishing -- refreshed the sha and was rejected anyway, i.e. another
writer is racing the branch -- was the one nobody could see. It now returns
its own message, and the post-loop return is documented as a fail-closed
backstop rather than dead code that would return None (i.e. SUCCESS).
Selftest 25 -> 27. Mutation-verified both: reverting expect_file, and making the
second-rejection branch unreachable again -- both CAUGHT.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(standards): the reused-branch check asserted an end state and proved nothing
Mutation-checking the previous commit caught its own test. Reverting the
expect_file fix left the selftest GREEN, because the check asserted only "the
file got created".
With the bug present the read retries, swallows the scripted PUT response, reads
its `{}` body as the file, and the run reaches the same end state by a different
path. Same outcome, wrong reason -- so the check could not distinguish fixed from
broken, in either direction.
Assert the READ COUNT instead: 2 when a 404 on a reused branch is believed as
absence, 5 when it is wrongly treated as the eventual consistency window. That is
the thing the fix actually changes. Also catches the stub's exhaustion assertion
and records it as a failure rather than letting it abort the whole selftest.
Re-verified: reverting expect_file is now CAUGHT (reads=3, expected 2).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore: drop the committed .pyc here too (backend#1602)
Same artifact as .github#204, removed on this branch as well. This branch was cut
after #200, so it carries the file; without this, merging #197 after #204 would
put it straight back and the fix would look like it had held.
The .gitignore is identical to #204's, so whichever merges first the other
resolves cleanly.
Selftest: 27 checks, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@LukasWodka
LukasWodka deleted the ci/1577-rank-tables-read-agent-column branch August 14, 2026 13:53
Sign up for freeto 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

@LukasWodka@shujaatTracebloc