Skip to content

Name the columns the Timing screen was already drawing - #71

Open
jerome-queck wants to merge 2 commits into
mainfrom
timing-screen-column-header
Open

Name the columns the Timing screen was already drawing#71
jerome-queck wants to merge 2 commits into
mainfrom
timing-screen-column-header

Conversation

@jerome-queck

Copy link
Copy Markdown
Member

Closes #70.

Twenty-five columns of figures and not one of them named on screen. A viewer could not tell Gap
from Interval, Last from Best, or which of the three Best columns belonged to which sector.

The design system had specified the header all along. web/design-system/timing-screen.html:58
defines .driver-row-header with all twenty-five labels, and
web/design-system/components/driver-row/driver-row.css already lays it on the same grid track
list as the rows — with header cells wearing the class of the column beneath, so a label cannot
drift from the figures it names. The application simply never rendered it: neither
web/timing-screen.ts nor web/index.html contained the string header. This carries it across,
which is the direction ADR-0010 asks changes to travel.

Decisions worth naming

  • The labels are one list, beside the rows that fill those columns. A static block in
    index.html would have been twenty-five strings in a second file, free to drift from the markup
    they name.
  • The header is the table's first child, as the design system lays it out. That is also what
    the row striping counts from (.driver-row:nth-child(even)), so the application's striping now
    matches the design system's reference rather than differing from it by one.
  • It carries no data-driver, so a click on it opens nobody by construction rather than by a
    guard in main.ts.

Tests

The existing test asserted column order — "Gap sits left of Interval, in the order the header
names the columns" — while no header existed to name them. It now also asserts that the header is
rendered, that it has a cell for every cell a row has, that the labels most easily confused are
present, and that clicking it opens nobody. One cell short and every label right of the gap names
the wrong column while looking perfectly plausible, so the count is the assertion that matters.

test/run, npm run typecheck and shellcheck are green, and it was checked in a browser against
the backfilled Zandvoort 2026 Practice 1 with twenty-two Drivers on screen.

Not in scope

The issue asked that the header stay put when the field scrolls. The screen does not scroll: the
density budget puts the whole field on one --screen-height: 1300px screen, which is the product's
premise. Adding position: sticky would have been building for a case the design excludes. Worth
revisiting only if the field ever outgrows the screen.

Assisted-by: Claude Opus 5 (reasoning: high)
Co-authored-by: Claude noreply@anthropic.com

jerome-queck and others added 2 commits August 21, 2026 17:02
Formula 1 has closed the legacy SignalR endpoint the upstream recorder used.
A negotiate against `livetiming.formula1.com/signalr` now answers 401 with
`WWW-Authenticate: Basic realm="Authentication"` and `Bearer`, so the live path
received nothing at all — the Ingestor sat in a reconnect loop and the broker
carried no records. The replacement, `livetiming.formula1.com/signalrcore`,
still negotiates and subscribes without a credential.

Upstream chooses between the two clients by whether `F1_TOKEN` is *set*, not by
whether its value authenticates: unset omits `--auth` and takes the dead
endpoint, set passes `--auth` and takes the live one. So the fix is to set it,
and the value is deliberately not a credential — this project holds no F1TV
token and is not becoming a system that does (ADR-0002).

Whether the free subset actually arrives over an unauthenticated connection is
the measurement ADR-0002 leaves outstanding; #42 settles it against a live
Session. This change is what makes that measurement possible at all.

Verified against the running stack: the recorder now reports `Connection
established` and subscribes to all sixteen topics, `server/live.ts` connects to
the broker, and a browser's WebSocket receives its seed frame stamped
`mode: "live"`.

Assisted-by: Claude Opus 5 (reasoning: high)
Co-authored-by: Claude <noreply@anthropic.com>
Twenty-five columns of figures and not one of them named on screen. A viewer
could not tell Gap from Interval, Last from Best, or which of the three `Best`
columns belonged to which sector.

The design system had specified the header all along —
`web/design-system/timing-screen.html` defines `.driver-row-header` with all
twenty-five labels, and `driver-row.css` already lays it on the same grid track
list as the rows, with header cells wearing the class of the column beneath so a
label cannot drift from the figures it names. Only the application never
rendered it: neither `web/timing-screen.ts` nor `web/index.html` contained the
string `header`. This carries it across, which is ADR-0010's direction of
travel.

The labels are one list beside the row that fills those columns, rather than
twenty-five strings in a second file free to drift from it. The header is the
table's first child, as the design system lays it out, which is also what the
row striping counts from; it carries no `data-driver`, so a click on it opens
nobody by construction rather than by a guard in main.ts.

The existing test asserted column *order* ("Gap sits left of Interval, in the
order the header names the columns") while no header existed to name them. It
now asserts the header is rendered and has a cell for every cell a row has —
one short and every label right of the gap names the wrong column while looking
perfectly plausible.

Assisted-by: Claude Opus 5 (reasoning: high)
Co-authored-by: Claude <noreply@anthropic.com>
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.

The Timing screen renders no column header

1 participant