The board mirror has been built and unreachable for a while. resources/data/live.ts lifts the race's state out of the page its Cloudflare Worker serves, routes/api.ts serves it at GET /api/live with a minute of caching and a 503 carrying ok: false rather than a body of zeroes — and nothing fetched it. The only consumer left was the 404 page asking whether the race was on.
/results now carries the board above the archive sections.
How it behaves
The server renders a snapshot into the page and the client refreshes it from /api/live, both through the same LivePayload — which is the thing that stops the table drifting between them.
- A static build freezes the server snapshot, so the client refuses a seed older than two minutes and waits for its first poll rather than presenting build-time standings as current.
- The section is gated on having a payload at all. Off-season — which is now; the worker currently serves no state — the page is exactly as it was, rather than carrying a box saying something is broken when nothing is.
- Polling stops once the board reports the race over.
| State | What it shows |
|---|---|
| Running | the lap, who is still in, a countdown to the next bell, a quiet no fix against a runner whose tracker has gone silent |
| Finished | the last soul and the final lap |
| Unreachable | nothing |
Ties share a position, because in this format two runners on the same lap genuinely do.
Tests
live.ts had none, despite deciding what a reader is told during a race. It has fourteen now: the ranking rules, the lap arithmetic from the gun, the winner only existing once the board says so, and an outage reporting an outage rather than an empty field. Plus the wiring — that the section is present and seeded in both the up and down cases, so a static build made off-season can still reveal the board without a rebuild.
Verified in a browser against a stubbed /api/live in both the running and finished states, including the countdown ticking.
🤖 Generated with Claude Code