Skip to content

Architecture review 2026-10-07: findings index and decision audit #109

Open
16 of 19 issues completed
Open

Description

@dzid26

This review covers main at 18f1b46: docs, ADRs, every source and test file, CI, all 279 commits, and PRs/issues #1–#108. Protocol claims were checked against teslamotors/vehicle-command at the pinned TESLA_COMMIT (a4b43c1). Each finding has its own sub-issue; this issue is the index and the decision audit.

Summary

The protocol core is small, readable, and well tested at the level of primitives: framing, anti-replay, metadata and session crypto. Several product decisions are sound:

  • CHARGING_MANAGER as the default role;
  • one key per car, freshly generated for every pairing;
  • no INTERNET permission;
  • a transport seam that allows a simulated car.

The risks sit elsewhere:

  1. The BLE/protocol runtime is one large, untested Android class. It has threading bugs, drops car faults silently, and uses a polling policy that may keep the car awake (BLE: GATT callbacks mutate shared state from Binder threads, and GATT operations aren't serialized #110, Protocol: replies are routed by trial-decoding; car faults and session resyncs are silently dropped #111, Polling: Infotainment is polled every 10 s whenever the car is awake, which may keep it from sleeping #112, Background: the reconnect and discovery loop drains the phone, and unfiltered scans stop with the screen off #113). It also stands in the way of the library goal (Architecture: split the 1,500-line TeslaBleController and move the per-vehicle protocol state machine into core #118).
  2. What ships is not what is tested. Published APKs are debuggable debug builds, the release variant is never built, and version numbers don't follow the tags (Release: published APKs are debuggable debug builds, the release variant is never built, and versionName doesn't follow tags #115). Key storage deletes keys on transient errors (Keys: transient Keystore errors delete pairing keys, and private keys are decrypted on the main thread just to show IDs #116).
  3. History is short-lived. Retention is far shorter than battery-health trends need (Data policy: decide when "no migration" ends, and plan history retention for health trends #123), and capacity is mis-estimated for charge sessions the app only partly observed (Health: capacity and full range are over-estimated when a charge session is first seen mid-way #114).
  4. Effort goes to the wrong places. Nearly a quarter of all commits (63 of 279) went into the emulator screenshot pipeline (CI: replace the emulator screenshot pipeline with JVM screenshot tests #125), while the controller has no tests (Tests: Go vectors aren't wired to expected.txt, the request path has no oracle, and several tests are tautological #121).

Decision audit

Decision Source Verdict Follow-up
Port vehicle-command to Kotlin, Wire for protos, no FFI ADR-0001 ✅ Keep —
CHARGING_MANAGER as the default role ADR-0001 ✅ Keep —
Never wake the car to read SOC; Infotainment ~10 s while charging ADR-0001 ⚠️ Code differs: it polls whenever the car is awake #112
Fine location on every API level (no neverForLocation) ADR-0001 ✅ Keep; it costs a Play location declaration —
Software P-256 key wrapped by Keystore AES; opt-in plaintext for backup ADR-0001 → ADR-0005 ⚠️ Keep the two modes, but fix delete-on-error and give core a key-handle seam #116, #119
One key per car, fresh key on every pairing ADR-0005 ✅ Keep; the app should also notice when a key is revoked #111
Append-only CSV, 20k cap, rows dropped on format change ADR-0002 ❌ Being replaced (#94); retention still open #123
Fake car behind TeslaTransport ADR-0003 ✅ Keep; use it to drive the controller and simulate Binder threads #118, #110
Advertised name as identity, one link per car, cap of 3 ADR-0004 ✅ Keep; UI state is still keyed by address #120
No migration code ("the only install is the owner's") ADR-0004, AGENTS.md ✅ Keep while there are no users; decide now what ends it #123
Sign every build with the release key; ship debug APKs app/build.gradle.kts, android.yml ❌ Revisit #115
core multiplatform-ready, published as a library later master plan, ADR-0007 (#108) ⚠️ Right direction, but core is JCA-only today and the protocol runtime lives in the app #108, #119, #118, #120
Static-analysis "zero baseline" master plan ⚠️ Reached by raising thresholds to fit the code #127
Emulator screenshots on every PR, preview and release #44, #84, #88, #92, … ❌ Revisit: biggest cost centre, little signal #125, #126
Release notes generated from commits, no changelog #101 ✅ Keep; F-Droid still needs per-versionCode changelogs #128
Pre-1.0 hygiene: delete legacy code paths master plan ✅ Keep #123

Findings by area

Process notes

Suggested order: #111, #110, #112 (correctness on the car), then #115, #116, #114; then #118 (it makes the testing in #121 possible) and #123 alongside #94; the rest after that.

Activity

  1. added sub-issues on Oct 7, 2026
  2. dzid26 commented on Nov 1, 2026

    @dzid26
    CollaboratorAuthor

    Status after the 2026-11-01 sweep, checked against main at 57bee80:

    Asked the owner whether to close it or keep it as the audit trail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions