Skip to content

fix(ui): make Race's running-screen rule testable and drop the delta it never drew - #231

Merged
PurpleSentinel merged 1 commit into
mainfrom
fix/219-race-lap-delta-and-running-screen
Oct 21, 2026
Merged

PurpleSentinel merged 1 commit into
mainfrom
fix/219-race-lap-delta-and-running-screen

Conversation

@PurpleSentinel

Copy link
Copy Markdown
Contributor

Closes #219.

#219 was already half fixed

#219 and #221 are the same road test, filed twice. #221 was closed by #224, which gave Race its own screen — so the headline complaint is fixed and on the device:

criterion state
current lap counting up in mm:ss.sss ✅ RaceScreen, nine cells; update_elapsed advances it on every observation
fastest lap ✅
session remaining ✅
--:--.--- before the first crossing ✅ presenter, asserted in test_ui_foundation
Track Day unchanged ✅ TrackdayScreen untouched
a decision recorded on lap_delta ❌
host tests cover Race populated and Track Day not ❌ the Race half only, at presenter level
fields repaint only when their value changes ❌ for the track name

This closes the three.

The routing was never asserted

running_screen() compared the mode to DeviceMode::race inside a private member of screen_router.cpp. That comparison is the only thing keeping a Track Day session off a screen with lap figures on it, and no test could reach it.

ui::running_screen_for(DeviceMode) now states the rule in the component, and the router asks it. The default is deliberately the withholding screen: a mode added without a thought for this rule gets the one that cannot show a lap time.

Four assertions, the last of them the one worth having:

// a mode is drawn on RaceScreen exactly when it is permitted lap times
assert((running_screen_for(mode) == RunningScreen::race) == visibility_for(mode).lap_times);

Grant laps to a mode routed to TrackdayScreen and they silently never appear — which is exactly the bug this issue reported. Route a mode without them to RaceScreen and it shows what #132 forbids. Neither can now land without failing a test.

lap_delta: the flag goes

Race was granted lap_delta when its running screen had no lap fields at all. The screen it has now shows three figures and no delta, and #58 — the reference mapping and validity rules a delta worth trusting needs — is still open.

So it is false for every mode, with a test holding it there. A permission for something nothing draws describes a display that does not exist, which is the same mistake as a plausible reading. The field stays in ModeVisibility because #58 is what flips it back.

One real repaint

set_track_name was called on every display tick, and lv_label_set_text invalidates whether or not the text differs. The armed track cannot change during a session, so that was a repaint of the widest label on the screen 25 times a second — sitting next to three lap rows that were already change-gated for precisely that reason (#213). Same gate, same place.

Verification

  • make check → CHECK_RC=0, including the four new assertions in device-mode-test
  • make firmware-container-build → FW_RC=0, 32% of the app partition free
  • Bench-verifiable: the routing and the delta decision are host tests. The track-name gate is not directly observable — it removes a repaint rather than changing a pixel, so what is checkable on the bench is that the Race screen still shows the track name it did before.
  • A lap time end to end still needs a drive, and A session interrupted by power loss is lost entirely, including its laps #222 means the re-test has to be stopped deliberately on the device before power-off.

🤖 Generated with Claude Code

…it never drew

Issue #219 and #221 are the same road test: a Race session started on pit exit,
timed laps, and showed none of them. #221 was fixed in #224, which gave Race its
own screen. Three of #219's acceptance criteria were still open.

The routing was the important one. Track Day withholding live lap times is a
compliance rule, and the screen it draws has no lap labels anywhere in it - so
the mode comparison inside the router's screen lookup was the only thing
enforcing that rule, and nothing asserted it. ui::running_screen_for states it
once, defaults to the screen that cannot show a lap time, and the tests pin it
for every mode plus the invariant that ties the two rules together: a mode is
drawn on the Race screen exactly when it is permitted lap times. Grant laps to a
mode routed to TrackdayScreen and they would never appear, which is the bug this
issue reported.

lap_delta is now false everywhere. Race was granted it when its running screen
had no lap fields at all; the screen it has shows three figures and no delta, and
the reference mapping a trustworthy delta needs is still #58. A permission for
something nothing draws describes a display that does not exist.

The Race screen's track name is written only when it changes. The router handed
it over every display tick while the armed track cannot change during a session,
and lv_label_set_text invalidates whether or not the text differs - a repaint of
the widest label on the screen 25 times a second, beside three lap rows already
change-gated for that reason (#213).

Closes #219

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@PurpleSentinel
PurpleSentinel merged commit 83ae331 into main Oct 21, 2026
3 checks passed
@PurpleSentinel
PurpleSentinel deleted the fix/219-race-lap-delta-and-running-screen branch October 21, 2026 10:13
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.

Race mode shows only the countdown: the session screen has no lap time fields

1 participant