Skip to content

Patch dashboard runs from SSE payloads instead of full refetch (BEN-49)#53

Merged
benSepanski merged 1 commit intomainfrom
claude/nifty-bardeen-IDLC6
May 4, 2026
Merged

Patch dashboard runs from SSE payloads instead of full refetch (BEN-49)#53
benSepanski merged 1 commit intomainfrom
claude/nifty-bardeen-IDLC6

Conversation

@benSepanski
Copy link
Copy Markdown
Owner

Context

BEN-49: src/web/Dashboard.tsx refetched /api/runs and /api/events/recent on every SSE event except usage/tick/settings, so a live run with frequent turn events caused per-event table rebuilds, flicker, and wasted bandwidth.

TL;DR

Patch the dashboard runs list in-memory from the SSE event payload; only fall back to /api/runs for unknown runIds, and use /api/runs/:id to top up token totals when a run finishes.

Summary

  • New src/web/dashboardEvents.ts — pure helpers applyTurnEvent, applyRunFinishedEvent, replaceRun, hasRun. No React deps. 11 unit tests in dashboardEvents.test.ts.
  • src/web/Dashboard.tsx::useEventStreamturn increments turnCount on the matching row in-memory; only falls back to GET /api/runs if the runId is unknown (stale tab).
  • runFinished stamps status + finishedAt immediately for instant feedback, then a single GET /api/runs/:id fills in authoritative tokens + cost via replaceRun. Recent-events feed is refreshed once per finish (so new error rows surface).
  • runStarted keeps the existing GET /api/runs fallback (rare event; SSE payload is Issue-shaped, not ApiRun-shaped).
  • docs/FRONTEND.md documents the new SSE → state convention next to the data-sources table.

Demo

n/a — automated cron run; no browser MCP in this environment. Manual smoke-test: pnpm dev WORKFLOW.md --mock, open the dashboard during a long mock run, verify devtools Network shows no GET /api/runs per turn SSE event (only on runFinished → one /api/runs/:id plus /api/events/recent), and the runs <tbody> no longer flickers / scroll-jumps as turns stream in.

Alternatives

  • Debounce the existing full refetch to ~300ms per burst — rejected: the ticket calls out incremental updates as the preferred fix and the payload already carries the runId we need.
  • Targeted /api/runs/:id on every turn — rejected: turn events fire many times per second per agent; we'd just be moving the load from /api/runs to /api/runs/:id. Pure in-memory turnCount++ is enough; authoritative tokens land at runFinished.
  • Reactive store (Zustand / Jotai) — rejected: out of scope, and a single useState<ApiRun[]> plus pure reducer matches the dashboard's existing patterns.

Test Plan

  • pnpm all — typecheck + fmt:check + lint + test + eval (131 unit + 5 eval, all green)
  • pnpm build:web — bundle builds (184ms)
  • New dashboardEvents.test.ts covers turn-increment, no-op when runId is missing, finished-status update, finishedAt-preservation when already set, replaceRun by id, and hasRun lookups.

Generated by Claude Code

The dashboard refetched `/api/runs` and `/api/events/recent` on every
SSE event except usage/tick/settings, so a live run with frequent turn
events caused per-event table rebuilds, flicker, and wasted bandwidth.

Add a small pure reducer in `src/web/dashboardEvents.ts`
(`applyTurnEvent` / `applyRunFinishedEvent` / `replaceRun` / `hasRun`)
and rewire `Dashboard.tsx` so:

- `turn` increments `turnCount` on the matching row in-memory; only
  falls back to a full `/api/runs` if the runId is unknown (stale tab).
- `runFinished` stamps `status` + `finishedAt` immediately for instant
  feedback, then a single `/api/runs/:id` fills in the authoritative
  token + cost totals via `replaceRun`. Also refreshes the recent-events
  feed once.
- `runStarted` falls back to `/api/runs` (rare, payload is `Issue`-shaped
  not `ApiRun`-shaped).

Adds 11 unit tests in `dashboardEvents.test.ts` and documents the
SSE-to-state convention in `docs/FRONTEND.md`. `pnpm all` green
(131 unit + 5 eval); `pnpm build:web` 184ms.
@benSepanski benSepanski merged commit 01530ea into main May 4, 2026
2 checks passed
@benSepanski benSepanski deleted the claude/nifty-bardeen-IDLC6 branch May 4, 2026 13:05
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.

2 participants