fix(deck): preserve done/archived and validate target board on move

Addresses the round-1 review on PR #885:

- Preserve `done` across a cross-board move. The internal card-update route
  (the only one that works cross-board — the board/stack-scoped route 404s for
  a card not already on that board) does not accept a done value, so a "done"
  card is re-marked done after the move. Deck stamps the current time there, so
  the original timestamp isn't preserved — documented as a route limitation.
  (`archived` is already preserved: CardService only mutates it when sent.)
- Validate that target_stack_id is on target_board_id before moving, so the
  parameter is load-bearing and a mismatch fails loudly instead of misreporting.
- Skip the same-board guard's get_stacks round-trip on a same-stack reorder.
- Add unit coverage (done-restore call, destination validation, same-stack
  skip) and integration coverage (done preservation, target-board mismatch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-10 23:41:07 +02:00
co-authored by Claude Opus 4.8
parent 437eaa0872
commit 798a00d89d
4 changed files with 243 additions and 67 deletions
+10 -5
View File
@@ -1274,20 +1274,25 @@ def configure_deck_tools(mcp: FastMCP):
board-manage permission. Use deck_reorder_card for moves within a
single board.
The destination is determined by target_stack_id; target_board_id must
be the board that owns it (it is used to report the resulting location).
target_stack_id must be a stack on target_board_id; the move is
rejected otherwise.
Args:
source_board_id: The ID of the board the card currently lives on
source_stack_id: The ID of the stack the card currently lives in
card_id: The ID of the card to move
target_board_id: The ID of the destination board (must own target_stack_id)
target_stack_id: The ID of the destination stack
target_board_id: The ID of the destination board
target_stack_id: The ID of the destination stack (must be on target_board_id)
order: Position within the destination stack (default 0 = top)
"""
client = await get_client(ctx)
await client.deck.move_card_to_board(
source_board_id, source_stack_id, card_id, target_stack_id, order
source_board_id,
source_stack_id,
card_id,
target_board_id,
target_stack_id,
order,
)
return CardOperationResponse(
success=True,