Skip to content

Releases: jasoneplumb/cue

v0.15.0-beta

Choose a tag to compare

@jasoneplumb jasoneplumb released this 12 Sep 23:13

Promotion to beta; no code changes from 0.15.0-alpha. The field record — 11,300 shadow-compared real-world steps with zero divergences and 23/23 ride traces replaying exactly — together with the verified ablation evidence and the host fault-injection campaign no longer squares with an alpha label. The equivalence contract has held in the field; beta says so.

v0.15.0-alpha

Choose a tag to compare

@jasoneplumb jasoneplumb released this 12 Sep 18:49

A custom zone drawn over an untagged road now does what the overlay was
built for. The scorer's meaningful-absence gate rejected exactly the roads
riders draw zones on — sparsely tagged classes where OSM silence means
nothing — so a drawn zone was inert everywhere it mattered. The rider's
assertion now substitutes for the missing coverage evidence, and narrowly:
it never contradicts present tags, and the class, lane, and speed gates
still hold. RFC 0009 records the decision, the confidence ordering, and
the NFR-001 trade-off. The desk exporter also says, per zone and segment,
WHY an inert zone is inert.

Alongside it, the ablation evidence grew teeth: recorded decisions are
verified before tables publish, and a host fault-injection campaign
documents where the shadow comparison can and cannot catch drift.

