Files
Mike Schwarz 8edd4b919e live-state: an older refresh never writes over a newer one; one refresh at a time (#5)
## What a user gets

The Studio floor's finished-work list never steps back to an older answer once a newer one has been on screen.

## The race

A live-state refresh is many `rig` calls: since #3, up to ten closing-note reads, each allowed six seconds. The companion started a refresh on a fixed 10-second clock (`setInterval`), so two refreshes of one output could be in flight at once, and `writeLiveState` wrote whichever finished last. An older, slower refresh could therefore overwrite a newer snapshot, putting a closed row back at its earlier `closedAt` and result. The timer and write weakness predates #3; #3's longer read path brought finished-work history into it.

## The fix, in two parts

1. **Newer wins.** `writeLiveState` numbers each refresh when it starts, per output file. A refresh that started before one already written there is dropped: it returns its state and writes nothing.
2. **One refresh at a time.** The new `startLiveState()` schedules the next refresh only after the current one finishes, with no fixed clock. `--once` (interval 0) still runs exactly once, and `stop()` cancels. The CLI entry uses it.

What's unchanged: same-version note binding, unknown and retry behaviour, and cache bounds. `recentDone` and `buildLiveState` aren't touched.

## Tests

Two fail-first tests in `test/live-state.test.mjs`:
- an older refresh that finishes last never writes over a newer one;
- the scheduler runs one refresh at a time, and `interval 0` runs once.

Results:
- **The test file:** 14 of 14 pass with the change; 12 of 12 on main.
- **Against main's source:** the race test fails, with the older `closedAt` 22:00 shown instead of 22:02.
- **The whole suite:** `node --test test/*.test.mjs` passes 316 of 317. The one failure is `observatory-p6.test.mjs` "run from stdin as documented…", which fails the same way on main `ef7dcea` and is unrelated to this change.

## Cost

+77/-12 across 2 files: `live-state.mjs` +32/-11 and the test +45/-1. No new dependencies.

## Credit

Follows #3. The finding, fix and tests are studio-impl@studio-build's, from the race studio-qa@studio-build found while reviewing the port of #3. studio-qa accepted it, and the commit keeps its original author line.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-10-24 16:33:44 -07:00
..