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:
@@ -110,7 +110,7 @@ extension BoardStore {
|
||||
// gone is not one to pop: the stack is about to be cleared with the session anyway.
|
||||
guard let store else { return .failed }
|
||||
|
||||
guard HistoryStaleness.isCurrent(expectations, under: store.rootURL) else {
|
||||
guard HistoryStaleness.isCurrent(expectations) else {
|
||||
store.banners.postSkippedStep(direction, subject: subject)
|
||||
return .skipped
|
||||
}
|
||||
@@ -157,11 +157,11 @@ extension BoardStore {
|
||||
|
||||
/// Registers a create's step: undo removes the folders, redo puts them back byte-for-byte.
|
||||
///
|
||||
/// **Removal, not a tombstone**, exactly as 13 words it: an undone create leaves *no trace*,
|
||||
/// because the item was born of the gesture being undone — a tombstone would leave a trash row
|
||||
/// for a card the user never really made. `purgeIsUnrecoverable` is untouched by this: that flag
|
||||
/// is about Delete Immediately, whose loss is the user's own final gesture, while this loss is
|
||||
/// one ⇧⌘Z away.
|
||||
/// **Removal, not a move into the trash**, exactly as 13 words it: an undone create leaves *no
|
||||
/// trace*, because the item was born of the gesture being undone — filing it in the trash would
|
||||
/// leave a card the user never really made for them to find. `purgeIsUnrecoverable` is untouched
|
||||
/// by this: that flag is about Delete Immediately, whose loss is the user's own final gesture,
|
||||
/// while this loss is one ⇧⌘Z away.
|
||||
///
|
||||
/// The honest edge, recorded rather than papered over: anything that happened *inside* the
|
||||
/// created folder through an operation that registers no step of its own — an attachment added by
|
||||
@@ -169,19 +169,19 @@ extension BoardStore {
|
||||
/// 13's own two rulings (remove the folder; attachment operations register nothing in v1) rather
|
||||
/// than from anything decided here.
|
||||
///
|
||||
/// **Its staleness predicate is existence and liveness, and deliberately nothing else** (13:
|
||||
/// "existence/liveness for create/delete/restore steps"). A create's after-value *is* the item's
|
||||
/// being there, so the undo validates that the folders are still there and still live and the
|
||||
/// redo that they are still gone. The same honest edge follows: a foreign *edit* inside a created
|
||||
/// card does not stop ⌘Z from removing it, because the create never wrote that field — while a
|
||||
/// foreign *delete* does, since the trash row the user is looking at is not this step's to purge.
|
||||
/// **Its staleness predicate is existence, and deliberately nothing else** (13: "existence …
|
||||
/// for create/delete/restore steps"). A create's after-value *is* the item's being there, so the
|
||||
/// undo validates that the folders are still at their paths and the redo that they are still
|
||||
/// gone. The same honest edge follows: a foreign *edit* inside a created card does not stop ⌘Z
|
||||
/// from removing it, because the create never wrote that field — while a foreign *delete* does,
|
||||
/// since the card the user is looking at in the trash is at a different path now.
|
||||
func registerCreation(_ items: [CreatedItem], kind: HistoryPhrase.Kind, subject: String? = nil) {
|
||||
guard !items.isEmpty else { return }
|
||||
let operation: WriteOperation = kind == .lane ? .createLane : .createCard
|
||||
registerStep(
|
||||
HistoryPhrase.name(.add, kind: kind, count: items.count),
|
||||
subject: subject,
|
||||
undoExpects: items.map { .live($0.folder) },
|
||||
undoExpects: items.map { .present($0.folder) },
|
||||
redoExpects: items.map { .absent($0.folder) }
|
||||
) { _ in
|
||||
// Reversed, so a lane and a card created by one gesture unwind child-first — the same
|
||||
@@ -282,14 +282,4 @@ extension BoardStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Puts an item's tombstone back — **with the timestamp it carried**, not with `now`.
|
||||
///
|
||||
/// The inverse of Put Back is the item returning to the trash exactly where it was, and the trash
|
||||
/// sorts by `deleted` (03-board-ui.md § Trash ▸ Contents): re-stamping would file the row under
|
||||
/// today and quietly reorder a list the user was reading. A prior that was malformed (or, by
|
||||
/// construction impossibly, missing) falls back to `now` — the item has to be tombstoned, and an
|
||||
/// unreadable timestamp is not a value to preserve.
|
||||
static func restoreTombstone(_ prior: FieldValue<Date>, in document: inout FrontmatterDocument) {
|
||||
document.set(FrontmatterKeys.deleted, to: .date(prior.value ?? Date()))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user