Added

  • Rider-drawn custom zones satisfy the meaningful-absence gate on
    untagged, sparsely tagged roads; RFC 0009 records why personal assertion
    substitutes for coverage evidence and what confidence it earns (#39)
  • Per-zone, per-segment inertness diagnostics in cue-zone-export: each
    drawn zone reports "scores" or "INERT — why", so a rider can tell a
    broken zone from a deliberate exclusion (#39)
  • --segments <cache-dir> on cue-zone-export and cue-events-export
    reads a phone's region cache in place of an Overpass extract — no
    Overpass round-trip, no bbox disclosure, and segment ids from the exact
    region the ride ran against (#39)
  • Field-corpus verifier (tools/cue-field-verify) and a ten-scenario host
    fault-injection campaign, with committed aggregate evidence; all 23
    private traces pass — 57,783 samples, 88.1 km, 42 cues (#42)
  • Invariant tests: score ↔ rejectionReason parity across every gate
    combination, the RFC 0009 confidence identity and ordering, and the
    store → scorer custom-zone bridge end to end (#39)

Fixed

  • Ablation decision diffing compares every decision sharing a millisecond
    instead of silently keeping only the last; the verifier fails closed
    when its output directory already exists and accepts integer-typed
    booleans from non-Python producers (#42)
  • Custom-zone import error lifecycle: a stale error banner cannot survive
    a clean import, a save failure cannot be masked by zone notes, and
    import with no region loaded is refused instead of promoting an empty
    app to ready (#39)

Changed

  • cue-zone-export default output lands beside a --segments cache
    directory, never inside it (#39)
  • CI review workflow: claude-code-action 1.0.202 → 1.0.217 (#41)

v0.14.0-alpha

Choose a tag to compare

@jasoneplumb jasoneplumb released this 31 Aug 19:06

A rider can now say "this squeeze only matters going this way." Custom
zones drawn in webmap.dev carry the direction they were drawn in, and a
directional zone biases cueing only on the pass that matches it — the case
hand-drawn zones exist for, and the only way two zones on the same road
can be told apart. The kernel is untouched: RFC 0002 D5 already put the
spatial join phone-side, so the gate sits upstream of what
personal_memory[] records and a recorded ride still replays bit-exactly
through an unmodified cue_policy.c. No schema bump either.

Alongside it, four fixes on the Pico BLE and actuator path, and a
review-workflow change prompted by measuring this release's own cost.

Added

  • Directional custom zones (#30, RFC 0008): the custom-zone GeoJSON
    contract gains one optional directional boolean — absent or false
    means bidirectional, so every file exported before it existed keeps its
    exact meaning. Direction lives in the LineString's vertex order alone; a
    second bearing field could disagree with the geometry it duplicates.
    Each (zone, segment) match resolves to two bits along that segment's
    own node order, so the ride-time comparison is exact rather than a fuzzy
    bearing match, and it fits on a personal-memory record without
    disturbing RFC 0002 D7's 5 KiB budget (17 B → 18 B packed, still
    rounding to 20 B).
    • Alignment is the same side of perpendicular (90°), reusing
      RouteEventTracker.approachGateDeg's directed convention rather than
      inventing a third threshold. Deliberately wide: anything tighter drops
      legitimate cues where a road bends or on approach, and too wide a gate
      degrades only to the previous fire-both-ways behavior.
    • Direction latches per approach but only once corroborated —
      directionLatchSamples consecutive agreeing samples, the discipline
      SegmentMatcher.hysteresisSamples already applies. Latching on the
      first fix let one transient course reading gate a zone out for an
      entire approach, a suppressed cue and strictly worse than what it
      replaced.
    • Zone evidence and in-ride tap evidence are now separate record
      fields
      . A tap is about the place and applies whichever way the rider
      is going; a zone is about a direction through it. Keeping them apart
      is what lets an import be cleared without touching a rider's own
      markers — so importing a file now replaces the zone set, and deleting
      a zone from the file actually clears it.
    • cue-custom-zone-merge gates on the same bearing and the same latch,
      so a desk what-if predicts what the phone did. heading_deg_x10 is
      optional (NFR-005), so a trace without it applies directional zones
      both ways and says so; --strict refuses instead, failing before it
      writes. A bearingless segment is reported separately from a missing
      course, because re-recording fixes one and cannot fix the other.
  • DIAG reports an undelivered DECISION (#7): the MCU surfaces a
    decision the link never delivered, so a dropped report is visible rather
    than silently absent.

Fixed

  • Actuator state races the BTstack async_context IRQ (#23): actuator
    state is now synchronized against the IRQ that can preempt it.
  • ATT long-write assembly state survived a disconnect (#22): reset on
    disconnect, so a reconnecting client cannot inherit a half-assembled
    write.
  • SESSION_STOP status code and led_probe cancel asymmetry (#24).
  • Desk tools refused schema_version 2 (#6): cue-review-merge and
    cue-events-export now accept v2 traces, which the personal-memory
    feature has been emitting since 0.12.0-alpha.

Changed

  • RFC 0007 — miniaturized cue device (#28): ESP32-H2, LiPo, and the
    loudness question, recorded as a decision record.
  • Review workflow reads only the delta on follow-up rounds (#36):
    measured on #30's stack, the five test and build jobs finish in ~2
    minutes wall clock in parallel while the review job ran 11 minutes to
    76 minutes — review is effectively the entire PR wait, and every round
    re-read the whole PR even when the change since the last verdict was one
    comment. The verdict comment now carries a reviewed-sha marker and
    later rounds scope to the diff since it; --max-turns drops 25 → 10.
    The six review dimensions are unchanged — late rounds on #30 were still
    finding real defects, so this targets latency, not rigor.
  • GitHub Actions pinned to full commit SHAs; CI, release, license and C99
    badges added to the README; library.json chip keywords and community
    scaffolding synced from the working archive.

v0.13.0-alpha — initial public release

Choose a tag to compare

@jasoneplumb jasoneplumb released this 13 Aug 21:15

First public release of cue: 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.

What the contract holds on so far: 11,300 shadow-compared real-world steps with zero divergences across 8 instrumented rides; 23/23 recorded ride traces replay exactly; on-target certification on Raspberry Pi Pico W (RP2040); byte-identical decisions across x86-64 / ARM32 / RISC-V in CI.

Highlights

  • kernel/ — the whole decision layer in two C99 files: 1,016 B Cortex-M0+ text, 420 B state, 72 B worst-case stack, no allocation, no OS calls.
  • replay/ — the bit-exact replay harness (verify / author / stats), with the trace schema.
  • mcu/ — Pico W firmware port with the committed on-target pass certificate and the hiltest certification tooling.
  • docs/results.md and docs/ablations.md — aggregated field evidence and a replay-based ablation study (the notice window is the load-bearing noise gate; a distance-only window demonstrably fails the field speed range).
  • Quickstart: make test, then make demo-corpus for a synthetic, coordinate-free ride corpus the analysis tools consume on a fresh clone.

Licensed Apache-2.0. The cycling safety cue is the demonstrator; the kernel and its replay contract are the asset.