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:
@@ -744,7 +744,7 @@ public struct LegacyTombstone: Sendable, Equatable {
|
||||
///
|
||||
/// `title` is the card's as written, `nil` for an untitled one: "Untitled" is a rendering, never a
|
||||
/// value (03-board-ui.md § Card face), so the phrasing layer decides what to call it. The path is
|
||||
/// carried as its two identity components rather than as a URL, `BoardStore.liveItem`'s convention,
|
||||
/// carried as its two identity components rather than as a URL, `ItemPath`'s convention,
|
||||
/// so the write derives its path from the store's *current* root.
|
||||
public struct LooseCardFiles: Sendable, Equatable {
|
||||
public let laneID: ItemID
|
||||
|
||||
@@ -1391,12 +1391,18 @@ public enum BoardWriter: Sendable {
|
||||
try? FileManager.default.setAttributes([.posixPermissions: permissions], ofItemAtPath: url.path)
|
||||
}
|
||||
|
||||
// MARK: - Tombstone (retiring)
|
||||
// MARK: - Tombstone (retired, awaiting removal)
|
||||
//
|
||||
// The tombstone model is retired (01-storage-format.md § Deletion, resettled 2026-07-28): the
|
||||
// app's delete is the physical move above, and no `deleted:` key is ever written again. The
|
||||
// three calls below are kept only while their callers are still being moved across — the
|
||||
// migration removes the last keys any of them could act on, and they go with the last consumer.
|
||||
// app's delete is the physical move above, and no `deleted:` key is ever written again.
|
||||
//
|
||||
// **These have no app callers left.** Every consumer moved across with the store swap — the
|
||||
// delete is `deleteCardToTrash`, the lane delete is `removeLane`, the restore is an ordinary
|
||||
// `moveItem`, and the legacy keys are handled by the two `migrate…` calls above. They are kept
|
||||
// here for exactly one more beat because `purgeItem` below is still live (Delete Immediately's
|
||||
// board-side purge) and the three read as one family; the pair and
|
||||
// `stripTombstonedChildren` go together in the trash's cleanup pass, with the suites that
|
||||
// still pin their byte-level behaviour.
|
||||
|
||||
/// Tombstones a lane or card in place: writes `deleted: <now>` into its own `index.md` —
|
||||
/// the whole of a delete (01-storage-format.md § Deletion). The folder never moves, never
|
||||
|
||||
Reference in New Issue
Block a user