feat(onboarding,ui): trust-first onboarding + Button primitive + honest privacy surface#759
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 23 minutes and 40 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (18)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…surface Adds a reusable <Button variant size> primitive (4 variants × 5 sizes) with focus ring baked in, and an honest privacy disclosure surface so trust claims are visible at the moments they matter. - Button primitive matches the design handoff spec exactly, includes forwarded ref, defaults type=button, focus-visible ring on every interaction. - WhatLeavesMyComputerSheet lists the five things that actually leave the laptop (model downloads, cloud providers, skill sync summaries, crash reports, account/billing/chat routing). Copy is intentionally conservative to not overpromise: chat routing goes through our backend, skill sync summaries go to the memory service. - WhatLeavesLink is a tiny reusable trigger to drop near any network-touching action. - PrivacyPanel (Settings → Privacy & Security) surfaces the same list above the existing analytics toggle, so the full story has a settled home. Tests: 10 Button tests, 6 sheet/link tests. yarn compile + yarn lint clean.
ContextGatheringStep previously ran the Rust-side learning.linkedin_enrichment
pipeline silently in useEffect on mount. That is exactly the "surveillance"
shape OpenHuman is positioned against. This change gates the pipeline behind
an explicit user click and surfaces what will happen before it happens.
- Removed silent auto-run. New intro card explains what the step does, what
will be read, and what happens if you skip ("nothing is read" — now a true
statement).
- Two controls on the intro: primary "Start when ready" (or "Continue" when
no Gmail to read) and ghost "Skip for now".
- WhatLeavesLink visible on both the intro and the running view.
- Body copy softened throughout to describe what is actually happening
(third-party LinkedIn scraper, local profile file) without overclaiming.
- WelcomeStep slide 1 rewritten to handoff copy (mono eyebrow, display title,
honest subtitle) with WhatLeavesLink in the footer. Carousel slides 2/3
preserved. Subtitle copy is deliberately conservative: chat routing does
go through our backend, so the line describes the routing truthfully.
- E2E login-flow spec updated: new heading markers ("Getting to know you" /
"Reading your connected accounts" / "Context Ready"), expanded candidate
actions to include "Skip for now" and "Start when ready". Prefers Skip so
the real Rust enrichment pipeline stays out of E2E.
Tests: 4 WelcomeStep tests (copy, privacy link, CTA, disabled/loading);
4 ContextGatheringStep tests (user-driven gate does not auto-run, no-Gmail
branch marks skipped without RPC, Skip invokes onNext, Start fires pipeline
exactly once with correct method). Full yarn test:unit suite green
(498 passed, 2 pre-existing skips).
… WelcomeStep test - Rebase onto upstream/main (20 commits since PR merge base) - Resolve PrivacyPanel.tsx conflict: keep upstream capability-backed dynamic privacy list (PR tinyhumansai#760) rather than the static whatLeavesItems fallback — the dynamic system supersedes the static one - Resolve WelcomeStep.tsx conflict: keep simplified interface from upstream (nextDisabled/nextLoading/nextLoadingLabel removed) plus WhatLeavesLink footer from this PR - Resolve login-flow.spec.ts conflict: remove ReferralApplyStep comment (step was removed in upstream PR tinyhumansai#772), keep ContextGatheringStep user-driven gate copy from this PR - Fix WelcomeStep.test.tsx: remove test that passes now-removed props (nextDisabled, nextLoading, nextLoadingLabel) — update to verify CTA is always enabled in simplified interface - Apply Prettier formatting across files reformatted post-rebase - All quality checks pass: typecheck clean, lint 0 errors, format unchanged, 534 unit tests passed (2 pre-existing skips)
9f7e43f to
bd6030d
Compare
…st privacy surface (tinyhumansai#759) Co-authored-by: Jwalin Shah <jshah1331@gmail.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
Summary
<Button variant size>primitive (4 variants × 5 sizes) with focus ring baked in — foundation for future UI consolidation.WhatLeavesMyComputerSheet+WhatLeavesLinkprivacy surface, reused in onboarding footer and Settings → Privacy & Security. Copy is intentionally conservative and matches what the backend actually does.ContextGatheringStepno longer auto-runs the Rust-side LinkedIn enrichment pipeline on mount. It is now user-driven: an intro card explains what will happen, with "Start when ready" and "Skip for now" controls.WelcomeStepslide 1 rewritten to the design handoff copy (mono eyebrow, display-font title, honest subtitle). Carousel slides 2/3 preserved.login-flow.spec.tsupdated to match the new ContextGatheringStep headings and prefer "Skip for now" so the real enrichment pipeline stays out of E2E.Problem
Two trust-shaped gaps in the current onboarding:
ContextGatheringStepkicked off a Gmail → LinkedIn scrape pipeline insideuseEffecton mount, before the user had seen what was about to happen. That is exactly the "nothing ever leaves your computer" lie the README explicitly rejects.PrivacyPanelonly surfaced the analytics toggle.A third, lower-level gap: there was no shared
Buttoncomponent, so every flow reinvented the same Tailwind utilities slightly differently.Solution
UI primitive (
app/src/components/ui/Button.tsx)Matches the design handoff spec exactly: 4 variants (
primary/secondary/ghost/danger) × 5 sizes (xs/sm/md/lg/xl).forwardRef, defaulttype="button", focus-visible ring applied by default on every instance. Intentionally not ripping existing ad-hoc buttons in this PR — it lands the primitive cleanly and leaves adoption incremental.Privacy surface (
app/src/features/privacy/)whatLeavesItems.tsis the single source of truth: 5 items that really do leave the laptop (model downloads; cloud provider calls; skill sync summaries to the memory service; crash reports; sign-in / billing / chat routing).WhatLeavesMyComputerSheetis a portal modal with backdrop, Escape-to-close,aria-modal.WhatLeavesLinkis a tiny underlined trigger for any screen that might hit the network.PrivacyPanelin Settings now surfaces the same list above the analytics toggle.Copy audit was intentional before commit — three lines were softened because they were slightly stronger than what the backend actually supports (skill data does sync to our memory service per
17-skills-memory-inference-flow.md; chat messages are routed through our backend to the selected model perchat.rs; the LinkedIn pipeline uses Apify, not a user-chosen scraper).Onboarding honesty pass
WelcomeStepslide 1: eyebrowOPENHUMAN · LOCAL BY DEFAULT+ display-font "Hi. I'm OpenHuman." + honest subtitle ("routes to the cloud when you pick a cloud model"). Footer hasWhatLeavesLink. Slides 2/3 untouched.ContextGatheringStep: the pipeline now fires only from an explicit user click. Intro card describes what gets read, and "skip this and nothing is read" is finally a true statement. The running UI keeps its existing progress visualization, plusWhatLeavesLink. Body copy is softened throughout.Intentional deferrals (keeping the bar high on overpromise):
sourcesSlice— would duplicate the existingdraft.connectedSourcesstate inOnboarding.tsx.MirrorMomentStep— no Rust-sidescan_sources/ observation generator exists, so any stub would fake the payoff and undercut everything else this PR is trying to do. Gate hard = don't create.Drift commit (
9f7e43fe): the pre-push hook surfaced two unrelated items already drifting onmain(cargo fmt ordering insrc-tauri/src/lib.rs, one-line wrap inwebview_accounts/mod.rs,Cargo.lockversion 0.52.27 → 0.52.28 to matchpackage.json). Picked up here so this PR can push cleanly rather than ride--no-verify.Submission Checklist
yarn test:unitgreen (498 passed, 2 pre-existing skips).login-flow.spec.tsupdated to match new ContextGatheringStep heading markers and to prefer "Skip for now" so the real Rust enrichment pipeline stays out of E2E. No new E2E file.whatLeavesItems.tscarries a short rationale block explaining why the list exists and why copy must not soften. Privacy components are small and self-evident.Impact
ContextGatheringStepnow requires an explicit click to start — meaningful UX change; the step no longer auto-completes on reachable users. (2) New "What leaves my computer?" affordance visible onWelcomeStepandContextGatheringStep. (3) Settings → Privacy & Security now explains what leaves the machine in addition to the analytics toggle.<Button>primitive incrementally.Related
openhumanclaudedesign.zip(v2 onboarding pass).<Button>adoption.