From 0e942400d59d92c61e1815277ca5bd44bfc6d0a1 Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Mon, 6 Jul 2026 19:33:05 -0700 Subject: [PATCH] Transcript Incremental Projection Nucleic-Session: 0FFD007B-0696-4517-9429-129C7B0FD5AC Co-authored-by: Nucleic --- .../NucleicRemote/Views/SessionDetailView.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift b/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift index 678c49b..2afc6f8 100644 --- a/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift +++ b/NucleicRemote/NucleicRemote/Views/SessionDetailView.swift @@ -600,14 +600,21 @@ struct TranscriptList: View { /// The band is wider than any bar-height delta, so only a deliberate scroll crosses it. private let bottomUnfollowThreshold: CGFloat = 64 - /// The live scroll phase, used to tell *user* scrolling (finger down / flick decelerating) + /// The live scroll phase, used to tell *user* scrolling (an active drag / flick decelerating) /// from programmatic motion (autoscroll animations, anchor re-pins, inset changes). Only a /// user-driven phase may disengage bottom-following — a programmatic perturbation can only /// ever re-engage it — which structurally breaks every geometry→state→geometry feedback /// cycle: no chain of layout reactions can take the gate false and sustain itself. + /// + /// `.tracking` (finger down, no displacement yet) deliberately does NOT count: a finger + /// resting on the transcript scrolls nothing, but touching down *stops a live deceleration*, + /// and that stop emits a final far-from-bottom geometry reading under `.tracking`. Tapping + /// the chevron mid-deceleration raced exactly that emission against the tap's "follow again" + /// — when the stop reading landed after it, following disengaged right back and the chevron + /// stuck until a second tap. Real scroll-aways always pass through `.interacting`. @State private var scrollPhase: ScrollPhase = .idle private var isUserScrolling: Bool { - scrollPhase == .tracking || scrollPhase == .interacting || scrollPhase == .decelerating + scrollPhase == .interacting || scrollPhase == .decelerating } var body: some View {