Let a card bounced twice keep its label, instead of crashing the queue #154

Merged
nectenda-agent merged 1 commit from worktree-idempotent-labels into main 2026-09-24 17:29:41 +01:00
Collaborator

Bouncing a card that already carried merge-conflict (NEC-52, bounced for the second time) got a 400 "label already exists", crashing the queue mid-bounce, before it saved state.

  • Vikunja.addLabel / removeLabel are idempotent for exactly those two responses; every other error still throws. Tested both ways, and mutation-checked.
  • bounce logs its reason before its side effects.

Changelog

NONE

Bouncing a card that already carried `merge-conflict` (NEC-52, bounced for the second time) got a 400 "label already exists", crashing the queue mid-bounce, before it saved state. - `Vikunja.addLabel` / `removeLabel` are idempotent for exactly those two responses; every other error still throws. Tested both ways, and mutation-checked. - `bounce` logs its reason before its side effects. ## Changelog NONE
Let a card bounced twice keep its label, instead of crashing the queue
Some checks failed
Release note / release-note (pull_request) Successful in 16s
CI / promote (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
04b6d388e9
The merge queue bounces a card by labelling it merge-conflict and moving
it to Ready. A card bounced once, reworked and handed back still carries
the label, since it only comes off on a merge. Bouncing it again asked
Vikunja to add a label the task already had, got a 400, and threw, in
the middle of the bounce and before the queue saved its state. The next
tick would have done the same: NEC-52, 24 Sep 2026, at the moment the
queue resumed after the NEC-15 revert.

- The Vikunja client's addLabel treats "already exists on the task" as
  success, and removeLabel treats a label that is not there as success.
  Every other error still throws; both directions are tested, and
  swallowing everything fails the test too.
- bounce logs its reason before its side effects, so a failure can no
  longer hide why a card was being bounced. That reason had to be read
  off the card this time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015k9tkUtbU3wBpCHAHq7Qas
cruelacid force-pushed worktree-idempotent-labels from 04b6d388e9
Some checks failed
Release note / release-note (pull_request) Successful in 16s
CI / promote (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
to d52e839ea9
All checks were successful
Release note / release-note (pull_request) Successful in 16s
CI / build (pull_request) Successful in 5m0s
CI / e2e (pull_request) Successful in 5m5s
CI / promote (pull_request) Has been skipped
CI / build (push) Successful in 4m43s
CI / e2e (push) Successful in 4m49s
CI / promote (push) Successful in 29s
2026-09-24 16:52:07 +01:00
Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda!154
No description provided.