The lane-resize release gets its own hold — the strip stops two-stepping through the stale snapshot

LaneWidthHold: after the release the session's frozen standard and the
WRITTEN unit count keep governing the strip until a landed snapshot
carries that width back — dividing the already-grown window by the
stale unit total in between was the visible two-step. A deliberately
separate type from CommittedHold: that hold stands in for an
arrangement and any landing retires it; this one stands in for a value
and only a landing that carries it will do. Echo reads through
LaneLayoutMath.displayUnits so the width-1 key-removal case compares
right; the watch rides landedReloads so a value-equal echo still
answers; width writes now return whether bytes reached disk so a
refused or no-op write dissolves the hold instead of arming it; the
1500ms timeout family covers the rest.

Drag-perf card 231e3693.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-08-01 19:33:33 -04:00
parent f6105d4389
commit 409f430813
6 changed files with 591 additions and 32 deletions
+17 -6
View File
@@ -1518,7 +1518,14 @@ public final class BoardStore: HealHost {
/// rethrows, so the rethrow is swallowed here rather than propagated to a gesture that has no
/// second thing to do about it. The lane stays at its old width, which is the truth nothing was
/// written.
public func setLaneWidth(_ id: ItemID, units: Int) {
///
/// **Returns whether bytes reached disk**, which is the same question as "is an echo reload
/// coming": all three do-nothing paths above answer `false`, and so does a refusal. The edge
/// drag's release hold reads it an overlay that outlived a write nobody made would draw a
/// width the board never got (`LaneResizeSession.end`). Discardable because every other caller
/// has nothing to do with the answer.
@discardableResult
public func setLaneWidth(_ id: ItemID, units: Int) -> Bool {
writeLaneWidths([(id, max(1, units))])
}
@@ -1529,11 +1536,12 @@ public final class BoardStore: HealHost {
///
/// Lanes already at the one-unit floor simply hold there on a decrease the batch is not
/// refused because one member has nowhere to go, matching the style batch's silent-skip shape.
public func stepLaneWidths(_ ids: Set<ItemID>, by delta: Int) {
@discardableResult
public func stepLaneWidths(_ ids: Set<ItemID>, by delta: Int) -> Bool {
let changes: [(ItemID, Int)] = snapshot.lanes
.filter { ids.contains($0.id) }
.map { ($0.id, max(1, LaneLayoutMath.displayUnits(of: $0) + delta)) }
writeLaneWidths(changes)
return writeLaneWidths(changes)
}
/// The one commit point every width mechanism shares the edge drag, the context-menu stepper,
@@ -1545,14 +1553,16 @@ public final class BoardStore: HealHost {
/// `background`): a default lane's frontmatter stays clean whichever mechanism wrote it. A
/// hand-written `width: 1` is legal and preserved until the app itself next edits width the
/// unchanged-units guard below skips it, so only a real change reaches the remove.
private func writeLaneWidths(_ changes: [(id: ItemID, units: Int)]) {
///
/// Returns whether the bracket actually wrote see `setLaneWidth` for who asks and why.
private func writeLaneWidths(_ changes: [(id: ItemID, units: Int)]) -> Bool {
let writes: [(folder: URL, units: Int, prior: FieldValue<Int>, title: String?)] = changes.compactMap { change in
guard let lane = snapshot.lanes.first(where: { $0.id == change.id }),
LaneLayoutMath.displayUnits(of: lane) != change.units
else { return nil }
return (rootURL.appendingPathComponent(change.id.rawValue), change.units, lane.width, lane.title.value)
}
guard !writes.isEmpty else { return }
guard !writes.isEmpty else { return false }
// The closure's signature is spelled out because of `try?`: with the error discarded at the
// call site Swift stops inferring the typed `throws(BoardWriteError)` and widens it to `any
@@ -1563,7 +1573,7 @@ public final class BoardStore: HealHost {
try Self.setWidth(write.units, at: write.folder)
}
}
guard landed != nil else { return }
guard landed != nil else { return false }
// resize prior width (13-native-undo.md Rules). One step whatever the batch's size the
// menu items step every selected lane in one gesture, and one gesture is one step.
@@ -1589,6 +1599,7 @@ public final class BoardStore: HealHost {
try Self.setWidth(write.units, at: write.folder)
}
}
return true
}
/// The width write itself, spelled once so the gesture and its redo cannot drift apart on the