Materialize the trash — store, undo, and the container universe

Phase 2 swaps every consumer: Liveness and its ancestor walk are gone,
replaced by ItemContainer — a UUID set plus the container side it
lives on, presence the whole test, one selection boundary instead of
the old liveness law. Deletion stages by place: board cards move to
the trash at a store-minted head rank, trash-side delete is permanent
behind its confirmation, Delete Immediately skips the trash from
anywhere, lane delete captures the subtree and removes the folder.
Restore has no method at all — moveCards resolves members in either
container, so drag-out and cut-paste are the ordinary moves 13 calls
them, registering ordinary Move steps. The delete inverse moves the
card back to its captured lane and rank; redo replays the captured
trash rank, a value the gesture actually wrote; lane undo recreates
the subtree byte-faithfully in session. Purges register nothing —
where 13's trash section contradicts its own Rules on that, Rules
wins, filed for ruling. Staleness collapsed to present-or-absent: a
container is a path, so a foreign restore fails the delete step's
expectation structurally. Legacy tombstones migrate on the loose-file
tail hook, cards oldest-first so minting above top reproduces the
retired newest-first column, lanes returning live, one folded loss
row naming both directions. Put Back, restoreByDrag,
receiveRestoredCards, TrashEntry, and the kind machinery are deleted;
the trash column renders the container correctly with its full face
rework left to phase 3.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-28 17:47:56 -04:00
parent 16c10d61c3
commit 53bc71f7fb
53 changed files with 3459 additions and 3655 deletions
+9 -9
View File
@@ -665,9 +665,9 @@ struct LooseFilePasteTests {
defer { destination.tearDown() }
let target = try BoardStore(rootURL: destination.root)
harness.store.select([ItemID(rawValue: Ident.card1)], liveness: .live)
harness.store.select([ItemID(rawValue: Ident.card1)], in: .board)
harness.clipboard.copy(from: harness.store)
target.select([ItemID(rawValue: Ident.lane4)], liveness: .live)
target.select([ItemID(rawValue: Ident.lane4)], in: .board)
await harness.clipboard.paste(into: target)?.value
let arrived = try arrivedCard(in: destination)
@@ -693,9 +693,9 @@ struct LooseFilePasteTests {
defer { destination.tearDown() }
let target = try BoardStore(rootURL: destination.root)
harness.store.select([ItemID(rawValue: Ident.card1)], liveness: .live)
harness.store.select([ItemID(rawValue: Ident.card1)], in: .board)
harness.clipboard.copy(from: harness.store)
target.select([ItemID(rawValue: Ident.lane4)], liveness: .live)
target.select([ItemID(rawValue: Ident.lane4)], in: .board)
await harness.clipboard.paste(into: target)?.value
let arrived = try arrivedCard(in: destination)
@@ -718,9 +718,9 @@ struct LooseFilePasteTests {
defer { destination.tearDown() }
let target = try BoardStore(rootURL: destination.root)
harness.store.select([ItemID(rawValue: Ident.card1)], liveness: .live)
harness.store.select([ItemID(rawValue: Ident.card1)], in: .board)
harness.clipboard.copy(from: harness.store)
target.select([ItemID(rawValue: Ident.lane4)], liveness: .live)
target.select([ItemID(rawValue: Ident.lane4)], in: .board)
await harness.clipboard.paste(into: target)?.value
#expect(harness.fixture.exists("\(cardPath)/notes.txt"))
@@ -735,7 +735,7 @@ struct LooseFilePasteTests {
defer { destination.tearDown() }
let target = try BoardStore(rootURL: destination.root)
harness.store.select([ItemID(rawValue: Ident.lane1)], liveness: .live)
harness.store.select([ItemID(rawValue: Ident.lane1)], in: .board)
harness.clipboard.copy(from: harness.store)
await harness.clipboard.paste(into: target)?.value
@@ -760,7 +760,7 @@ struct LooseFilePasteTests {
defer { destination.tearDown() }
let target = try BoardStore(rootURL: destination.root)
harness.store.select([ItemID(rawValue: Ident.card1)], liveness: .live)
harness.store.select([ItemID(rawValue: Ident.card1)], in: .board)
harness.clipboard.copy(from: harness.store)
await harness.clipboard.stagingSettled()
// The snapshot goes missing between the copy and the paste 04's degraded paste.
@@ -768,7 +768,7 @@ struct LooseFilePasteTests {
try FileManager.default.removeItem(at: harness.staging.appendingPathComponent(staged))
}
target.select([ItemID(rawValue: Ident.lane4)], liveness: .live)
target.select([ItemID(rawValue: Ident.lane4)], in: .board)
await harness.clipboard.paste(into: target)?.value
let arrived = try arrivedCard(in: destination)