# Focus Fader Stutter — Bisect Log Companion to FEEDBACK_STUTTER_BUG.md. One kill-switch per suspect; flip one, rebuild, drag a Focus Fader while 60hz feedback streams, record the result here, then either keep it off or restore it and move to the next. ## Ranked suspect list | # | Suspect | Where | Switch | |---|---------|-------|--------| | 1 | appendLog per message (even when panel hidden) | ArrangeFunctionsWebSocket.appendLog | `DEBUG_DISABLE_APPEND_LOG` | | 2 | logScrollView.post(fullScroll) per message | inside appendLog | covered by #1 | | 3 | Runnable flood (~3 posts/msg, 300+/sec) | appendLog + dispatch handlers | mostly covered by #1 | | 4 | flashCard per message at 60hz | ArrangeFunctionsWebSocket.flashCard → ArrangeCardView.flashActivity | `DEBUG_DISABLE_NETWORK_FLASH` | | 5 | setText at 60hz on feedback TextView | FocusFeedbackWidgetView.setTextFromNetwork | `DEBUG_DISABLE_FEEDBACK_SETTEXT` | | 6 | LAYER_TYPE_SOFTWARE + blur glow on fader | FocusFaderWidgetView ctor (also FaderWidgetView) | `DEBUG_DISABLE_GLOW` (one per class) | | 7 | new LinearGradient every onDraw | FocusFaderWidgetView.onDraw (also FaderWidgetView) | `DEBUG_DISABLE_GRADIENT_FILL` (one per class) | | 8 | Log.d full-JSON concat per message | ArrangeFunctionsWebSocket.onMessage | `DEBUG_DISABLE_RECEIVE_LOGCAT` | | 9 | Echo stream (sent values come back, run appendLog+flashCard mid-drag) | handleWidgetUpdateF | partially covered by #1 | | 10 | vibrator.vibrate at value edges | FocusFaderWidgetView.checkEdgeHaptic | not yet added | ## Verdict (2026-07-31) **appendLog was the stutter.** A/B confirmed: re-enabling it brings the stutter back immediately. Receive-logcat kept off as a freebie (no felt difference). Everything else exonerated and restored to original behavior — including the glow/software-layer rendering, which Paul tested and cleared. Final switch states: `DEBUG_DISABLE_APPEND_LOG = true`, `DEBUG_DISABLE_RECEIVE_LOGCAT = true`, all others `false` (original behavior). **Timecode fluidity root cause (found by Paul, same day):** REAPER's audio buffer size. REAPER emits OSC feedback per audio block, so a large buffer makes updates arrive in chunky bursts — uneven cadence no client-side rendering can smooth. Lowering the buffer restored fluid feedback. The drawText rewrite of FocusFeedbackWidgetView (done just before this discovery) stays: it's the cheapest render path and collapses same-frame updates to one draw regardless of source pacing. ## Test runs ### Run 1 — DEBUG_DISABLE_APPEND_LOG = true (suspects 1+2, most of 3) - Date: 2026-07-31 - Switches off: appendLog (all in/out log lines + auto-scroll posts) - Side effect while off: debug log panel shows nothing new when opened - Result: **CONFIRMED CULPRIT — "way smoother"** with appendLog disabled. - A/B re-test same day: re-enabled appendLog, stutter came back immediately; disabled again. Not a placebo — appendLog is definitively implicated. Left OFF for now; permanent fix TBD. ### Run 2 — DEBUG_DISABLE_RECEIVE_LOGCAT = true (suspect 8) - Date: 2026-07-31 - Switches off: appendLog (kept off from Run 1) + per-message Log.d in onMessage - Side effect while off: incoming messages no longer visible in logcat - Result: **No perceptible difference.** Kept off anyway (free optimization, nobody reads logcat during performance). ### Run 3 — DEBUG_DISABLE_GLOW = true (suspect 6) - Date: 2026-07-31 - Switches off: appendLog + receive-logcat (from Runs 1-2) + shadow-layer glow and software rendering in FocusFaderWidgetView AND FaderWidgetView - Side effect while off: faders lose their glow — plain value line + dot - Result: **Exonerated.** Still smooth with glow off, but no felt difference attributable to it — Paul: "the glow wasn't an issue." Turned back ON (original software-layer glow restored) at end of bisect. ### Run 4 — DEBUG_DISABLE_NETWORK_FLASH = true (suspect 4) - Date: 2026-07-31 - Switches off: appendLog + receive-logcat + glow (Runs 1-3) + network-triggered activity-ring flashes (local touch flashes still work) - Side effect while off: cards don't blink green on desktop-driven updates - Result: **SKIPPED — suspect was already inert.** The tablet's "Activity: ON/OFF" button (default OFF) was off during all stutter tests, and flashActivity() early-returns on that flag before any timer work. Kill switch left in place (harmless, skips a registry lookup) but this suspect is exonerated for the observed stutter. ### Run 5 — DEBUG_DISABLE_FEEDBACK_SETTEXT = true (suspect 5, plus its share of 3) - Date: 2026-07-31 - Switches off: appendLog + receive-logcat + glow (Runs 1-3) + the ENTIRE widget_feedback UI path: the runOnUiThread post, registry lookup, and setText all skipped (placed before the post, so this also removes 60/sec of the runnable flood) - Side effect while off: feedback readouts (timecode etc.) freeze at last text - Result: **Nothing earth-shaking — no clear felt difference.** Switch turned back OFF (readouts are needed regardless). 60hz setText is tolerable now that appendLog is gone; candidate for once-per-frame conflation later, not a primary culprit. ### Run 6 — DEBUG_DISABLE_GRADIENT_FILL = true (suspect 7) - Date: 2026-07-31 - Switches off: appendLog + receive-logcat + glow (kept from earlier runs); gradient fill replaced with flat translucent fill in both fader classes - Side effect while off: fader fill is flat color, no fade-to-transparent - Result: **No felt difference — gradient turned back ON** (look kept). Create-once gradient (setLocalMatrix) stays on the permanent-fix list as hygiene, not a culprit.