Skip to content

Prod release SP-152 — dev → main - #2506

Merged
jjramirezn merged 60 commits into
mainfrom
dev
Jul 24, 2026
Merged

Prod release SP-152 — dev → main#2506
jjramirezn merged 60 commits into
mainfrom
dev

Conversation

@jjramirezn

Copy link
Copy Markdown
Contributor

Release page: prod release sp 152

Merge after the backend release PR is Live on Render (peanut-api-ts SP-152).

Changelog (PRs new to main)

Note: the eslint check is advisory (continue-on-error: true) and red from pre-existing lint debt on both branches — not a release blocker.

🤖 Generated with Claude Code

kushagrasarathe and others added 30 commits July 17, 2026 14:47
Name mismatch (Bridge BE01) is the top cause of returned SEPA/ACH
deposits, but the beneficiary/account-holder name was shown as a plain
row while amount and reference got prominent warnings. Add a warning so
users send from an account in their own name and enter the recipient
name exactly as shown.
Fold the name-match guidance into the existing 'Double check before
sending' checklist card instead of a separate warning card, so there is
one source of pre-send do-nots (no drift, no signal dilution from a
fourth alarm card). Omit it for MX/SPEI, where paying from a third-party
account is a supported flow and the own-name rule does not apply.
BE01 validates the creditor (recipient) name too, not just the sender
account. Add the recipient-name-exact line alongside the sender rule in
the same non-MX branch.
fix: warn about name mismatch on bank deposit details
Hotfix debt from the 2026-07-16/17 card-issuance outage. main carries the
callback-ref fix that dev lacks; without this back-merge the next dev → main
release would revert prod to the broken wrapper.
…lent again

The Jul-16/17 card outage ran 19h and was found by a customer in Dhaka, not by
us. The reason is structural, not bad luck: a WebSDK that never launches throws
nothing, requests nothing and logs nothing. Sentry cannot see code that does not
run, so the only trace was throughput quietly going to zero. This closes that
class of failure rather than the one instance of it.

