Skip to content

feat(ui): show the overrun counting up and route the rest period - #151

Merged
PurpleSentinel merged 1 commit into
mainfrom
feature/overrun-and-rest
Aug 20, 2026
Merged

PurpleSentinel merged 1 commit into
mainfrom
feature/overrun-and-rest

Conversation

@PurpleSentinel

@PurpleSentinel PurpleSentinel commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Part of #142 — the overrun and rest scope. The review screen and the deliberate-stop
confirmation remain open there, so this deliberately does not close it.

The gap

A session that ran out simply stopped. The countdown sat at 00:00 with nothing to say it had
ended — on a track day, the moment a driver most needs telling — and the rest period they had
configured never appeared at all.

Nothing was missing from the state machine. SessionController already modelled
overtime, session_overrun_ms, rest and rest_remaining_ms, host-tested since the rest
workflow landed. What was missing was routing: the router reduced six states to one boolean
and sent everything that was not running or overtime to the dashboard.

What it does now

Phase Clock Line beneath Colour
Session counts down lap estimate green → red ramp
Overrun counts up OVER RUN deep purple
Rest counts down REST green → red ramp

Rest is drawn on the same screen with the same fixed cells and the same ramp, because it is
the same kind of thing: a clock the driver is watching run out.

Colour chosen on contrast, not on name

Candidate Contrast vs the black panel
#6A0DAD literal "deep purple" 2.27:1
#8A2BE2 blueviolet 3.52:1
#9A4DFF chosen 4.88:1
ramp red #FF3B30 5.92:1
ramp green #2FD16D 10.46:1

Every other state on this screen sits between 5.9 and 10.5. A 10 mm numeral at 2.27:1 is hard
work in daylight, so the literal answer was the wrong one; #9A4DFF still reads as a deep
saturated purple. Trivial to darken if it looks bright on the panel.

Two decisions worth reviewing

No sign on the overrun clock. The field is five fixed cells, and a sixth would need 664 px
of a 600 px panel. The colour and the caption already say which way it counts.

Double tap passes through review. confirm_stop lands there by design, so the tap
carries on to rest programmatically rather than rearranging a tested state machine — a review
screen later inserts itself at that point. If review ever becomes a screen the driver sees,
this flow gains a stop before rest.

Double tap

Two taps rather than one because this ends a session and a stray touch in a moving car must
not. The first tap is still delivered as a press: holding it back pending a possible second
would delay every press by the 400 ms window, and the screens that act on a double tap ignore
single presses anyway.

Verification

35 host suites and 70 simulator tests, with new coverage for the counting-up format, the
caption per phase, the ratio and ramp during rest, and that the overrun colour matches no
point on the ramp.

End to end on the panel:

session start: 0 over 60 s
state=running   remaining=59935  overrun=0     rest=-1
state=overtime  remaining=0      overrun=67    rest=-1     <- by itself, at zero
session phase: overtime -> rest                            <- double tap
state=rest      remaining=0      overrun=6384  rest=1199999
session phase: rest -> ready                               <- double tap
state=ready

The 60 second session ran 60,010 ms, and there were no accidental transitions in the
seconds either side of each tap. Probe removed and its absence confirmed on the final image;
no watchdog triggers.

Still open on #142

The review screen itself, and the deliberate-stop confirmation UI. #142 stays open for them.

A session that ran out simply stopped. The countdown sat at 00:00 with nothing to say
it had ended, which on a track day is the moment a driver most needs telling, and the
rest period they had configured never appeared at all.

Nothing was missing from the state machine. SessionController already modelled
overtime, session_overrun_ms, rest and rest_remaining_ms, with the transitions between
them host tested since the rest workflow landed. What was missing was routing: the
router reduced six states to one boolean and sent everything that was not running or
overtime to the dashboard, so rest was invisible and overtime was indistinguishable
from a session still going.

The countdown field now turns round and counts up once the session is spent, and the
line beneath it stops reporting a lap estimate, which is meaningless when the session
is over, and says OVER RUN instead. Rest is drawn on the same screen with the same
fixed cells and the same green-through-red ramp, because it is the same kind of thing:
a clock the driver is watching run out.

The overrun colour is chosen on measured contrast rather than by name. The literal
"deep purple" #6A0DAD manages 2.27:1 against the black panel where every other state
here sits between 5.9 and 10.5, and a 10 mm numeral at 2.27:1 is hard work in daylight.
#9A4DFF reads as a deep saturated purple and lands beside the ramp's red.

The overrun clock carries no sign. The field is five fixed cells and a sixth would need
664 px of a 600 px panel; the colour and the caption already say which way it counts.

Double tap ends whichever clock is running because this ends a session, and a stray
touch in a moving car must not. The first tap is still delivered as a press: holding it
back pending a possible second would delay every press by the 400 ms window, and the
screens that act on a double tap ignore single presses. confirm_stop lands in review by
design, so the double tap carries through to rest programmatically rather than
rearranging a tested state machine; a review screen later inserts itself there.

Verified on the panel end to end. A 60 second session ran for 60,010 ms, transitioned
to overtime by itself at zero, moved to rest on a double tap with 20 minutes on the
clock, and returned to ready on a second, with no accidental transitions in the seconds
either side of each tap.

Closes #142

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@PurpleSentinel
PurpleSentinel merged commit 3267de7 into main Aug 20, 2026
3 checks passed
@PurpleSentinel
PurpleSentinel deleted the feature/overrun-and-rest branch August 20, 2026 13:42
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.

2 participants