Commit Graph

341 Commits

Author SHA1 Message Date
Claude Haiku 4.5 48f1057ff0 fix(ci): remove duplicate native_build_changed properties and add comprehensive release-job gating tests
ChatGPT review findings:
- Removed duplicate native_build_changed object property in classifyFiles() return (lines 69-71)
- Removed duplicate native_build_changed property in manual dispatch return (lines 150-152)

Added explicit behavioral tests for release-job gating:
- Dart-only changes on master → release skipped (native_build_changed=false)
- Android changes → release runs (native_build_changed=true)
- CI-only changes (.github/) → release runs (native_build_changed=true)
- Config changes (pubspec.yaml, build.yaml) → release runs (native_build_changed=true)
- Mixed changes → release runs (native_build_changed=true)
- Manual dispatch → release always runs (native_build_changed=true)
- Invalid Git SHA → safe fail to trigger release (native_build_changed=true)
- Unrelated changes (docs/, website/) → release skipped (native_build_changed=false)

All 52 tests pass. Release job condition verified to depend on:
- analyze passing
- test shards passing
- debug APK passing
- native_build_changed==true
- master ref

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-30 16:39:59 -04:00
Claude Haiku 4.5 b1abb6b086 ci: implement option 3 gate (skip release builds for Dart-only changes)
- Add isNativeBuildPath() to detect Android code, CI changes, and build config
- Update classifyFiles() to return native_build_changed output
- Update all detectAndroidChanges() return statements to include native_build_changed
- Add native_build_changed to GitHub Actions output
- Update release job condition to use native_build_changed output
- Skip release APK/AAB builds when only Dart/Flutter code changes
- Preserve and test all existing behavior (app_changed, android_changed)
- Add comprehensive test coverage: 42 tests, 100% pass rate

Tested scenarios:
- Dart-only changes (lib/, test/, assets/) → native_build_changed=false, skip release
- Native Android changes (android/, pubspec.yaml) → native_build_changed=true
- Dependency/config changes (pubspec.lock, build.yaml, .github/) → native_build_changed=true
- CI-only changes (.github/workflows/) → native_build_changed=true
- Mixed changes verified
- Invalid Git SHAs fail safe to true
- Manual workflow dispatch runs full build
- Historical repository commits tested
- Repository fixture tests verified

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-30 16:28:45 -04:00
Claude Haiku 4.5 70553e04a4 ci: implement option 3 gate (skip release builds for Dart-only changes)
- Add isNativeBuildPath() detector to distinguish Dart-only from native changes
- Add native_build_changed output to detect job
- Conditional release job: skip for Dart-only PRs, run for native/dependency changes
- Preserves all other jobs (analyze, test, debug APK) running always

