Drag instrumentation — render counters, hot-path signposts, and the invariants that prove the gates

BoardRenderMetrics (DEBUG-only, the pathfinder's counter bag plus a
strip-body discriminator that tells a failed gate from a direct
Observation invalidation) counted at BoardView/LaneView/CardFaceView/
TrashLaneView bodies and MasonryLayout's callbacks. DragSignposts wraps
dropUpdated, retargetCards, commitDrop, and the commit-to-covering-
snapshot release pause; input latency reports honestly against
NSApp.currentEvent's mach base or labels itself base=none — no event
timestamp rides the drop path. BoardRenderPerformanceTests hosts the
real BoardView off-screen: a value-equal reload runs zero lane and zero
card bodies, a one-card edit repaints one card of 180. The lane-body
budget is <= laneCount with the headerInk chain documented and a
two-way tripwire that fails when the fix lands. Methodology in
RENDER-INSTRUMENTATION.md. Release build proves it all compiles out.

Drag-perf card a450ad09.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-08-01 20:04:01 -04:00
parent 409f430813
commit 0218ae4c21
11 changed files with 861 additions and 0 deletions
+23
View File
@@ -577,6 +577,10 @@ final class DragSession {
source: BoardStore,
mixesKinds: Bool
) {
// A new drag's first `sinceLastMs` must not be the gap since the previous drag's last sample.
#if DEBUG
DragSignposts.resetInputSampling()
#endif
endHold()
restingLayouts.clear()
self.kind = kind
@@ -664,6 +668,12 @@ final class DragSession {
/// that guard reads.
func commit(into store: BoardStore) {
guard isActive else { return }
// **The release pause starts here** (`DragSignposts`): this is the one path that arms a hold,
// so every begin has an end a refused release opens nothing. Closed at `handOff`,
// `expire`, or `endHold`, each with its own outcome.
#if DEBUG
DragSignposts.beginReleasePause()
#endif
sourceStore?.transient.dragMembers = .empty
watchdog?.cancel()
watchdog = nil
@@ -688,6 +698,9 @@ final class DragSession {
/// already been handed off or replaced by a second drag's is not this one's to end.
func expire(_ hold: CommittedHold) {
guard self.hold == hold else { return }
#if DEBUG
DragSignposts.endReleasePause(outcome: "timeout")
#endif
withAnimation(Motion.dragReflow(reduced: Motion.prefersReducedMotion)) { end() }
}
@@ -697,10 +710,20 @@ final class DragSession {
/// the board it belongs to a reload on some other board says nothing about this one.
func handOff(root: BoardRootKey, generation: Int) {
guard let hold, hold.isRetired(byRoot: root, generation: generation) else { return }
// The span the release-pause signpost exists for: commit the covering snapshot.
#if DEBUG
DragSignposts.endReleasePause(outcome: "echo")
#endif
end()
}
private func endHold() {
// A no-op for the two paths above, which have already closed their interval with a more
// specific outcome; the backstop for every other teardown (`end()` from the watchdog, a
// cancel, a second drag beginning).
#if DEBUG
DragSignposts.endReleasePause(outcome: "cleared")
#endif
hold = nil
holdTimeoutTask?.cancel()
holdTimeoutTask = nil