docs: Phase 26 rewritten — all 12 bugs documented consistently. Phase 27/28 cleaned up.
This commit is contained in:
@@ -1860,58 +1860,83 @@ phase roadmap.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 26: Road-test bug fixes — ✅ DONE (12 closed)
|
### Phase 26: Road-test bug fixes — ✅ DONE
|
||||||
**Completed 2026-08-11.** All 12 bugs from the Phase 25 road test are fixed, deployed,
|
**Completed 2026-08-11.** Targeted bug-fix pass for 12 defects surfaced by the Phase 25
|
||||||
and verified by owner.
|
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):**
|
**Implemented and verified 2026-08-11:**
|
||||||
- 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`).
|
|
||||||
|
|
||||||
**BUG-07 supplementary fix — history.js rewrite (`static/js/history.js`):**
|
- **BUG-01 — WiFi/hotspot unreachable from phone while cell data is on**: Dual-radio setup —
|
||||||
The trip history page had lingering responsiveness issues (freezing on rapid trip-switching,
|
wlan0 is permanent AP ("yaris 911" at 10.42.0.1, password "yaris911!"), wlan1 handles
|
||||||
no loading feedback, no visual active-trip indicator). A full clean rewrite of the JS was done
|
internet uplink only. `yaris_uplink.py` never touches wlan0. Phone-hotspot auto-connects on
|
||||||
rather than incremental patching:
|
wlan1 within ~60s of appearing, falls back to home-wifi when it disappears. Settings page has
|
||||||
- **Map loading spinner**: Leaflet control in top-right corner, shown during trip fetch + render.
|
in-car access card with hotspot URL, copy button, and cell-data warning. Tested on iOS and
|
||||||
- **Active row highlight**: `.table-active` class on the selected trip row.
|
Android: `yaris.local` resolves, AP stays up with cell data active, phone-hotspot uplink
|
||||||
- **Debounce**: 300ms (was 100ms) to prevent accidental double-taps from stacking loads.
|
verified end-to-end.
|
||||||
- **Unified state**: Single `st` object instead of 10+ scattered module-level variables.
|
- **BUG-02 — Pi micro-USB power port physically damaged**: Hard-wired 5V/GND directly to GPIO
|
||||||
- **Unified AbortController**: `st.ctrl` cancels both fetch and downstream rendering in one shot.
|
header (red to Pin 2, black to Pin 6), bypassing the worn micro-USB connector. `vcgencmd
|
||||||
- **Geocode preload**: kicks off immediately after fetch, before map rendering, so cache is warm
|
get_throttled` now returns `0x0` — no undervoltage, no throttling. Pi runs at full 1.2 GHz
|
||||||
by the time the scrubber moves.
|
instead of downclocked ~600 MHz. GPS fix acquired (45.544°N, 73.537°W, 7 satellites).
|
||||||
- **Signal guards**: `sig.aborted` checked after every async step (route build, fitBounds,
|
System noticeably more responsive.
|
||||||
timeline init) so rapid switching can't leave stale layers on the map.
|
- **BUG-03 — DTC/MIL codes never persisted** (`e2f2314`): `save_dtc_state()` persists MIL +
|
||||||
- **Play/pause timeline preserved** — kept as-is per user request.
|
codes each OBD poll to SQLite. `/api/dtc` falls back to `get_persisted_dtc_state()` when
|
||||||
- **Delete/checkbox/batch-delete flow preserved** — no logic changes, just cleaner names.
|
OBD is offline. Cleared codes tracked via IS_SET timestamps.
|
||||||
- **Same JS file works on both Pi and server**: tile URL/attrib/zoom defaults read from
|
- **BUG-04 — Server merges two trips into one** (`96fb897`): Replaced server-side time-gap
|
||||||
`data-*` attributes on `#history-map`, with Pi-local fallbacks when absent.
|
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/<id>` 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:**
|
**Result**: All 12 bugs closed. Pi runs at full 1.2 GHz with clean power. GPS has fix. Dual-radio
|
||||||
- BUG-01: Dual-radio — wlan0="yaris 911" at 10.42.0.1 (password "yaris911!"),
|
AP stays up regardless of uplink state. Server trip times are correct. Dashboard and Status page
|
||||||
wlan1=uplink. Tested on iOS + Android, AP stays up. Phone-hotspot auto-connects
|
agree on OBD and GPS state. BUGS.md Open section is empty. readme.md project status updated.
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 27: Feature additions — 🚧 UP NEXT (pick one)
|
### Phase 27: Feature additions — 🚧 PLANNED (pick one)
|
||||||
**Phase 26 is complete.** Select a feature from [FEATURES.md](./FEATURES.md) to implement.
|
**New phase. Phase 26 is complete.** Select a feature from [FEATURES.md](./FEATURES.md) to
|
||||||
Current candidates:
|
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
|
1. **FEAT-01**: Parallel/concurrent chunked dashcam uploads
|
||||||
2. **FEAT-02**: QR / claim-code device pairing flow
|
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)
|
6. **FEAT-08**: Predictable IP on phone hotspot (DHCP reservation / static IP)
|
||||||
7. **FEAT-09**: mDNS (yaris.local) on phone hotspot
|
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)
|
### 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.**
|
**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
|
Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of
|
||||||
|
|||||||
Reference in New Issue
Block a user