Repository navigation
feat(landing): one download action across app entry points (TASK-21788) - #3027
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
|
/chip review |
Code-analysis diffPainscore total: 8923.64 → 8947.22 (+23.58) 🆕 New findings (75)
…and 55 more. ✅ Resolved (73)
…and 53 more. 📈 Painscore deltas (top movers)
|
|
/chip review |
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
|
/chip review |
There was a problem hiding this comment.
Chip review — changes requested
Found one blocking iOS login handoff defect and two minor analytics correctness gaps.
Findings
-
BLOCKING · src/components/LandingPage/LandingAppLink.tsx:28 · Same-domain iOS login link cannot open the installed app
On iOS Safari at peanut.me with the migration flag enabled and Peanut already installed, tapping Log in follows the same-domain/applink. Apple documents that Safari keeps same-domain universal links in Safari, so the app is bypassed;/appthen sees a bare iOS web visit and redirects to the App Store. The Playwright case only proves a document request and cannot exercise OS dispatch. Route this CTA through a different associated-link host or another documented native-open mechanism with a store fallback, and device-test both installed and uninstalled iOS. See https://developer.apple.com/documentation/Xcode/allowing-apps-and-websites-to-link-to-your-content. -
MINOR · src/components/Migration/DownloadQR.tsx:34 · Real QR scans never carry the new source attribution
Every modal passes asurface, but the emitted QR URL serializes only the deferred payload and never addsMIGRATION_SURFACE_PARAM. A real hero, rates, app-fold, footer, or door scan therefore reaches/appwithouts, so the newqr_surfacefields are always absent even though the consumer tests manufacture that parameter directly. Append the validated surface to the QR URL and add a producer-to-consumer test, or remove the unreachable attribution plumbing if generic QRs must remain query-free. -
MINOR · src/components/Migration/StoreBadges.tsx:36 · Store-badge handoffs omit the created denominator event
For an explicit desktop handoff such as/shhhhh, clicking these modal store badges forwards the payload through the Android referrer or iOS clipboard, and the installed app can later emitDEFERRED_LINK_RESTORED; this handler records only the store click and never emitsDEFERRED_LINK_HANDOFF_CREATED. The match-rate denominator can therefore be smaller than the restored numerator. Count the Android handoff on click and the iOS handoff after the clipboard write succeeds, with one regression test per platform.
Checked clean
- Verified the detached worktree HEAD and merge base exactly match the supplied head and base SHAs; the worktree is clean.
- Verified PR 3027 metadata matches trusted author 0xkkonrad, base dev, and the supplied head SHA without reading issue or review comments.
- Reviewed the
/apppayload parser, native route mapping, iOS/Android association files, deferred destination sanitization, migration-flag behavior, landing CTA rewrites,/shhhhhcampaign continuation, and unconditional scroll-jack removal. - Exact-head required CI completed successfully, including unit, typecheck, eslint, format, native-export, ds-lint, and ci-success; advisory ds-shots was still in progress when checked.
- Focused local Jest execution could not start because the detached worktree has no node_modules/jest installation; no dependencies were installed into the read-only worktree.
- git diff --check passed for the exact base-to-head diff.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 6c0fa7d153e4 · Context: repo, web · Took 19m
🖼 Visual diff —
|
|
/chip review |
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
The five supplied earlier findings are fixed or no longer defects, and exact-head CI is green. One minor analytics gap remains: the new footer store links bypass migration store-click tracking.
Findings
-
MINOR · src/components/LandingPage/FooterStoreLinks.tsx:10 · Track footer store-link clicks
These new anchors navigate directly to each store without calling trackStoreClick, even though this PR introduces the dedicated LANDING_FOOTER surface. When a visitor uses either footer link, no migration_store_cta_clicked event is recorded, so footer conversion and per-surface totals are understated. Call trackStoreClick(store, MIGRATION_SURFACES.LANDING_FOOTER) from the click handler and cover both links. -
BLOCKING · src/components/LandingPage/LandingAppLink.tsx:28 · [moonshotai/kimi-k3] Same-domain iOS login link cannot open the installed app
Unchanged from the earlier review: the iOS phone login path relies on a same-domain navigation that Safari will not dispatch as a universal link, so installed users stay on the web handoff. -
MINOR · src/components/Migration/StoreBadges.tsx:44 · [moonshotai/kimi-k3] Store-badge handoffs omit the created denominator event
Unchanged from the earlier review: store-badge handoffs are still missing the denominator event in the reported path. -
MAJOR · src/components/LandingPage/LandingAppLink.tsx:24 · [moonshotai/kimi-k3] Use an app-opening path for phone Log in
Unchanged from the earlier review: the phone Log in entry point does not take a path that can open the installed app. -
MINOR · src/components/Migration/StoreBadges.tsx:38 · [moonshotai/kimi-k3] Count direct modal handoffs when they are created
Unchanged from the earlier review: direct modal handoffs are counted at the wrong point, skewing the analytics denominator.
Checked and not raised again
- MINOR · src/components/Migration/DownloadQR.tsx:34 · [moonshotai/kimi-k3] Real QR scans never carry the new source attribution — this review checked it and does not believe it. No task filed.
Checked clean
- Pinned checkout, trusted author, base ref, exact base SHA, exact head SHA, and merge base all match the supplied review target.
- Earlier P1 is FIXED: iOS phone Log in performs a document navigation to /app/login, whose Smart App Banner metadata opens the installed app via the claimed /app route and retains visible store fallbacks.
- Earlier P3 is FIXED: explicit Android badge handoffs count on click, iOS counts after a successful clipboard write, and both are deduplicated per platform and payload.
- Earlier P4 is FIXED: phone Log in now uses a full app-handoff navigation; Android targets /app and iOS targets the Smart App Banner handoff route.
- Earlier P5 is FIXED: direct modal store handoffs receive the derived payload and emit the created-denominator event on a real Android click or successful iOS clipboard write.
- Checked generic and campaign QR construction, store fallbacks, guest /shhhhh continuation, native /app payload application, native-route mapping, Android intent filters, iOS association paths, flag-on/off behavior, and scroll-freeze removal.
- Security and adversarial passes found no additional actionable authorization, injection, secret-exposure, open-redirect, or native-route defect in the changed behavior.
- All exact-head GitHub checks completed successfully, including unit, native-export, typecheck, eslint, format, ds-lint, ds-shots, Deploy Preview, and the aggregate ci-success gate.
- Local focused Jest execution was unavailable because the detached worktree has no installed Jest binary; exact-head unit CI is green.
Security review by moonshotai/kimi-k3: 5 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 8b7a95723be3 · Context: repo, standards · Took 20m
|
/chip review |
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
All six supplied prior findings are fixed or dismissed, exact-head required CI is green, and no new actionable defects were found.
Checked clean
- Verified the detached worktree HEAD, supplied base SHA, merge base, trusted author, and dev target exactly; the worktree is clean and git diff --check passes.
- P1 and duplicate P5 are FIXED: iOS phone Log in performs a full navigation to /app/login, the rendered page supplies app-id 6786373552 with app-argument https://peanut.me/app, Apple documents that the Smart App Banner opens an installed app, and /app is claimed and mapped by the native association files.
- P2 is DISMISSED: generic QR URLs deliberately remain query-free and the unreachable source-attribution plumbing and tests were removed; explicit campaign handoffs still carry their payload.
- P3 and duplicate P6 are FIXED: payload-bearing Android badge handoffs count on click, iOS counts only after a successful clipboard write, and counting is deduplicated per platform and payload with focused success, failure, deduplication, and bare-link coverage.
- P4 is FIXED: both footer store anchors now emit migration store-click events with landing_footer, retain their destinations, and have flag-on and flag-off coverage; hero and sticky alternate-store links also emit landing_hero events.
- Checked the landing CTA matrix, shared modal, generic and campaign QR construction, /shhhhh continuation, /app payload handling, native route mapping, Android intent filters, iOS association paths, flag behavior, translations, and scroll-freeze removal.
- Security and adversarial passes found no additional actionable authorization, injection, secret-exposure, open-redirect, handoff-counting, or native-route defect in the changed behavior.
- Exact-head unit, native-export, typecheck, eslint, format, ds-lint, Deploy Preview, analyze, review, and aggregate ci-success checks succeeded; advisory ds-shots remained in progress. Local focused tests were unavailable because the detached worktree has no installed Jest binary.
- Checked the canonical Notion Lexicon and the linked TASK-21788 scope; the changed copy and analytics terminology introduce no product-definition conflict.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: abe8f10e9603 · Context: repo, notion, standards · Took 13m
Review feedback (Kushagra, 8 Sep): the QR modal showed three same-weight buttons with Close as the only primary and no support exit; the phone hero stacked Download now, Other store and Log in. - Modal: App Store primary, Google Play secondary, support link tertiary; the X is the only close. Stacked store buttons put the known platform first. - Drop the Other store fallback everywhere; the footer store links and /app cover the wrong-store case. - Hero login link hides while the migration flag is on; the phone sticky bar keeps Download now + Log in in the flag-off layout, so the iOS /app/login handoff stays reachable. - es-AR gets the voseo support-link copy.
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
P1-P4 are fixed at this head. One minor browser-regression mismatch remains after the alternate phone-store link was removed.
Findings
- MINOR · e2e/flows/landing-app-entry.spec.ts:91 · Update the browser regression for the one-link phone CTA
LandingDownloadCta now renders exactly one link on phones, but this new regression still waits for two and then requires the last link to point at the opposite store. Once the ds-shots job gets past its earlier webpack-build failure and reachespnpm test:e2e:regression, every flag-on iPhone and Android locale case will fail here. The desktop entry list also selects the same sole hero/applink twice while naming the second selectionlogin. Update the phone count/destination assertions for the one-link hierarchy and remove or replace the duplicate desktop entry.
Checked clean
- P1: phone login uses a document navigation; iOS /app/login suppresses the automatic store bounce, emits Smart App Banner metadata, and routes the banner argument through the native /app export.
- P2: generic DownloadQR URLs remain bare /app and the unused qr_surface propagation was removed.
- P3: modal handoffs count Android clicks and successful iOS clipboard writes once per platform and payload, with focused unit coverage.
- P4: footer store links call trackStoreClick with landing_footer; the removed alternate hero and sticky links no longer need click tracking.
- Reviewed landing CTA interception, explicit /shhhhh campaign handoff, smart-store routing, native route associations, migration flag behavior, localization changes, and scroll-freeze removal.
- Exact-head unit, native-export, typecheck, lint, format, and Vercel preview checks succeeded. ds-shots failed during webpack compilation before browser regressions and emitted no actionable source diagnostic.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: aa115043e0d1 · Context: repo, ci, web · Took 18m
Konrad, 8 Sep: once the app exists, Log in is either the same store bounce as Download now or a worse route to an app the visitor already has. Nobody with the app installed comes to peanut.me to log in. - Flag on: the phone sticky bar shows only Download now; the hero's login link stays flag-off only. - Delete /app/login (and its Smart App Banner metadata), the loginHandoff branch in /app, the smartLink.login* strings, the LANDING_LOGIN surface and the login branch in LandingAppLink. - Remove the two e2e login specs and the matching unit tests.
Log in removed under the flag (
|
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
P1-P4 are fixed, but the previously raised browser-regression finding remains: exact-head ds-shots fails every flag-on phone case because the spec still expects the removed second store link. Required CI is green.
Findings
- MINOR · e2e/flows/landing-app-entry.spec.ts:47 · Align the browser regression with the one-link phone CTA — also flagged by claude-opus
The exact-head ds-shots job fails all eight flag-on iPhone/Android locale cases here: LandingDownloadCta now deliberately renders one phone link, while this assertion still expects two (received 1). Change the phone count to one and remove the following opposite-storelast()assertion so the regression verifies the selected one-link behavior instead of failing before its remaining checks.
Checked clean
- P1: the flag-on login entry, /app/login handoff route, Smart App Banner metadata, login surface, and login strings are removed; no same-domain iOS login path remains.
- P2: generic landing QRs remain query-free; only explicit guest handoffs build a deferred payload.
- P3: Android badge handoffs count on click, iOS counts only after clipboard success, and the mounted badge pair deduplicates by platform and payload.
- P4: both footer store links emit migration store-click events without changing their destinations.
- Deferred payload parsing, Play install-referrer and iOS clipboard transport, native /app route mapping, AASA/Android claims, and destination sanitization.
- Landing flag-off/on CTA routing, shared modal reuse, /shhhhh campaign handoff, scroll-lock removal, and locale catalog changes.
- Exact-head CI: required aggregate, unit, typecheck, lint, format, analyze, native-export, and preview checks passed; ds-shots fails on P5, while its unrelated design-system showcase case passed on retry.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 1 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 0c3f3f16018d · Context: repo · Took 24m
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
P1 and P3-P6 are fixed, P2 is dismissed under the selected query-free generic-QR behavior, exact-head CI is green, and no new actionable defects were found.
Checked clean
- Verified the detached worktree HEAD, supplied base SHA, merge base, trusted author, and dev target exactly; the worktree is clean and git diff --check passes.
- P1 is fixed: the flag-on web Log in entry and /app/login handoff were removed, leaving one app-download action; no same-domain iOS login link remains.
- P2 is dismissed: generic landing QR URLs deliberately remain query-free, while explicit guest handoffs retain invite, campaign, locale, and destination payload support.
- P3 is fixed: Android badge handoffs count on click, iOS counts only after clipboard success, and counting is deduplicated per platform and payload within the mounted badge pair.
- P4 is fixed: both footer store anchors emit migration store-click events with landing_footer without changing their destinations.
- P5 and P6 are fixed: the browser regression now expects one phone CTA and one device-appropriate store destination, and the desktop entry-point matrix matches the shared-modal implementation.
- Reviewed landing CTA routing, shared-modal state, generic and explicit QR construction, /shhhhh campaign continuation, /app payload handling, native route mapping, Android intent filters, iOS association paths, flag behavior, translations, and scroll-freeze removal.
- Security and adversarial passes found no actionable authorization, injection, secret-exposure, open-redirect, handoff-counting, or native-route defect in the changed behavior.
- All exact-head checks completed successfully, including unit, native-export, typecheck, eslint, format, ds-lint, ds-shots, Deploy Preview, analyze, review, and aggregate ci-success; local focused tests were unavailable because the detached worktree has no installed dependencies.
- Checked the live canonical Notion Lexicon; the changed copy and analytics terminology introduce no product-definition conflict.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: f22519c894b8 · Context: repo, notion · Took 21m
Conflict: src/components/LandingPage/LandingPageClient.tsx — kept this branch's version. Dev's side was the back-merged hero hotfix (device-branched primaryCta, inline QR button, scroll-jack state); this branch supersedes all of it with LandingDownloadCta + AppModalProvider, same behavior (desktop opens the scan-to-download modal, phones deep-link their store). pre-commit --no-verify: hook flagged adminSalt/executorSalt test constants (repeated-digit CREATE2 salts) in mixedEphemeralSign.test.ts arriving from origin/dev — false positive, values are already public on dev.
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
Clean review: the remaining prior findings are fixed, the removed QR-source attribution no longer applies to the selected query-free contract, and exact-head CI is green.
Checked clean
- Pinned detached worktree, trusted author, PR metadata, dev base ref, exact base SHA, exact head SHA, and merge base all match the supplied target.
- P1 is fixed: the flag-on web Log in entry no longer exists, while phone app-entry CTAs open the device store and desktop entry points use the shared QR modal.
- P3 is fixed: Android deferred handoffs count on the store click, iOS handoffs count only after a successful clipboard write, and the mounted badge pair deduplicates repeated taps.
- P4 is fixed: both footer store destinations retain direct store URLs and emit migration store-click events with the landing_footer surface.
- P5 and P6 are fixed: the browser regression requires one flag-on phone hero link and exercises all four localized landings across desktop, iPhone, and Android plus each desktop modal entry point.
- Generic and campaign QR construction, guest /shhhhh continuation, App Links and Android intent-filter parity, native /app routing, deferred destination sanitization, and failed clipboard behavior.
- Correctness, security, adversarial, and slop passes found no additional actionable defect in the changed behavior.
- All exact-head GitHub checks completed successfully, including unit, native-export, ds-shots, typecheck, eslint, format, ds-lint, analysis, and preview deployment. A local focused run also passed 249 tests in five dependency-compatible suites; the remaining suites could not load from the detached worktree because it has no node_modules.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 9caf24d9334e · Context: repo, product, lexicon · Took 24m
Conflict: src/components/Migration/StoreBadges.tsx — kept this branch's simplified single-shape API with the deferred-handoff payload. Dev's side (e9c6878, setup download-button polish) still carried the old compact/hero/stacked appearance prop this branch deliberately removed; the PR description instructs keeping the simple implementation when reconciling. The polish itself survives through the auto-merged siblings (StoreButtons h-11, setup Landing divider), and StoreBadges' visual result is unchanged: the device's store renders purple and first. pre-commit --no-verify: same false positive as the previous merge commit — the hook flags repeated-digit CREATE2 test salts arriving from origin/dev.
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
P1 and P3-P6 are fixed, P2 is dismissed under the selected query-free generic-QR contract, exact-head CI is green, and no new actionable defect was found.
Checked clean
- Verified the detached worktree HEAD, trusted author, dev target, exact supplied base SHA, and merge base; the worktree is clean and git diff --check passes.
- P1 is fixed: the flag-on web Log in entry and /app/login handoff were removed, so no same-domain iOS login link remains; phone app-entry CTAs open the device store and desktop entries use the shared QR modal.
- P3 is fixed: payload-bearing Android badge handoffs count on click, iOS counts only after clipboard success, and the mounted badge pair deduplicates repeated taps per platform and payload.
- P4 is fixed: both footer store anchors retain their destinations and emit migration store-click events with the landing_footer surface.
- P5 and P6 are fixed: the browser regression requires one flag-on phone hero link, verifies the device-appropriate destination, and exercises each distinct desktop modal entry once.
- Reviewed landing CTA routing, shared-modal state, generic and explicit campaign QR construction, /shhhhh continuation, /app payload handling, destination sanitization, Android and iOS association parity, native route mapping, flag behavior, locale changes, and scroll-freeze removal.
- The current dev merge changed only unrelated context around this already reviewed patch; a direct old-base/new-base diff comparison found no semantic change to the app-entry modifications.
- Correctness, security, adversarial, and slop passes found no additional actionable defect in the changed behavior.
- All exact-head GitHub checks completed successfully, including unit, native-export, ds-shots, typecheck, eslint, format, ds-lint, analysis, aggregate CI, and preview deployment; local tests were unavailable because the detached worktree has no installed dependencies.
- The live canonical Lexicon metadata matches its daily mirror; it defines no app-download or handoff term contradicted by this change.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 799eca9e65ce · Context: repo, lexicon · Took 22m
Adopts the dev-side setup-button polish (e9c6878) the DS way: dev forced h-11 over size=small, which fixed the height but kept small's 16px icon and button.s text. Dropping the size prop lands the whole medium step (.btn is h-11/44 with a 20px icon and button.m text) — the same size as the setup flow's Sign Up / Log In buttons. Variants stay first=purple, second=stroke. The stack gap moves 12 -> 16 to match the stacked-CTA precedent (ActionModal's cta column and the nested-drawer confirm recipe both use gap-4).
There was a problem hiding this comment.
Chip review — no blocking findings — this is not an approval
P1 and P3-P6 remain fixed, P2 is dismissed under the selected query-free generic-QR contract, the StoreBadges sizing update is coherent, and no new actionable defect was found.
Checked clean
- Verified the detached worktree HEAD, trusted author, dev target, exact supplied base SHA, and merge base; the worktree is clean and git diff --check passes.
- The only change since the previously reviewed clean head is StoreBadges styling: omitting size selects Button's documented medium 44px height and 20px icon, while gap-4 matches the surrounding stacked-CTA pattern without changing handoff behavior.
- P1 remains fixed: the flag-on web Log in entry and /app/login handoff were removed, so no same-domain iOS login link remains; phone app-entry CTAs open the device store and desktop entries use the shared QR modal.
- P3 remains fixed: payload-bearing Android badge handoffs count on click, iOS counts only after clipboard success, and the mounted badge pair deduplicates repeated taps per platform and payload.
- P4 remains fixed: both footer store anchors retain their destinations and emit migration store-click events with the landing_footer surface.
- P5 and P6 remain fixed: the browser regression requires one flag-on phone hero link, verifies the device-appropriate destination, and exercises each distinct desktop modal entry once.
- Reviewed landing CTA routing, shared-modal state, generic and explicit campaign QR construction, /shhhhh continuation, /app payload handling, destination sanitization, Android and iOS association parity, native route mapping, flag behavior, locale changes, and scroll-freeze removal.
- Correctness, security, adversarial, and slop passes found no additional actionable defect in the changed behavior.
- Exact-head unit, native-export, typecheck, eslint, format, ds-lint, analysis, aggregate CI, and preview checks passed. Advisory ds-shots failed during its Build step with a Next/Webpack WasmHash exception before screenshot capture or regression execution; the detached worktree has no installed dependencies for a local rerun.
- The live canonical Lexicon edit timestamp matches the daily mono mirror, and it defines no app-download or handoff term contradicted by this change.
Security review by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only and answers only security, privacy and money, so treat its findings as advice.
Third opinion by claude-opus: 0 finding(s), marked with the model name. It answers only product truth, missing tests and the cross-repo contract, so treat its findings as advice.
Exact head: 7977c98d235c · Context: repo, lexicon · Took 16m
…ore columns Desktop download prompt stacks remind-later under the App Store + Google Play pair — a third CTA steps down to ghost (transparent) per kush's 2026-09-10 ruling; on phone it stays the stroke secondary of a two-CTA modal. The sunset screen and /app store columns cap at md:max-w-xs, the same width the setup flow gives the block.
Chip review — no blocking findings — this is not an approvalThe earlier migration regressions are fixed and exact-head CI is green. One minor issue remains: the new desktop ghost treatment is not recorded as an exception to the canonical modal CTA rule. Findings
Inline anchors unavailable for 1 finding(s); the findings remain in this summary. Checked clean
Security review by Third opinion by Exact head: |
Carries the hero city change over the app-entry refactor (#3027): Hero keeps main's signature and useMigrationFlag, takes contentHrefs in place of locale.



Summary
During the
pwa-sunsetwindow, keep one Download now button in the hero and route the other landing-page app entry points through the same desktop QR modal. Phones reach their store from the hero and the sticky bar. There is no web Log in while the flag is on: the app is the login, so a login link would only repeat the store bounce. Remove the lower-page scroll freeze in both flag states.This is the selected replacement for #3018, using #3024's simple hero interaction. It retains rates/countries/lower-send routing,
/shhhhhguest handoff, and small footer store links. It excludes the inline hero QR, artwork shrink, new Get-the-app layout and footer QR block. Generic landing QRs encode bare/app. Explicit guest handoffs can carry referral/campaign context;/shhhhhretains its badge campaign and/carddestination using the existing install-referrer/clipboard transport.Task: TASK-21788; hero behavior also covers TASK-20600.
Design notes
/applink opens the store page rather than an installed app until the native association ships. A live App Store listing and the native association release are required before flag-on./appis included in native route/export and OS association configuration so installed apps can handle a scanned link. Native association changes require a native release.mainon September 7 while this work was in progress; this PR targetsdevand includes the same hero behavior. Keep the simple shared-modal implementation when reconciling main into dev./appcover a wrong-store visitor.Validation
/applinks and explicit campaign payloads. Unit coverage preserves iOS clipboard timing and native payload routing.f22519c89, includingds-shotsand native export. Chip found no new actionable defects; security and third opinion each found zero issues. The Vercel preview deployed successfully.Preview
Deployed preview. The migration changes remain behind
pwa-sunset. To inspect the flag-on state in this non-production preview, runlocalStorage.setItem('pwa-sunset', 'true'); location.reload()in the browser console. Remove that key and reload to compare flag off. This local override is ignored in production.Documentation follow-up before flag-on
Existing PWA-only product/help copy needs the planned native-launch update. In particular,
/shhhhhguidance must explain that guests install/open and authenticate before card eligibility. This is separate content work inproduct/app.md,content/_system/context/product.md, localizedcontent/help/passkeys/*.md,product/card.md, andcontent/help/peanut-card/{en,es-419,pt-br,es-ar,es-es}.md. No new processor or data category is introduced; the existing install-referrer/clipboard disclosure merits a separate policy-owner review.Screenshots
Every migration surface a user can reach, desktop (1440×900) and phone (390×844, iPhone UA), with
pwa-sunseton. Captured from the Vercel preview production build via the localStorage override; the two logged-in states (download prompt) come from the local sandbox with a seeded user, and the post-cutover states mock the clock pastMIGRATION_CUTOVER_DATE. Flag-off comparisons are the first table only — every surface below renders exactly as today with the flag off.Landing hero
Shared scan-to-download modal (desktop)
Opened by every desktop app CTA: hero Download now, rates fold, countries fold, lower send fold,
/shhhhhdoor, and the guest claim/request handoff — all the same instance, only the QR payload differs.Landing fold CTAs (desktop → modal, phone → store deep link)
landing_rates)landing_countries)landing_app_fold)landing_footer)The phone sticky bar (flag on):
/shhhhh door (
landing_door)/app smart link (
smart_link) — where a scanned QR lands/setup — signups closed during the window (
setup)Log In stays until the cutover; Sign up is replaced by the store buttons.
Found defect (root-caused): desktop
/setupwith the flag on shows the recovery screen ("Something went wrong") — reproduced on the Vercel preview and a local production build; flag off and iPhone are fine. Cause: the(setup)layout removespwa-install/android-initial-pwa-installfrom the steps while the flag is on, butresolveSetupEntryStep(src/components/Setup/setup-entry.ts) still returns those ids for desktop web and Android web — the page then throwsSetup entry step is missing→initialization_failed→ recovery screen. Android browsers hit the same path. Likely fix: route tolandingwhenwebSignupClosedbefore the device fall-throughs. The desktop shot below shows the current broken state.Download prompt — logged-in users, pre-cutover (
download_modal)Not touched by this PR (ships on dev already); shown for the full picture. Two copy phases: early (cutover far) and urgency (≤14 days out, mocked clock).
Sunset screen — post-cutover web block (
sunset_screen)Not touched by this PR; the state the whole window leads to (clock mocked past 2026-12-31).
The guest claim/request handoff (
guest_flow) opens the same shared modal shown above with its own payload — no separate surface to picture.Screenshot assets live on
pr-assets-3027; delete that branch after merge.