Commit Graph

310 Commits

Author SHA1 Message Date
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
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 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
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 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 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
Developer 9f73fd4cd4 fix(alerts): remediate P0 gateway auth, P1 Zyla schema, and budget safeguards (#31, #32) 2026-10-10 18:23:32 -04:00
Developer 625999245e feat(alerts): address review hardening for multi-source road alerts (#31) 2026-10-10 17:46:01 -04:00
Developer bcae4881d6 feat(alerts): multi-source road alert architecture with Zyla #4814 and Georgia 511 (#31) 2026-10-10 17:28:17 -04:00
Developer 789769c20e fix(alerts): enforce atomic count pairing and eliminate orphan vote loophole in firestore.rules 2026-10-10 16:35:35 -04:00
Developer bb3e8fb8c4 feat(alerts): authoritative cross-device road alert vote aggregation via Firestore transactions 2026-10-10 03:18:47 -04:00
Developer de94bbb3e3 fix(alerts): harden road alert voting, isolate Waze OSINT adapter, purge OpenWebNinja 2026-10-10 02:58:15 -04:00
Developer 7bd5a0e585 feat(alerts): native community road alerts and experimental Waze OSINT adapter
- Support 10 native alert categories: police, accident, hazard, pothole, debris, disabledVehicle, roadClosure, construction, traffic, weatherHazard
2026-10-10 02:31:06 -04:00
Developer 082b22fe00 fix: implement stationary lean-angle calibration recovery for right-pinned or remounted sensors
- Permit recovery from stale or right-pinned lean angle calibration when motorcycle is physically upright
2026-10-10 00:28:32 -04:00
Developer ab4b322d85 fix: complete acceptance review hardening for navigation, routing, social, maintenance, and lean-angle calibration
- Voice navigation: configure Bluetooth SCO/A2DP and audio focus ducking; announce maneuvers and support mute
2026-10-10 00:05:21 -04:00
Developer 618ef8798b feat(navigation): implement shared turn-by-turn navigation, route preferences, and garage/telemetry enhancements 2026-10-09 21:03:22 -04:00
Developer 28dc54a0c5 ci: allow flavored APK output in android debug verification step 2026-10-09 19:23:25 -04:00
Developer 3ba94777a1 fix: resolve Android CI breakpoint overflow and address Codex PR #28 findings
- Fix RenderFlex overflow at short landscape breakpoint (640x320) by scaling center controls in ResponsiveDashboardLayout and clamping LeanAngleIndicator bounds
2026-10-09 18:53:39 -04:00
Developer 20da9ee27d feat(core): reconcile local development, hybrid design, sensor fusion, and docs
- Consolidate Hybrid v1 tokens, theme extensions, and core UI components (HybridCard, HybridMetricTile, HybridRidingActionBar, HybridStaticRecBadge)
2026-10-09 05:12:01 -04:00
Developer 602aa962e2 fix(website): isolate Firebase configuration for staging and enforce safety guards 2026-10-08 10:50:28 -04:00
Developer bd278cdfd3 docs: update comprehensive platform feature report and qa audit record 2026-10-02 12:40:42 -04:00
Developer 8fd337c672 fix(mobile): apply qa defect remediation for stop barrier, photo attribution, and alert dismissal 2026-10-02 12:40:08 -04:00
Developer c956ffd7bd feat(website): add club curated routes, live squad chat, and portal navigation 2026-10-02 12:39:38 -04:00
Developer 368858670d feat(website): add club moderation, stats, and group rides management 2026-10-02 11:07:44 -04:00
Developer aced2b5435 fix: open club updates from the notification bell 2026-10-01 08:32:06 -04:00
Developer f495ec0cac feat: add club members and wall management 2026-10-01 08:31:45 -04:00
Developer d378db4c86 fix(social): resolve community feed discoverability, tab routing, live comments, and responsive overflows 2026-09-30 09:49:02 -04:00
Developer 71cd994b2f feat(mobile): add community social feed, tactical layers, club wall, launch curves, and curvy routes (v1.0.2+102) 2026-09-29 11:50:48 -04:00
Developer 9bc16329ef feat(website): apply stitch tactical design tokens and group ride firestore sync 2026-09-27 07:56:56 -04:00
Developer f20a09addf feat(website): discrete group rides showcase and management architecture lock 2026-09-25 18:36:54 -04:00
Developer 69fefd7b56 feat(website): create separate showcase and management group rides pages 2026-09-25 16:00:47 -04:00
Developer 126f2c6c5f feat(website): add Group Rides Hub navigation links for authenticated riders 2026-09-25 15:35:55 -04:00
Developer 30539108fa fix(group-rides): address PR #27 review findings and responsive dashboard layout 2026-09-25 15:35:32 -04:00
Developer 67c25b5c50 feat(website): build interactive group rides hub with live pack radar, filters, and modals 2026-09-25 14:35:58 -04:00
Developer 46ce052e0c feat(group-rides): add mobile join request moderation UI and service (Phase 3B)
Connects mobile group ride details to the Phase 3A moderation server endpoint (GET /api/group-rides/[rideId]/join-requests).
2026-09-24 14:17:19 -04:00
Billie Ponder c1aa68ac43
feat(group-rides): secure club join moderation and discovery (Phase 3A) (#26)
* feat(clubs): enable admin group ride governance

* feat(clubs): add secure member ride discovery

* fix(clubs): protect meeting location in ride discovery

* feat(group-rides): secure club join moderation

* test(clubs): update ride discovery expectations

* test(founder-portal): update rides governance expectations

* fix(group-rides): resolve pre-merge findings on join moderation and discovery

- Block participant hard deletes for accepted status and organizer role for all callers

- Support atomic accessUids removal on invitation decline in firestore.rules

- Restrict mutual-block checks to approvals in GroupRideService, allowing decline of blocked requests

- Implement cursor-paginated candidate scanning with block filtering in website discovery API

- Add comprehensive emulator, vitest, and unit tests covering all 5 findings

* fix(discovery): page candidates until 30 eligible rides collected or query exhausted

- Remove artificial 150 candidate scan ceiling in club rides discovery route

- Continue cursor pagination until 30 unblocked eligible rides are collected or upcoming schedule query is exhausted

- Add test verifying pagination continues past 150 blocked rides to collect all 30 eligible rides

---------

Co-authored-by: Developer <dev@example.com>
2026-09-24 12:00:48 -04:00
Billie Ponder 1e7e670a17
fix(ops): query actor_user_id on AuditEvent and optimize session health check (#25)
Co-authored-by: Developer <dev@example.com>
2026-09-22 02:05:50 -04:00