chore: back-merge main into dev (2026-08-11) - #2665
Conversation
#2647 fixed this defect at useZeroDev.ts:222 but missed its sibling here, so half the campaign failures are still undiagnosable in production. Sentry's console integration serializes each console argument. Passing an object holding an array of claims lands in the issue as the literal "[object Object]" — so the two facts the warning exists to carry, which campaign and why, were both unreadable. PEANUT-UI-SJC is a live example from today; the registration-side sibling now reads "utm:pix=unknown" instead. Pre-join the pairs into one string, exactly as useZeroDev.ts does. The message stays constant so Sentry keeps grouping these into a single issue rather than opening one per campaign combination. This matters right now: three live marketing tags (brazil, pix, faster-payments) currently resolve to no campaign, and the invite page was the surface that could not say which. Test pins the payload is a string, names both campaigns and reasons, and pins the message constant. Verified non-vacuous: reverting to the object payload fails it, restoring the join passes.
Ask our most active users for a 15-min founder call (TASK-21189). The cohort lives in the PostHog flag user-interviews-invite (release condition on username), never in code - list edits and the kill switch are one click in PostHog and no usernames ship in the bundle. The card leads the carousel for targeted users, opens the shared cal.com event via the Capacitor-safe helper, and inherits the standard 7-day X-dismissal. Temporary campaign: delete the card, flag, and i18n keys when it ends.
…n-payload fix(badges): make the invite-page campaign warning readable in Sentry
…rdown checklist Applied from the automated review pass: (1) await openExternalUrl so a native Browser.open failure surfaces in CarouselCTA's onClick catch instead of a detached rejection; (2) the analytics comment no longer claims flag exposures equal impressions (they fire per evaluation, prod-only, dismissed users included) and points readers at cal.com bookings + a $host filter; (3) the delete-together checklist now names the dev/home-ctas preview entry so teardown removes all three copies.
The committed aleks-n-hugo/15min event 404s (CodeRabbit catch, verified). Replaced with the hugo0+abalinda dynamic group link, which resolves and books both hosts' mutual availability.
Aleks isn't a founder; only Hugo is. All four locales, the dev preview, and the code comments now say team.
feat(home): flag-gated user-interview invite card in the carousel
The shared icon container is size-8, and the Tailwind preflight img max-width clamps any larger logo back to 32px - so the size bump rides the existing iconContainerClassName prop (tailwind-merge lets size-11 override size-8). The asset already animates: it is the animated webp, which Next serves untouched (ANIM chunk verified through /_next/image).
ui: render the waving mascot at 44px (follow-up to #2654)
…end copies The card-vs-Peanut markup was modeled twice in the frontend — once as a server action, once copied into the merchant page with a header saying to delete it when #2108 landed. #2108 landed. Both computed their own dolarapi call and their own issuer fee, and neither could agree with the rate on screen. The hook keeps its signature and its never-fails contract: a backend outage falls back to the same static table as before, so a frontend deploy that precedes the backend degrades to today's numbers instead of blanking a surface.
…compute Also splits the two failure kinds: a 404 is the backend proving there is no comparison to publish, so the row is hidden rather than filled with the static assumption, which exists for an unreachable backend.
Review found the distinction collapsing at four points, each publishing a saving claim on evidence there is none: - a well-formed zero markup threw, so the hook fell back to the static 9.13% - an out-of-band locked-price recompute silently returned the market markup, still tagged live — the exact failure the recompute exists to prevent - the merchant page and the post-card-spend nudge both turned the hook's null into the static table, striking through every menu price by 9.13% fetchCardMarkup now returns null for 'the backend published no comparison' and throws only when the response could not be obtained or trusted. Also bounds the live observation age client-side, formats the CompareSavings date in UTC (a hydration mismatch on statically generated pages for any viewer west of Greenwich), rejects a negative percent instead of publishing it as a range, and formats amounts in the page locale.
…0811-100504 content: publish latest to production (src/content → peanut-content@062cdba)
…dates
Both CodeRabbit findings are the same defect class as the last round — a
literal check that misses an equivalent representation and falls through to the
static claim.
The wire pattern admits "0.0" and "0.00", not just "0". Matching the text
sent those down the invalid path, so a backend saying 'no gap to show' produced
a 9.13% saving claim. The check now compares the parsed value.
new Date('2026-02-30') is 2 March, so a typo in a hand-authored MDX date would
publish a verification date that never happened. verifiedAt is now round-tripped
against an exact YYYY-MM-DD.
…0811-102159 content: publish latest to production (src/content → peanut-content@c708cdd)
…0811-103319 content: publish latest to production (src/content → peanut-content@5954b68)
feat(fx): consume the shared card-markup endpoint, delete both frontend copies
Carries the /fx/card-markup consumer (#2658) plus the hotfixes that went straight to main.
|
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: 7157.18 → 7155.4 (-1.78) 🆕 New findings (267)
…and 247 more. ✅ Resolved (261)
…and 241 more. 📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
|
Superseded by #2668, which is This PR was never failing CI — every check on its head SHA was green ( The cause: this branch carries three unsigned commits from the content-publish bot ( #2668 is the same back-merge collapsed into one signed commit, off the current Follow-up worth filing: the content-publish workflow should sign its commits (or author them through the GitHub API, which signs automatically). Until then every main→dev back-merge will hit this, and each one has to be squashed — which costs the merge ancestry and makes the next back-merge re-present the same delta. |
Pull request was closed
Routine back-merge.
mainwas 20 commits ahead ofdev.Carries #2658 (the
/fx/card-markupconsumer, which deletes both duplicate card-comparison modules) plus the hotfixes that shipped straight to main.No conflicts. Verified locally:
typecheckclean, 229 suites / 2925 tests green.