History rows now carry the (filter, start, end) they were loaded for. Only
a reload for that same range keeps the rows on screen (an SSE refresh);
a filter or range change always goes through loading, and a failed load
shows the error state instead of the previous filter's rows. Replaces the
causeless silentNext flag (review finding NQ-210-1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- api/events.ts: fetch-based reader for GET /api/v1/admin/events (admin JWT
in the Authorization header via apiFetch, never in the URL), an incremental
SSE frame parser that buffers frames split across chunks and drops malformed
frames, and bounded-backoff reconnect with a clean abort on stop.
- api/useTransitions.tsx: one stream per signed-in shell (TransitionsProvider
in App) fanned out to screens; no provider means no stream.
- Today: Undo posts /instances/{id}/uncomplete, disables every Undo while in
flight, shows a dismissible message on failure, and refetches the snapshot;
any transition refetches in place. Mark done stays inert.
- History: quest transitions refetch the active filter in place; rows stay
read-only.
- Tests for parsing, stream auth/teardown/reconnect, Undo, and live refetch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>