Implement Finder file drops

Files from Finder land on the board per 04-interactions.md § Drag & drop:

- Dropped on a card, they copy into its attachments/ (any type, multi-file),
  the face highlighting while hovered; the hovered card is resolved by
  hit-testing the same analytic masonry frames the card zones are built
  from, so attach-beats-create adds no drop region and cannot drift from
  the dispatch.
- Dropped on lane empty space, one card per file — filename minus extension
  as the title (a blank stem omits the key), fresh GUID, rank at the drop
  position through the ordinary insertion machinery, the file attached —
  all in one bracket; a failed import removes the just-minted card, so
  creating-then-abandoning never leaves an empty card behind.
- Every board drop surface now declares .fileURL beside the two board
  types (the single-target-dispatch rule); tombstoned surfaces are inert;
  file sessions ride a distinct session mode with their own watchdog and
  no hysteresis, leaving the board-drag machinery untouched.
- Also: four empty fixture directories pinned with .keep files so git
  preserves them, and a test-only visibility fix in DragSessionTests.

811 unit tests (12 new).

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-27 21:20:46 -04:00
parent 90cf82d740
commit 8f116934b4
13 changed files with 992 additions and 59 deletions
+3 -1
View File
@@ -21,7 +21,9 @@ import SwiftUI
/// snapshot's live lanes;
/// - it is **never a drop target** "no move or paste ever targets the trash" (04-interactions.md
/// The trash), so nothing here declares an `onDrop` at all and a session over the column falls
/// through to the strip's own target, where a cursor over no lane simply holds the proposal;
/// through to the strip's own target, where a cursor over no lane simply holds the proposal. That
/// covers **Finder file drops** too, which "on tombstoned cards are inert" ( The trash): a file
/// session over this column resolves to no lane, so no row highlights and a release refuses;
/// - it has **no new-card button**: nothing is created in the trash.
///
/// ### No editing in the trash