One tap before the squeeze.
A deterministic decision kernel with a field-enforced equivalence contract: the same C file runs live on a phone, as an MCU actuator, and in offline replay, and all three must agree, bit for bit, on every decision. On the field corpus so far the contract holds over 11,300 shadow-compared real-world steps with zero divergences, and 23/23 recorded ride traces replay exactly (field results; why it's built this way).
The demonstrator is a context-aware cycling safety cue. An iPhone + Apple Watch prototype combines map context, GPS, rider motion, and explicit rider feedback to warn a cyclist with one low-distraction haptic tap 5–20 seconds before entering a "squeeze zone" (narrow lane, no shoulder or bike lane, high-speed mixed traffic). After the ride, the rider grades each cue (useful, false alarm, too late, unrecognized) and replayable traces tune the policy offline.
The bike is the demonstrator. The reusable asset is the pipeline:
sensor input → feature extraction → local decision → low-latency cue
→ field logging → replayable validation → MCU migration
| Contribution | Sole author: decision kernel and equivalence contract, replay harness, phone↔MCU shadow-comparison protocol, trace format, aggregation and ablation tooling, MCU ports. AI-assisted implementation gated by the tests, replay, and hardware-in-the-loop checks described below. Platform SDKs and map data are third-party. |
| Status | Working demonstrator on private hardware. Not a product, not a safety device, no users but the author. |
| Results | 23/23 traces replay exactly; 11,301 steps logged, 11,300 compared, 0 divergences across 8 instrumented rides, over a 23-trace/88.1 km/57,783-step corpus recorded 2026-07-20 to 2026-08-08. Re-verified 2026-09-12 against a tree identical to dd8a7db25522734de1dbec614f66113c69d80dcb. Field results · re-verification · case study |
| Reproduction | The ride corpus is private (NFR-005), so a fresh clone cannot reproduce the field figures. It can run the machinery: make test, make demo-corpus, then python3 tools/cue-results/aggregate.py demo-rides and python3 tools/cue-ablation/ablate.py demo-rides over a synthetic, coordinate-free corpus. |
| Limitations | Agreement is consistency, not correctness: three runtimes share one kernel and therefore share its defects. One logged step was never compared. 22 of 49 watch dispatches have no recorded live delivery. Rider grades cover 33 cues from one rider. Ablations are counterfactual replays over fixed trajectories, not measured rider responses. Nothing here measures safety. |
Cyclists need attention cues before road geometry compresses their options. A
warning inside the squeeze zone is too late; a warning that fires too often is
noise. The cue policy gates on severity, confidence, and time-to-event, with
cooldown and speed suppression, and emits at most one HEAD_UP cue per route
event. Missed coverage is preferable to noisy cueing.
The system starts phone + wearable so the live cue loop can be field-tested quickly. The decision layer is a deterministic, allocation-free C kernel that replays recorded traces first and migrates to an MCU evaluation board later, making the demo a vendor-facing decision-layer reference architecture, not just a consumer app. There is no learned model anywhere in the pipeline: the cue policy is a hand-written, integer-only rule gate, which is what makes its decisions bit-exact replayable.
┌──────────────────────┐ ┌────────────────┐ ┌───────────────────────┐
│ iPhone prototype │─────►│ Apple Watch │─────►│ MCU ports │
│ ride logging │ │ one haptic │ │ portable cue-policy │
│ GPS cleanup / map │ │ cue │ │ kernel │
│ matching │ │ marker │ │ replay trace harness │
│ squeeze events │ │ confirmation │ │ hiltest-certified: │
│ cue-policy exec │ │ low- │ │ Pico W · ESP32-S2 │
│ after-ride review │ │ distraction │ │ BLE ride link + │
│ replay trace export │ │ output │ │ buzzer cue (RFC 0006)│
└──────────────────────┘ └────────────────┘ └───────────────────────┘
Shared spine: normalized samples + route events + cue decisions + reviews
Map matching and route-event generation stay phone-side in the first architecture. Only normalized samples, compact route events, and the cue-policy kernel move toward MCU evaluation boards.
make test # kernel, replay, MCU host tests + the minimal example
make demo-corpus # synthetic, coordinate-free ride corpus → demo-rides/
python3 tools/cue-results/aggregate.py demo-rides # the results tables
python3 tools/cue-ablation/ablate.py demo-rides # the ablation sweepEmbedding the kernel is two files: kernel/cue_policy.h and
kernel/cue_policy.c (C99, integer-only, no allocation, no OS calls).
examples/minimal is the whole API in ~40 lines;
PORTING.md covers taking it to an MCU, and
kernel/CMakeLists.txt / library.json cover CMake and PlatformIO embeds.
| Path | Purpose |
|---|---|
docs/rfcs/ |
Architecture decision records |
examples/ |
Minimal kernel embedding (built + run in CI) |
fuzz/ |
libFuzzer harness for the trace-JSON tokenizer |
ios/ |
iPhone + Watch prototype: app + watch targets, SPM packages (map import/scoring, matcher, ride engine, watch link) |
kernel/ |
Portable C cue-policy kernel (cue_policy.h) + tests |
mcu/ |
Pico W firmware port + on-target certification (hiltest) |
replay/ |
Replay harness (replay_cli) + replay_trace.schema.json + example traces (FR-010) |
tools/ |
Desk tools: results aggregator, ablation sweep, demo-corpus generator, OSM tag audit, GPX ride simulator |
- Phase 0 - Design record. Establish the design record (kept in the private working archive); adopt repo conventions. (done)
- Phase 1 - Vertical slice. Ride logging, composite squeeze-zone events, cue policy, watch haptic, after-ride review, trace export (FR-001…FR-009). (code complete: all nine RFC 0003 deliverables merged)
- Phase 2 - Replay loop. Portable kernel + replay harness reproduce recorded cue decisions deterministically (FR-010, NFR-003). (done, and verified against the first field trace)
- Phase 3 - Field proof. Three-ride engineering proof, then ten-ride case study with before/after policy comparison. (in progress: 23-trace / 88 km corpus, 13 graded rides; see docs/results.md)
- Phase 4 - MCU migration. Board-neutral migration matrix (done); on-target certification live on two silicon families: Pico W (RP2040) and ESP32-S2 (Xtensa), with committed pass certificates in
mcu/hiltest-runs/(done; further ports tracked as issues).
See docs/README.md for the full documentation index,
docs/results.md for the aggregated field results
(reproducible via tools/cue-results/aggregate.py), and
docs/design-aspects.md for the decision-layer
design walkthrough: seven design decisions, each with reasoning, value, and
tradeoff. The
authoritative requirements live in the project's design record, which stays
in the private working archive; its requirement IDs (FR-xxx / NFR-xxx) are
the shared vocabulary used throughout this repo and its RFCs.
To view exported rides on a map (squeeze zones plus per-ride cue events on webmap.dev's overlay pair), see docs/webmap-overlays.md. To grade the cues a ride fired and merge the grades back into its trace, see docs/grading-guide.md.
See CONTRIBUTING.md for development workflow and guidelines.
Copyright © 2026 Jason E. Plumb.
Licensed under the Apache License 2.0.
BTstack note for integrators: mcu/pico-cue builds against
BTstack via the pico-sdk, which is
free for open-source use but requires a commercial license from BlueKitchen
for commercial products. This repository vendors only its own
btstack_config.h (Apache-2.0), so the repo's license is unaffected, but a
commercial firmware build inherits BTstack's terms.
The live loop runs end to end: the iPhone app imports a real OSM region,
scores composite squeeze zones, matches GPS to segments, and runs the same
C kernel live that replay_cli runs offline. Cues deliver via the watch
haptic and (since RFC 0006) a Pico W buzzer that executes the kernel
on-board while the phone shadow-compares every step. Rides export schema-v2
traces, graded after the ride and fed back into the spec §13 tuning loop.
Field record so far (docs/results.md): 23 traces, 88.1 km, 57,783 kernel steps; 11,300 phone↔Pico shadow-compared steps with zero divergences; 23/23 traces replay bit-exact. The replay harness doubles as a research instrument (docs/ablations.md). The kernel is hiltest-certified on two silicon families: Pico W (RP2040) and ESP32-S2 (Xtensa LX7), with committed pass certificates, and CI proves byte-identical decisions across x86-64, ARM32, and RISC-V on every push.
Repo conventions adapted from infobento.com.