80 lines
7.8 KiB
Markdown
80 lines
7.8 KiB
Markdown
# MOTORSIGNAL DEBUGGING MAP
|
|
|
|
This document maps common symptoms in the MotorSignal app to their specific root causes in the GNSS/Telemetry/Speedometer subsystems. Use this guide to jump directly to the responsible layer during triage.
|
|
|
|
## 1. Symptom: "Speedometer shows 0 while moving"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Permissions Issue**: If OS-level location permissions were denied or revoked, `LocationService` stream does not initialize.
|
|
- *Check*: `LocationService.hasPermissions()`
|
|
- **Deadband Overreach**: If the rider is moving slower than 1.3 MPH (0.6 m/s), `LocationService._applyEmaFilter` enforces 0.0 to prevent stationary jitter.
|
|
- *Check*: `LocationService._applyEmaFilter`
|
|
- **Validation Rejection**: The OS is sending fixes with terrible accuracy (> 80m-100m) or physically impossible acceleration, causing `LocationService._isValidPosition` to silently drop the fix instead of updating the EMA.
|
|
- *Check*: Look for `Accuracy poor` or `Impossible acceleration` logs from `_emitGpsDiagnostic`.
|
|
|
|
## 2. Symptom: "Speedometer freezes at a high speed during a tunnel/dead zone"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Signal Loss Freeze**: When GPS fixes stop arriving, `LocationService` stops emitting new positions. However, `TelemetryService._emitSample()` continues to fire at 20Hz using `_latestPosition` (which contains the last known high speed).
|
|
- *Status (RESOLVED)*:
|
|
1. **Recording Health (Phase 1D)**: `RideStateMachine._recordTelemetryEvidence()` checks `_lastSeenGpsTimestamp` and only refreshes GPS freshness when a genuinely newer GPS fix arrives. After `evidenceStaleAfterMs` (4000 ms) without a new fix, `RideStateMachine` truthfully transitions recording health to `DEGRADED`.
|
|
2. **Speed Presentation (Phase 1E)**: `TelemetrySample` now exposes `isSpeedFresh` and `freshSpeed`, evaluating the GNSS fix age against the canonical 4000 ms staleness bound. `SpeedReadout` consumes `freshSpeed` and truthfully presents `--` when GPS is stale or unavailable, preventing frozen speeds from being displayed while avoiding fabricated zero-speed measurements. When fresh GPS fixes resume, numerical speed presentation automatically recovers.
|
|
|
|
## 3. Symptom: "Speedometer lags significantly behind real-world braking/acceleration"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **EMA Tuning Conflict**: `LocationService._applyEmaFilter` uses a fast dynamic alpha (0.90) for accelerating/braking and 0.75 for cruising. If the delta threshold (> 0.4 m/s) isn't being tripped cleanly due to noisy GPS, it may stick to the slower 0.75 cruising alpha.
|
|
- *Check*: `LocationService._applyEmaFilter`
|
|
|
|
## 4. Symptom: "Leaning the bike on the kickstand records a new 'Max Lean Angle' record"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Low-Speed Gate Failure**: `RideStateMachine._processStats` restricts dynamic metrics (lean, accel, braking) to speeds `>= 3.0 MPH`. If a false GPS speed spike momentarily registers > 3.0 MPH while the bike is tilted on the kickstand, it can permanently update `state.maxLeanLeft` or `state.maxLeanRight`.
|
|
- *Check*: `RideStateMachine._processStats` (`isDynamicallyMoving = sample.speed! >= 3.0`).
|
|
|
|
## 5. Symptom: "App constantly auto-starts a ride while parked in the driveway"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Auto-Start Jitter**: `RideStateMachine._onTelemetryUpdate` promotes a `ready` state to `riding` if `sample.speed! >= 1.5`. If `LocationService` fails to enforce the 0.6 m/s (1.3 MPH) deadband correctly, GPS multipath bounce in a driveway can trigger a false start.
|
|
- *Check*: `LocationService._applyEmaFilter` deadband logic.
|
|
|
|
## 6. Symptom: "Dashboard flickers or UI lags severely during high-speed rides"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Provider Granularity Issue**: The dashboard is supposed to isolate high-frequency (20Hz) UI updates entirely within `SpeedReadout` (which uses `.select` on the telemetry provider). If an outer widget (like `ResponsiveDashboardLayout` or `DashboardScreen`) accidentally watches the root `telemetryStreamProvider` without `.select`, it will trigger 20 rebuilds per second of the entire screen.
|
|
- *Check*: `EvolutionPortraitDashboard` and `ResponsiveDashboardLayout` usage of `ref.watch`.
|
|
|
|
## 7. Symptom: "GPS Weak / Degraded indicator won't go away even with clear skies"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Pre-commit DB Failure or Watchdog Staleness**: The dashboard claims `RECORDING` or `DEGRADED` based entirely on the primary `RecordingHealthContract` in `RideStateMachine`. If `_lastDbCommitMonotonicMs` stops advancing (due to a SQLite deadlock) or `_lastAcceptedTelemetryTime` stops advancing, health defaults to degraded.
|
|
- *Check*: Database flush interval in `RideStateMachine._persistOwnedTelemetrySnapshot` and the `_evaluateRecordingHealth` watchdog loop.
|
|
|
|
## 8. Symptom: "Trip distance or moving time inflated after riding through tunnel/dead zone"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Stale GNSS Integration (RESOLVED in Phase 1F)**: When GPS fixes stop advancing, `TelemetryService` emits cached positions at 20Hz. Previously, `_movingTimeAccumulator` continued to increment based on the cached speed, and upon GPS recovery, the distance between pre-outage coordinates and post-outage coordinates could be added as an artificial catch-up jump.
|
|
- *Resolution*: `RideStateMachine._processStats` gates moving/stopped time on `sample.isSpeedFresh && _lastSample!.isSpeedFresh`. Distance and elevation require `hasFreshGps = sample.isSpeedFresh && (_lastSample?.isSpeedFresh ?? false)`. When GPS is lost, time and distance cease accumulating; upon recovery, the first fresh fix resets baseline coordinates without integrating across the outage gap.
|
|
- *Check*: `RideStateMachine._processStats` time accumulation, distance, and elevation gating.
|
|
|
|
## 9. Symptom: "Performance launch timer records anomalous 0-60 time or finishes without GPS"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Stale Speed in Performance State Machine (RESOLVED in Phase 1F)**: If GPS fixes stop during an active launch or countdown, the state machine previously retained cached speeds, allowing runs to complete across signal loss or trigger high-speed launch anomalies upon recovery.
|
|
- *Resolution*: `PerformanceLaunchStateMachine` and `PerformanceTimerService` inspect `sample.isSpeedFresh`. In `launched` or `countdown`, active runs abort immediately with `PerformanceAbortReason.gpsLost`. In `ready`, the state machine reverts to `idle`, preventing high-speed launch anomalies when fresh GPS resumes.
|
|
- *Check*: `PerformanceLaunchStateMachine._onTelemetryUpdate` and `PerformanceTimerService._onTelemetryUpdate`.
|
|
|
|
## 10. Symptom: "Compass/Heading indicator remains stuck pointing in old direction after turning into tunnel/garage"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Stale GNSS Heading Override (RESOLVED in Phase 1G)**: When GPS fixes stopped advancing while moving, `TelemetryService` continued to use the cached `_latestPosition.heading`, overriding live compass heading indefinitely.
|
|
- *Resolution*: `TelemetryService._emitSample()` gates GPS heading selection on `isGpsFresh` (4000 ms bound). When GPS fix age exceeds 4000 ms, heading immediately falls back to live hardware compass.
|
|
- *Check*: `TelemetryService._emitSample()` heading selection and `CompassService.headingStream`.
|
|
|
|
## 11. Symptom: "Map marker shows vehicle at active location when GPS signal is lost"
|
|
|
|
**Possible Causes & Investigation:**
|
|
- **Unindicated Stale Map Coordinate (RESOLVED in Phase 1G)**: `DashboardMapPanel` rendered the vehicle marker identically whether coordinates were current or stale.
|
|
- *Resolution*: `DashboardMapPanel` watches `s.value?.isGpsFresh`. When stale, the marker is dimmed and a subtle `LAST KNOWN LOCATION` badge is displayed, preserving the last-known position truthfully without fabricating position.
|
|
- *Check*: `DashboardMapPanel` and `TelemetrySample.isGpsFresh`.
|