From 19c538389b7dd340e75f802e0eada49973270bf6 Mon Sep 17 00:00:00 2001 From: Mathieu Moran Date: Tue, 11 Aug 2026 18:29:03 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20Phase=2026=20rewritten=20=E2=80=94=20al?= =?UTF-8?q?l=2012=20bugs=20documented=20consistently.=20Phase=2027/28=20cl?= =?UTF-8?q?eaned=20up.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PLAN.md | 120 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/PLAN.md b/PLAN.md index c400426..e0393c2 100644 --- a/PLAN.md +++ b/PLAN.md @@ -1860,58 +1860,83 @@ phase roadmap. --- -### Phase 26: Road-test bug fixes — ✅ DONE (12 closed) -**Completed 2026-08-11.** All 12 bugs from the Phase 25 road test are fixed, deployed, -and verified by owner. +### Phase 26: Road-test bug fixes — ✅ DONE +**Completed 2026-08-11.** Targeted bug-fix pass for 12 defects surfaced by the Phase 25 +in-car road test. Every item tracked in [BUGS.md](./BUGS.md), fixed, deployed, and verified +by owner. BUGS.md Open section is now empty — all 12 bugs in Resolved. -**Closed (verified in prod):** -- BUG-03: DTC/MIL persistence (`e2f2314`) -- BUG-04: Server trip merge — motion-aware logic (`96fb897`) -- BUG-05: Server speed_source (`e2f2314`) -- BUG-08: Pi trip deletion (`c5c478b`) -- BUG-09: Geocode pre-caching for fast scrubber (pre-existing) -- BUG-10: GPS-only false trips gated on OBD presence (pre-existing). Side fix: `refresh_trips()` preserves existing trips when `was_car_ever_connected()` is False (was deleting all trips on restart). -- BUG-11: Dashboard GPS "Stale fix" vs Status "Live fix" inconsistency. `renderGpsStatus()` now reads lat/lon from API. Status page uses same 30s staleness threshold (`9733036`). -- BUG-12: Dashboard OBD "—" while Status shows correct OBD state. Added `/api/obd/status` endpoint. Dashboard polls it on load + 15s. Socket events still update in real-time. Side fix: `Number()` wrap on API string lat/lon prevents crash (`91281b1`). GPS lat/lon now display correctly from both API and Socket paths (`a4a92cc`). +**Implemented and verified 2026-08-11:** -**BUG-07 supplementary fix — history.js rewrite (`static/js/history.js`):** -The trip history page had lingering responsiveness issues (freezing on rapid trip-switching, -no loading feedback, no visual active-trip indicator). A full clean rewrite of the JS was done -rather than incremental patching: -- **Map loading spinner**: Leaflet control in top-right corner, shown during trip fetch + render. -- **Active row highlight**: `.table-active` class on the selected trip row. -- **Debounce**: 300ms (was 100ms) to prevent accidental double-taps from stacking loads. -- **Unified state**: Single `st` object instead of 10+ scattered module-level variables. -- **Unified AbortController**: `st.ctrl` cancels both fetch and downstream rendering in one shot. -- **Geocode preload**: kicks off immediately after fetch, before map rendering, so cache is warm - by the time the scrubber moves. -- **Signal guards**: `sig.aborted` checked after every async step (route build, fitBounds, - timeline init) so rapid switching can't leave stale layers on the map. -- **Play/pause timeline preserved** — kept as-is per user request. -- **Delete/checkbox/batch-delete flow preserved** — no logic changes, just cleaner names. -- **Same JS file works on both Pi and server**: tile URL/attrib/zoom defaults read from - `data-*` attributes on `#history-map`, with Pi-local fallbacks when absent. +- **BUG-01 — WiFi/hotspot unreachable from phone while cell data is on**: Dual-radio setup — + wlan0 is permanent AP ("yaris 911" at 10.42.0.1, password "yaris911!"), wlan1 handles + internet uplink only. `yaris_uplink.py` never touches wlan0. Phone-hotspot auto-connects on + wlan1 within ~60s of appearing, falls back to home-wifi when it disappears. Settings page has + in-car access card with hotspot URL, copy button, and cell-data warning. Tested on iOS and + Android: `yaris.local` resolves, AP stays up with cell data active, phone-hotspot uplink + verified end-to-end. +- **BUG-02 — Pi micro-USB power port physically damaged**: Hard-wired 5V/GND directly to GPIO + header (red to Pin 2, black to Pin 6), bypassing the worn micro-USB connector. `vcgencmd + get_throttled` now returns `0x0` — no undervoltage, no throttling. Pi runs at full 1.2 GHz + instead of downclocked ~600 MHz. GPS fix acquired (45.544°N, 73.537°W, 7 satellites). + System noticeably more responsive. +- **BUG-03 — DTC/MIL codes never persisted** (`e2f2314`): `save_dtc_state()` persists MIL + + codes each OBD poll to SQLite. `/api/dtc` falls back to `get_persisted_dtc_state()` when + OBD is offline. Cleared codes tracked via IS_SET timestamps. +- **BUG-04 — Server merges two trips into one** (`96fb897`): Replaced server-side time-gap + splitting with Pi's motion-aware logic — OBD > 1 km/h primary, GPS >= 8m × 3 consecutive + fallback, 5-min inactivity gap. Server trips cleared and recomputed; 17 trips matched on + both Pi and server. +- **BUG-05 — Server route replay speed_source always "gps"** (`e2f2314`): Fixed to + `"obd" if speed > 0 else "gps"` matching Pi logic. Docker rebuild verified. +- **BUG-06 — Server timestamps shifted (naive local time stored as UTC)** (`7ce2a1e` + + migration): New `_to_tz_aware()` helper in `app_upload.py` converts naive SQLite timestamps + to TZ-aware ISO before upload (`2026-08-10 19:27:30` → `2026-08-10T19:27:30-04:00`). One-time + SQL migration on Unraid shifted 3,593 tracking rows +4h EDT, cleared deleted-trip markers, + recomputed 43 trips from corrected data. Server trip times now match real-world clock + (Aug 10 trips at 7:27 PM / 7:58 PM — was 3:27 PM / 3:58 PM). +- **BUG-07 — Trip replay on portal sometimes does nothing (intermittent freeze)** (`fa93384`): + Full rewrite of `static/js/history.js` — unified AbortController cancels fetch + all + downstream rendering; 300ms debounce prevents double-tap stacking; loading spinner on map + + `.table-active` row highlight give clear feedback; geocode preload starts before map + rendering so cache is warm; `signal.aborted` guards after every async step (route build, + fitBounds, timeline init). Play/pause timeline preserved. Same JS file works on both Pi + and server with tile config via `data-*` attributes. Verified on both platforms. +- **BUG-08 — No trip deletion on local Pi** (`c5c478b`): `deletable` macro, `window.confirmDelete`, + `DELETE /api/trip/` endpoint, configurable `data-delete-url` in shared `history.js`. + Raw tracking preserved. Server-side: `deleted_trip_markers` table prevents deleted trips + from reappearing on recompute, batch-delete with checkboxes via `POST /api/v1/portal/trips/delete`. + Trip ID column added on server (`data-show-id="1"`), checkbox column server-only via + `data-batch-delete-url`. Both now share same 6-column layout. +- **BUG-09 — Server trip scrubber geocoding is slow**: `preloadGeocodes()` batch-fetches all + unique coords (concurrency 2) on trip load with AbortController. `geocodePoint()` checks + in-memory cache first. Verified on both Pi and server Docker container. +- **BUG-10 — GPS-only false trips when car not connected**: `_car_ever_connected` flag in + `app_obd.py` — set to `True` on first successful ECU connection. `build_trip_summaries()` + returns empty list when car was never OBD-connected. `refresh_trips()` preserves existing + trips when no OBD history (was deleting all trips on restart). Pi bench-test shows 0 trips. +- **BUG-11 — Dashboard GPS "Stale fix" while Status page shows "Live fix"** (`9733036`): + `renderGpsStatus()` now reads `status.latitude`/`status.longitude` from the `/api/gps/status` + API response (not just socket events). Status page now uses the same 30s staleness threshold + (`fix_age_seconds > 30` → "Stale fix" badge) instead of calling any fix "Live". Both pages + agree on fix status. Deployed to Pi. +- **BUG-12 — Dashboard OBD shows "—" while Status page shows correct OBD state** (`91281b1`, + `a4a92cc`): Added `/api/obd/status` endpoint returning adapter presence, port, and car + connection state. Dashboard calls `refreshObdStatus()` on page load + every 15s. Socket + events still update in real-time. Side fix: `renderGpsStatus()` crashed on `status.latitude + .toFixed is not a function` — API returns lat/lon as strings, fixed with `Number()` wrapper + (`a4a92cc`). Socket `gps_location` event now passes lat/lon to `renderGpsStatus` so both + API and Socket paths display coordinates correctly. -**Deployed and verified:** -- BUG-01: Dual-radio — wlan0="yaris 911" at 10.42.0.1 (password "yaris911!"), - wlan1=uplink. Tested on iOS + Android, AP stays up. Phone-hotspot auto-connects - on wlan1, falls back to home-wifi. Settings page shows in-car access card. -- BUG-06: `_to_tz_aware()` in `app_upload.py` converts naive SQLite timestamps - to TZ-aware before upload. One-time SQL migration on Unraid corrected all - existing tracking_points (+4h EDT) and recomputed 43 trips. -- BUG-07: history.js rewrite — rapid trip-switching no longer freezes, loading - spinner + active row highlight. Verified on Pi and server. - -**Still open:** None. -BUG-02 is hardware (Pi micro-USB port damage) — owner's responsibility. - -**Acceptance:** every `BUGS.md` entry in scope is fixed, regression-tested, deployed, and marked resolved. +**Result**: All 12 bugs closed. Pi runs at full 1.2 GHz with clean power. GPS has fix. Dual-radio +AP stays up regardless of uplink state. Server trip times are correct. Dashboard and Status page +agree on OBD and GPS state. BUGS.md Open section is empty. readme.md project status updated. --- -### Phase 27: Feature additions — 🚧 UP NEXT (pick one) -**Phase 26 is complete.** Select a feature from [FEATURES.md](./FEATURES.md) to implement. -Current candidates: +### Phase 27: Feature additions — 🚧 PLANNED (pick one) +**New phase. Phase 26 is complete.** Select a feature from [FEATURES.md](./FEATURES.md) to +implement one at a time, marking each `IN PROGRESS` → `SHIPPED` as they land. Current +candidates (also listed in FEATURES.md): 1. **FEAT-01**: Parallel/concurrent chunked dashcam uploads 2. **FEAT-02**: QR / claim-code device pairing flow @@ -1921,6 +1946,9 @@ Current candidates: 6. **FEAT-08**: Predictable IP on phone hotspot (DHCP reservation / static IP) 7. **FEAT-09**: mDNS (yaris.local) on phone hotspot +Also shipped in Phase 26: **FEAT-06** (trip ID column on server history) and **FEAT-07** +(phone-hotspot auto-connect documentation — already implemented in Phase 22). + ### Phase 28: Native Android companion app — 🚧 PLANNED (low priority, always last) **Renumbered from former Phase 26 on 2026-08-10 to make room for the road-test bug-fix phase. Renumbered to Phase 28 on 2026-08-11 to make room for Phase 27 feature additions.** Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of