Files
on_the_level/app
thejayman77 604d61ebb2 Voice init-race fix + velocity-aware Surface lock
Voice (final P1 from audit): the policy is no longer consumed until TTS is
ready, so a phrase can't be queued and then spoken stale after init. When
ready, the policy evaluates the CURRENT reading (silent if moving, correct
instruction if settled). VoiceSpeaker drops its pending-text queue and just
exposes isReady; the policy is remember(speaker) so each VOICE session starts
fresh. Covers all of Codex's cancellation cases (movement, unlock, invalid
placement, foreground loss, mode change, shutdown).

Velocity-aware Surface lock (Jay's observation + Codex): the fixed 400 ms
dwell made a slowly-arriving bubble wait, delaying the level sound, while a
fast crossing could still lock. LockDetector now takes a movement rate:
- error <=0.2 deg AND rate <=0.3 deg/s -> lock after a short 175 ms confirm;
- faster than that -> dwell never accumulates (a center fly-through never
  locks); slowing to a stop inside the zone starts a fresh confirmation;
- 0.35 deg exit hysteresis and the single shared lock (sound/lime/haptic)
  unchanged.
LevelPipeline feeds SettlingDetector.movementRateDegreesPerSecond (was
discarded); Edge passes null -> classic fixed 400 ms dwell. Simple gated
machine, no adaptive-dwell formula.

Tests: slow-entry-locks-promptly, fast-traversal-never-locks, intermediate-
speed-no-accumulate, slowing-inside-zone-fresh-dwell, exit hysteresis,
feedback debounce, Edge fixed-dwell fallback. 82 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 10:27:47 -04:00
..