Repository navigation
Gate capture cannot be opened on the device, so no circuit can be promoted out of provisional #204
Description
Objective
Make gate capture reachable on the device. It is built, host-tested, wired into the
simulator, and there is no way to open it on the hardware.
This is the last thing between the device and a timed lap
The chain is complete except for one link:
- No circuit can arm timing, because every one in the UK pack is provisional (No circuit in the UK pack can arm timing: all 24 are provisional #139)
- A provisional circuit is promoted by capturing its geometry on the device (Define a Test Circuit: a fixed road loop for end-to-end timing, GNSS and logging tests #184)
- The capture screen exists and cannot be opened on the device
So no lap has ever been timed, and the whole timing chain - engine, lap state machine,
crossing validation, interpolation, logger - remains unproven against reality. All of it is
host-tested. None of it has seen a real crossing.
What is already there
firmware/components/ui/gate_capture.cpp GateCaptureController, 13 states
firmware/components/ui/gate_capture_screen.cpp GateCaptureScreen, 6 actions
tests/cpp/test_gate_capture.cpp host tests
simulator/src/application_screen.cpp 31 references, fully wired
firmware/main/ 0 references
The two ends that matter are already correct, which is worth stating because they are what
make this worth doing rather than rebuilding:
gate_capture.cpp:172setsgeometry_status = device_capturedon save, so a captured
circuit is promoted out of provisional and will arm timing.SdTrackStore::write_atomicwrites into thedevice-capturedpack rather than over the
distributed one, so a capture can never be confused with shipped data and wiping a
downloaded pack cannot delete your own work.
Nothing in the capture logic needs changing. This is wiring.
Scope
- A way in. Recommended: a new
SETUPentry,CAPTURE GATES, operating on the circuit
currently loaded. The simulator enters from its track-selection screen through
TrackSelectionAction::capture_information, but the device's track list is a
carousel with no equivalent action, and "load the circuit, then capture its gates" is
the clearer mental model anyway - A screen root and a
GateCaptureScreen, as the other full-panel screens are built - Route the six
GateCaptureActions - previous gate, next gate, toggle endpoint,
capture, save, cancel - Feed
update_fix()from the GNSS pipeline, so accuracy, fix age and the captured
coordinate are live - Hand it the existing
track_store_and the session-active flag, so capture is
refused while a session runs and while moving - Reload the catalogue and re-apply the track after a successful save, so the newly
captured circuit arms without a restart - Log the outcome. A capture that silently did not save is the failure most likely to be
discovered at the circuit rather than in the paddock
The button question, and the recommendation
GateCaptureScreen is a button panel - button_for(), add_buttons_to_group() - from
the UI generation before #128 reworked everything into press-and-hold carousels. Every
other full-panel screen on the device is gesture-driven.
Two options:
- Wire it as it is. Fast, and it works. Inconsistent with the rest of the device.
- Rebuild it in the carousel idiom first. Consistent, and considerably more work before
anything can be captured.
Recommendation: (1), and say so in the issue that follows. This screen is used stationary,
in a paddock, with the car switched off - which is the one place on this device where a
button panel is not a liability. Getting a circuit captured is worth more right now than
getting it captured consistently, and the consistency work is easier to judge once somebody
has actually used the screen in the field.
Acceptance criteria
- A user can open gate capture on the device, with no rebuild
- All four gates and both endpoints of each can be captured and saved
- Capture is visibly refused while a session is active or the car is moving
- An invalid or partial capture never replaces a valid definition
- After saving, the circuit reads as
device_capturedand timing arms -
make checkand the simulator suite pass
This also reopens the question #108 was closed on
#108 "Capture and persist four circuit gates safely on device" was closed in August with the
acceptance criterion "a user can capture, validate, save, reload, and select all four lines
without rebuilding firmware". That criterion is not met and never was on the device - the
same shape of premature close as #18, where the work was built and host-tested and nothing
called it.
Worth deciding whether #108 reopens or stays closed with this issue carrying the remainder.
Not in scope
- Rebuilding the capture screen in the carousel idiom
- Changing any capture, validation or persistence logic. It is written, tested, and its two
critical behaviours - promoting provenance and writing to a separate pack - are already
right - Capturing while moving. Deliberately refused
Activity
feat(ui): make gate capture reachable on the device (#205)
PurpleSentinel commentedon Oct 21, 2026
Decision on #108
#108 stays closed. This issue carries the remainder.
Reopening it would split one piece of work across two issues: #108's criterion ("a user can capture, validate, save, reload, and select all four lines without rebuilding firmware") and this issue's criteria are the same criterion, and it is this issue that has the wiring, the counts and the refusal reporting attached to it. A closed issue that was closed early is a matter of record; two open issues describing the same unverified capture would be a matter of confusion at the circuit.
What #108 got wrong is worth keeping as the lesson rather than as an open ticket: it was closed on work that was built and host-tested and called by nothing. Same shape as #18, #204, #214, #219 and #222. The remedy is the acceptance criteria on this issue staying unticked until a capture happens on hardware — which is also why #232 refs this issue rather than closing it.
State of this issue after #232
Done:
SETUP→CAPTURE GATES, on the circuit already loaded (feat(ui): make gate capture reachable on the device #205)GateCaptureScreen, six actions routed (feat(ui): make gate capture reachable on the device #205)update_fix()fed from the pipeline every tick (feat(ui): make gate capture reachable on the device #205)track_store_and the session-active flag handed over (feat(ui): make gate capture reachable on the device #205)Still open, and only provable at a circuit:
device_capturedand timing armsEverything short of a valid save is now checkable on the bench: capture four endpoints anywhere, press
SAVE, and the refusal readsAN ENDPOINT IS OUTSIDE THIS CIRCUIT'S GEOFENCEwith nothing written to the card. A successful save is impossible away from the circuit by design, which is the whole reason this issue cannot be closed from a desk.