604d61ebb2
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>