Watchdog: if the modal is open and the SDK has not launched within 20s, show the
error UI instead of the infinite spinner. Deliberately keyed on `visible` ALONE —
every silent path (null container, token that never arrives, script that never
loads) ends with the init effect simply not running, so anything keyed on those
deps would also never run. Watching the one fact the user experiences ("I opened
it and nothing happened") catches the whole class, including causes we have not
thought of yet.

Telemetry: kyc_sdk_launched / kyc_sdk_launch_timeout / kyc_sdk_init_failed. The
timeout event carries hadAccessToken / sdkScriptLoaded / hadContainer, which are
the three facts that distinguish the silent stalls from each other. Makes
"opened but never launched" alertable instead of archaeology.

Also corrects the mechanism comments shipped in #2441: the one-commit delay comes
from headlessui's <Transition> promoting tree state inside an effect, NOT the
Portal (isolation-tested: dialog-only mounts the container synchronously;
transition-only does not). The fix was right, the explanation was not, and a
wrong comment misleads the next reader.

Tests: the watchdog fires and surfaces the error UI when the SDK never launches,
and does not fire once it has.
feat(kyc): watchdog + telemetry so a stuck Sumsub SDK can never be silent again
The in-app card is composited layer-by-layer in code, so it drifted from
the finalised Rain art (what Apple Wallet shows): it rendered a mascot with
no PEANUT wordmark and an inverted-white Visa with no tier. Swap the top row
to the PEANUT lockup (mascot + black wordmark) and a black VISA with a
Platinum tier line. Closes TASK-20469.
The composited hand used -rotate-15 + h-full + a negative top inset, which
shoved it up so the fingertips crowded the Visa and the gesture tilted off
from the finalised Rain art. Anchor it upright at the bottom (h-90%) so the
fingertips clear the top logos and the arm sweeps to the bottom-right corner.
Two corrections after seeing the real card:
- The PEANUT wordmark was rendering white (PEANUT_LOGO is the dark-bg
  variant). Use PEANUTMAN + PEANUT_LOGO_BLACK for the black lockup the
  finalised art shows.
- The bottom-anchored hand covered the eye toggle and the revealed
  PAN/CVV. Slide it diagonally off the bottom-right corner while details
  are shown or being fetched (loading skeletons included), and move the
  masked/error eye inline with the number so it stays in a hand-free zone.
  The hand slides back when the card is re-masked.
Lowering the per-transaction limit left the card holding more than its
new target: the auto-balancer only ever tops up (rebalance-decision
no-ops when collateral >= limit), so the excess sat in the collateral
contract indefinitely. After the limit PATCH succeeds, sign a FORCED
collateral-only withdrawal of the excess back to the user's smart
wallet - the PATCH-first ordering keeps the auto-balancer from racing
the withdrawal by topping the collateral back up.

UX: the user only sees the passkey prompt. The unified displayed
balance is identical before/after (both buckets are folded into one),
and the intent kind AUTO_REBALANCE maps to INTERNAL_TRANSFER, which
history hides. Failures are non-fatal by design: the limit change
already stuck, and re-saving the limit retries the return.

forceStrategy on useSignSpendBundle exists because live-balance routing
would pick smart-only (a self-transfer no-op) whenever the smart wallet
covers the amount - the exact trap the lock-card flow comments around.
CodeRabbit review: the forced-path insufficient branch skipped the CARD_WITHDRAW_FAILED capture resolveSpendStrategy emits, leaving a gap in the withdraw funnel for the excess-return flow; and the forced branch had no direct tests.
…mit-decrease

feat(card): return excess collateral to wallet on limit decrease
Backend now marks every Bridge rail blocked for UK residents with reason
code 'uk_resident_blocked'. Surface it honestly instead of the generic
'we couldn't unlock this / contact support' (ID-failure) framing:

- InitiateKycModal gains a 'region-unavailable' variant — 'Not available
  in the UK', regulatory copy, single 'Got it' dismiss (no verify, no
  contact-support)
- add-money + withdraw bank pages pick that variant when the gate's reason
  is uk_resident_blocked

Card block rides on the existing eligibility machinery (BE denylist).
- title 'Not available for UK residents' (conveys residence, not the
  destination country — a UK resident is blocked even withdrawing to SEPA)
- drop the card mention from the bank-flow copy
- CTA 'Withdraw funds' -> /withdraw so users can exit via crypto
- wire the region-unavailable variant into AddWithdrawCountriesList (the
  country-selection modal), not just the add-money/withdraw bank pages
fix(card): match in-app card art to finalised Visa Platinum lockup
A restaurant tip settled $9.18 above its auth and silently overdrew the
user's collateral to -$6.31; her next deposit repaid it invisibly and she
reported 'my deposit was not fully credited' (2026-07-21). The FE clamped
negative spending power to $0 and buried the adjustment in a week-old
receipt, so nothing anywhere explained the balance drop.

- receipt: Authorized + Adjustment breakdown (cause-neutral copy — Rain
  does not say whether it was a tip, FX true-up, or incidentals)
- feed: 'Adjusted' flag on settlement-adjusted card rows
- card screen: 'Card balance due' banner from negative spendingPower
  instead of the silent $0 clamp
A re-settle back to exactly the auth amount leaves settlementAdjusted
stuck true; the tooltip claimed the charge 'differed' while the receipt
showed equal amounts. Split the copy: matched vs unknown vs delta.
…ailable check (Hugo review)

The 'reason.code === uk_resident_blocked' -> region-unavailable ternary was
copy-pasted across the add-money/withdraw bank pages and the country-list.
Centralize in one helper alongside getKycModalVariant.
The bare-badge /invite screen labeled its primary CTA "Claim your badge"
while actually routing to signup, and framed login as an alternative to
claiming rather than the other path to it. Only logged-out visitors ever
see this variant (logged-in users are auto-claimed), so the buttons now
say what they do: Sign up / Log in, with the description explaining that
either one claims the badge.
Keeps all per-variant strings (title, description, ctaLabel, loginLabel)
in one place instead of burying one ternary in the JSX.
feat(kyc): honest UK-resident block on Bridge bank flows (TASK-20729)
…copy

fix: honest signup/login CTAs on vanity badge claim screen
SimpleFi (early Argentina QR provider) is deprecated and its creation
path was removed in peanut-api-ts#1218. Drop the FE-side remnants: the
payment-app logo asset + export, the DEPRECATED_SIMPLEFI avatar branch
in getAvatarUrl, and the SIMPLEFI keys in test mocks.

Historical rows are safe: 247 transaction intents with provider
DEPRECATED_SIMPLEFI still arrive on the wire, so the Provider union
keeps the value (mirrors DEPRECATED_SQUID), their kind=QR_PAY still
dispatches to the qrPay strategy (locked by the vendored
qr_pay-deprecated_simplefi render-snapshot case), and getAvatarUrl now
falls back to undefined -> generic default avatar (new test).
Grafana has been decommissioned at Peanut; support agents now use the
prod DB + PostHog per the updated ops playbook (mono 2d873bc). Drop the
dead links the FE still generated: the Crisp session-data
grafana_dashboard entry (useCrispUserData / crisp.ts / useCrispProxyUrl
/ crisp-proxy page), the GRAFANA_DASHBOARD_BASE_URL constant, and the
dev invites-graph click-to-Grafana handler (click now just selects the
node). The Crisp session-data push itself is unchanged beyond the
deleted entry.
…afana

chore: remove decommissioned SimpleFi + Grafana remnants
The Welcome-@anon handbook's real pitfalls (comms rules, urgency
hierarchy, task ownership, DoD, sick/weekend policy, security,
invoicing) as a 23-question quiz, so new joiners actually retain them.
Single self-contained file in public/ per the quiz paved path: zero
deps, zero build-graph impact. Linked from /dev with a plain <a>
(public/ files aren't app routes). Prettier-ignored like dev-quiz:
hand-tuned inline CSS/JS.
Safari drops transient user activation across the awaited toBlob, so
clipboard.write always rejected and COPY silently became a download —
construct the ClipboardItem synchronously around the Promise<Blob>.
Guard the null-blob path (createObjectURL(null) threw uncaught and
killed both buttons), defer revokeObjectURL past the download fetch,
skip petal-rain repaints while the tab is hidden, and derive the boot
banner count from QUESTIONS.length.
R3 from the P2P send-link/request follow-ups audit (TASK-20131).
getContributorsFromCharge took charge.payments.at(-1) with no status filter,
so a failed (or pending) last payment still produced a contributor row — the
"Contributors (N)" count was inflated and could show a failed payer's name.
The BE collected total counts SUCCESSFUL payments only; match it: pick the last
SUCCESSFUL payment and drop charges that have none.
kushagrasarathe and others added 22 commits July 23, 2026 12:46
Switch from Option A (which deleted the Bank/Crypto method screen and left an
ambiguous country list — users couldn't tell bank was an option) to Option B:

- Keep the up-front Bank/Crypto method screen (bank is clearly visible).
- After the user picks Bank + a country, go STRAIGHT to that country's deposit
  screen instead of showing a second "From Bank / From Crypto" list:
    - AR/BR  -> /add-money/<country>/manteca (Manteca surfaces Pix/Mercado Pago)
    - other bank-supported countries -> /add-money/<country>/bank
  Every add method for a given country converges on one of these two screens
  anyway, so the per-country list was pure repetition where bank is live.
- Coming-soon countries (bank not enabled) keep the per-country screen — there
  it's still useful: it shows the "soon" bank state and the crypto fallback.

Net effect: the user clicks "bank" once, up front; the duplicate second
selection is gone. This reverts the Option A page/view/test churn — the diff is
now just handleCountryClick routing (+ effect-deps cleanup) and its tests.
feat: Peanut Welcome Club onboarding quiz (static HTML in public/)
…hod-selection

fix(add-money): remove the duplicate method selection, not the method screen (TASK-20033)
The numbers-flex caption in the appeal-tweet pool hardcoded the original
'213 tried, 7 got in' placeholder, so shared tweets contradicted the
rejection screen itself, which already renders the real computeDoorTally
counts. Build the pool per share from the same tally so the two surfaces
always agree.
…tors-successful-only

fix(request-pot): count only successful payers as contributors
Konrad's call: rather than interpolating the live tally into the share
caption, remove the fake-stats caption entirely ('213 tried, 7 got in')
and de-number 'rejection #1' → 'my first rejection'. A no-digits test
locks the invariant so stat-flavored captions can't sneak back in.
…ve-tally

fix(card): remove hardcoded-stats rejection-share captions
- Banner: "$X will come off your next deposit" event framing instead of
  "Card balance due" — a prepaid card must not grow a credit-card bill,
  and "settled above its authorized amount" was auth/capture jargon the
  affected users don't have. Copy names example causes (tips, updated
  totals) without asserting one; Rain doesn't report the cause.
- Receipt: "Authorized" row renamed "Initial hold" (the one hold term
  consumers already know) and the explanation moved from the row's
  info-icon tooltip to a visible CardAdjustmentNotice below the details
  card — the merchant-recourse sentence is the receipt's only action, so
  it can't hide behind a tap most users never make. Over-captures only;
  under-captures return money and need no warning.
- parseCents moved to transaction-details.utils, shared by rows + notice.
@justaname.id/react 0.4.0 + sdk 0.3.0 drop ethers entirely (siwens 0.1.0 is
viem-only). Zero code changes — the API surface we use (JustaNameProvider,
usePrimaryName, JustaName.init, .subnames.*) is unchanged. viem bumped to
^2.48.0 to satisfy the new peer dep (resolves 2.55.0).
…rade

chore(deps): upgrade justaname to 0.4.0/0.3.0 (ethers-free, viem-only)
…ust-visibility

feat(card): show settlement adjustments + next-deposit deduction banner
One internal page answering "what does a user in state X actually
experience?" — per funnel state, every in-app activation surface
(verbatim copy + gating condition + source file, transcribed from the
journey UI inventory so drift is traceable) next to every lifecycle
email/push, fetched LIVE from the sandbox API's __dev/journey-spec
(api PR #1234) so the board always shows the real machine. Degrades
honestly when the running API predates the endpoint. Includes the
inventory's 7 product-issue findings as collapsible warning cards and
a live per-user nudge inspector.
… finding

Two Hugo-reviewed corrections. (1) The in-flow KYC terminal modal and
home's WelcomeUnlockModal both celebrated "You're unlocked" — the flow
modal never stamps activationCelebratedAt (by design: home's rich modal
lists what unlocked), so users completing Sumsub in-flow got the
celebration twice. Neutralize the in-flow terminal to "All set" so home
owns THE celebration. (2) Explorer finding 3 was wrong: SHHHHH /
CARD_FIRST_SWIPE / CARD_SPENT_1K all have live API award triggers
(prod: 1,499/274/12 awards); the stale TODO(card-launch) comments in
badge.utils.ts that misled the audit are deleted, the finding now
records the retraction, and the inference-only finding on the
unreachable card-override branch is flagged for runtime verification.
…rmed 200s degrade gracefully instead of crashing
…-cta

# Conflicts:
#	src/app/(mobile-ui)/dev/page.tsx
feat(activation): Spend-with-Peanut chooser + /dev/journey Activation Journey Explorer (TASK-20471 + 20596 tooling)
…dev-2026-07-22

chore: back-merge main → dev (2026-07-22)
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Jul 24, 2026 12:46pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b8ce87cd-7e04-4aba-898b-68728bf8feb1

📥 Commits

Reviewing files that changed from the base of the PR and between 2e65a2e and 01a7c8d.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/assets/payment-apps/simplefi-logo.svg is excluded by !**/*.svg, !**/*.svg
📒 Files selected for processing (68)
  • .prettierignore
  • package.json
  • public/onboarding-quiz/index.html
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
  • src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsx
  • src/app/(mobile-ui)/add-money/page.tsx
  • src/app/(mobile-ui)/dev/full-graph/page.tsx
  • src/app/(mobile-ui)/dev/journey/EmailCard.tsx
  • src/app/(mobile-ui)/dev/journey/FindingsStrip.tsx
  • src/app/(mobile-ui)/dev/journey/JourneyBoard.tsx
  • src/app/(mobile-ui)/dev/journey/RulesLegend.tsx
  • src/app/(mobile-ui)/dev/journey/SurfaceCard.tsx
  • src/app/(mobile-ui)/dev/journey/UserInspector.tsx
  • src/app/(mobile-ui)/dev/journey/__tests__/journeyData.test.ts
  • src/app/(mobile-ui)/dev/journey/journeyData.ts
  • src/app/(mobile-ui)/dev/journey/journeyTypes.ts
  • src/app/(mobile-ui)/dev/journey/page.tsx
  • src/app/(mobile-ui)/dev/journey/useJourneySpec.ts
  • src/app/(mobile-ui)/dev/page.tsx
  • src/app/(mobile-ui)/dev/payment-graph/page.tsx
  • src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx
  • src/app/crisp-proxy/page.tsx
  • src/assets/payment-apps/index.ts
  • src/components/AddMoney/components/AddMoneyBankDetails.tsx
  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx
  • src/components/Badges/badge.utils.ts
  • src/components/Card/CardFace.tsx
  • src/components/Card/CardLimitEditModal.tsx
  • src/components/Card/YourCardScreen.tsx
  • src/components/Card/share-asset/rejectionCaptions.ts
  • src/components/Global/InvitesGraph/index.tsx
  • src/components/Home/ActivationCTAs.tsx
  • src/components/Home/__tests__/ActivationCTAs.test.tsx
  • src/components/Invites/InvitesPage.tsx
  • src/components/Kyc/InitiateKycModal.tsx
  • src/components/Kyc/KycVerificationInProgressModal.tsx
  • src/components/Kyc/SumsubKycWrapper.tsx
  • src/components/Kyc/__tests__/SumsubKycWrapper.test.tsx
  • src/components/TransactionDetails/TransactionCard.tsx
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx
  • src/components/TransactionDetails/__tests__/TransactionCard.test.tsx
  • src/components/TransactionDetails/__tests__/render-snapshot.test.tsx
  • src/components/TransactionDetails/__tests__/transaction-predicates.test.ts
  • src/components/TransactionDetails/__tests__/transactionTransformer.test.ts
  • src/components/TransactionDetails/__tests__/useReceiptViewModel.test.ts
  • src/components/TransactionDetails/provider-rows/CardAdjustmentNotice.tsx
  • src/components/TransactionDetails/provider-rows/CardPaymentRows.tsx
  • src/components/TransactionDetails/provider-rows/__tests__/CardAdjustmentNotice.test.tsx
  • src/components/TransactionDetails/provider-rows/__tests__/CardPaymentRows.settlement-adjustment.test.tsx
  • src/components/TransactionDetails/strategies/registry.ts
  • src/components/TransactionDetails/transaction-details.utils.ts
  • src/constants/analytics.consts.ts
  • src/constants/support.ts
  • src/hooks/useCrispProxyUrl.ts
  • src/hooks/useCrispUserData.ts
  • src/hooks/useMultiPhaseKycFlow.ts
  • src/hooks/wallet/__tests__/useReturnExcessCollateral.test.tsx
  • src/hooks/wallet/__tests__/useSignSpendBundle.test.tsx
  • src/hooks/wallet/useReturnExcessCollateral.ts
  • src/hooks/wallet/useSignSpendBundle.ts
  • src/utils/__tests__/balance.utils.test.ts
  • src/utils/__tests__/general.utils.test.ts
  • src/utils/__tests__/history.utils.test.ts
  • src/utils/balance.utils.ts
  • src/utils/capability-gate.ts
  • src/utils/crisp.ts
  • src/utils/general.utils.ts
  • src/utils/history.utils.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 6244.06 → 6263.81 (+19.75)
Findings: +31 net (+150 new, -119 resolved)

🆕 New findings (150)

  • critical complexity — src/components/Global/InvitesGraph/index.tsx — CC 518, MI 53.17, SLOC 1709
  • critical complexity — src/utils/general.utils.ts — CC 202, MI 57.68, SLOC 763
  • critical complexity — src/components/TransactionDetails/TransactionDetailsReceipt.tsx — CC 161, MI 52.87, SLOC 352
  • critical complexity — src/components/AddWithdraw/AddWithdrawCountriesList.tsx — CC 123, MI 56.91, SLOC 351
  • critical method-complexity — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — CC 109 SLOC 170
  • critical complexity — src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx — CC 101, MI 54.48, SLOC 352
  • critical complexity — src/utils/capability-gate.ts — CC 92, MI 60.96, SLOC 244
  • critical complexity — src/components/AddMoney/components/AddMoneyBankDetails.tsx — CC 83, MI 58.02, SLOC 153
  • critical complexity — src/hooks/useMultiPhaseKycFlow.ts — CC 66, MI 57.44, SLOC 330
  • critical complexity — src/components/Home/ActivationCTAs.tsx — CC 63, MI 59.1, SLOC 223
  • critical complexity — src/components/Kyc/SumsubKycWrapper.tsx — CC 57, MI 60.77, SLOC 278
  • critical complexity — src/components/Invites/InvitesPage.tsx — CC 55, MI 56.74, SLOC 127
  • critical complexity — src/components/TransactionDetails/TransactionCard.tsx — CC 55, MI 50.06, SLOC 167
  • critical complexity — src/components/TransactionDetails/provider-rows/CardPaymentRows.tsx — CC 52, MI 49.27, SLOC 131
  • critical complexity — src/app/(mobile-ui)/dev/journey/journeyData.ts — CC 1, MI 22.71, SLOC 327
  • high hotspot — src/app/(mobile-ui)/add-money/[country]/bank/page.tsx — 55 commits, +531/-455 lines since 6 months ago
  • high hotspot — src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx — 51 commits, +525/-240 lines since 6 months ago
  • high complexity — src/utils/history.utils.ts — CC 47, MI 45.25, SLOC 168
  • high complexity — src/components/Kyc/InitiateKycModal.tsx — CC 46, MI 55.73, SLOC 84
  • high hotspot — src/components/AddWithdraw/AddWithdrawCountriesList.tsx — 44 commits, +709/-523 lines since 6 months ago

…and 130 more.

✅ Resolved (119)

  • src/components/Global/InvitesGraph/index.tsx — CC 520, MI 53.13, SLOC 1714
  • src/utils/general.utils.ts — CC 199, MI 57.49, SLOC 755
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx — CC 160, MI 52.89, SLOC 352
  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx — CC 123, MI 56.9, SLOC 351
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — CC 108 SLOC 170
  • src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx — CC 101, MI 54.47, SLOC 352
  • src/utils/capability-gate.ts — CC 89, MI 60.9, SLOC 239
  • src/components/AddMoney/components/AddMoneyBankDetails.tsx — CC 82, MI 58.12, SLOC 153
  • src/hooks/useMultiPhaseKycFlow.ts — CC 66, MI 57.68, SLOC 325
  • src/components/Home/ActivationCTAs.tsx — CC 54, MI 59.07, SLOC 186
  • src/components/Invites/InvitesPage.tsx — CC 54, MI 56.84, SLOC 126
  • src/components/TransactionDetails/provider-rows/CardPaymentRows.tsx — CC 52, MI 51.55, SLOC 128
  • src/components/TransactionDetails/TransactionCard.tsx — CC 52, MI 50.35, SLOC 164
  • src/components/Kyc/SumsubKycWrapper.tsx — CC 51, MI 60.96, SLOC 248
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx — 53 commits, +524/-448 lines since 6 months ago
  • src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx — 49 commits, +518/-233 lines since 6 months ago
  • src/utils/history.utils.ts — CC 49, MI 45.09, SLOC 170
  • src/app/crisp-proxy/page.tsx — CC 42, MI 61.18, SLOC 120
  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx — 40 commits, +698/-512 lines since 6 months ago
  • src/components/TransactionDetails/TransactionCard.tsx:65 — CC 40 SLOC 89

…and 99 more.

📈 Painscore deltas (top movers)

File Before After Δ
src/app/(mobile-ui)/dev/journey/journeyData.ts 0.0 9.4 +9.4
src/hooks/wallet/useReturnExcessCollateral.ts 0.0 9.0 +9.0
src/app/(mobile-ui)/dev/journey/UserInspector.tsx 0.0 6.4 +6.4
src/components/TransactionDetails/provider-rows/CardAdjustmentNotice.tsx 0.0 5.9 +5.9
src/app/(mobile-ui)/dev/journey/useJourneySpec.ts 0.0 5.8 +5.8
src/app/(mobile-ui)/dev/journey/JourneyBoard.tsx 0.0 5.6 +5.6
src/app/(mobile-ui)/dev/journey/page.tsx 0.0 4.0 +4.0
src/app/(mobile-ui)/dev/journey/SurfaceCard.tsx 0.0 3.9 +3.9
src/app/(mobile-ui)/dev/journey/RulesLegend.tsx 0.0 3.6 +3.6
src/app/(mobile-ui)/dev/journey/FindingsStrip.tsx 0.0 3.6 +3.6
src/app/(mobile-ui)/dev/journey/EmailCard.tsx 0.0 2.7 +2.7
src/components/Kyc/InitiateKycModal.tsx 8.8 10.3 +1.5
src/components/Home/ActivationCTAs.tsx 11.1 12.3 +1.2
src/app/(mobile-ui)/add-money/page.tsx 7.3 8.5 +1.2
src/hooks/wallet/useSignSpendBundle.ts 13.5 14.5 +0.9
src/components/Card/CardLimitEditModal.tsx 8.3 9.2 +0.9
src/components/TransactionDetails/provider-rows/CardPaymentRows.tsx 11.8 12.6 +0.9
src/app/(mobile-ui)/dev/journey/journeyTypes.ts 0.0 0.9 +0.9
src/utils/balance.utils.ts 7.0 7.8 +0.8
src/components/Card/YourCardScreen.tsx 7.7 8.3 +0.7

@github-actions

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 2127 ran, 0 failed, 0 skipped, 28.3s

📊 Coverage (unit)

metric %
statements 60.8%
branches 44.3%
functions 49.8%
lines 61.1%
⏱ 10 slowest test cases
time test
2.6s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
0.9s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.3s src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx › Bank withdrawal keeps the $1 minimum for sub-$1 amounts
0.3s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.2s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in validateInviteCode body
0.2s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in validateInviteCode
0.2s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › keeps stickers off the username pill (final pass respects the keep-out)
0.1s src/utils/__tests__/demo-balance.test.ts › auto-refills a wallet older than the TTL on cold start
0.1s src/utils/__tests__/demo-balance.test.ts › debits and floors at zero
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid 9-digit US account
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@jjramirezn
jjramirezn merged commit 760ede2 into main Jul 24, 2026
24 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants