docs: correct the false Wi-Fi premise; add UI and live-tracking phases
The plan's headline section claimed the Rider 650 has on-device Wi-Fi and a
Data Sync menu that uploads to Bryton's cloud with no phone involved. It
does not. The unit has ANT+ and Bluetooth only; its sole sync route is BLE
to the Bryton Active app. Confirmed on the physical device, corroborated by
BikeRadar's hands-on. Likely origin: conflation with the Rider 750 / S800,
which do have Wi-Fi.
Impact is narrower than it first appears and no built code is invalidated:
everything downstream of Bryton's cloud never depended on how a ride got
into that cloud, so the poller, ingestion, schema, wear engine and all of
Phase 0 stand. What was invalidated is the product promise — Phase 1 was
called "Zero-touch ride history" and claimed to fix the original complaint
(having to remember to open the Active app). It does not; it is one-tap.
Renamed accordingly rather than leaving the doc overclaiming.
Corrections propagated everywhere the premise had spread: PLAN.md's opening
sections, Phase 1, top risks (the chain is now longer and has a human link
that fails silently — earns a "nothing ingested in N days" nudge), and the
verification checklist; DECISIONS.md D3's justification; README.md, which
was additionally stale on nearly every other point (claimed no code written,
Postgres, compose, four containers); and RESEARCH.md, where the claim
originated under a "verified" header it had not earned. RESEARCH.md is
annotated rather than rewritten — it is a record of what was found, and the
correction is part of that record. USB path facts are marked unverified too,
since they came from the same unverified batch.
D20 records the process lesson: the plan contained the right check ("first
action before writing any code"), it was never run, and nothing downstream
required it to have been. Device capabilities get confirmed on the device
before being written as fact.
Also adds the two phases requested before this came up, both grounded in
feasibility research rather than assumption:
- Phase 1A, an open-ended UI pass done together, including the verbose field
surface driven off activity_field_inventory.
- Phase 1B, live tracking. Constrained hard by reality: iOS suspends
backgrounded PWAs and implements no Web Bluetooth, and Bryton's own Live
Track needs the phone relaying over BLE, so the tracking client cannot be
our PWA. Shape that works is OwnTracks POSTing to our API for position,
with the server deriving distance/pace/elevation; HR and power need BLE and
are explicitly a second-class opt-in, not a blocker. Two rules written in:
live positions must never become activities (invariant #6), and "no privacy
zones, ever" does not extend to a public live link.
Inserted as 1A/1B rather than renumbering Phases 2-5, whose numbers are
referenced from DECISIONS.md, deploy/README.md and code comments.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R2ZKeWkZV7ehf7fivrAkkG
This commit is contained in:
+51
-5
@@ -26,18 +26,31 @@ Bryton BLE is a dead end regardless, and the *server* does all syncing.
|
||||
**Kept as insurance:** the backend stays strictly API-first with a CI-enforced OpenAPI contract, so
|
||||
if Apple ever makes the PWA route untenable, a native client is a code-generation exercise.
|
||||
|
||||
### D3 — Bryton cloud poller is the primary ingestion path
|
||||
### D3 — Bryton cloud poller is the primary ingestion path — **premise corrected, decision survives**
|
||||
**Chosen:** server-side poller against the reverse-engineered Bryton Active API, every 15-20 min.
|
||||
**Rejected:** Strava as a source (no `export_original` — decoded smoothed streams only; plus the
|
||||
June 2026 tier restructure caps new apps at 10 users and requires a paid dev subscription);
|
||||
BLE/ANT-FS direct (nobody has reverse-engineered Bryton's BLE — weeks of work, breaks on firmware
|
||||
updates); depending on the Bryton Active phone app (the original complaint).
|
||||
**Why:** the Rider 650 has on-device Wi-Fi (`Main Menu -> Data Sync`) and uploads to Bryton's cloud
|
||||
with no phone involved, and the cloud API returns the **original unmodified FIT bytes**. That's both
|
||||
zero-touch *and* higher fidelity than the current Strava route.
|
||||
updates, and separately impossible from an iOS PWA, which has no Web Bluetooth at all).
|
||||
**Why:** the cloud API returns the **original unmodified FIT bytes** — higher fidelity than the
|
||||
Strava route, and everything downstream of the cloud is ours.
|
||||
**Fallbacks, both built:** USB watch folder (also the historical-backfill mechanism, so it stays
|
||||
exercised rather than bit-rotting) and manual upload.
|
||||
|
||||
> **Corrected 2026-09-22.** This entry originally justified itself with "the Rider 650 has on-device
|
||||
> Wi-Fi (`Main Menu -> Data Sync`) and uploads to Bryton's cloud with no phone involved… That's both
|
||||
> zero-touch *and* higher fidelity," and listed "depending on the Bryton Active phone app (the
|
||||
> original complaint)" as *rejected*. **The Wi-Fi premise was false** — the Rider 650 has ANT+ and
|
||||
> Bluetooth only, and its only sync route is BLE to the Active app (confirmed on the physical
|
||||
> device; see `docs/PLAN.md`, "How rides actually reach the app"). So the rejected option is in fact
|
||||
> the only one available, and the chain is
|
||||
> `head unit → BLE → Active app → Bryton cloud → poller`.
|
||||
>
|
||||
> **The decision itself still stands** — polling Bryton's cloud for original FIT bytes remains the
|
||||
> best available primary path, and nothing downstream of the cloud depended on how rides got into
|
||||
> it. What changes is the *claim*: this is one-tap, not zero-touch, and it does not fix the original
|
||||
> complaint. See D20 for the process lesson.
|
||||
|
||||
### D4 — Python / FastAPI / Postgres+PostGIS — **database choice superseded by D15**
|
||||
**Chosen:** Python 3.12, FastAPI, Pydantic v2, SQLAlchemy 2.0 async, Alembic, PostgreSQL 16 + PostGIS 3.4.
|
||||
**Rejected:** TypeScript full-stack, Go.
|
||||
@@ -400,6 +413,39 @@ manual deploy — `deploy/README.md`'s "Publishing the image" section.
|
||||
|
||||
---
|
||||
|
||||
### D20 — The Rider 650 has no Wi-Fi; verify device capabilities on the device
|
||||
|
||||
**What happened:** the plan's headline section, "The sync breakthrough," asserted that the Rider 650
|
||||
has on-device Wi-Fi and a `Main Menu → Data Sync` entry that uploads rides to Bryton's cloud with no
|
||||
phone involved. It does not. The Rider 650 has ANT+ and Bluetooth only; its sole sync route is BLE to
|
||||
the Bryton Active app. Confirmed on the physical device, and corroborated by BikeRadar's hands-on
|
||||
("ANT+ and Bluetooth connectivity", syncing via "Bryton's Active App"). The most likely origin of
|
||||
the error is conflation with the Rider 750 / S800, which do have Wi-Fi.
|
||||
|
||||
**Why it survived so long:** the plan *did* contain the right check — "First action before writing
|
||||
any code: on the Rider 650, go to `Main Menu → Data Sync`… and confirm a test ride uploads without
|
||||
the phone." It was never run, and nothing downstream required it to have been. An entire phase was
|
||||
planned, and Phase 0 fully built and deployed, on top of an unverified device capability that was
|
||||
written down in the declarative voice of a finding rather than the provisional voice of an
|
||||
assumption.
|
||||
|
||||
**What it cost, and didn't:** less than it first appeared. Everything downstream of Bryton's cloud —
|
||||
ingestion, dedupe, schema, wear engine, garage, notifications, all of Phase 0 — never depended on
|
||||
how a ride reached that cloud, so no built code was invalidated. What was invalidated was the
|
||||
*product promise*: Phase 1 was called "Zero-touch ride history" and claimed to fix the original
|
||||
complaint (having to remember to open the Active app). It does not. It is one-tap, and the
|
||||
complaint stands. That renaming, not a refactor, was the actual repair.
|
||||
|
||||
**The rule going forward:** a physical-device capability that a phase depends on is confirmed **on
|
||||
the device** before it is written down as fact. Model-adjacent sources (a spec page for a different
|
||||
unit in the same family, a review of a sibling model) do not count. Until confirmed, such a claim is
|
||||
written as an open question in `docs/RESEARCH.md`, not as a premise in `docs/PLAN.md` — and any
|
||||
phase resting on it carries the verification as its first task, not as a footnote. The same applies
|
||||
to the remaining unverified device claims: the USB `.fit` path layout, and whether the
|
||||
`intervalssync` protocol still retrieves activities from a current Bryton account.
|
||||
|
||||
---
|
||||
|
||||
## Deliberately deferred
|
||||
|
||||
- **Finish the Watchtower auto-updater** (D19) — retry with a maintained image; `velodrome` is
|
||||
|
||||
Reference in New Issue
Block a user