Realign code with the 2026-07-30 findings-resolution rulings

Delete Immediately is removed entirely (ruling ae1dd96, Redesign card
d40bfac1): the delete vocabulary is purely staged — board → trash,
trash → permanent (confirmed on no-git boards), Empty Trash for bulk.
Gone: File ▸ Delete Immediately (⌥⌘⌫) and its validation, both
⌥-alternate context rows (card + the permanently-disabled lane row),
the VO custom action, BoardStore.deleteImmediately,
TrashModel.canDeleteImmediately, TrashConfirmations' .purge action
(zero surviving callers — trash-side Delete always used
.deleteTrashCards), and the pinning tests. purgePrompt drops its
now-single-purpose container parameter (.trash is the only surviving
caller). BoardWriter.purgeItem survives — create-undo rollback still
needs it — with its comment rewritten. README's trash paragraph drops
the ⌥⌘⌫ sentence.

The other 2026-07-30 rulings (2ec2c95 registry freshness stamp,
c741b02 unified-log-as-coerce-consumer) required no code changes —
already conformant.

Both schemes 1844 tests / 318 suites green.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-30 15:13:31 -04:00
parent 9ca8ed84de
commit 785ef5fe14
15 changed files with 83 additions and 483 deletions
+1 -44
View File
@@ -3392,7 +3392,7 @@ public final class BoardStore: HealHost {
///
/// Its own method rather than a flag on `delete(_:)` because it is a different act with a
/// different safety story: it registers **no undo step**, and `purgeIsUnrecoverable` stays `true`
/// 13-native-undo.md Rules settles this by name ("Permanently delete (Delete Immediately,
/// 13-native-undo.md Rules settles this by name ("Permanently delete (the trash's Delete,
/// Empty Trash) the confirm *is* the safety"). A stack entry here would be a promise the
/// filesystem cannot keep.
///
@@ -3427,49 +3427,6 @@ public final class BoardStore: HealHost {
}
}
/// **Delete Immediately skips the trash from anywhere** (03-board-ui.md § Trash;
/// 11-command-nexus.md: "Board window, card selection skips the trash from anywhere").
///
/// The one method whose targets can be in either container, and the reason is the command's own
/// wording: from a lane it bypasses the trash the ordinary delete would have used, and from the
/// trash it is the permanent delete the card is already one keystroke from. Cards only a lane's
/// delete is physical already, so there is nothing for "skip the trash" to mean on one.
///
/// **It registers no undo step**, `deleteTrashCards`' ruling and its wording.
///
/// The selection is cleared rather than walked to a successor: unlike , this is the command a
/// confirmation stands in front of, and what follows it is reading the board rather than pressing
/// the key again.
///
/// - Parameters:
/// - ids: the items to purge the caller's explicit set, not this store's selection.
/// - container: **which side those ids live on**, supplied rather than read off the selection
/// (added with the context menu's -alternate 11-command-nexus.md Context menus). The
/// menu-bar caller passes the selection's own container and behaves exactly as before; a
/// context-menu caller passes `.board`, because "the click names its target" and the target can
/// legitimately sit on the other side of the container boundary from a standing selection
/// (797d020's explicit-set resolution, whose whole point is that the two can disagree). Reading
/// it off the selection here would silently resolve a board card against `.trash` and purge
/// nothing a confirmed destructive command turning into a no-op, which is the one outcome a
/// confirmation must never lead to.
public func deleteImmediately(_ ids: Set<ItemID>, in container: ItemContainer) {
let paths = ItemPath.resolve(ids, in: container, snapshot: snapshot).filter { !$0.isLane }
guard !paths.isEmpty else { return }
let root = rootURL
try? performWrite { () throws(BoardWriteError) -> Void in
for path in paths {
switch path {
case .trashCard:
try BoardWriter.purgeTrashCard(at: path.folder(under: root), inBoard: root)
default:
try BoardWriter.purgeItem(at: path.folder(under: root))
}
}
}
clearSelection()
}
/// **Empty Trash ** purges every card in `<root>/.trash/`, in one bracket.
///
/// Not undoable, `deleteTrashCards`' ruling this is the other half of 13's "Permanently delete".