Realign code with the 2026-07-31 rulings
The trash sorts by modified descending — the arrival rank mint retires (Ranks.isOrderedForTrash one comparator, loader + merged order agree; the legacy deleted: migration stamps modified from the tombstone timestamp where parseable; delete undo steps validate existence-only; agent guide v8). Trash selection goes kind-blind — ranges, marquee, Select All, and the successor walk sweep both kinds; the guard moves to the exits (mixed-payload drop refusal, copy/cut validation). The copy stamping preflight widens back to comment depth (load-scoped posture — the board always loads, the gesture refuses whole). Fixes a latent no-op: trashed-lane drag restore never fired (DragSession.beginLanes hard-coded the board container). 2403 tests in 413 suites green. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -183,6 +183,11 @@ struct TrashLaneRowView: View {
|
||||
/// **Multi-drag carries the whole trash-side lane selection**, in the column's own order, and a
|
||||
/// row outside the selection drags alone — the card face's targeting rule at the other level.
|
||||
///
|
||||
/// **A kind-blind selection can span both kinds, and the session says so** (04-interactions.md ▸
|
||||
/// The trash, ruled 2026-07-31): a `.lanes` session cannot carry the cards in it, so rather than
|
||||
/// drop them silently the flag travels and the release refuses with the notice
|
||||
/// (`DragSession.mixesKinds`) — "pickup is allowed — the selection is legal".
|
||||
///
|
||||
/// Refused under the read-only lock and while an inline editor is focused, like every other
|
||||
/// mutating gesture; a refusal is an item provider carrying nothing, so no session begins.
|
||||
private func startDrag() -> NSItemProvider {
|
||||
@@ -190,6 +195,8 @@ struct TrashLaneRowView: View {
|
||||
let ids = draggedIDs
|
||||
let rows = store.snapshot.trashedLanes.filter { ids.contains($0.id) }
|
||||
guard !rows.isEmpty else { return NSItemProvider() }
|
||||
let mixesKinds = SelectionGrammar.mixesKinds(
|
||||
ItemReferenceSet(ids: ids, container: .trash), in: store.snapshot)
|
||||
|
||||
let root = store.rootURL
|
||||
let payload = DragPayload(
|
||||
@@ -212,7 +219,12 @@ struct TrashLaneRowView: View {
|
||||
// standard width; the restored lane then draws at whatever `width` its untouched
|
||||
// frontmatter still says, on the next reload.
|
||||
units: rows.map { _ in 1 },
|
||||
source: store
|
||||
// **The session's container is this row's**, matching the payload's — which is what
|
||||
// routes the release to `BoardStore.restoreLanes` (the move *out* of `.trash/`) rather
|
||||
// than to `moveLanes`' strip permutation, and what the mixed-payload exit keys on.
|
||||
container: .trash,
|
||||
source: store,
|
||||
mixesKinds: mixesKinds
|
||||
)
|
||||
return payload.itemProvider()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user