This prevents redundant release artifact builds for Dart-only changes,
reducing storage quota consumption and CI time.
2026-10-30 16:18:16 -04:00
Billie Ponder 8fc267d5fd
fix(clubs,routes): owner no longer shown "Request to Join"; Route Planner starts at rider's area (#89)
* fix(clubs): respect existing membership in join presentation (#72)

* fix(routes): start planner from cached rider location (#76)

---------

Co-authored-by: Developer <dev@example.com>
2026-10-26 07:04:37 -04:00
Billie Ponder 63df8f9a50
Fix/forms keyboard batch2 (#87)
* fix(group_rides): make Join Group Ride dialog keyboard-safe in landscape (#69)

* fix(group_rides): responsive landscape form and keyboard scrolling in CreateGroupRideScreen (#70)

* fix(group_rides): constrain and scroll Attach Saved Route sheet in landscape (#75)

* fix(routes): make RoutePlannerScreen keyboard-safe and scrollable in landscape (#76)

* fix(clubs): make CreateClubScreen keyboard-safe and scrollable in landscape (#77)

* fix(forms): address PR #87 review findings on saved-route sheet and stop list auto-scrolling

---------

Co-authored-by: Developer <dev@example.com>
2026-10-26 01:51:12 -04:00
Billie Ponder 2524cd066e
fix(ui): landscape layout fixes for clubs, group rides and feed share (batch 3) (#88)
* fix(group_rides): prevent card bottom overflow in landscape grid (#68)

* fix(feed): ensure feed content and empty state scroll clear of share button (#71)

* fix(feed): make ShareRecentSessionModal keyboard-safe and scrollable in landscape

* fix(clubs): responsive grid and constrained card sizing in landscape (#73)

* fix(group_rides): prevent horizontal control clipping in Live Formation landscape (#74)

---------

Co-authored-by: Developer <dev@example.com>
2026-10-18 05:00:38 -04:00
Billie Ponder 74943a8420
Fix/garage layout batch4 (#86)
* fix(garage): improve landscape layout (#62)

* fix(garage): make service dialog responsive (#63)

* fix(garage): truncate service type dropdown (#64)

* fix(garage): avoid compact landscape card overflow (#62)

---------

Co-authored-by: Developer <dev@example.com>
2026-10-18 02:10:52 -04:00
Billie Ponder 3f64083bdd
Fix/landscape dashboard replay batch1 (#85)
* fix(dashboard): resolve landscape clipping and nav rail alignment (#54)

* fix(alerts): constrain road incident report modal in landscape (#55)

* fix(performance): adapt launch setup layout in landscape (#56)

* fix(performance): resolve 68px countdown overflow in landscape (#57)

* fix(history): resolve 12px card overflow in landscape (#59)

* fix(map): remove duplicate replay action in landscape (#60)

* fix(replay): optimize ride replay layout in landscape (#61)

* fix(dashboard): prevent Start Session button text clipping in landscape (#54)

* fix(dashboard): position lean angle title above rider graphic to prevent overlap (#54)

---------

Co-authored-by: Developer <dev@example.com>
2026-10-17 19:06:30 -04:00
Billie Ponder 1fdca019fb
Speed up Android CI with parallel checks (#83)
Co-authored-by: Developer <dev@example.com>
2026-10-17 15:47:56 -04:00
Billie Ponder 2d1bfbeef6
Fix/android followup 81 49 (#82)
* Fix coarse location labels and squad feed copy

* fix(social): align feed/share/inspector colors with app theme (#49)

* Avoid fabricated social feed locations

---------

Co-authored-by: Developer <dev@example.com>
2026-10-17 15:13:09 -04:00
Billie Ponder b005bb00ae
fix(android): resolve BUG-001 through BUG-005 (#78)
* fix(dashboard): ensure Touring map follows rider and supports recenter (#48)

* fix(social): make shared session telemetry read-only and authoritative (#50)

* fix(social): use recorded telemetry for feed charts and verify GPS badge (#51)

* fix(social): standardize community feed typography and theme colors (#49)

* fix(social): prevent horizontal overflow in GPX export snackbar (#52)

- Wrap GPX export snackbar message Text in Expanded with maxLines: 2 and TextOverflow.ellipsis

- Add ValueKey('gpx_export_button_<id>') for deterministic testing

- Wrap narrow feed header/metric/empty-state Row labels in Flexible to prevent overflow under 320px/360px at 1.5x text scale

- Add BUG-005 widget tests across 320x640, 360x800, and 800x480 viewports at 1.5x text scale

* fix(social): harden share modal, inspector theming, and PR #78 accuracy (#49, #50, #51, #52)

- Require a selected recorded Ride in ShareSessionModal before enabling publish

- Theme ShareSessionModal and FeedTelemetryInspectorModal for Light and Dark modes

- Use LayoutBuilder width for FeedTelemetryInspectorModal scrubber drag/tap

- Route PopupMenuButton export_gpx action through the overflow-safe GPX snackbar

- Enforce telemetrySamples >= 2 when provided to verifyGpsCriteria

* fix(android): remediate map follow smoothness, orientation controls, starting location, and landscape overflow (#79, #80, #81, #52)

* fix(android): stop Pro upsell sheet overflowing in landscape (#52 / BUG-005)

The "Forensic CSV & PDF Export" Pro upsell sheet showed "BOTTOM OVERFLOWED BY 90
PIXELS" in landscape on a Pixel 8a. showProUpgradeSheet built a non-scrolling Column
inside a default modal bottom sheet, which Flutter caps at 9/16 of the screen height
(about 230 dp in landscape) - shorter than the header, description and two actions.

Use isScrollControlled and wrap the content in a SingleChildScrollView so the sheet can
take the full height and never overflows. This also covers every other caller (garage,
add motorcycle, ride detail).

Tests: pro_upgrade_sheet_landscape_test covers 914x411 (Pixel 8a), 800x360 and 780x360
at 1.0x and 1.3x text scale plus NOT NOW dismissal. Verified to fail on the old code
(RenderFlex overflowed 64-144 px) and pass on the fix. Full suite 1700 passed,
flutter analyze clean. Not validated on the physical device yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(social): require telemetry evidence, geodesic GPS threshold, and 3 MPH lean gate (#50, #51)

---------

Co-authored-by: Developer <dev@example.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 14:35:33 -04:00
Billie Ponder 2ca069fdb9
fix(sensors): clear stale calibration state and preserve remount recovery (#46)
Co-authored-by: Developer <dev@example.com>
2026-10-15 07:40:34 -04:00
Billie Ponder 267f69f23d
ci: introduce manual Azure Pipelines Android pilot (#44)
* ci: add manual nonpublishing Azure Android pipeline pilot

* ci(azure): reclaim hosted runner disk and bound Gradle resources

---------

Co-authored-by: Developer <dev@example.com>
2026-10-15 03:42:45 -04:00
Billie Ponder e06ee51d70
ci(android): upload debug APK on demand and shorten artifact retention (#43)
Co-authored-by: Developer <dev@example.com>
2026-10-15 03:38:47 -04:00
Billie Ponder ac76257210
feat(website): smooth continuous replay camera follow and mobile tile loading (#42)
* feat(website): smooth continuous replay camera follow and mobile tile loading

- Smooth camera following: compute frame-rate-independent camera translation with 32px dead-zone and velocity clamping to keep motorcycle centered without camera oscillation or outrunning tile loading.
- Mobile tile rasterization: configure tile layers with updateWhenIdle: false, keepBuffer: 8, and updateInterval: 100 to eliminate Leaflet mobile pan tile freezing and black voids.
- Interactive follow controls: gracefully suspend auto-follow on user drag/zoom; add 'Following'/'Re-center' toggle and 'Fit Route' controls.
- Tile error recovery: single retry with backoff for transient tile errors before reporting fallback status.
- Add comprehensive unit tests in telemetry-camera-follow.test.ts and component behavioral tests in replay-map-camera-follow.test.tsx.

* fix(website): isolate tab recentering from sample advancement and suspend follow on manual zoom

- P1: Stop camera recentering at every telemetry sample boundary. In web-telemetry-replay-modal.tsx, isolate the map recentering and size invalidation effect to run solely on activeTab changes rather than on currentPoint index advancements. Track latest interpolated position via latestPositionRef, allowing the smooth camera follow engine to exclusively drive camera updates during playback without raw snapping.
- P2: Suspend follow mode upon user-initiated zoom gestures (pinch, wheel, double click via zoomstart) alongside dragstart. Guard programmatic zoom operations (initial fitBounds and fitRoute) using isProgrammaticZoomRef so initial map setup does not inadvertently disable follow mode.
- Add regression coverage in replay-map-camera-follow.test.tsx verifying sample boundary crossings within the dead-zone do not trigger raw panTo snapping, and verifying manual zoom suspends following until explicit Re-center.

---------

Co-authored-by: Developer <dev@example.com>
2026-10-15 01:56:09 -04:00
Billie Ponder e0de6f22ba
feat(website): smooth motorcycle replay animation with 60 FPS sub-sample interpolation (#40)
* feat(website): smooth motorcycle replay animation with 60 FPS interpolation and shortest-path heading

* fix(website): eliminate map pan thrashing, pause snapping, and non-finite coordinate exceptions in replay

* chore(website): remove development test page and screenshots, add authentic telemetry verification

* fix(website): reset replay carry on ride switch and translate fixture to synthetic coordinates

---------

Co-authored-by: Developer <dev@example.com>
2026-10-14 22:02:32 -04:00
Billie Ponder f5b734cccd
Merge pull request #37 from bponders12-cell/fix/v1.1-completed-ride-sync-recovery
fix(sync): completed-ride outbox recovery and cloud confirmation reconciliation
2026-10-14 17:11:43 -04:00
Developer a658cae3c5 Merge origin/master into fix/v1.1-completed-ride-sync-recovery
Reconciles PR #37 with master after #36 and #39. Worker changes are now
identical to master; only the Dart sync recovery and tests remain.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 16:45:23 -04:00
Billie Ponder d8670be7ea
Merge pull request #38 from bponders12-cell/fix/website-production-hardening-20261014
fix(website): production hardening — truthful states, labelled examples, support center
2026-10-14 16:18:42 -04:00
Developer 04e56a985d fix(website): harden account peak-lean states, stale metrics hygiene, and demo-chat error precedence
- Handle loading, unauthenticated, permission-denied, and unavailable states truthfully in metric-card-lean (Peak Lean Angle KPI) rather than falling back to '--' and 'No IMU roll data'

- Reset metrics state to null on auth change and in onStatusChange loading/error branches to prevent stale metrics retention

- Add race condition guard in AppCloudData.loadData to discard in-flight results if firebaseAuth.currentUser changed during asynchronous fetch

- Prioritize Disconnected and Connecting states over sample example messages in real club mode in founder-chat.tsx

- Clear chat messages on channel switch in founder-chat.tsx to eliminate cross-channel message bleed, and fix invalid py-0.2 Tailwind classes to py-0.5

- Add regression tests in account-metrics-truthfulness.test.tsx and founder-routes-chat.test.tsx
2026-10-14 16:05:37 -04:00
Developer 5e1ce969cc fix(website): truthful account metrics error states and persistent demo chat labeling
- Replace false zero metrics (0 miles / 0 rides / 100% Cloud Synced) on loading, unauthenticated, permission-denied, or network errors with truthful states

- Update AppCloudData to query motorcycles and rides via Promise.allSettled and report granular CloudDataStatus

- Update AccountPage KPI cards to display Loading…, —, or Unavailable with explicit contextual status and error recovery

- Fix founder demo chat to permanently preserve Example thread and example badges during preview=demo simulation instead of flipping to Live Connected

- Add 8 unit/component tests in account-metrics-truthfulness.test.tsx and 6 tests in founder-routes-chat.test.tsx
2026-10-14 15:49:12 -04:00
Developer 9c43a4f92e Merge remote-tracking branch 'origin/master' into temp/pr38-reconcile-20261014 2026-10-14 15:23:24 -04:00
Developer b61d1ebeec fix(website): monotonic timestamp ride IDs, zero-budget cursor guard, and modal input preservation
- Guard advancePlaybackIndex against spuriously advancing when budgetMs <= 0 on duplicate timestamps
- Use monotonic millisecond timestamp in commitGroupRide to eliminate timestamp corruption and collision hazards
- Preserve CreateGroupRideModal form inputs on failed commit so users do not lose typed data
- Add regression tests in vitest suites for zero-budget duplicate timestamps, timestamp fidelity, and input preservation
2026-10-14 15:07:00 -04:00
Developer a709b058b3 fix(website): replay edge-case resilience and concurrent ride submission guards
- Add replay regression test suite covering irregular/jittered timestamps, identical/zero dt, inverted timestamps, large gaps, pause/resume timing reconciliation, manual seek, speed changes, and large datasets (144k points).
- Harden advancePlaybackIndex against non-finite/NaN budget and timestamp delta anomalies.
- Reset lastTimeRef and cap frameDelta in WebTelemetryReplayModal to eliminate sudden jumps on speed switching or background tab resumes.
- Guard group-ride creation with in-flight isSubmitting state and disabled submit button in CreateGroupRideModal; guarantee unique collision-free ride IDs across concurrent submissions.
- Remove obsolete Vercel reference in website/.env.example in favor of Vultr VPS and Caddy; add npm test script.
2026-10-14 14:45:41 -04:00
Billie Ponder 25abf2815e
Merge pull request #39 from bponders12-cell/release/r2-worker-verification-20261014
feat(r2-worker): authenticated /r2/verify endpoint and lightweight metadata verification
2026-10-14 14:30:33 -04:00
Developer dd35b216d1 fix(website): persisted-only ride creation and reconciled replay timing (PR #38 hardening)
Phase 1 — group ride creation (no phantom rides):
- Check authentication and Firestore availability BEFORE touching UI state; an unauthenticated
  user (or unavailable Firestore) now gets an actionable error and no phantom ride, instead of a
  local entry that was never saved.
- Insert the ride into UI state ONLY after batch.commit() confirms the write; on commit failure
  nothing is inserted and an error is shown.
- Prevent duplicate submissions: the create modal disables its submit button while in flight, and
  the hub guards with a ref.
- The join code remains the real Firestore document id (no fabricated ids).
- Extract commitGroupRide (pure, dependency-injected) so every path is unit-testable.

Phase 2 — replay playback timing:
- The elapsed clock and rider marker both derive from the same cursor, so they cannot drift.
- Manual seeks (scrub, restart, corner jump, arrow keys) go through seekTo(), which reconciles
  playback timing (clears carry/last-frame) so no stale budget is applied after a seek.
- Make gap compression explicit: a caption labels the timeline as recorded elapsed time and warns
  that dead time in multi-segment recordings is skipped during playback.

Tests: commitGroupRide (unauthenticated / unavailable / commit-ok / commit-failed); group-rides
hub now uses an authenticated mock with deterministic Firebase — authenticated create persists,
unauthenticated create is blocked with no phantom, a failed commit leaves no phantom, and the
create modal blocks duplicate submits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 13:12:49 -04:00
Developer 6956e809a3 fix(website): truthful group-ride creation — no false success, no fabricated GPS (Phase 3)
Creating a ride from the hub had two integrity problems:
- The "Created … success" toast fired optimistically before the Firestore write, and a
  commit failure was only console.error'd — so a user could be told the ride was created
  when nothing persisted (the ride would then vanish on the next snapshot).
- Every created ride wrote a hardcoded meetingPoint at 34.5378, -83.9849 (Helen, GA)
  regardless of the typed location — fabricated GPS attached to real rides.

Fixes:
- Report success only after `batch.commit()` resolves; on failure, roll back the optimistic
  insert and show an error. When there is no authenticated session / Firestore, keep the
  local entry for responsiveness but make no cloud-success claim.
- Extract buildWebGroupRidePayload (pure): stores the rally point as displayName/address
  text and omits latitude/longitude (the web form has no map picker / geocoder, so we never
  fabricate coordinates). mapFirestoreRideToSummary already treats a missing coordinate as
  "not pinned yet".

Join-by-code, join/leave, edit, and delete flows were reviewed and persist/authorize
correctly; no changes needed there.

Tests: buildWebGroupRidePayload asserts no fabricated lat/lon, rally-point text/fallback,
authoritative organizer/access fields, scheduled-time handling, and club identity. Existing
group-ride UI tests remain green.

Known limitation: true address autocomplete and automatic route-distance calculation require
a geocoding/routing API that does not exist in this codebase; distance and rally point remain
free-text until that backend lands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:49:16 -04:00
Developer 30feb85aac feat(r2-worker): add authenticated /r2/verify endpoint and HEAD metadata support 2026-10-14 12:43:35 -04:00
Developer ae1980b4ed fix(website): synchronize telemetry replay playback with recorded time (Phase 4)
The replay loop advanced the cursor by one sample every 50 ms / speed, assuming a uniform
20 Hz stream. Recorded telemetry is not always uniform (segment breaks and GPS-loss gaps up
to 5 s), so the rider marker drifted out of sync with the elapsed-time readout — which is
derived from real timestamps — and "1x" did not match real time across gaps.

Make playback timestamp-driven:
- Add advancePlaybackIndex(points, fromIndex, budgetMs): a pure helper that consumes a
  budget of virtual recorded time, advancing by the real delta between samples so the
  marker tracks the elapsed-time clock. Disconnected transitions (per
  areTelemetryPointsConnected) are compressed to a single 50 ms step so playback never
  stalls across multi-second dead time. No coordinates are altered.
- Drive the rAF loop with frameDelta * playbackSpeed plus carry-over, resuming from an
  index ref so manual scrubs are honored.

Verified sound without changes: SHA-256-checked R2/inline telemetry load, CSV/GPX parse and
export integrity, loading/error/empty overlays, and tile-provider fallback.

Tests: advancePlaybackIndex covers uniform cadence, carry-over, gap compression, end-clamp,
and empty input. Existing replay/export/corner tests remain green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:36:07 -04:00
Billie Ponder 384f6b66a9
Merge pull request #36 from bponders12-cell/codex/master-consolidation-20261012
feat(consolidation): master convergence candidate for full PR stack (#27-#33) and Schema 8
2026-10-14 12:31:26 -04:00
Developer 4eb2075c7a docs(website): device-connections backend contract for the full "build real" feed (W-devices)
Documents the blocker: a richer connected-devices panel (platform, app version, last-seen,
accessory pairing) needs a FastAPI endpoint that does not exist yet. Records the proposed
GET /api/v1/account/connections contract and the website wiring to adopt it, and notes what
already shipped truthfully without a backend change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:12:02 -04:00
Developer 3cd8bbefa3 feat(website): grounded FAQ and validated contact on Support Center (W2)
The Support page was a single static line plus a mailto link. There is no public
ticket backend (only the internal ops console), so rather than simulate ticket
submission, improve the page truthfully:
- Add an FAQ grounded in features that actually ship (offline recording/sync,
  billing + 2FA managed in the mobile app, GPX/CSV export, session revocation,
  radar live-presence rules, public vs authenticated group rides).
- Add a validated contact form (name/email/topic/message) that opens a prefilled
  email in the visitor's own client. It never claims a ticket was filed and states
  plainly that the message is not sent until the visitor sends it.
- Keep support@motorsignal.app as the real, working fallback channel.
- Preserve the existing public-page visual system (content-page / eyebrow / faq-section).

Tests: FAQ + real mailto render; invalid input shows validation errors and no
submission claim; valid input opens a mailto (no simulated ticket) with the topic
and email encoded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:11:20 -04:00
Developer 2cb3ef9694 fix(website): label fallback club routes and chat as examples (W-routes, W-chat)
When a club has no curated routes or a chat channel has no messages, the data layer
returned fixture content with no indication it was sample data, so riders could mistake
MotorSignal's "Coastal Marshes" route or canned chat messages for their club's real data.

Flag fixture-sourced content and label it in the UI:
- Add isExample to ClubRoute and ChatMessage; set it on every fixture fallback path
  (empty Firestore collection/channel and the dev demo preview).
- Founder Routes: amber "Examples" count, an explanatory banner, and a per-card "Example"
  badge when the routes shown are samples.
- Founder Chat: an "Example thread" pill (instead of "Live Connected") and a banner when
  the only messages are examples, so the header never claims a live conversation that
  does not exist.

Tests: example-labelled routes render the banner/badge/count; example-labelled chat
renders the banner and "Example thread" pill and does not claim "Live Connected".
Existing route/chat tests (real data, no isExample) remain green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:08:15 -04:00
Developer 217e5a11c0 fix(website): replace fabricated account states with truthful ones (W-2FA, W-devices, W-metrics)
The account page asserted several things that were not backed by real state:
- Two-Factor Authentication was hardcoded to "ENABLED" for every signed-in user.
  Now derives from the real Firebase multiFactor enrollment and shows "NOT ENABLED"
  (enroll in the mobile app) unless a factor is actually enrolled.
- "App Connections & Sync" showed a hardcoded connected iOS app (iPhone 16 Pro, v4.1.0,
  "14m ago") and a paired "Cardo Packtalk Edge". Replaced with truthful states: real
  Google account link, authenticated-device count from the real /api/account/sessions
  data, and an honest "Unavailable on web" for Bluetooth comms/accessories (a browser
  cannot observe hardware pairing). Header status reflects real sign-in state.
- Dashboard metrics initialised to fabricated totals (12,480 mi / 184 rides / 56.4 deg).
  Now initialise to zero; AppCloudData replaces them with the rider's real ride totals.
- Dead controls fixed: "Manage Devices" and "Review active sessions" now anchor the real
  Active Device Sessions panel; the telemetry-privacy control no longer presents an
  unverified setting with a no-op "Change" button (managed in the mobile app).

Also adds the Phase 1 website feature audit matrix (docs/).

Tests: account-truthful-states asserts no fabricated device/pairing/sync claims render
and that 2FA is never shown as ENABLED without a real enrolled factor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 12:02:18 -04:00
Developer de6d575cee fix(sync): harden worker metadata headers, token refresh on confirmation, and reconciliation ownership isolation
- Set X-MotorSignal-* headers on Worker GET /r2/verify responses and return 503 TEMPORARY_ERROR when Firestore ownership lookup fails with 429/5xx
2026-10-14 11:27:46 -04:00
Developer c014c2f04f fix(website): stop club rank matrix from faking a permission save (WEB-W1)
The Ranks & Roles "Operational Permission Matrix" previously waited ~400ms and
showed a "Saved" state without persisting anything. No Firestore document, API
route, or security rule stores or enforces a per-rank capability matrix; club
authorization is role-based (Owner/Admin via getPortalPermissions). Persisting
the matrix would require frozen security-rule changes and would create an
unenforced permission model that misleads owners.

Make the control truthful instead of faking success:
- Render the matrix as a read-only reference of the standard governance model
  by default (persistenceAvailable=false): no Save/Reset controls, disabled
  toggles, a "View-only reference" indicator, and a notice stating that access
  is enforced by Owner/Admin roles and per-rank customization is planned.
- Remove the fake setTimeout save handler and the unconditional success state.
- Retain a forward-compatible editable path behind persistenceAvailable for
  when a backend contract ships.
- Document the precise backend contract required to enable persistence.

Tests: read-only matrix renders no Save control, reports no save, and does not
mutate permissions even for Owner/Admin; editable path still fires toggle/save
/reset when persistenceAvailable=true.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-14 11:20:29 -04:00
Developer cff4734678 fix(sync): harden R2 cloud confirmation verification, add worker tests, and resolve CI backup gate
- Enforce positive bundle size, matching SHA-256, user-scoped object keys, and legacyUnverified status for historical bundles in R2UploadService and FirebaseSyncProvider

- Update SyncManager reconciliation to accept legacyUnverified status, mark historical rides as synced without re-upload, and track legacy unverified counts

- Add 18-test vitest suite for Cloudflare Worker /r2/verify endpoint covering CORS, auth, validation, ownership, HEAD/GET, legacy bundles, and errors

- Harden test/disposable_backup_recovery_verification_test.dart with candidate path discovery and CI skip guard
2026-10-14 10:34:06 -04:00
Developer 5e0db4c191 fix(sync): harden cloud confirmation states, R2 edge 404 handling, and in-flight cancellation 2026-10-13 22:05:25 -04:00
Developer d431f11a13 fix(sync): harden cloud confirmation with R2 verification and account isolation 2026-10-13 21:31:06 -04:00
Developer c6c8c8df29 fix(sync): completed-ride outbox recovery and cloud confirmation reconciliation 2026-10-13 20:17:55 -04:00
Developer 493192078f fix(ui): landscape dashboard 3-column layout, decoupled alert presentation policy, truthful GPS contract, and diagnostics HUD 2026-10-13 18:11:47 -04:00
Developer ad99da10ba fix(alerts): decouple tactical map horizon, add diagnostics HUD, and trace Zyla pipeline 2026-10-13 14:47:30 -04:00
Developer 5fcaafbe36 fix(alerts): restore auth on startup, enforce token header, and prevent immutable list sort crashes 2026-10-13 13:50:37 -04:00
Developer 35f2b6982a fix: master consolidation fixes for Schema 8, legacy ride sync, performance timer isolation, and sync inspector 2026-10-13 10:24:24 -04:00
Billie Ponder f9e2bd6bed
fix(mobile): October 11 Pixel 8a field-test stabilization (navigation, sensors, sync, UI) (#33)
* fix(navigation): canonicalize turn maneuvers and protect road bends from false announcements

* fix(sensors): expand mount pitch tolerance, suppress dynamic zero drift, and add diagnostics

* feat(sync): add itemized SyncStatusInspectorScreen and non-destructive queue diagnostics

* fix(map): dismiss search keyboard on selection, add compact address card, and wire map controls

* fix(ui): split pause action with hazard report, harden profile contrast, and bind social ride picker

* ci(android): enable stacked PR validation, verify package identity, and guard release to master

* fix(auth): register CI debug SHA-1 in Firebase and wire authoritative webClientId to GoogleSignIn

---------

Co-authored-by: Developer <dev@example.com>
2026-10-12 06:34:32 -04:00
Developer 92d883ff90 fix(backend): cast cost calculation to numeric for postgresql round compatibility 2026-10-10 20:44:19 -04:00
Developer b552a43a6a build(android): sign debug build with release key when present for device compatibility 2026-10-10 20:23:30 -04:00
Developer 8a60da6328 fix(alerts): default road alert providers backend URL to production gateway with environment fallback 2026-10-10 20:19:50 -04:00
Developer 32907213c4 fix(alerts): exactly-once Zyla request accounting and Firebase QA/prod isolation (#31, #32)
- Fixed Zyla request accounting to record each actual upstream HTTP attempt exactly once, eliminating double-counting when body parsing, JSON decoding, or normalization fails
2026-10-10 19:56:16 -04:00
Developer f8b86babd2 fix(alerts): atomic monthly DB usage limits and real Firebase gateway auth (#31, #32)
- Replaced JSON usage tracker with PostgreSQL/SQLAlchemy-backed PersistentUsageTracker using atomic row-level UPSERT reservations
2026-10-10 19:31:09 -04:00