- 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
- 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
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>
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>
* fix(website): expand Founder Portal layout width to fill available canvas
* fix(website): restore mobile padding, preserve public main landmark, and harden width test
Apply responsive mobile padding to .site-page-frame under 760px. Render semantic <main> for public routes and <div> for portal routes with internal <main> via SitePageFrame. Assert max-w-[1536px] exclusively and reject old max-w-[1440px] cap in founder-portal.test.cjs.
---------
Co-authored-by: Developer <dev@example.com>
Add the disabled Founder Portal Club Rides scaffold aligned with the live GroupRide.clubId domain.
Keep production discovery and actions disabled until a privacy-preserving read path and real management destinations are implemented.