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:
@@ -416,6 +416,12 @@ struct BoardDropContext {
|
||||
/// event time is the geometry that genuinely moves under a stationary cursor: the grid, which the
|
||||
/// autoscroll driver scrolls on purpose, and `DropSlotMath`'s own containment arithmetic.
|
||||
func retargetCards(inLane laneID: ItemID) {
|
||||
// `DragSignposts` — begin/end with a `defer` rather than a scoped closure, so the guards
|
||||
// below keep their early returns and this reads as instrumentation rather than a rewrite.
|
||||
#if DEBUG
|
||||
let span = DragSignposts.beginRetargetCards()
|
||||
defer { DragSignposts.endRetargetCards(span) }
|
||||
#endif
|
||||
guard session.isDraggingCards, let cursor = globalCursor() else { return }
|
||||
guard let resting = session.restingLayouts.layout(
|
||||
inLane: laneID,
|
||||
@@ -732,6 +738,12 @@ struct BoardDropContext {
|
||||
/// from proposing to committed and keeps drawing the arrangement it was showing — the shadows at
|
||||
/// their landing slots, the originals lifted out — until this store's echo reload lands.
|
||||
func commitDrop() -> Bool {
|
||||
// The synchronous half of the release, every refusing branch included (`DragSignposts`); the
|
||||
// *pause* the user feels starts inside, at `DragSession.commit(into:)`, and outlives this.
|
||||
#if DEBUG
|
||||
let span = DragSignposts.beginCommitDrop()
|
||||
defer { DragSignposts.endCommitDrop(span) }
|
||||
#endif
|
||||
guard session.isActive, let kind = session.kind, let sourceRoot = session.sourceRoot else {
|
||||
return false
|
||||
}
|
||||
@@ -944,6 +956,13 @@ struct LaneDropDelegate: DropDelegate {
|
||||
func dropEntered(info: DropInfo) { retarget(info) }
|
||||
|
||||
func dropUpdated(info: DropInfo) -> DropProposal? {
|
||||
// The per-event span, and the input sample (`DragSignposts`). One delegate sees any one
|
||||
// event — single-target dispatch has no fall-through — so the cadence is not double-counted.
|
||||
#if DEBUG
|
||||
let span = DragSignposts.beginDropUpdated()
|
||||
DragSignposts.sampleInput()
|
||||
defer { DragSignposts.endDropUpdated(span) }
|
||||
#endif
|
||||
retarget(info)
|
||||
return context.isFileSession(info) ? context.fileDropProposal() : context.dropProposal()
|
||||
}
|
||||
@@ -1000,6 +1019,11 @@ struct StripDropDelegate: DropDelegate {
|
||||
func dropEntered(info: DropInfo) { retarget(info) }
|
||||
|
||||
func dropUpdated(info: DropInfo) -> DropProposal? {
|
||||
#if DEBUG
|
||||
let span = DragSignposts.beginDropUpdated()
|
||||
DragSignposts.sampleInput()
|
||||
defer { DragSignposts.endDropUpdated(span) }
|
||||
#endif
|
||||
retarget(info)
|
||||
return context.isFileSession(info) ? context.fileDropProposal() : context.dropProposal()
|
||||
}
|
||||
@@ -1055,6 +1079,11 @@ struct TrashDropDelegate: DropDelegate {
|
||||
func dropEntered(info: DropInfo) { retarget(info) }
|
||||
|
||||
func dropUpdated(info: DropInfo) -> DropProposal? {
|
||||
#if DEBUG
|
||||
let span = DragSignposts.beginDropUpdated()
|
||||
DragSignposts.sampleInput()
|
||||
defer { DragSignposts.endDropUpdated(span) }
|
||||
#endif
|
||||
retarget(info)
|
||||
return context.isFileSession(info) ? context.fileDropProposal() : context.dropProposal()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user