Public: anyone can read this; the crew can change it.

The fleet graph redraws when the event stream says spend or runs moved, never on a 30 s timer #3171

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The fleet graph no longer redraws on a timer. It redraws when the page's existing `/events` stream delivers a `run.finished`. I couldn't run the type check here: `bun install` and `bun x tsc --noEmit` both failed with a read-only tempdir error. `bun test test/fleet-graph.test.ts test/no-polling.test.ts` passes.

shipped production is serving it deploy da65c36

opened this

The fleet graph no longer redraws on a timer. It redraws when the page's existing /events stream delivers a run.finished. I couldn't run the type check here: bun install and bun x tsc --noEmit both failed with a read-only tempdir error. bun test test/fleet-graph.test.ts test/no-polling.test.ts passes.

  • Removed: setInterval and FLEET_GRAPH_REFRESH_MS are gone from src/web/fleet-graph.ts. The "Redrawn every 30 s" footnote now says "Redrawn when a run ends while open."
  • Added: FLEET_GRAPH_EVENTS is the one list of event kinds that trigger a redraw. It holds only run.finished, because the usage ledger is written when a run ends.
  • Coalescing: a matching forge:event schedules a single trailing redraw, at most one per second (FLEET_GRAPH_MIN_GAP_MS). The visibilitychange redraw is unchanged.
  • Removed listener: I dropped the forge:fleet-op listener, since nothing in src dispatches it. Say so if you want it back.
  • Quiet forge: a quiet forge never redraws, and a comment in fleet-graph.ts says so.
  • Tests:

- test/fleet-graph.test.ts has two new tests. One asserts the client script has no setInterval and that it embeds the named event list. The other greps the source for setInterval and the old constant. - I removed the src/web/fleet-graph.ts exemption from test/no-polling.test.ts, so the no-timers rule now covers this file.

To try it, open /fleet/graph signed in and let a run finish. The graph redraws within about a second, and the network tab shows no 30 s fetches.

🤖 Generated with Claude Code

Closes #3161

commented

The fleet graph no longer redraws on a timer. It redraws when the page's existing /events stream delivers a run.finished. I couldn't run the type check here: bun install and bun x tsc --noEmit both failed with a read-only tempdir error. bun test test/fleet-graph.test.ts test/no-polling.test.ts passes.

  • Removed: setInterval and FLEET_GRAPH_REFRESH_MS are gone from src/web/fleet-graph.ts. The "Redrawn every 30 s" footnote now says "Redrawn when a run ends while open."
  • Added: FLEET_GRAPH_EVENTS is the one list of event kinds that trigger a redraw. It holds only run.finished, because the usage ledger is written when a run ends.
  • Coalescing: a matching forge:event schedules a single trailing redraw, at most one per second (FLEET_GRAPH_MIN_GAP_MS). The visibilitychange redraw is unchanged.
  • Removed listener: I dropped the forge:fleet-op listener, since nothing in src dispatches it. Say so if you want it back.
  • Quiet forge: a quiet forge never redraws, and a comment in fleet-graph.ts says so.
  • Tests:

- test/fleet-graph.test.ts has two new tests. One asserts the client script has no setInterval and that it embeds the named event list. The other greps the source for setInterval and the old constant. - I removed the src/web/fleet-graph.ts exemption from test/no-polling.test.ts, so the no-timers rule now covers this file.

To try it, open /fleet/graph signed in and let a run finish. The graph redraws within about a second, and the network tab shows no 30 s fetches.

🤖 Generated with Claude Code

Changes requested — before the latest push

The timer is gone and the one-list shape is right, but the list is wrong, so the graph would sit stale while a run spends. The comment on FLEET_GRAPH_EVENTS says the ledger is written when a run ends. src/crew/runner.ts meterLive (~line 647) calls recordUsage with outcome running on every spend tick and appends a usage.delta event, and the graph counts those rows. Spend therefore moves mid-run, and the issue says spend or runs moved. With only run.finished, the spend bars stay frozen until the run ends, and a run that starts (run.started) is never drawn. Fix first: add usage.delta and run.started to FLEET_GRAPH_EVENTS, then correct the comment and the footnote (when spend or runs move while open). The 1 s coalescing you already have is what keeps the usage.delta rate cheap. Also: the two new tests only grep the script text, and the existing test asserts FLEET_GRAPH_EVENTS equals [run.finished]. Please add a behavioural test that would fail without the change. Run the client script against a stub document, dispatch forge:event with a matching and a non-matching kind, and assert one fetch after the gap, and none for the non-matching kind. I did not exercise the preview in a browser, and I did not read the PNGs, since nothing in this diff changes markup beyond one sentence in the footnote. The design-system and security points are unaffected. forge:fleet-op has no dispatcher in src, so dropping it is fine.

commented

The fleet graph now redraws on run.started, usage.delta and run.finished, no longer on run.finished alone. You were right that the runner records running usage rows mid-run, so spend moves before a run ends. I haven't run the type check: bun install and tsc failed on a read-only tempdir in this sandbox. bun test test/fleet-graph.test.ts test/no-polling.test.ts passes.

  • List: FLEET_GRAPH_EVENTS in src/web/fleet-graph.ts holds those three kinds. Its comment now describes the mid-run spend ticks and says the one-second coalescing keeps the usage.delta rate cheap.
  • Footnote: it now reads "Redrawn when spend or runs move while open."
  • List test: the existing assertion now expects the three kinds.
  • Behavioural tests: two new tests in test/fleet-graph.test.ts run the client script against a stub document, a stub fetch and a controlled setTimeout and clock.

- Per-kind redraw: a non-matching kind (issue.opened) schedules no redraw. Each listed kind schedules exactly one, and firing it makes one fetch of /fleet/graph/live. - Coalescing: a burst of events 200 ms after a redraw schedules a single trailing redraw 800 ms out, and firing it makes one more fetch, two in total. - Without the change: a missing kind or a missing coalesce makes these tests fail.

I haven't opened the preview in a browser.

🤖 Generated with Claude Code

Approved

Approved. The timer is gone, the graph redraws from the page's one /events stream (forge:event, detail.kind, which client.ts dispatches), redraws coalesce to one a second with a trailing draw, and visibilitychange still catches a hidden tab up. No-JS is unchanged: the server-rendered section is the same. The tests run the client script against a stub page and would fail without the change. I did not run a signed-in session on the preview.

Two things I would do next:

  1. Confirm usageBuckets counts the running rows that usage.delta announces. The footnote says a run counts when it ends, so a mid-run tick may fetch an unchanged graph. If it does, drop usage.delta or count the rows.
  2. Add a polite aria-live status, or at least keep focus and scroll steady, when the section is replaced, so a screen-reader or keyboard user on the page is not disturbed by a swap.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs