Repository navigation
fix(errors): refuse issue moves from a state the client no longer sees - #2322
Conversation
A transition request can now carry the workflow state the client last saw (expectedState on the internal API, expected_state on v2). When the issue has since moved, the request is a 409 and nothing is written, so a stale tab no longer silently overwrites another tab's move. ErrorIssueTransitionError is now self-describing, so the dashboard toasts the server's message instead of "An unexpected error occurred", and a 409 re-reads the issue so the losing tab shows the state that won.
The in_progress lease is now guarded on the state the move was validated from, a stale move to the state the issue already has stays a no-op, and a hub row with a write still out sends no expected state.
Maple review🟢 Confidence 10/10 · safe to merge. The guard is checked before the lease and Adds an optional
|
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 8 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
Follow-up to #2310. Local verification there (comment) found that a stale tab could overwrite another tab's move whenever its move was valid from the current state, and that the 409 toast read "An unexpected error occurred".
What changed
expectedStateon the internal API,expected_stateon v2. If the issue has moved since, the request gets a 409 and writes nothing, including thein_progresslease. Without it, behavior is unchanged. A stale move to the state the issue already has is still a no-op.in_progresslease is now guarded on the state the move was validated from, so a move that loses its race takes no lease.ErrorIssueTransitionErroris now anHttpTaggedError(409,error_issue_transition_conflict, public message). The client'sdisplayErrorfound no public body on the old plainSchema.TaggedError, so it fell back to the unexpected-error text. Wire fields are unchanged.apps/iosopenapi.json for the new v2 field. The anticipated-errors check passes with no change.The MCP
transition_error_issuetool is unchanged; agents read and then move, so it does not take an expected state yet.Tests
Typecheck is clean for domain, backend, api, web and ai.
oxlint -c .oxlintrc.effect.jsonis clean on the changed files.Conflict toast (issue page, rendered through the real kit toast in the web lab; the descriptions are
toLoadFailureoutput for the decoded 409 under each error class)I did not run the two-tab check against a live local stack. Port 5499 belongs to another worktree's running stack, so the 409 path is covered by the PGlite test and the client decode tests above.
🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.