docs: sign off Phase 25 road test, add BUGS.md, renumber Android to Phase 27

This commit is contained in:
Mathieu Moran
2026-08-10 23:42:39 -04:00
parent d216aac97e
commit 3e626830d5
3 changed files with 328 additions and 29 deletions
+128 -22
View File
@@ -1400,7 +1400,7 @@ including two UX polish passes and multiple bug-fix rounds.
**Roadmap ordering note (2026-08-10):** the late phases are intentionally sequenced as
Phase 25.5a–25.5d (configuration/sync/status work) -> Phase 25 (real-car acceptance gate) ->
Phase 26 (Android, always last).
Phase 26 (road-test bug fixes) -> Phase 27 (Android, always last).
### Phase 25.5a: Device configuration sync backend — ✅ COMPLETE (connection-driven server sync)
**Server API and Pi sync thread implemented.** Server stores device config; Pi fetches when internet available and applies changes without restart.
@@ -1714,7 +1714,14 @@ architecture.
`/` HTML places `Overview` before `Live GPS`.
---
### Phase 25: Pre-install Yaris 2013 compatibility test — 🚧 PLANNED (core-system gate)
### Phase 25: Pre-install Yaris 2013 compatibility test — ✅ DONE (owner road test; full checklist not followed)
**Owner conducted the in-car road test and checked for bugs. Per explicit owner instruction this
phase is marked complete — however, the full Phase 25 acceptance checklist was NOT rigorously
worked through item-by-item (an engineer was not present; several checklist items were skipped or
only informally observed). Treat the system's compatibility with the 2013 Yaris as validated by
the owner's practical drive, not as a documented item-by-item pass.** Bugs surfaced by the road
test are cataloged in `BUGS.md` and tracked for fixing in Phase 26. The former Phase 26 Android
slot was renumbered to **Phase 27 (always last)** to make room — see the roadmap note below.
**Added 2026-08-09; intentionally immediately before the Android app.** Bench tests, synthetic
routes, attached-hardware tests, and stationary Pi runs cannot prove the complete system works
when temporarily connected to and powered by the actual 2013 Toyota Yaris. This phase is the
@@ -1725,20 +1732,38 @@ cable routing, trim work, and final installation are explicitly outside the road
handled by the owner after this phase passes.
Prepare a temporary, removable test setup before driving:
- Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power
- ~~Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power
source without permanently mounting or routing anything. Secure every temporary component and
cable so it cannot interfere with pedals, steering, airbags, visibility, occupants, or loose-item
safety during the controlled drive; remove the setup after testing.
- Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm
safety during the controlled drive; remove the setup after testing.~~ — ✅ **DONE** (owner set up
the temporary test rig).
- ~~Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm
`vcgencmd get_throttled` shows no current power fault at idle and under load with the temporary
representative power setup. This validates electrical compatibility, not final cable routing.
- Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and
representative power setup. This validates electrical compatibility, not final cable routing.~~ —
⚠️ **OPEN — NOT DONE.** The Phase 19/20 undervoltage/throttling warning was **not** resolved
before the test. The intended power source is the **cigarette-lighter USB charger**, with the
5V/GND to be **hard-wired onto the Pi's GPIO header** (bypassing the worn micro-USB port — see
BUG-02). Whether the cigarette-lighter USB supplies clean, non-undervolting 5V under the Pi's
load still needs to be verified. **Action**: hard-wire 5V/GND to the GPIO header, then run
`vcgencmd get_throttled` at idle and under load and confirm **no current** fault before
declaring the power source adequate. If the lighter charger undervolts, it is **not** a
sufficient power source and a higher-rated/supported PSU must be chosen. (Cigarette-lighter
USB alone, on a worn/loose connector, is the most likely culprit for residual throttling.)
- ~~Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and
remote server. Use a uniquely timestamped test window so generated records can be reconciled
without deleting unrelated history.
- Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS
antenna view, dashcam recording mode, free space, and remote server health before moving.
- Use a second person for UI/log observations while the vehicle is moving, or record diagnostics
for review afterward. The driver must not operate or troubleshoot the UI while driving.
without deleting unrelated history.~~ — ⚠️ **SKIPPED** (owner: "didn't do it but don't very
care"). Acceptable to skip the pre-test backup/baseline, but be aware there is now **no
pre-test record** to reconcile test drive rows against, and no pre-drive SQLite backup exists.
- ~~Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS
antenna view, dashcam recording mode, free space, and remote server health before moving.~~ —
🟡 **PARTIAL.** Pre-move verification was done and the hot-spot is connectable, but
**`yaris.local` does not resolve** on the phone → tracked as **BUG-01**. Everything else on this
line checked out (service/watchdog/mounts/free space/remote health) per the owner.
- ~~Use a second person for UI/log observations while the vehicle is moving, or record diagnostics
for review afterward. The driver must not operate or troubleshoot the UI while driving.~~ —
⛔ **SCRATCHED** (owner: "will do it solo"). **Safety note kept**: the driver must NOT operate or
troubleshoot the UI while driving; solo testing relies on recording diagnostics for later
review.
Run a controlled route containing ignition-off/on, stationary idle, low-speed streets, normal road
speed, several complete stops, turns, a short GPS-obstructed segment if safely available, and a
@@ -1747,22 +1772,34 @@ clean trip end:
adapter firmware, and verify real speed/RPM/coolant/fuel/throttle/MIL/DTC values. Compare wheel
speed against the instrument cluster at several safe speeds. Record unsupported PIDs (especially
odometer PID A6) as capabilities, not failures, and verify reconnect after ignition cycling and a
deliberate USB disconnect/reconnect.
deliberate USB disconnect/reconnect. — ✅ **DONE** (owner: "seems to work — OBD connects, DTC
codes working, throttle working, speed, etc."). Negotiabd protocol/firmware values not explicitly
logged, and odometer PID A6 support remains unconfirmed (expected unsupported on the 2013 Yaris —
see Phase 24.6).
- **GPS and motion logging:** confirm fixes while stationary and moving, route coordinates on the
offline map, OBD-speed-first motion detection, GPS displacement fallback when OBD is deliberately
unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift.
unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift. —
✅ **DONE** (owner: "seems to work for the trip"). **Cross-ref:** the *server-side* trip-boundary
mismatch (BUG-04) is the known follow-up.
- **Trip boundary/replay:** after the inactivity timeout, verify exactly one trip (or the expected
number for deliberate ignition gaps), correct start/end time and coordinates, plausible
distance/average/max speed, km/mi and km/h/mph values, route polyline, start/end markers, timeline
scrubber, play/pause marker position, and stopped portions of the route.
scrubber, play/pause marker position, and stopped portions of the route. —
🟡 **PARTIAL / bug reported.** Local replay observed OK, but the server-side trip-splitting and
replay issues are tracked in **BUG-04** (server merges two trips) and **BUG-05** (server replay
`speed_source`), with **BUG-06** (timezone shift affecting times) also relevant.
- **Local web UI:** test the final Phase 23 interface on the actual phone over the Pi/phone network at
`http://yaris.local/`; verify the explicit **In-car / Local Pi** identity, dashboard telemetry,
DTC page, trip history, dashcam library, settings, alerts, responsive layout, reconnect behavior,
and no new browser console/API errors.
and no new browser console/API errors. —
🟡 **PARTIAL / bug reported.** Reaching the UI over the Pi hotspot is blocked by `yaris.local`
not resolving on the phone → **BUG-01**. Other local UI pages work once reachable.
- **Dashcam workflow:** create a known short real clip, switch the camera safely into USB storage
mode, detect/list it without confusing the OBD adapter, import only that selected file, verify
thumbnail/playback/Range seeking, preserve the source until checks finish, and confirm the camera
returns to recording afterward. Test deletion only with the disposable clip.
returns to recording afterward. Test deletion only with the disposable clip. —
⏳ **DEFERRED** (owner: "will test later stages"). Not yet exercised as part of this test; remains
a follow-up for the Phase 26 bug-fix/verification pass.
- **Alerts:** safely exercise conditions that can be simulated without damaging hardware (upload
backlog, temporary GPS loss while OBD reports motion, and disposable threshold overrides).
Confirm local bell transition/recovery/cooldown behavior and offline alert-state reconciliation
@@ -1771,12 +1808,31 @@ clean trip end:
transport can reliably deliver ntfy notifications while WiFi/Ethernet is unavailable, including
authentication, timeout, retry, and recovery. If that cannot be made reliable on the actual
modem/network, remove the ntfy feature and its settings rather than retain a transport that fails
in the only situation where it is useful.
in the only situation where it is useful. —
🟡 **PARTIAL / done in part.** Owner reports alerts "seem to work for engine and DTC codes +
power". The SIM868 **ntfy path remains unverified** (no real SIM on the modem yet, so the
"determine whether the SIM868 transport can reliably deliver ntfy" sub-item is still open).
- **Power/reliability:** perform multiple normal ignition/power cycles, confirm automatic boot,
service/watchdog startup, SIM868 power-on, OBD/GPS recovery, no SQLite corruption, and no current
undervoltage/throttling. The deferred Phase 14 clean-shutdown limitation must be explicitly
accepted or resolved with representative delayed-power/ignition-sense hardware before declaring
the design ready for permanent installation.
the design ready for permanent installation. —
🟡 **PARTIAL — Pi logs checked 2026-08-10 (at home, car not connected).** Verified from the live
Pi:
- `yaris-obd.service` **active**; uptime 2:48h with **no crash/restart** in the current boot
window (systemd auto-restart + the 10s hardware watchdog did not need to fire since startup).
- `vcgencmd get_throttled` → **`0x50000` = NO current undervoltage right now** (only the
historical "occurred" bits 0x40000/0x10000 remain set). Confirms the Pi is not *currently*
undervolting on whatever power is connected at home, but does not prove the in-car
cigarette-lighter source yet (re-check under load in the car after hard-wiring — see the open
power item above and BUG-02).
- OBD reconnect loop logging as designed ("handshake succeeded / ECU did not respond" = car not
on/not connected here). Uploads syncing fine ("sent N tracking rows").
- No SQLite corruption or tracebacks in the log tail.
**Still open**: a real multi-ignition-cycle verification *in the car* (boot recovery, watchdog
restart under power loss, OBD/GPS recovery, no corruption) with the final hard-wired power
source has not been demonstrated. The Phase 14 clean-shutdown limitation remains **accepted**
(delayed-power / ignition-sense hardware not yet present).
Verify the complete remote path after connectivity returns:
- Confirm every test-window tracking row uploads exactly once and the selected dashcam clip resumes
@@ -1786,9 +1842,12 @@ Verify the complete remote path after connectivity returns:
vehicle-scoped trip summary/replay, route and timeline agreement with the local Pi, archived clip
thumbnail/playback/Range seeking/download, synchronized alert history/current state without
duplicate transitions after an offline interval, and absence of local-only OBD/cellular/Pi
controls.
controls. —
🟡 **PARTIAL.** Owner can connect to the remote server; the portal is reachable. The main
blocker is the **Pi hotspot** reachability issue (**BUG-01**), which affects exercising the
portal from the in-car phone. Server-side trip/replay/time issues (BUG-04/05/06) also remain.
- The Android companion is intentionally outside this core acceptance gate and remains the final,
low-priority Phase 26. Its own hotspot/cellular binding, trip display, and disposable clip relay
low-priority Phase 27. Its own hotspot/cellular binding, trip display, and disposable clip relay
require separate real-phone/in-car acceptance when that phase is implemented.
Acceptance requires a written result for every item, captured negotiated protocol/PID support,
@@ -1800,7 +1859,54 @@ phase roadmap.
---
### Phase 26: Native Android companion app — 🚧 PLANNED (low priority, always last)
### Phase 26: Road-test bug fixes — 🚧 PLANNED
**Renumbered/added 2026-08-10 after the Phase 25 owner road test.** This phase (the former Phase 26
Android slot, which is now **Phase 27**) is a targeted bug-fix pass for the defects surfaced by the
in-car road test. Each item references its tracking entry in `BUGS.md`; distinct fixes should be
committed individually with a `fix(bug-N): ...` prefix and each closed out in `BUGS.md` as it
lands. The current known issues from the road test (also recorded in `BUGS.md`):
1. **BUG-01 (WiFi/hotspot reachability).** While cell data is on, a phone connected to the Pi's
no-internet hotspot cannot load `yaris.local`, `10.42.0.1`, or the Pi's DHCP address at all —
the phone OS keeps cellular as the default route (Phase 11/22 "smart network switching"
behavior). It only works once the user disables cell data, then `http://<dhcp-ip>/` loads but
`yaris.local` and `10.42.0.1` still do not. Also: the live hotspot subnet is `10.112.0.x`, not
the documented `10.42.0.1`. Fix scope: make the documented/reachable address correct, surface
the real DHCP address in the Pi UI, document the cell-data behavior, and see if `yaris.local`
unicast fallback can be extended to the AP subnet.
2. **BUG-02 (micro-USB power port damaged).** Hardware-only (worn power connector). Action is
documentation + owner hard-wiring 5V/GND to the GPIO header pins; no code.
3. **BUG-03 (DTCs not persisted).** The SQLite `dtc` table is created but never written or read;
DTC codes/MIL live only in memory in `app_obd.py` and vanish on OBD disconnect/reboot.
`get_overview_stats` also queries a non-existent `dtc_codes` table. Fix: persist on each poll,
read back when disconnected, fix the stats query, add a "cleared/since" concept.
4. **BUG-04 (server merges two trips into one).** The Pi splits trips by *motion* (OBD wheel
speed + sustained GPS displacement, inactivity gap); the server splits only by *time gap* and
filters by duration. Parked idle tracking rows bridge two drives into one server-side trip.
Fix: mirror the Pi's motion-boundary logic server-side.
5. **BUG-05 (server replay speed_source).** Server `get_trip_route` hardcodes `speed_source: "gps"`
even when OBD speed is present (it already returns raw `speed`). Fix: mirror the Pi's
`obd if speed>0 else gps` logic.
6. **BUG-06 (server timezone is UTC-shifted).** `tracking_points.recorded_at` is `TIMESTAMPTZ`
but the Pi sends naive local (Montreal) time with no offset; Postgres (UTC container) treats
it as UTC, so server times/trip boundaries are off by the EDT offset. Fix: Pi sends
timezone-aware timestamps; server displays/stores in `America/Toronto`; optional one-time
migration to correct already-stored rows.
7. **BUG-07 (trip replay sometimes does nothing).** Intermittent `/history` replay failure —
needs reproduction/diagnostics (likely an API/DB race or map-not-ready timing). Add targeted
diagnostics before fixing.
8. **BUG-08 (no trip deletion on the local Pi).** The Pi's `components.html` `data_table` macro
lacks the `deletable` arg, `base.html` lacks `window.confirmDelete`, `history.js` hardcodes the
*server* delete endpoint, and there is no `DELETE /api/trip/<id>` route on the Pi. Fix: add all
four pieces and make the delete endpoint configurable in `history.js`.
**Acceptance for Phase 26:** every `BUGS.md` entry in scope is fixed, regression-tested, deployed,
marked resolved, and the corresponding fix recorded here.
---
### Phase 27: 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.**
Revives the phone-relay goal (Phase 11/12) properly this time, using a real native app instead of
a web page - the only way to actually hold a WiFi connection to the Pi's hotspot and a cellular
connection to the internet open simultaneously (`ConnectivityManager.bindProcessToNetwork()`,