chore: back-merge main → dev (2026-08-20) - #2769
Conversation
The site directory had no route to any legal document, and the two links that existed (Terms, Privacy in the footer nav) sat apart from the five card-programme documents, which were reachable only mid-application from CardTermsScreen. App-store review and the card issuer both expect those permanently reachable, so all seven now live in one Legal column. - Legal column: Terms of Service, Privacy Policy, Card Terms (U.S.), Card Terms (International), E-Sign Consent, Account Opening Privacy Notice, Prohibited Activities Policy — locale-routed like the manifest entries, so a Spanish reader lands on Spanish prose. - Resources column is gone; Help Center, Pricing and Supported Networks move to the top of Learn More. The manifest's "Terms" entry is dropped (a stale Notion export superseded by the /terms page) along with "Jobs", which already sits in the footer nav above. - Footer nav drops Terms and Privacy — one home per document. - footerTerms/footerPrivacy now read "Terms of Service"/"Privacy Policy", the labels a legal column wants; footerResources gives up its slot to the new Legal keys across all four catalogs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018GWaH5h1Prm6zpeXkKWcZR
`apt-get update`, run inside `npx playwright install-deps chromium`, stalls intermittently on the runner's Azure mirrors. On 2026-08-19 it killed the e2e job three consecutive times on one commit — each run ignoring azure.archive.ubuntu.com, then hanging on archive.ubuntu.com noble-security until the 6-minute cap — while sibling runs minutes apart cleared the same step in seconds. Unrelated branches hit it the same afternoon, so it is not branch-specific. The stall is transient, so retry rather than mask: three attempts with a 150s per-attempt cap, dropping to the canonical archive after the first failure. One bad mirror now costs an attempt instead of the whole job. Deliberately still exits non-zero once the attempts are spent. Since `Run E2E tests` is continue-on-error, a setup step is the only thing that can red this job — making the install non-fatal would leave a genuinely missing system library silently unreported. The job cap moves 6 → 9 minutes to fit three bounded attempts; it stays well under the job's own 20-minute ceiling, so the fail-fast property that `ci-success` depends on is preserved. Verified by extracting the run block and exercising it under `bash -e` with fakes for npx/sudo/timeout: succeeds on first pass, recovers on a third attempt, and exits 1 when all three stall. The guarded pkill/sed cleanups return non-zero without aborting the script. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018GWaH5h1Prm6zpeXkKWcZR
Review feedback on the retry loop. `timeout` already runs the attempt in its own process group and signals that whole group, so the apt children do receive the SIGTERM — `--kill-after=15s` escalates to SIGKILL for any that ignore it. That makes `sudo pkill -9 -f '[a]pt-get'` both redundant and unsafe: it matched by command line across the entire runner, so it could have killed unrelated package work rather than only this step's descendants. Removed. The apt partial-list cleanup stays — that clears state a killed attempt leaves behind, which is what the next attempt trips over. Re-verified under `bash -e` with fakes: succeeds first pass, recovers on the third attempt, exits 1 when all three stall. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018GWaH5h1Prm6zpeXkKWcZR
The two QR-scanner catch blocks only console.error'd. Sentry's console
integration already forwards that as captureException(err), but the
event is titled by the inner error, untagged and payload-less, so a
live support case ("Error processing QR code" on Itaú Pix terminals)
left no findable trace.
Capture explicitly with error_type=qr_scan_processing plus the first
64 chars of the payload, and downgrade the console call to info so the
console integration does not emit a second event for the same throw.
The paste path forwards arbitrary clipboard text and a scanned Peanut claim link carries a bearer secret, so a blanket 64-char excerpt could ship a user's secret to Sentry (CodeRabbit). Gate the excerpt on the EMVCo "000201" payload-format indicator — Pix / Mercado Pago / QR3 are machine-generated merchant data and the family this report exists for. Everything else keeps qrLength only. One helper now owns the rule.
A static Pix QR with a personal key embeds the payee's CPF/phone inside the first 64 chars, so even an EMVCo-gated excerpt ships PII; no excerpt is safe by construction. Replace it with qrKind (pix/emv/url/other) — a closed enum derived on-device — next to qrLength. Tests assert the exact extra object and that a claim-link secret never leaves the device.
…ps-retry fix(ci): retry Playwright system-deps install past apt mirror stalls
Scan failures cannot be diagnosed from a family enum; the report needs the payload itself. Send it in full as extra.qrPayload next to qrLength and qrKind. This carries payee/merchant data, a claim link's fragment, or whatever the paste path hands in — a privacy trade the code owner accepted on 2026-08-19 (PR #2757); the helper is the single place to change if that call is reversed.
…pture fix(qr-scanner): make onScan throws findable in Sentry
…s-audit-z4ed53 feat(footer): Update legal links in Footer
…0820-104554 content: publish latest to production (src/content → peanut-content@cebac1c)
The eslint job has been advisory since it was split out of `format`, so a lint error could land on main unnoticed. `pnpm lint` is at 0 errors today (64 warnings), so there is nothing to pay down before turning the gate on. Drop `continue-on-error` — with it set the check reports green whatever eslint says, which makes any "required check" flag a no-op — and add the job to `ci-success.needs`. The branch ruleset requires only `ci-success`, so this makes lint blocking on main and dev with no ruleset edit. Warnings still do not gate. Ratchet to `--max-warnings` separately. Claude-Session: https://claude.ai/code/session_01P6CXdiGhc3io26wXXDsjjk
ci: make eslint blocking on peanut-ui
…s and screen heights The paste link was positioned from the top of the viewport while the drawer's collapsed peek grew from the bottom, and vaul resolves a fractional snap point against the drawer's own content height. The peek therefore changed with both the locale (pt-BR wraps the drawer's body text to two lines) and the screen height, so the two met and the link went under the drawer — every locale below 667px, and pt-BR on tall phones such as the S24 Ultra. Give the drawer a full-height content box so px snap points are exact visible heights, and anchor the paste actions a fixed gap above that known peek.
jsdom has no layout, so the geometry was verified in a browser. What this pins is the coupling that would silently regress: the anchor offset must be derived from QR_DRAWER_PEEK_PX, so changing the peek can never leave the paste link behind again.
The PR body references them by commit SHA, which keeps resolving after the files leave the tree.
…taining block Review findings on the first pass: h-full resolves a percentage height against the initial containing block, which on a mobile browser with a retractable toolbar is the LARGE viewport. vaul resolves a snap point against window.innerHeight, so the two disagreed by the height of the toolbar and the collapsed peek grew by that much — putting the drawer back over the paste link on exactly the Chrome Android phones the bug was reported from. A headless browser has no toolbar, so the measurement matrix could not see it. h-[100dvh] tracks innerHeight. The expanded snap also became a fixed height on a drawer that no longer grows with its content, so a longer translation or a larger font-size setting cut the share button off with nothing to scroll: the shared max-h-[80vh] cap is never reached inside a 520px window. Cap the scroll area to the expanded window instead, less the rem-based drag-handle block, so the scroll region lands on the bottom of the viewport at any font size. Also move the shared geometry into a constants module so the scanner no longer imports the drawer component, and drop min-h-[200px], which h-[100dvh] made dead.
…k-drawer-overlap fix(qr-scanner): keep paste link above the My QR drawer on all locales and screen heights
…into-dev-20260820 # Conflicts: # src/components/Global/QRBottomDrawer/index.tsx # src/components/Global/QRScanner/__tests__/index.test.tsx # src/components/Global/QRScanner/index.tsx # src/components/Global/QRScanner/useQRScanner.ts
|
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: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Code-analysis diffPainscore total: 7292.27 → 7299 (+6.73) 🆕 New findings (21)
…and 1 more. ✅ Resolved (21)
…and 1 more. 📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
Back-merge of
mainhotfixes intodevso dev is a clean superset before the next release.Brings over (main-only):
reportQrScanError+ tests, kept in fullConflict resolution (4 files, all QRScanner/QRBottomDrawer):
QRBottomDrawer/index.tsx,QRScanner/index.tsx: dev side kept — it is the refined superset of main's hotfix (deterministic peek,QR_DRAWER_EXPANDED_PXCSS var, iOS 15.0–15.3h-screenfallback, pointer-events wrappers, paste-chip copyuseCopiedCode).QRScanner/useQRScanner.ts: union of imports — dev'sensureNativeCameraPermission+ main'sreportQrScanError; both call sites auto-merged.QRScanner/__tests__/index.test.tsx: dev constants kept (CHIP_LABELmatches dev copy) + main'sPIX_PAYLOADre-added for the Sentry-report tests.Verified locally: prettier clean,
jest QRScanner32/32 pass,tsc --noEmitclean.🤖 Generated with Claude Code
https://claude.ai/code/session_01QniCxBnNTbMzj4QCQHAwWT