Files
yaris-obd/BUGS.md
T

215 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# yaris-obd Bug Tracker
Standalone bug/issue tracker for the yaris-obd project, kept **separate from `PLAN.md`**. Use this
file to record, track status, and hand off bugs to another agent/session. `PLAN.md` still summarizes
bug-fix progress in its phase sections (and Phase 26 is the dedicated road-test bug-fix phase), but
the authoritative, issue-by-issue record lives **here**.
## How to use this tracker
- **File format**: one `## BUG-XX` section per issue. Keep the numbering sequential.
- **Status field**: `OPEN` → `IN PROGRESS` → `FIXED` (commit ref) → `CLOSED` (deployed + verified)
or `WONTFIX`/`DUP` as appropriate.
- **Relate to phases**: each entry's `Phase` field links a bug to the relevant `PLAN.md` phase so an
agent can find the surrounding context and acceptance criteria.
- **When fixed**: keep the original symptom/impact recorded (don't delete history), set status to
`FIXED`, add the commit SHA in the `Fix` field, then move to `CLOSED` after deploy/verify. Also
drop a one-line mention in the corresponding `PLAN.md` phase.
- **For future bugs**: add new `## BUG-XX` entries here rather than only burying them in chat
history. Keep them SMALL and one-issue-per-entry so they are easy to pick up and verify.
---
## Open bugs
### BUG-01 — WiFi/hotspot unreachable from phone while cell data is on (and wrong documented gateway)
- **Status**: `OPEN`
- **Severity**: Medium (usability of the in-car hotspot from a phone)
- **Area**: Networking / Pi hotspot (`yaris-uplink`, NetworkManager shared AP, docs)
- **Phase**: Phase 26
- **Symptom**: While a phone is connected to the Pi's no-internet hotspot and cell data is on, the
phone cannot load `yaris.local`, `10.42.0.1`, **or** the Pi's DHCP address at all. With cell data
disabled, `http://<dhcp-ip>/` loads, but `yaris.local` and `10.42.0.1` still do not. The working
address seen was `10.112.<...>`.
- **Root cause (confirmed)**: Phone-OS "smart network switching" — with a no-internet WiFi network
associated and cellular available, the OS keeps cellular as the whole-device default route, so no
traffic (even a plain page navigation or `fetch()`) reaches the Pi hotspot. Disabling cell data
forces the hotspot WiFi to become the default network. This is the same OS-level ceiling
documented in Phase 11/22. Separately, the actual NetworkManager shared-AP subnet is `10.112.0.x`,
**not** the documented `10.42.0.1`, and `yaris.local` mDNS isn't resolved from the phone on the
Pi AP.
- **Fix scope / actions**:
- Make the documented/reachable address correct (surface the Pi's real DHCP-assigned address in
the UI / status page rather than hardcoding `10.42.0.1`).
- Extend the `yaris.local` unicast (shared-dnsmasq) fallback to the AP subnet so it resolves from
a phone on the Pi hotspot.
- Clearly document the cell-data limitation and the workaround (disable cell data / "smart
network switching").
- **Acceptance**: phone on the Pi hotspot can load the web UI via a documented, correct address
(optionally `yaris.local`), and the cell-data caveat is documented.
---
### BUG-02 — Micro-USB power port on the Pi is physically damaged
- **Status**: `OPEN`
- **Severity**: Hardware (reliability/power)
- **Area**: Hardware / power
- **Phase**: Phase 26
- **Symptom**: The Pi's micro-USB 5V power connector is worn/damaged and no longer makes a reliable
connection. Power is likely to drop under vibration in the car.
- **Root cause**: Physical wear on the connector.
- **Fix scope / actions**: No code. Owner hard-wires 5V and GND directly to the Pi's GPIO header
(pins 2/4 for 5V, 6/9/14/20/25/30/34/39 for GND) with a suitable PSU, bypassing the micro-USB
port. Confirm `vcgencmd get_throttled` shows no current undervoltage after rewiring (the Phase
19/20 alerts monitor this).
- **Acceptance**: Stable power with no undervoltage/throttling under load.
---
### BUG-03 — DTC/MIL codes are never persisted; lost on OBD disconnect or reboot
- **Status**: `CLOSED` (commit `e2f2314`; deployed + verified 2026-08-11)
- **Fix**: Persist MIL + codes to SQLite on each poll (`save_dtc_state`), `/api/dtc` falls back to
the persisted snapshot when OBD is offline, `get_overview_stats` counts the real `dtc` table,
and a schema migration rebuilds the unused `NAME/STATUS/DTC_ID` table. Cleared codes are tracked
via `IS_SET` + `FIRST_SEEN_AT`/`LAST_SEEN_AT`. Tests: `tests/test_dtc_persistence.py`.
- **Severity**: Medium (lost diagnostic data; also a stats bug)
- **Area**: `modules/app_obd.py`, `modules/app_sql.py`, `get_overview_stats`
- **Phase**: Phase 26
- **Symptom**: Stored DTC trouble codes and MIL state live only in the in-memory `dtc_codes` global
in `app_obd.py`. They vanish as soon as OBD disconnects or the Pi reboots. Separately,
`get_overview_stats` queries a table named `dtc_codes` that does not exist (the created table is
`dtc`), so the post-road-test state may be wrong/broken.
- **Root cause**: The SQLite `dtc` table is created in schema but is never written to or read from
by any code path. No DTC persistence exists at all.
- **Fix scope / actions**:
- Persist MIL + DTC codes to the `dtc` SQLite table on each successful poll.
- Read back from SQLite when OBD is disconnected so last-known codes stay visible.
- Fix `get_overview_stats` to query the real `dtc` table (and use current MIL/DTC state).
- Add a "cleared/since" concept so a code that was cleared is distinguishable from one still set.
- **Acceptance**: Codes set during a drive survive a power cycle / OBD disconnect and appear on the
DTC page and overview stats.
---
### BUG-04 — Server merges two separate trips into one (motion boundary mismatch)
- **Status**: `CLOSED` (commit `96fb897`; deployed + verified 2026-08-11)
- **Fix**: Replaced pure time-gap splitting with Pi's motion-aware logic: OBD speed > 1 km/h
primary, GPS displacement >= 8 m (3 consecutive) fallback, 5-min inactivity gap. Server
trips cleared and recomputed: 17 trips on both Pi and server.
---
### BUG-05 — Server route replay reports `speed_source: "gps"` even when OBD speed is present
- **Status**: `CLOSED` (commit `e2f2314`; deployed + verified 2026-08-11)
- **Fix**: `get_trip_route` now mirrors the Pi's logic: `"obd"` when speed > 0, otherwise `"gps"`.
Server docker container rebuilt and health-checked.
---
### BUG-06 — Server timestamps are shifted (Postgres stores naive local time as UTC)
- **Status**: `OPEN`
- **Severity**: High-ish (all server trip times / boundaries off by the EDT offset)
- **Area**: Pi upload (`modules/app_upload.py` / SQL), `server/sql`, `server/modules/db.py`, portal
display
- **Phase**: Phase 26
- **Symptom**: Server shows trip times (and effectively trip boundaries/comparisons against the Pi)
shifted by the Montreal-timezone-to-UTC offset (~4-5 hours depending on DST).
- **Root cause**: `tracking_points.recorded_at` is `TIMESTAMPTZ`, but the Pi sends **naive local
(Montreal) time** (`datetime.now()`) with no offset. Postgres (UTC container timezone) interprets
that naive string as UTC.
- **Fix scope / actions** (delicate — touches sending, storage, and display):
- Pi should send timezone-aware timestamps in local Eastern time (or explicit UTC).
- Server should store/read as `America/Toronto` (or consistent UTC) and display in Eastern.
- Optional one-time migration to correct already-stored rows (depends on offset at insert time —
needs a decision: re-map by DST window or accept a best-effort correction). Rebuilding the
server `trips` table may be needed. **Get owner sign-off on migrating existing data.**
- **Acceptance**: New data displays at the correct local time on the portal; existing shifted rows
are corrected (or explicitly accepted as-is if the owner opts out of migration).
---
### BUG-07 — Trip replay on the portal sometimes does nothing
- **Status**: `OPEN` (needs reproduction/diagnostics)
- **Severity**: Low/Medium (intermittent UI)
- **Area**: `static/js/history.js` (shared Pi+server), server `/api/v1/portal/trip/<id>`
- **Phase**: Phase 26
- **Symptom**: Clicking a trip to replay on the `/history` page intermittently does nothing — no
route renders, no error shown.
- **Root cause**: Not yet isolated. Plausible contributors: an API/DB race (`recompute_trips`
running concurrently with a route read), DB lock, or clicking before the map is ready. Note
`history.js` uses shared parsing that expects space-separated Pi timestamps and `"T"`-separated
server ones — verify both.
- **Fix scope / actions**: Add targeted diagnostics (log/reproduce) before fixing. Check map
readiness, error handling on the trip-fetch, and the shared timestamp parsing. Add an explicit
"failed to load route" state instead of silent inaction.
- **Acceptance**: Replay is reliable; any failure surfaces a visible error rather than doing
nothing.
---
### BUG-08 — No trip deletion on the local Pi (only on the remote portal)
- **Status**: `CLOSED` (commit `c5c478b`; deployed + verified 2026-08-11)
- **Fix**: Added `deletable` param to `data_table` macro, `window.confirmDelete` helper in
`base.html`, `DELETE /api/trip/<id>` route + `app_sql.delete_trip()`, and configurable
`data-delete-url` in `history.js` (shared Pi+server). Trip 1967 deleted, 18→17 trips,
2028 tracking rows preserved.
---
### BUG-09 — Server trip scrubber geocoding is slow on each step
- **Status**: `OPEN`
- **Severity**: Medium (UX)
- **Area**: `static/js/history.js` `showReplayPoint()` / `scheduleGeocode()`
- **Phase**: Phase 26
- **Symptom**: Scrubbing through the trip timeline on the server portal is sluggish — the location
name takes a long time to appear because each scrub step fires a fresh `/api/geocode` HTTP
request (debounced 600ms). On the Pi this is fast (offline reverse_geocoder), but the server
calls Nominatim which adds latency.
- **Root cause**: Every `showReplayPoint()` call triggers `scheduleGeocode()` → debounced
`fetch(/api/geocode...)`. No pre-caching or batch loading.
- **Fix scope / actions**: Pre-fetch geocode results for ALL trip points when the route is first
loaded. Store in a local JS map keyed by rounded coordinate. Show cached label instantly during
scrubbing. Only fall back to live fetch for uncached points. Optionally batch-geocode at the
server API level too (accept multiple lat/lon pairs).
- **Acceptance**: Scrubbing through trip replay shows location names near-instantly.
### BUG-10 — GPS-only false trips generated when car is not connected
- **Status**: `OPEN`
- **Severity**: Medium (data quality)
- **Area**: `modules/app_trip.py` `build_trip_summaries()`, `modules/app_sql.py` `refresh_trips()`
- **Phase**: Phase 26
- **Symptom**: The Pi generates trips from GPS data alone (GPS jitter/drift) even when the car
isn't connected. Since the Pi bench-tests with no OBD, GPS displacement fallback creates
phantom "trips" from stationary GPS noise.
- **Root cause**: The GPS motion fallback (3+ consecutive 8m displacements) can be satisfied by
GPS jitter over time, especially indoors or in weak-signal areas. The system doesn't gate trip
detection on whether OBD was ever present.
- **Fix scope / actions**:
- **Option A (strict)**: Only start trips when OBD wheel speed has been detected at least once
since the app started (a `car_was_connected` flag). No OBD ever = no trips, even with GPS.
- **Option B (lenient)**: Increase GPS motion requirements when OBD has never been seen (e.g.
require 10+ consecutive displacements of 20m+ instead of 3×8m).
- **Recommend Option A** — it matches the real-world use case: the Pi is powered by the car's
ignition, so OBD should always be reachable when the car is running. No OBD = bench test,
don't generate trips.
- **Acceptance**: Bench-testing the Pi (no car connected) produces zero trips. Real driving with
OBD connected still produces correct trips.
---
## Resolved bugs
### BUG-03 — DTC/MIL codes are never persisted; lost on OBD disconnect or reboot
- **Status**: `CLOSED` 2026-08-11
- **Commit**: `e2f2314`
- **Verification**: Deployed to Pi, service restarted clean, `/api/dtc` returns persisted snapshot
when OBD offline, `/api/stats` shows `active_dtc: 0`, `save_dtc_state`/`get_persisted_dtc_state`
confirmed present in running code.
### BUG-05 — Server route replay speed_source always "gps"
- **Status**: `CLOSED` 2026-08-11
- **Commit**: `e2f2314`
- **Verification**: Server git reset to origin, Docker rebuild, `/health` OK on LAN and Cloudflare
Tunnel. `get_trip_route` now uses `"obd" if speed > 0 else "gps"` matching Pi logic.