Also carries forward the Phase 0 wrap-up commit that never landed: PR #12 reported merged but was based on PR #11's branch, which main had already absorbed, so its content went nowhere (same trap as #7/#8/#9). Verified by checking main's actual file contents rather than trusting the merged flag.
The correction
The plan's headline section claimed the Rider 650 has on-device Wi-Fi and a Data Sync menu uploading to Bryton's cloud phone-free. It does not — ANT+ and Bluetooth only, sole sync route is BLE to the Active app. Confirmed on the physical device, corroborated by BikeRadar's hands-on ("ANT+ and Bluetooth connectivity", syncing via "Bryton's Active App"). Likely origin: conflation with the Rider 750 / S800, which do have Wi-Fi.
No built code is invalidated. Everything downstream of Bryton's cloud never depended on how rides got into it, so the poller, ingestion design, schema, wear engine and all of Phase 0 stand. What was invalidated is the promise: Phase 1 was "Zero-touch ride history" and claimed to fix the original complaint. It doesn't — it's one-tap. Renamed rather than left overclaiming.
Propagated the correction everywhere the premise had spread: PLAN.md's opening + Phase 1 + top risks + verification; D3's justification; README.md (additionally stale on nearly everything else — claimed no code written, Postgres, compose, four containers); and RESEARCH.md, where it originated under a "verified" header it hadn't earned. RESEARCH.md is annotated, not rewritten — it's a record of what was found, and the correction belongs in that record. USB path facts flagged unverified too, same 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.
The two requested phases
Phase 1A — Make it yours: an open-ended UI pass done together, including the verbose field surface (driven off activity_field_inventory, so unknown/vendor fields appear rather than vanish).
Phase 1B — Live tracking: constrained by research, not assumption. iOS suspends backgrounded PWAs and implements no Web Bluetooth; Bryton's own Live Track needs the phone relaying over BLE. So the tracking client cannot be our PWA. Shape that works: OwnTracks POSTing position to our API, server deriving distance/pace/elevation. HR/power need BLE → explicitly second-class opt-in, not a blocker on the useful 80%. 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.
Plus the verbose-capture schema work from the same request: field-agnostic parsing, activity_fit_messages for the non-time-series long tail, activity_field_inventory so the UI renders everything dynamically.
Inserted as 1A/1B rather than renumbering Phases 2–5, whose numbers are referenced from DECISIONS.md, deploy/README.md and code comments — shifting them silently is exactly what D20 is about.
Targets `main` directly — no stacking this time.
Also carries forward the Phase 0 wrap-up commit that never landed: PR #12 reported merged but was based on PR #11's branch, which `main` had already absorbed, so its content went nowhere (same trap as #7/#8/#9). Verified by checking `main`'s actual file contents rather than trusting the merged flag.
## The correction
The plan's headline section claimed the Rider 650 has on-device Wi-Fi and a `Data Sync` menu uploading to Bryton's cloud phone-free. **It does not** — ANT+ and Bluetooth only, sole sync route is BLE to the Active app. Confirmed on the physical device, corroborated by [BikeRadar's hands-on](https://www.bikeradar.com/features/first-look-friday/bryton-650-gps) ("ANT+ and Bluetooth connectivity", syncing via "Bryton's Active App"). Likely origin: conflation with the Rider 750 / S800, which do have Wi-Fi.
**No built code is invalidated.** Everything downstream of Bryton's cloud never depended on how rides got into it, so the poller, ingestion design, schema, wear engine and all of Phase 0 stand. What was invalidated is the *promise*: Phase 1 was "Zero-touch ride history" and claimed to fix the original complaint. It doesn't — it's one-tap. Renamed rather than left overclaiming.
Propagated the correction everywhere the premise had spread: PLAN.md's opening + Phase 1 + top risks + verification; D3's justification; README.md (additionally stale on nearly everything else — claimed no code written, Postgres, compose, four containers); and RESEARCH.md, where it originated under a "verified" header it hadn't earned. RESEARCH.md is **annotated, not rewritten** — it's a record of what was found, and the correction belongs in that record. USB path facts flagged unverified too, same 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.
## The two requested phases
- **Phase 1A — Make it yours**: an open-ended UI pass done together, including the verbose field surface (driven off `activity_field_inventory`, so unknown/vendor fields appear rather than vanish).
- **Phase 1B — Live tracking**: constrained by research, not assumption. iOS suspends backgrounded PWAs and implements no Web Bluetooth; Bryton's own Live Track needs the phone relaying over BLE. So the tracking client **cannot be our PWA**. Shape that works: OwnTracks POSTing position to our API, server deriving distance/pace/elevation. HR/power need BLE → explicitly second-class opt-in, not a blocker on the useful 80%. 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.
Plus the verbose-capture schema work from the same request: field-agnostic parsing, `activity_fit_messages` for the non-time-series long tail, `activity_field_inventory` so the UI renders everything dynamically.
Inserted as 1A/1B rather than renumbering Phases 2–5, whose numbers are referenced from DECISIONS.md, deploy/README.md and code comments — shifting them silently is exactly what D20 is about.
No code changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01R2ZKeWkZV7ehf7fivrAkkG
docs/PLAN.md's Phase 0 section and its "Done when"/Verification entries
still described the original Postgres+RLS, docker-compose, auto-redeploying
design — none of which is what actually got built and deployed. Marks it
done, states the two deliberate deviations plainly (SQLite not Postgres+RLS,
manual redeploy not automatic), and separates what's actually verified
(login persists a session, checked by scripts/smoke-test.sh after a real bug)
from what nobody has tried yet (PWA home-screen install).
docs/DECISIONS.md D19 records the auto-update investigation: the real fix
for Unraid's own "not available" update-check badge (a third, independent
place the D17 self-signed cert needed trusting — Unraid's PHP update
checker doesn't share Docker's own certs.d), the structural reason "up to
date" can't be fully trusted on this host even after that fix (CI builds on
the same dockerd the app runs on, so the local :latest tag is always fresh
regardless of whether the container was recreated from it), the failed
first Watchtower attempt (stale image, wrong Docker API version) and why
CI-triggers-a-redeploy was rejected again rather than reconsidered.
"Deliberately deferred" gets three new entries: finishing Watchtower,
migrating Gitea/CI to a dedicated VM (raised as the real fix for the
root cause D19 kept running into), and persisting the accumulated
host-local trust files across a reboot.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R2ZKeWkZV7ehf7fivrAkkG
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
BBergle
merged commit b467465f75 into main2026-09-21 23:22:44 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Targets
maindirectly — no stacking this time.Also carries forward the Phase 0 wrap-up commit that never landed: PR #12 reported merged but was based on PR #11's branch, which
mainhad already absorbed, so its content went nowhere (same trap as #7/#8/#9). Verified by checkingmain's actual file contents rather than trusting the merged flag.The correction
The plan's headline section claimed the Rider 650 has on-device Wi-Fi and a
Data Syncmenu uploading to Bryton's cloud phone-free. It does not — ANT+ and Bluetooth only, sole sync route is BLE to the Active app. Confirmed on the physical device, corroborated by BikeRadar's hands-on ("ANT+ and Bluetooth connectivity", syncing via "Bryton's Active App"). Likely origin: conflation with the Rider 750 / S800, which do have Wi-Fi.No built code is invalidated. Everything downstream of Bryton's cloud never depended on how rides got into it, so the poller, ingestion design, schema, wear engine and all of Phase 0 stand. What was invalidated is the promise: Phase 1 was "Zero-touch ride history" and claimed to fix the original complaint. It doesn't — it's one-tap. Renamed rather than left overclaiming.
Propagated the correction everywhere the premise had spread: PLAN.md's opening + Phase 1 + top risks + verification; D3's justification; README.md (additionally stale on nearly everything else — claimed no code written, Postgres, compose, four containers); and RESEARCH.md, where it originated under a "verified" header it hadn't earned. RESEARCH.md is annotated, not rewritten — it's a record of what was found, and the correction belongs in that record. USB path facts flagged unverified too, same 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.
The two requested phases
activity_field_inventory, so unknown/vendor fields appear rather than vanish).Plus the verbose-capture schema work from the same request: field-agnostic parsing,
activity_fit_messagesfor the non-time-series long tail,activity_field_inventoryso the UI renders everything dynamically.Inserted as 1A/1B rather than renumbering Phases 2–5, whose numbers are referenced from DECISIONS.md, deploy/README.md and code comments — shifting them silently is exactly what D20 is about.
No code changes.
🤖 Generated with Claude Code
https://claude.ai/code/session_01R2ZKeWkZV7ehf7fivrAkkG
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