Live tape now holds on scroll, resumes at top, and lazy-loads deep history

The live tape no longer depends on a manual pause button in live mode. Scrolling away from the top now holds the tape automatically, Jump to top resumes it, the options hot head is capped at 100 rows, and older history is fetched from ClickHouse only when the scroll gate requests it.

Created 2026-05-16 during issue islandflow-0sa.

Summary

This change aligns the tape with the intended operator workflow: hold the live head while investigating older rows, keep historical prints valid even when old, and avoid preloading a large ClickHouse backlog until the user actually scrolls into it.

Changes Made

  • Removed the live-mode Pause/Resume control from tape pane actions while keeping replay pause behavior intact.
  • Changed live tape status copy from manual Paused semantics to scroll-held Held.
  • Capped the live options head at 100 rows.
  • Stopped scoped live history from auto-hydrating in the background.
  • Made scoped options and equities snapshots prefer hot cached rows first, then backfill from ClickHouse when needed.
  • Made options and equities history retention effectively unbounded on the client so deep scrolling does not get trimmed away prematurely.

Context

The tape previously mixed several behaviors: a manual pause button, automatic scroll holding, scoped background auto-hydration, and a much deeper options hot head. That created two user-visible problems: the live control model felt redundant, and older prints could disappear or feel inconsistent when switching views or waiting for newer rows to arrive.

Important Implementation Details

  • apps/web/app/terminal.tsx: live usePausableTapeView now treats scroll position as the hold source of truth.
  • apps/web/app/terminal.tsx: options live snapshot and retention now use a strict LIVE_OPTIONS_HEAD_LIMIT = 100.
  • apps/web/app/terminal.tsx: scoped history auto-hydration helper now returns no channels, so ClickHouse history stays lazy.
  • services/api/src/live.ts: scoped option/equity snapshots now filter the hot cache first, then merge ClickHouse backfill without seam duplicates.
statusLabel("connected", true, "live") === "Held"
statusLabel("connected", true, "replay") === "Paused"

Validation

  • Passed: bun test apps/web/app/terminal.test.ts services/api/tests/live.test.ts
  • Passed: bun --cwd=apps/web run build

Issues, Limitations, and Mitigations

  • Scoped snapshots can still backfill from ClickHouse when the hot cache does not have enough matching rows. This is intentional so focused views do not start empty.
  • Deep history is now lazy rather than eager, which reduces surprise and load, but the first deep-scroll request still depends on ClickHouse latency.

Follow-up Work

No additional follow-up issues were created in this turn.