🔍 Problem
The spring-tick scheduling closure is duplicated at 9 sites across pkg/tui:
tea.Tick(time.Second/time.Duration(springFPS), func(time.Time) tea.Msg { return springTickMsg{gen: gen} }) appears 7× verbatim: model.go:692-694, springs.go:79-81, springs.go:103-105, springs.go:151-153, springs.go:200-202, zoomspring.go:188-190, zoomspring.go:311-313
- Plus 2 variants at
phaseHoldDuration cadence: springs.go:74-76, springs.go:541-543
Every site must remember to capture gen before the closure — the exact mistake class that caused the stacked-tick bug in #218. The discipline is currently enforced by convention at 9 call sites; one slip reintroduces the bug.
Two small riders in the same neighbourhood:
- 📋
showXLabels := chartH >= 6; barsH = chartH - 1 layout math recomputed independently at 7 sites (chart.go:1040-1044, chart.go:1189-1193, chart.go:513, chart.go:1289-1292, zoomspring.go:110-114, zoomspring.go:230-234, series.go:304-307) with the magic number 6 unnamed — and overlayYTicks already drifted to a different >= 5 guard
- 📋 The cross-fade midpoint math (
(0.5-r)/0.5 out / (r-0.5)/0.5 in) implemented twice with different clamping styles: chart.go:1148-1149 vs model.go:802-813
🛠️ Suggested shape
springTickCmd(gen int) tea.Cmd and springHoldCmd(gen int) tea.Cmd helpers that capture gen internally
- A
chartLayout(chartH int) (barsH int, showXLabels bool) helper with the threshold as a named const, used by all 7 sites
- A shared
crossfade(r float64) (fadeOut, fadeIn float64) helper
⚠️ Notes
🔍 Problem
The spring-tick scheduling closure is duplicated at 9 sites across
pkg/tui:tea.Tick(time.Second/time.Duration(springFPS), func(time.Time) tea.Msg { return springTickMsg{gen: gen} })appears 7× verbatim:model.go:692-694,springs.go:79-81,springs.go:103-105,springs.go:151-153,springs.go:200-202,zoomspring.go:188-190,zoomspring.go:311-313phaseHoldDurationcadence:springs.go:74-76,springs.go:541-543Every site must remember to capture
genbefore the closure — the exact mistake class that caused the stacked-tick bug in #218. The discipline is currently enforced by convention at 9 call sites; one slip reintroduces the bug.Two small riders in the same neighbourhood:
showXLabels := chartH >= 6; barsH = chartH - 1layout math recomputed independently at 7 sites (chart.go:1040-1044,chart.go:1189-1193,chart.go:513,chart.go:1289-1292,zoomspring.go:110-114,zoomspring.go:230-234,series.go:304-307) with the magic number 6 unnamed — andoverlayYTicksalready drifted to a different>= 5guard(0.5-r)/0.5out /(r-0.5)/0.5in) implemented twice with different clamping styles:chart.go:1148-1149vsmodel.go:802-813🛠️ Suggested shape
springTickCmd(gen int) tea.CmdandspringHoldCmd(gen int) tea.Cmdhelpers that capture gen internallychartLayout(chartH int) (barsH int, showXLabels bool)helper with the threshold as a named const, used by all 7 sitescrossfade(r float64) (fadeOut, fadeIn float64)helperspringTickMsg.