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:
@@ -227,8 +227,16 @@ public final class ClipboardStore {
|
||||
/// the text (04 ▸ Grammar). The field consumes the selector natively, so this guard is belt over
|
||||
/// braces — but a board command that stayed armed under an editor would be exactly the kind of
|
||||
/// fall-through 04 is careful about.
|
||||
///
|
||||
/// **A mixed trash selection closes it — this is one of the two exits the kind guard moved to**
|
||||
/// (04-interactions.md ▸ The trash, ruled 2026-07-31 with kind-blind trash selection): "the
|
||||
/// pasteboard's payload types are per-kind, so Cut and Copy grey out via ordinary menu validation
|
||||
/// while a trash selection mixes kinds — no failed gesture, no beep". It is also what keeps
|
||||
/// `capture`'s single `kind` honest: the manifest names one payload type, and a set spanning both
|
||||
/// never reaches it.
|
||||
public func canCopy(from store: BoardStore) -> Bool {
|
||||
guard !store.isEditingInline else { return false }
|
||||
guard !SelectionGrammar.mixesKinds(store.selection, in: store.snapshot) else { return false }
|
||||
return SelectionGrammar.kind(of: store.selection, in: store.snapshot) != nil
|
||||
}
|
||||
|
||||
|
||||
@@ -498,13 +498,10 @@ enum UITestLaunch {
|
||||
|
||||
// The delete goes last so the trashed card's identity is one the lanes above have already
|
||||
// finished with — and through the ordinary delete door, so `.trash/` ends up holding exactly
|
||||
// what a user's ⌘⌫ would have put there, stamps and `order` included.
|
||||
// what a user's ⌘⌫ would have put there: the `modified` stamp that positions it, its `order`
|
||||
// riding along untouched.
|
||||
let doomed = cardURLs[trashedCardIndex.lane][trashedCardIndex.card]
|
||||
try BoardWriter.deleteCardToTrash(
|
||||
at: doomed,
|
||||
inBoard: root,
|
||||
order: Ranks.append(toVisible: [] as [Double])
|
||||
)
|
||||
try BoardWriter.deleteCardToTrash(at: doomed, inBoard: root)
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user