Realign code with the 2026-07-31 rulings

The trash sorts by modified descending — the arrival rank mint retires
(Ranks.isOrderedForTrash one comparator, loader + merged order agree;
the legacy deleted: migration stamps modified from the tombstone
timestamp where parseable; delete undo steps validate existence-only;
agent guide v8). Trash selection goes kind-blind — ranges, marquee,
Select All, and the successor walk sweep both kinds; the guard moves to
the exits (mixed-payload drop refusal, copy/cut validation). The copy
stamping preflight widens back to comment depth (load-scoped posture —
the board always loads, the gesture refuses whole). Fixes a latent
no-op: trashed-lane drag restore never fired (DragSession.beginLanes
hard-coded the board container).

2403 tests in 413 suites green.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-07-31 18:35:07 -04:00
parent 542ab169a3
commit bec75e4282
37 changed files with 1200 additions and 551 deletions
+21
View File
@@ -554,6 +554,27 @@ public final class BannerCenter {
postLoss(Self.skippedFoldersMessage(count: count))
}
/// **The mixed-kind drag that tried to leave the trash** (04-interactions.md The trash, ruled
/// 2026-07-31 with kind-blind trash selection): "pickup is allowed the selection is legal but
/// every out-of-trash drop target refuses the mixed payload, and the release surfaces a notice
/// explaining the rule the refused drag ends like any refusal, rows staying put".
///
/// **A loss row**, with the relocation family and `postSkippedFolders`: nothing failed no write
/// was attempted and nothing is wrong with the board, but the gesture the user made did not
/// happen, which is exactly the warning-tone "didn't arrive" register. The wording is 04's own,
/// verbatim, and lives here because BannerCenter owns the phrasing ( Clipboard).
///
/// It is the *teaching* half of the guard: C/X grey out silently (menu validation says no
/// before the gesture starts), while the drag has no such surface to say it in advance so the
/// drop-time explanation "is where the rule teaches itself".
public func postMixedTrashDrag() {
postLoss(Self.mixedTrashDragMessage)
}
/// 04-interactions.md The trash's own sentence.
nonisolated static let mixedTrashDragMessage =
"Cards and lanes leave the trash separately \u{2014} restore one kind at a time"
/// Removes a dismissable row: a one-shot failure, a loss row, or a signpost. **An id that names
/// an in-progress operation is ignored** rather than ending it, because "dismiss" and "cancel"
/// are different promises and a row that offers one must never quietly do the other.