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
+5
View File
@@ -146,6 +146,11 @@ struct LaneView: View, Equatable {
}
var body: some View {
// The strip's gate, observed (`BoardRenderMetrics`) DEBUG only, and a `let _` because
// `body` is a `@ViewBuilder` and a bare `Void` call is not a view.
#if DEBUG
let _ = BoardRenderMetrics.countLaneBody()
#endif
// `spacing: 0` and the padding moved inside: the accent band is **full-width** along the
// lane's top edge, so it must sit outside the content inset rather than in it.
VStack(alignment: .leading, spacing: 0) {