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:
@@ -627,24 +627,30 @@ struct TrashUndoTests {
|
||||
#expect(!fixture.exists(card1Path))
|
||||
}
|
||||
|
||||
@Test("The redo files the card under the rank the delete minted, not a fresh one")
|
||||
func redoUsesTheCapturedTrashRank() throws {
|
||||
/// **There is no rank to capture or replay** (01-storage-format.md § Deletion, re-ruled
|
||||
/// 2026-07-31): a delete is a folder move plus a `modified` stamp, so the card's `order` rides
|
||||
/// along untouched through delete, undo and redo alike, and the redo is just the forward write
|
||||
/// run again.
|
||||
@Test("The redo re-runs the delete, and `order` is untouched at every leg")
|
||||
func redoRerunsTheDelete() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (store, history) = try makeStore(fixture)
|
||||
|
||||
store.delete([card1])
|
||||
let minted = try #require(try document(fixture, ".trash/\(Ident.card1)").order.value)
|
||||
#expect(minted < 1024, "entry is at the top: a rank above the current topmost (order 1024)")
|
||||
#expect(try document(fixture, ".trash/\(Ident.card1)").order.value == 1024,
|
||||
"the lane rank rode along; nothing was minted")
|
||||
|
||||
history.undo()
|
||||
#expect(try document(fixture, card1Path).order.value == 1024)
|
||||
history.redo()
|
||||
|
||||
#expect(try document(fixture, ".trash/\(Ident.card1)").order.value == minted,
|
||||
"the redo replays the write's own captured rank")
|
||||
#expect(try document(fixture, ".trash/\(Ident.card1)").order.value == 1024)
|
||||
// And the redone delete restamps, which is what puts it back on top of the column.
|
||||
#expect(try loadedTrash(fixture).map(\.id).first == card1)
|
||||
}
|
||||
|
||||
@Test("A multi-card delete is one step with a plural title, and lands newest-last on top")
|
||||
@Test("A multi-card delete is one step with a plural title, and the run lands on top")
|
||||
func batchDeleteIsOneStep() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
@@ -653,9 +659,11 @@ struct TrashUndoTests {
|
||||
store.delete([card1, card2])
|
||||
|
||||
#expect(history.undoActionName == "Delete 2 Cards")
|
||||
let first = try #require(try document(fixture, ".trash/\(Ident.card1)").order.value)
|
||||
let second = try #require(try document(fixture, ".trash/\(Ident.card2)").order.value)
|
||||
#expect(second < first, "each arrival in the run mints a rank above the one before it")
|
||||
// Both cards keep the ranks they had in their lane — nothing is minted, at either end of the
|
||||
// run — and both land above the board's existing resident by their fresh stamps.
|
||||
#expect(try document(fixture, ".trash/\(Ident.card1)").order.value == 1024)
|
||||
#expect(try document(fixture, ".trash/\(Ident.card2)").order.value == 2048)
|
||||
#expect(try loadedTrash(fixture).map(\.id).suffix(1) == [trashed])
|
||||
|
||||
history.undo()
|
||||
#expect(fixture.exists(card1Path))
|
||||
@@ -683,9 +691,8 @@ struct TrashUndoTests {
|
||||
#expect(try loadedTrash(fixture).map(\.id) == [trashed], "its cards are not trash cards")
|
||||
#expect(try loadedTrashedLanes(fixture).map(\.id) == [lane2])
|
||||
#expect(history.undoActionName == "Delete Lane")
|
||||
let trashRank = try #require(try document(fixture, ".trash/\(Ident.lane2)").order.value)
|
||||
let resident = try #require(try document(fixture, trashedPath).order.value)
|
||||
#expect(trashRank < resident, "entry is at the top — a rank above the current topmost")
|
||||
#expect(try document(fixture, ".trash/\(Ident.lane2)").order.value == laneRank,
|
||||
"the strip rank rides along; no trash rank is minted")
|
||||
|
||||
history.undo()
|
||||
|
||||
@@ -699,8 +706,8 @@ struct TrashUndoTests {
|
||||
|
||||
history.redo()
|
||||
#expect(fixture.exists(".trash/\(Ident.lane2)"))
|
||||
#expect(try document(fixture, ".trash/\(Ident.lane2)").order.value == trashRank,
|
||||
"the redo replays the write's own captured rank")
|
||||
#expect(try document(fixture, ".trash/\(Ident.lane2)").order.value == laneRank,
|
||||
"the redo re-runs the forward write, which has no rank to replay")
|
||||
}
|
||||
|
||||
@Test("A multi-lane delete is one step with a plural title")
|
||||
@@ -712,9 +719,9 @@ struct TrashUndoTests {
|
||||
store.delete([lane1, lane2])
|
||||
|
||||
#expect(history.undoActionName == "Delete 2 Lanes")
|
||||
let first = try #require(try document(fixture, ".trash/\(Ident.lane1)").order.value)
|
||||
let second = try #require(try document(fixture, ".trash/\(Ident.lane2)").order.value)
|
||||
#expect(second < first, "each arrival in the run mints a rank above the one before it")
|
||||
// Their strip ranks, untouched — a lane delete mints nothing either.
|
||||
#expect(try document(fixture, ".trash/\(Ident.lane1)").order.value == 1024)
|
||||
#expect(try document(fixture, ".trash/\(Ident.lane2)").order.value == 2048)
|
||||
|
||||
history.undo()
|
||||
#expect(fixture.exists(Ident.lane1))
|
||||
@@ -728,7 +735,9 @@ struct TrashUndoTests {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (store, history) = try makeStore(fixture)
|
||||
let trashRank = try #require(try document(fixture, trashedPath).order.value)
|
||||
// The `order` the row was *carrying* while trashed — its old lane rank, which the trash move
|
||||
// never rewrote and which this restore is about to overwrite.
|
||||
let carriedOrder = try #require(try document(fixture, trashedPath).order.value)
|
||||
|
||||
store.moveCards([trashed], toLane: lane2, at: 0)
|
||||
|
||||
@@ -740,8 +749,8 @@ struct TrashUndoTests {
|
||||
history.undo()
|
||||
#expect(fixture.exists(trashedPath), "back in the trash it came out of")
|
||||
#expect(!fixture.exists("\(Ident.lane2)/\(Ident.card4)"))
|
||||
#expect(try document(fixture, trashedPath).order.value == trashRank,
|
||||
"at the rank it was filed under")
|
||||
#expect(try document(fixture, trashedPath).order.value == carriedOrder,
|
||||
"the undo puts back the rank the restore overwrote")
|
||||
|
||||
history.redo()
|
||||
#expect(fixture.exists("\(Ident.lane2)/\(Ident.card4)"))
|
||||
|
||||
Reference in New Issue
Block a user