Skip to content

feat(ui): add a TRIGGER menu and start the session on a launch - #158

Merged
PurpleSentinel merged 1 commit into
mainfrom
feature/session-trigger-and-preselect
Aug 20, 2026
Merged

PurpleSentinel merged 1 commit into
mainfrom
feature/session-trigger-and-preselect

Conversation

@PurpleSentinel

Copy link
Copy Markdown
Contributor

Closes #155. Closes #157.

What it does

TRIGGER sits between TRACK and SETUP — both are set at the circuit before going out, rather
than buried among the rarely-touched options.

Trigger START Then
MANUAL begins the session as before
IMU arms, showing PENDING starts on forward acceleration reaching LAUNCH
GPS arms, showing PENDING starts at the line — wired, no receiver yet

The LAUNCH setting was stored, editable, and read by nothing. It now has a purpose.

Forward acceleration only

A launch is acceleration down the road, so braking, cornering and kerb strikes cannot start a
session — there's a test asserting −3 g does not fire. GravityCalibration::resolve
already returns exactly this, gravity removed and resolved into vehicle axes, with the
attitude tracking from #143 keeping it honest under body roll.

TRIGGER owns pit-exit auto-start

pit_exit_auto_start_enabled already meant "start when the car leaves the pits", with tested
automation behind it. GPS derives it, and the boolean leaves the device settings list —
offering one behaviour in two places invites the two disagreeing, the rule Mode set in #132.
The tested automation is reused unchanged; the trigger is simply the only thing that writes
it now. pit_entry_auto_stop_enabled is untouched: ending a session is a different question.

A trigger that cannot fire is worse than no trigger

The device would just sit there. LAUNCH at zero means off, so IMU refuses to arm and says
SET LAUNCH G TO ARM; GPS refuses with GPS UNAVAILABLE. Both report rather than waiting
silently. Confirmed on the panel.

Two defects found on the way

Section menus opened on their first item. Returning to TRIGGER showed MANUAL however IMU
was set — and the same was true of Mode and Track, which the carousel title partly hid for
Mode by showing the live value beside the wrong highlight. The value level already resolved
its current entry and called select_value; the section level had no equivalent to call.
Tracks match by identifier, not a remembered position, since the catalog is rebuilt from
the card at boot.

The menu carousel was passed a count of 4 against 5 entries, so Diagnostics was selectable
by the shell and never drawn. Pre-existing; adding TRIGGER would have made it worse. A
static_assert now ties the array to kMenuItemCount.

Design notes

Arming lives in the router. A pending session is one that has not been started yet, so
SessionController needs no new state and stays as tested. Double tap disarms — the same
gesture that ends a session and ends a rest period.

Settings reach v6. Everything before it predates the trigger, so migrating defaults to
MANUAL, which is what those devices were doing.

Verification

36 host suites and 70 simulator tests, with a new suite covering the ownership of pit-exit
auto-start, every refusal-to-arm case, and forward-only launch detection including the braking
and zero-threshold cases.

Confirmed on the panel end to end: the refusal at LAUNCH 0, arming after setting it, a real
launch starting the session, double tap disarming, and GPS reporting no receiver.

Follow-up

#156: as forward acceleration a car reaches roughly 0.3–1.0 G, but the LAUNCH ladder runs
0, 0.5, 1.0, 1.25 … 4.0, so six of ten choices can never fire and the useful region below
0.5 G is not offered. Not changed here because valid_launch_sensitivity whitelists exact
values, so a new ladder invalidates stored settings and resets everything — it needs a
migration of its own.

START was the only way to begin a session. A driver leaving the pits had to press it at
the right moment, which is a poor thing to ask of someone joining a circuit, and the
LAUNCH setting that should have automated it was stored, editable, and read by nothing.

TRIGGER sits between TRACK and SETUP, because both are set at the circuit before going
out rather than buried among the rarely-touched options. MANUAL behaves as before. IMU
and GPS arm the timer instead, showing the session screen with the clock held at the
configured duration and PENDING where the lap estimate goes, so the driver can see the
device is ready and waiting rather than wondering whether the press registered.

The IMU trigger reads forward acceleration only. A launch is acceleration down the road,
so braking, cornering and kerb strikes cannot start a session; a test asserts that -3 g
does not fire. GravityCalibration already returns exactly this, gravity removed and
resolved into vehicle axes, with the attitude tracking keeping it honest under body roll.

TRIGGER owns pit_exit_auto_start_enabled rather than sitting beside it. That setting
already meant "start when the car leaves the pits", with tested automation behind it, so
GPS derives it and the boolean leaves the device settings list. Offering one behaviour in
two places invites the two disagreeing, which is the rule Mode established.
pit_entry_auto_stop_enabled is untouched: ending a session is a different question.

A trigger that cannot fire is worse than no trigger, because the device simply sits
there. LAUNCH at zero means off, so IMU refuses to arm and says so; GPS refuses because
no receiver exists. Both report rather than waiting silently.

Arming lives in the router. A pending session is one that has not been started yet, so
SessionController needs no new state and stays as tested. A double tap disarms, the same
gesture that ends a session and ends a rest period.

Also fixes two things found on the way. Section menus opened on their first item rather
than the one in force, so returning to TRIGGER showed MANUAL however IMU was set - and
the same was true of Mode and Track, which the carousel title partly hid for Mode by
showing the live value beside the wrong highlight. The value level already resolved its
current entry and called select_value; the section level had no equivalent to call.
Tracks are matched by identifier rather than a remembered position, since the catalog is
rebuilt from the card at boot. Separately, the menu carousel was passed a count of four
against five entries, so Diagnostics was selectable by the shell and never drawn; a
static_assert now ties the array to the shell's count.

Settings reach v6 for the trigger. Everything before it predates the trigger, so
migrating defaults to MANUAL, which is what those devices were doing.

Closes #155
Closes #157

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@PurpleSentinel
PurpleSentinel merged commit f5d6f48 into main Aug 20, 2026
3 checks passed
@PurpleSentinel
PurpleSentinel deleted the feature/session-trigger-and-preselect branch August 20, 2026 17:23
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.

Section menus open on the first item, not the one currently in force Add a top-level TRIGGER menu: manual, IMU launch, or GPS line crossing

2 participants