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
+7 -22
View File
@@ -41,25 +41,19 @@ public enum TrashModel {
public let confirmTitle: String
}
/// The alert in front of a **permanent** card delete the trash's own / and File Delete
/// Immediately alike (03-board-ui.md § Trash: "Both confirm exactly where the loss is real ...
/// the alert stands between one keystroke and unrecoverable deletion").
/// The alert in front of a **permanent** card delete the trash's own / (03-board-ui.md §
/// Trash: "confirms exactly where the loss is real: the alert stands between one keystroke and
/// unrecoverable deletion").
///
/// `container` is where the command found the cards: the trash for the trash's Delete, the board
/// for a Delete Immediately that skips the trash from a lane. The prompt reads the same either
/// way what is being asked is whether to destroy these cards, and where they happen to be
/// sitting is not the question.
///
/// A sole card is **named**; several fold into a count. `nil` when the ids name nothing in that
/// container, which is also the command's own refusal so the prompt and the action can never
/// A sole card is **named**; several fold into a count. `nil` when the ids name nothing in the
/// trash, which is also the command's own refusal so the prompt and the action can never
/// disagree about whether there is anything to purge.
public static func purgePrompt(
for ids: Set<ItemID>,
in container: ItemContainer,
snapshot: BoardModel,
unrecoverable: Bool
) -> PurgePrompt? {
let targets = ItemPath.resolve(ids, in: container, snapshot: snapshot).filter { !$0.isLane }
let targets = ItemPath.resolve(ids, in: .trash, snapshot: snapshot).filter { !$0.isLane }
guard !targets.isEmpty else { return nil }
let subject: String
@@ -98,7 +92,7 @@ public enum TrashModel {
/// undo as its net).
private static func message(unrecoverable: Bool) -> String {
// m7-git: on a git board the content stays reachable in history, so the second sentence is
// the honest one and Delete Immediately does not confirm there at all
// the honest one and the trash's own Delete does not confirm there at all
// (`BoardStore.purgeIsUnrecoverable`).
unrecoverable
? "This can\u{2019}t be undone."
@@ -135,13 +129,4 @@ public enum TrashModel {
public static func canDelete(selection: ItemReferenceSet, in snapshot: BoardModel) -> Bool {
!ItemPath.resolve(selection.ids, in: selection.container, snapshot: snapshot).isEmpty
}
/// Whether File Delete Immediately has something to purge **a card selection, from anywhere**
/// (11-command-nexus.md: "Board window, card selection skips the trash from anywhere").
///
/// Cards only, in either container: a lane's delete is physical already and has undo as its net,
/// so there is nothing for "skip the trash" to mean on one.
public static func canDeleteImmediately(selection: ItemReferenceSet, in snapshot: BoardModel) -> Bool {
ItemPath.resolve(selection.ids, in: selection.container, snapshot: snapshot).contains { !$0.isLane }
}
}