Skip to content

fix(kanban): "no ClosedEvent" is not a hand-close (backend#1411) - #134

Merged
LukasWodka merged 1 commit into
developfrom
fix/1411-no-closed-event
Aug 3, 2026
Merged

fix(kanban): "no ClosedEvent" is not a hand-close (backend#1411)#134
LukasWodka merged 1 commit into
developfrom
fix/1411-no-closed-event

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Bugbot found this on #127 (High), after the promotion's head advanced to f7a50e8. It is real, and it is the same mistake as its earlier finding on #126 — one level further in, on the success path this time.

Five answers, one token

The closer lookup's --jq collapsed five distinct situations into NONE, and NONE now means Done, which kanban-archive hides the next day. Verified by running the old filter against each response shape:

responseold filter
ClosedEvent present, closer: nullgenuinely hand-closedNONE|
no ClosedEvent at all (nodes: [])NONE|
nodes: nullNONE|
issue: nullNONE|
repository: nullNONE|

Only the first is evidence of a hand-close. The rest are absence of evidence, and any one of them happening once — a close-event race, a null read — terminalizes shipped work and then archives it.

Command failure was already separated out as ERROR by #128. This is the identical hazard inside the responses that succeed.

The filter answers three ways now

if $e == null then "NOEVENT|" else <typename>|<baseRef> end

Neither decision needed changing. Both shells already fail closed on an unrecognised token, so NOEVENT lands where it belongs on its own:

kanban-closure-routernot in the PullRequest|Commit|NONE allowlist → UNREADABLE → Status unchanged
kanban-reconcileno NONE / PullRequest / Commit arm matches → SKIP, no Done asserted

That is the allowlist doing the job it was written for. The only behaviour change is that a no-evidence read stops masquerading as a hand-close.

Two log lines that would now lie

reconcile called NOEVENT a failed lookup when the read succeeded and simply found nothing; the router's warning said "could not read the closer" for a case where it read fine. NOEVENT gets its own message, and the router's now says "could not confirm".

Verified by running it, not by reading it

Extracted both decision blocks verbatim from the workflows and pushed every token through them under bash -e:

jq filter9 response shapes, including last-event-wins → correct token each
routerPR→develop/staging/mainOn dev/FR on staging/Prod; CommitOn dev; NONEDone; NOEVENT/ERROR/empty → unchanged + warning
reconcileNONEDone; PR/Commit → stage derived; NOEVENT/ERRORSKIP
actionlintclean on both files

Touches only the two kanban workflows, so it does not overlap #132 (repo-inventory.yml).

🤖 Generated with Claude Code


Note

Medium Risk
Changes only CI workflow shell/jq logic for kanban status routing, but wrong classification still affects which issues get Done/archived versus left unchanged.

Overview
Fixes a fail-wrong path in kanban issue-close routing: the GraphQL closer --jq filter used to emit NONE for both a real hand-close (ClosedEvent with closer: null) and several “no evidence” shapes (empty timeline, null nodes, missing issue/repo). With NONE now mapping to Done (and Done archiving), those ambiguous reads could wrongly terminalize and hide shipped work.

Both kanban-closure-router and kanban-reconcile now return NOEVENT| when there is no ClosedEvent on the timeline; only a present event with a null closer stays NONE. NOEVENT is treated as unreadable in the router (status unchanged + warning) and explicitly skipped in reconcile (no Done move). Router warning text is tightened from “could not read” to “could not confirm” the closer.

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

Bugbot on .github#127, High. The closer lookup's --jq collapsed FIVE distinct
answers into the single token NONE, and NONE now means Done, which
kanban-archive hides the next day:
ClosedEvent present, closer null -> NONE genuinely hand-closed
no ClosedEvent at all -> NONE the timeline said nothing
timelineItems.nodes null -> NONE ditto
issue null -> NONE nothing was read
repository null -> NONE nothing was read
Only the first is evidence of a hand-close. The rest are absence of evidence,
and just one of them needs to happen once -- a close-event race, a null read --
for shipped work to be terminalized and archived. Command failure was already
separated out as ERROR (Bugbot's earlier finding on .github#126); this is the
same mistake one level in, in the success path.
The filter now answers three ways instead of two, so "the timeline had no
ClosedEvent" is its own token:
jq: if $e == null then "NOEVENT|" else <typename>|<baseRef> end
Both shells already fail closed on an unrecognised token, so NOEVENT lands in
exactly the right place without touching either decision:
router: not in the PullRequest|Commit|NONE allowlist -> UNREADABLE -> no change
reconcile: no NONE / PullRequest / Commit arm matches -> SKIP, no Done asserted
That is the allowlist doing its job, so the only behaviour change is that a
no-evidence read no longer masquerades as a hand-close.
Also fixes two log lines that would now lie: reconcile called NOEVENT a failed
lookup when the read succeeded and simply found nothing, and the router's
warning said "could not read" for a case where it read fine. NOEVENT gets its
own message; the router's says "could not confirm".
Verified by extracting both decision blocks and running every token through
them under bash -e:
jq filter 9 response shapes, incl. last-event-wins -> correct token each
router PR/develop|staging|main -> On dev|FR on staging|Prod
Commit -> On dev, NONE -> Done
NOEVENT, ERROR, empty -> Status unchanged + warning
reconcile NONE -> Done, PR/Commit -> stage derived
NOEVENT, ERROR -> SKIP, no Done
actionlint clean on both files
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodkaLukasWodka self-assigned this Aug 3, 2026
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 35ef161. Configure here.

@LukasWodka
LukasWodka merged commit 5eaad72 into developAug 3, 2026
4 checks passed
@LukasWodka
LukasWodka deleted the fix/1411-no-closed-event 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@saadqbal