Redraw a copy's originals at the source — the resting layout follows the operation

The modifier flip (⌥ copy / ⌘ move) now reflows the source board once:
a copy re-admits the dragged originals into the resting layout, standing
dimmed in place, and a move lifts them out as before. This retires
DRAG-REORDER.md's operation-blind carve-out and makes 04-interactions.md's
"originals stay" true in flight, not just at echo. The one seam is
DragSession.hiddenMembers reading the observed operation.

Consequences carried honestly: copyCards now takes its index in the
lane's full rendered space (the zones counted the originals, so the
geometry's number is the writer's number — the old neighbour remap is
deleted); resolveOperation freezes under the committed hold exactly as
propose does, fixing a real bug where a settled within-board ⌥-copy drew
the move arrangement until the echo and visibly re-shuffled. Stationary
flips still wait for the next dropUpdated (their own Backlog card).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-08-01 08:07:54 -04:00
parent adf4fc5973
commit 8206a78ecc
9 changed files with 383 additions and 51 deletions
+8 -4
View File
@@ -212,10 +212,14 @@ struct CardFaceView: View {
// genuinely fires on the trash side too: "X works cut in the trash, paste into a lane is
// the keyboard-native restore" (04 The trash, resettled 2026-07-28).
.cutTreatment(of: card.id, in: store)
// The face being dragged out dims the same way while the session is in flight on the trash
// side, where the source stays visible: a restore is not a removal until the write lands.
// (On the board a dragged card is lifted out of the resting layout entirely, so this never
// has anything to act on there `LaneView.renderedCards`.)
// The face being dragged out dims the same way while the session is in flight, wherever the
// source stays visible which is now two places rather than one. On the **trash** side a
// restore is not a removal until the write lands, so the row never leaves. On the **board**
// side a drag whose effective operation is `.copy` leaves its originals in the resting
// layout, because the copy leaves them there (`DragSession.hiddenMembers`), and this is what
// marks them as the source of the drag rather than as ordinary neighbours. A `.move`'s
// originals are lifted out entirely and this has nothing to act on
// (`LaneView.renderedCards`).
.opacity(drops.session.isDragging(card.id) ? ClipboardTreatment.dimmedOpacity : 1)
.contentShape(Rectangle())
// **A card is one flattened accessibility element** (10-accessibility.md The board through