docs(deck): document assignedUsers preservation on cross-board move

Round-6 review: the docstrings listed preserved fields but omitted
assignedUsers. Verified empirically (Deck 1.15.9) that the update route's
board-change handling only remaps labels and leaves user assignments
untouched, so assignees carry over. Documented in both the client and MCP
tool docstrings, with the caveat that an assignee lacking access to the
target board stays assigned but cannot act on the card. Added
test_move_card_to_board_preserves_assigned_users to lock it in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-11 00:12:35 +02:00
co-authored by Claude Opus 4.8
parent 98c9d58e54
commit d887181307
3 changed files with 47 additions and 6 deletions
+5 -2
View File
@@ -437,8 +437,11 @@ class DeckClient(BaseNextcloudClient):
the same-titled label on the destination board, or cloning it there
when the user has board-manage permission — instead of leaving orphaned
labels behind. This mirrors Deck's native "Move/copy card" action. Card
identity (id, comments, attachments), ``archived`` state and the due
date are preserved.
identity (id, comments, attachments), ``archived`` state, the due date
and ``assignedUsers`` are preserved — the move does not re-validate
assignees against the destination board, so an assigned user without
access to the target board stays assigned but may not be able to act on
the card.
The internal ``/apps/deck/cards/{cardId}`` route is used: it reads the
target ``stackId`` from the body (the board/stack-scoped API route
+6 -4
View File
@@ -1269,10 +1269,12 @@ def configure_deck_tools(mcp: FastMCP):
"""Move a Nextcloud Deck card to a stack on a different board.
The card keeps its identity (same id, comments, attachments), along
with its archived state and due date. Deck remaps the card's
board-scoped labels to the destination board by title — reusing a
same-titled label there, or cloning it when you have board-manage
permission. Use deck_reorder_card for moves within a single board.
with its archived state, due date and user assignments (an assignee
without access to the target board stays assigned but cannot act on the
card). Deck remaps the card's board-scoped labels to the destination
board by title — reusing a same-titled label there, or cloning it when
you have board-manage permission. Use deck_reorder_card for moves
within a single board.
Two caveats from Deck's move route: the card's owner is reassigned to
the user performing the move (the original owner is not preserved), and
@@ -252,6 +252,42 @@ async def test_move_card_to_board_preserves_done_and_archived(
assert after.archived is True, "archived state was lost during the move"
async def test_move_card_to_board_preserves_assigned_users(
nc_client: NextcloudClient, two_boards_with_stacks: tuple
):
"""Assigned users carry over a cross-board move (the route doesn't touch them).
Deck's update route remaps labels on a board change but leaves the card's
user assignments untouched, so an assignee that exists on both boards stays
assigned.
"""
source_board_id, source_stack_id, target_board_id, target_stack_id = (
two_boards_with_stacks
)
suffix = uuid.uuid4().hex[:8]
card = await nc_client.deck.create_card(
source_board_id, source_stack_id, f"Assigned {suffix}"
)
# The test user owns both temporary boards, so it is a valid assignee on each
await nc_client.deck.assign_user_to_card(
source_board_id, source_stack_id, card.id, nc_client.username
)
before = await nc_client.deck.get_card(source_board_id, source_stack_id, card.id)
assert before.assignedUsers, "Card should have an assignee before the move"
await nc_client.deck.move_card_to_board(
source_board_id=source_board_id,
source_stack_id=source_stack_id,
card_id=card.id,
target_board_id=target_board_id,
target_stack_id=target_stack_id,
)
after = await nc_client.deck.get_card(target_board_id, target_stack_id, card.id)
assert after.assignedUsers, "Assigned users were dropped during the move"
async def test_move_card_to_board_rejects_stack_not_on_target_board(
nc_client: NextcloudClient, two_boards_with_stacks: tuple
):