Skip to content

Give the status page a live, always-flowing activity view - #745

Merged
xmap merged 1 commit into
mainfrom
status-relay-flowing-mode
Aug 29, 2026
Merged

xmap merged 1 commit into
mainfrom
status-relay-flowing-mode

Conversation

@xmap

@xmap xmap commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Summary

Step 4 of the status-page work (Steps 1-3 landed as #741, #742, #743). The scrubber built for REWIND now also renders a bounded 2-hour rolling window fed by the activity tail from Step 3, sharing the same subject-neutral document renderer:

  • scrubber.js: mount() gains a follow option that pins the cursor to the live edge and drops Play/"jump to last event" (both assume a closed timeline) by default, plus an onScrub callback so a caller can pause its own re-rendering the instant a viewer grabs the cursor rather than fight the drag. Also fixes a real gap: renderReadout assumed every non-primary lane was a "series" lane with a value; a non-primary markers lane (every domain lane in flowing mode) would have shown undefined in the readout. And a marker-label density cap (MAX_MARKER_LABELS), since a busy domain lane over 2 hours can hold far more points than a REWIND run's handful of lifecycle events.
  • page.html: a new "Live activity" section accumulates "activity" messages into a client-side buffer, bucketed many-to-one into the same seven domains as the live tables (Dataset/Distribution/Acquisition all land on "Datasets", say) plus an "Other" catch-all for the rest of the 42-type event vocabulary, so the lane count is fixed and the layout never reflows. Rebuilds the whole timeline document and calls mount() again on each update rather than patching the SVG incrementally (measured event volumes are tiny against the tick cadence, so this stays well inside budget). A "Paused: N new events" status line and a "Resume following" control complete the pause/resume loop.
  • Real bug fix: page.html's message handler had no actual kind switch — anything that wasn't run_history_index or a connection-state frame fell through the same path as a snapshot. An "activity" message (added in Step 3, never read by the frontend until now) would have blanked every live table the moment flowing mode's data started arriving in production. Now a real switch (msg.kind) with an explicit default that logs and drops, matching the relay's own forward-compatibility posture.

Test plan

  • Verified live in a browser (Playwright against a fake relay + producer, mirroring Step 1's verification approach — no JS test infra exists for this page yet, see docs/stack/frontend.md):
    • Flowing mode populates correctly with proper many-to-one domain bucketing and an empty-buffer initial state.
    • Dragging the slider pauses following, shows "Resume following", and a live "N new events since you started scrubbing" counter updates while the view stays frozen.
    • Clicking "Resume following" clears the status, re-renders, and resumes live tracking.
    • Programmatically sampled the DOM 78 times over 4 seconds spanning multiple activity messages: the Runs table (seeded with one open run) never blanked, confirming the kind-switch fix actually prevents the bug it was written for.
    • Full REWIND regression pass: Play and "Jump to last event" buttons still render and work, primary-lane fold (activepausedactiveended) and series-lane reading both still correct after the renderReadout generalization.
  • node --check on both scrubber.js and the inline script in page.html.

Not deployed to arcturus/lyra — this lands on main only.

🤖 Generated with Claude Code

Step 4: the scrubber built for REWIND (Step 1) now also renders a bounded
2-hour rolling window fed by the activity tail (Step 3), sharing the same
subject-neutral document renderer. mount() gains a `follow` option that
pins the cursor to the live edge and drops replay controls that assume a
closed timeline, plus an `onScrub` callback so page.html can pause its
own re-rendering the instant a viewer grabs the cursor rather than fight
the drag. Activity events bucket into the same seven domains as the live
tables (many-to-one: Dataset/Distribution/Acquisition all land on
"Datasets", say) plus an "Other" catch-all, so the lane count is fixed
and the layout never reflows.

Rebuilds the whole timeline document from an accumulated client-side
buffer on each update rather than patching the SVG incrementally:
measured event volumes are tiny against the tick cadence, so this stays
well inside budget without the added complexity.

Also fixes a real bug found while wiring this in: page.html's message
handler had no real `kind` switch, so an "activity" message (added in
Step 3, unread by the frontend until now) would have fallen through the
same path as a snapshot and blanked every live table the moment flowing
mode's data started arriving in production.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Coverage report

This PR does not seem to contain any modification to coverable code.

@xmap
xmap merged commit 9b91d8e into main Aug 29, 2026
19 checks passed
@xmap
xmap deleted the status-relay-flowing-mode branch August 29, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant