Skip to content

feat: add exact-locale Split guide foundation - #2657

Draft
0xkkonrad wants to merge 8 commits into
devfrom
feat/split-content-foundation
Draft

feat: add exact-locale Split guide foundation#2657
0xkkonrad wants to merge 8 commits into
devfrom
feat/split-content-foundation

Conversation

@0xkkonrad

@0xkkonrad 0xkkonrad commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds the native /{locale}/split/guides/{slug} family for en, es-419, and pt-br.
  • Publishes only exact locale files, with matching canonical, hreflang, sitemap, language switcher, BlogPosting, and breadcrumb signals.
  • Adds a manifest-backed six-page canary contract with raw source SHA-256 verification.
  • Reserves the Split namespace with true 404s and keeps the foundation inert until the separate content publish lands.
  • Preserves localized document language after hydration and restores the selected app language when navigating back to product UI.
  • Gives Split guide card CTAs route-scoped mascot clearance and enforces one BlogPosting schema contract.

Task

Intentional behavior and risk

  • Unknown /split paths return 404 instead of falling through to the generic recipient route.
  • Missing locale files return 404 and never emit fallback prose or SEO URLs. Split deliberately excludes es-ar and es-es from this canary.
  • The code foundation must reach production before mono publishes the content batch; reversing that order would expose missing routes.
  • No old-domain redirects or compatibility shims are included. The product has negligible legacy traffic and this cutover intentionally allows breaking changes.
  • The shared CTA only gains a semantic data hook. Its spacing is unchanged on the existing ~601 card CTA uses; the extra clearance is scoped to Split guide descendants.

Verification

  • Full Jest: 234 suites passed; 2,972 passed, 3 skipped.
  • Focused route/CTA tests: 7/7 passed.
  • Full TypeScript and ESLint passed; ESLint remains at 72 pre-existing warnings and 0 errors.
  • Content verifier passed both inert and joined modes. Joined: 762 files, 954 valid paths, 898 sitemap routes, six exact Split records with source hashes and the updated intent-taxonomy provenance.
  • Production webpack build passed with 1,055 static pages, including exactly six Split guide pages.
  • Browser/SEO QA passed all six routes, five negative 404 routes, sitemap membership, canonical/hreflang, one H1, schemas, CTA query preservation, and no console/hydration errors.
  • Responsive visual QA passed 18 CTA geometry checks at 320/375/768px, plus a non-Split regression page. The mascot now has 24px clearance.
  • Formatting and diff checks passed; the content submodule and verifier baseline were restored byte-clean after joined QA.

Screenshots

English desktop Spanish mobile
English group-trip guide on desktop Spanish currency guide on mobile
Portuguese content English final CTA
Portuguese guide steps and currency callout English final CTA with mascot clearance

The orphan pr-assets-2657 branch is evidence-only and should be deleted after merge.

Design notes

  • The marketing layout and all four literal landing routes server-render main[lang] plus a supported locale marker. The existing platform root still emits <html lang="en"> in raw HTML; hydration promotes the verified marketing locale to the document root. Browser QA observed the localized value within 100–250ms and gates on the hydrated state.
  • The document-language owner is re-evaluated on client pathname changes, so leaving localized marketing restores the user's selected product-app locale instead of the pre-mount language.
  • Split guide frontmatter declares BlogPosting only; the route emits that object and a separate breadcrumb. A redundant standalone Article object is rejected.
  • The Split verifier is intentionally cohesive: manifest, provenance, MDX, route, locale, metadata, CTA, and reciprocal-link failures block in one release contract.
  • No high-fan-in content loader signature changed. Split routes, loaders, switcher behavior, and CTA layout overrides remain isolated.

Rollout

  1. Merge and deploy this inert foundation to production.
  2. Synchronize the reviewed mono content branch with main, rerun source/provenance gates, and publish the six exact-locale pages through the content pipeline.
  3. Verify the six production URLs, app CTA locale handoff, sitemap, canonicals, and hreflang.
  4. Expand to the Split hub, alternatives, and the already-tested calculator engines in separate slices.

Docs and follow-up

  • The separate mono content batch contains the current Split product truth, guide template, locale rules, architecture notes, six compose sources, manifest, and six generated pages.
  • The content batch remains staged and unpublished until this foundation is live.

@vercel

vercel Bot commented Aug 10, 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 Aug 10, 2026 6:44pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a multilingual split-guide system with strict content and manifest validation, localized pages, metadata, locale switching, route ownership, document-language handling, and sitemap coverage. It also adds contract, verifier, routing, SEO, and content-check tests.

Changes

Split-guide publishing

Layer / File(s) Summary
Heading collision contracts
scripts/lib/split-guide-contract.ts, scripts/__tests__/split-guide-contract.test.ts
Adds fenced-code masking, source diagnostics, and recursive AST checks for disallowed H1 headings.
Manifest and content verifier
scripts/lib/verify-split-guides.ts, scripts/__tests__/verify-split-guides.test.ts
Validates manifests, frontmatter, JSX, MDX, provenance, claims, locale files, links, and required content structure.
Guide data and SEO helpers
src/lib/split-guides.ts, src/lib/__tests__/split-guides.test.ts
Adds publication checks, exact-locale route data, metadata, hreflang alternates, sitemap rows, and BlogPosting data.
Localized split-guide routes
src/app/[locale]/(marketing)/split/..., src/components/Marketing/LocaleSwitcher.tsx, src/constants/routes.ts, src/i18n/config.ts, src/app/__tests__/split-guides-route.test.tsx, src/components/Marketing/__tests__/*, src/i18n/app/AppIntlProvider.tsx
Adds route ownership, localized guide rendering, namespace 404 handling, route-scoped locale switching, CTA hooks, and route-owned document language.
Content verification and sitemap integration
scripts/verify-content.ts, src/app/sitemap.ts
Runs split-guide verification and includes only exact published locales in route coverage and sitemap output.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Visitor
  participant SplitGuidePage
  participant splitGuideData
  participant MDXRenderer
  Visitor->>SplitGuidePage: request localized guide path
  SplitGuidePage->>splitGuideData: load published guide
  splitGuideData-->>SplitGuidePage: return guide data
  SplitGuidePage->>MDXRenderer: render MDX content
  MDXRenderer-->>SplitGuidePage: return rendered content
  SplitGuidePage-->>Visitor: return page, metadata, and locale links
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: kushagrasarathe

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the exact-locale Split guide foundation.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/split-content-foundation

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.

❤️ Share

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

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 7157.18 → 7174.01 (+16.83)
Findings: +7 net (+24 new, -17 resolved)

🆕 New findings (24)

  • high complexity — src/lib/split-guides.ts — CC 40, MI 63.26, SLOC 150
  • high complexity — src/app/sitemap.ts — CC 24, MI 36.8, SLOC 184
  • medium high-mdd — src/app/sitemap.ts:32 — generateSitemap: MDD 77.4 (uses across many lines from declarations)
  • medium complexity — src/components/Marketing/LocaleSwitcher.tsx — CC 24, MI 68.05, SLOC 61
  • medium method-complexity — src/app/sitemap.ts:32 — generateSitemap CC 21 SLOC 176
  • medium complexity — src/i18n/app/AppIntlProvider.tsx — CC 21, MI 62.28, SLOC 78
  • medium complexity — src/constants/routes.ts — CC 14, MI 61.43, SLOC 46
  • medium complexity — src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx — CC 13, MI 59.76, SLOC 52
  • medium react-effect-derives-state — src/components/Marketing/LocaleSwitcher.tsx:54 — useEffect with empty deps + setState — derived state anti-pattern
  • medium react-effect-fetches — src/i18n/app/AppIntlProvider.tsx:52 — useEffect for async data fetching — use TanStack Query / server components
  • low high-dlt — src/i18n/app/AppIntlProvider.tsx:42 — AppIntlProvider: DLT 19 (calls 19 distinct functions — high context load)
  • low high-mdd — src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx:40 — SplitGuidePage: MDD 17.6 (uses across many lines from declarations)
  • low high-mdd — src/components/Marketing/LocaleSwitcher.tsx:43 — LocaleSwitcher: MDD 16.1 (uses across many lines from declarations)
  • low high-mdd — src/i18n/app/AppIntlProvider.tsx:42 — AppIntlProvider: MDD 15.2 (uses across many lines from declarations)
  • low high-mdd — src/i18n/app/AppIntlProvider.tsx:52 — : MDD 14.8 (uses across many lines from declarations)
  • low structural-dup — app/es-419/page.tsx:16 — 13 duplicate lines / 73 tokens with app/es-ar/page.tsx:16
  • low structural-dup — app/es-419/page.tsx:16 — 13 duplicate lines / 73 tokens with app/pt-br/page.tsx:16
  • low high-mdd — src/lib/split-guides.ts:114 — buildSplitGuideMetadata: MDD 11.8 (uses across many lines from declarations)
  • low structural-dup — components/Marketing/ArticleBackNav.tsx:29 — 7 duplicate lines / 55 tokens with components/Marketing/LocaleSwitcher.tsx:55
  • low missing-return-type — src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx:24 — generateStaticParams: exported fn missing return type annotation

…and 4 more.

✅ Resolved (17)

  • src/app/sitemap.ts — CC 23, MI 37.57, SLOC 174
  • src/app/sitemap.ts:27 — generateSitemap: MDD 73.8 (uses across many lines from declarations)
  • src/app/sitemap.ts:27 — generateSitemap CC 21 SLOC 167
  • src/components/Marketing/LocaleSwitcher.tsx — CC 19, MI 69.34, SLOC 52
  • src/i18n/app/AppIntlProvider.tsx — CC 17, MI 63.9, SLOC 71
  • src/constants/routes.ts — CC 14, MI 61.44, SLOC 46
  • src/components/Marketing/LocaleSwitcher.tsx:42 — useEffect with empty deps + setState — derived state anti-pattern
  • src/i18n/app/AppIntlProvider.tsx:49 — useEffect for async data fetching — use TanStack Query / server components
  • src/i18n/app/AppIntlProvider.tsx:40 — AppIntlProvider: MDD 17.0 (uses across many lines from declarations)
  • src/components/Marketing/LocaleSwitcher.tsx:31 — LocaleSwitcher: MDD 14.7 (uses across many lines from declarations)
  • src/i18n/app/AppIntlProvider.tsx:40 — AppIntlProvider: DLT 15 (calls 15 distinct functions — high context load)
  • src/i18n/app/AppIntlProvider.tsx:49 — : MDD 14.8 (uses across many lines from declarations)
  • app/es-419/page.tsx:16 — 13 duplicate lines / 61 tokens with app/es-ar/page.tsx:16
  • app/es-419/page.tsx:16 — 13 duplicate lines / 61 tokens with app/pt-br/page.tsx:16
  • components/Marketing/ArticleBackNav.tsx:29 — 7 duplicate lines / 55 tokens with components/Marketing/LocaleSwitcher.tsx:43
  • src/components/Marketing/LocaleSwitcher.tsx:31 — LocaleSwitcher: exported fn missing return type annotation
  • src/i18n/app/AppIntlProvider.tsx:40 — AppIntlProvider: exported fn missing return type annotation

📈 Painscore deltas (top movers)

File Before After Δ
src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx 0.0 6.9 +6.9
src/lib/split-guides.ts 0.0 6.4 +6.4
src/app/[locale]/(marketing)/split/[...path]/page.tsx 0.0 0.9 +0.9
src/i18n/app/AppIntlProvider.tsx 7.7 8.6 +0.9
src/app/[locale]/(marketing)/split/page.tsx 0.0 0.8 +0.8
src/app/sitemap.ts 14.3 13.4 -0.9

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 2975 ran, 0 failed, 0 skipped, 30.8s

📊 Coverage (unit)

metric %
statements 65.5%
branches 49.5%
functions 54.2%
lines 66.4%
⏱ 10 slowest test cases
time test
2.2s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
1.0s scripts/__tests__/verify-split-guides.test.ts › uses the default runtime compiler to reject a nested H1
0.9s scripts/__tests__/verify-split-guides.test.ts › allows forbidden page syntax when the default runtime compiler sees it inside fenced code
0.5s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.3s src/utils/__tests__/sentry.utils.test.ts › defaults to the client budget under a browser global
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/utils/__tests__/sentry.utils.test.ts › still lets a per-call timeoutMs win over the default
0.2s src/utils/__tests__/auth-token.test.ts › ignores the guarded marker and falls back to the plain token
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 › every sticker stays within canvas at any count
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
scripts/__tests__/verify-split-guides.test.ts (1)

122-135: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add one test that exercises the default MDX compiler.

runVerifier always injects a no-op validateMdx. No test runs compileSplitGuideMdx. The production path performs dynamic ESM imports of next-mdx-remote/serialize and remark-gfm and wires remarkRejectSplitGuideH1. A regression in that wiring, for example an import failure under the tsx entrypoint, would pass the whole suite.

Add one case that omits validateMdx and asserts that a body containing an H1 produces a split-guide-mdx diagnostic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/__tests__/verify-split-guides.test.ts` around lines 122 - 135, Add a
test case in the verifier tests that calls runVerifier without the validateMdx
argument, exercising the default compileSplitGuideMdx path. Use content
containing an H1 and assert that diagnostics include a split-guide-mdx check,
while leaving the existing injected-validator tests unchanged.
scripts/verify-content.ts (2)

729-731: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the split-guide slug derivation used in both passes.

Lines 200-202 and Lines 729-731 repeat the same listDirs plus hasPublishedLocalePage(..., 'en') filter, and the per-locale gate at Lines 310-314 and Lines 763-767 repeats too. A shared helper keeps the route pass and the sitemap pass from drifting.

♻️ Proposed helper
+function publishedSplitGuideSlugs(): string[] {
+    return listDirs(path.join(CONTENT_DIR, 'split-guides')).filter((slug) =>
+        hasPublishedLocalePage('split-guides', slug, 'en')
+    )
+}

Then use it in both passes:

-    const splitGuideSlugs = listDirs(path.join(CONTENT_DIR, 'split-guides')).filter((slug) =>
-        hasPublishedLocalePage('split-guides', slug, 'en')
-    )
+    const splitGuideSlugs = publishedSplitGuideSlugs()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify-content.ts` around lines 729 - 731, Extract the repeated
split-guide slug derivation into a shared helper that lists split-guide
directories and filters them through hasPublishedLocalePage('split-guides',
slug, 'en'). Replace the duplicate logic in both the route pass and sitemap
pass, and reuse the shared per-locale gate in each corresponding flow so both
passes remain consistent.

307-315: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Keep split-guide locale checks aligned.

The verifier and runtime use ['en', 'es-419', 'pt-br'], while scripts/verify-content.ts still derives split-guide routes from the broader SUPPORTED_LOCALES list that includes es-ar. Add es-ar to the split-guide locale sources or derive this loop from SPLIT_GUIDE_LOCALES so future locale additions do not accidentally manufacture supported split-guide routes without exact published files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify-content.ts` around lines 307 - 315, Update the split-guide
route generation in the hasRoute('split/guides/[slug]') block to iterate over
the exact split-guide locale source, preferably SPLIT_GUIDE_LOCALES, instead of
the broader SUPPORTED_LOCALES-derived values. Keep route creation gated by
hasPublishedLocalePage so only locales with exact published files produce
routes, and include es-ar through the shared split-guide locale definition.
src/components/Marketing/__tests__/locale-switcher.test.ts (1)

52-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the two boundary cases for the guide index and deeper paths.

hasRouteScopedLocaleSwitcher requires segments.length > 3. The suite does not pin the guide index path or a deeper path. /en/split/guides must return false, and /en/split/guides/a/b currently returns true. Pin both so a later change to the segment check fails loudly.

♻️ Proposed additions
         expect(hasRouteScopedLocaleSwitcher('/en/split')).toBe(false)
+        expect(hasRouteScopedLocaleSwitcher('/en/split/guides')).toBe(false)
         expect(hasRouteScopedLocaleSwitcher('/split/guides/group-trip')).toBe(false)
         expect(hasRouteScopedLocaleSwitcher('/en/blog/group-trip')).toBe(false)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Marketing/__tests__/locale-switcher.test.ts` around lines 52 -
58, Add boundary assertions to the hasRouteScopedLocaleSwitcher test for
/en/split/guides returning false and /en/split/guides/a/b returning true,
preserving the existing Split guide route cases and explicitly pinning the
segments.length > 3 behavior.
scripts/lib/split-guide-contract.ts (1)

33-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider narrowing the setext scan to skip fenced code blocks.

Line 36 flags any nonblank line that is followed by a =+ line. A fenced code sample that contains such a pair produces a blocking setext-h1 diagnostic, even though remark parses it as code and the authoritative plugin accepts it. The same applies to <h1> inside a fenced block on Line 37.

If fenced samples are expected in guide bodies, strip fenced regions before the scan.

♻️ Proposed refactor to skip fenced regions
 export function findSplitGuideHeadingCollisions(body: string): SplitGuideHeadingCollision[] {
     const collisions: SplitGuideHeadingCollision[] = []
-    if (/^[ \t]*#(?:[ \t]+|$)/m.test(body)) collisions.push('atx-h1')
-    if (/^(?![ \t]*$).+\r?\n[ \t]*=+[ \t]*$/m.test(body)) collisions.push('setext-h1')
-    if (/<h1(?:\s|>)/i.test(body)) collisions.push('html-h1')
-    if (/<Hero\b/.test(body)) collisions.push('hero')
+    // Fenced samples are code to remark; keep the cheap scan aligned with it.
+    const scannable = body.replace(/^[ \t]*(`{3,}|~{3,})[\s\S]*?^[ \t]*\1[ \t]*$/gm, '')
+    if (/^[ \t]*#(?:[ \t]+|$)/m.test(scannable)) collisions.push('atx-h1')
+    if (/^(?![ \t]*$).+\r?\n[ \t]*=+[ \t]*$/m.test(scannable)) collisions.push('setext-h1')
+    if (/<h1(?:\s|>)/i.test(scannable)) collisions.push('html-h1')
+    if (/<Hero\b/.test(scannable)) collisions.push('hero')
     return collisions
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lib/split-guide-contract.ts` around lines 33 - 40, Update
findSplitGuideHeadingCollisions to exclude fenced code-block regions before
running the setext-h1 and html-h1 scans, while preserving detection of headings
in normal guide content and the existing atx-h1/hero checks as appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/lib/verify-split-guides.ts`:
- Around line 457-472: Update the title-length validation in the split-guide
contract check to use the effective authored-title budget of 51 characters,
remove the unreachable rawLength > 60 condition, and revise the error message to
state the 51-character limit clearly while preserving the existing raw/effective
length details.
- Around line 699-712: Update compileSplitGuideMdx to remove the unsupported
format: 'mdx' property from mdxOptions, leaving remarkPlugins unchanged.

---

Nitpick comments:
In `@scripts/__tests__/verify-split-guides.test.ts`:
- Around line 122-135: Add a test case in the verifier tests that calls
runVerifier without the validateMdx argument, exercising the default
compileSplitGuideMdx path. Use content containing an H1 and assert that
diagnostics include a split-guide-mdx check, while leaving the existing
injected-validator tests unchanged.

In `@scripts/lib/split-guide-contract.ts`:
- Around line 33-40: Update findSplitGuideHeadingCollisions to exclude fenced
code-block regions before running the setext-h1 and html-h1 scans, while
preserving detection of headings in normal guide content and the existing
atx-h1/hero checks as appropriate.

In `@scripts/verify-content.ts`:
- Around line 729-731: Extract the repeated split-guide slug derivation into a
shared helper that lists split-guide directories and filters them through
hasPublishedLocalePage('split-guides', slug, 'en'). Replace the duplicate logic
in both the route pass and sitemap pass, and reuse the shared per-locale gate in
each corresponding flow so both passes remain consistent.
- Around line 307-315: Update the split-guide route generation in the
hasRoute('split/guides/[slug]') block to iterate over the exact split-guide
locale source, preferably SPLIT_GUIDE_LOCALES, instead of the broader
SUPPORTED_LOCALES-derived values. Keep route creation gated by
hasPublishedLocalePage so only locales with exact published files produce
routes, and include es-ar through the shared split-guide locale definition.

In `@src/components/Marketing/__tests__/locale-switcher.test.ts`:
- Around line 52-58: Add boundary assertions to the hasRouteScopedLocaleSwitcher
test for /en/split/guides returning false and /en/split/guides/a/b returning
true, preserving the existing Split guide route cases and explicitly pinning the
segments.length > 3 behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 848e7507-985b-4110-a04c-430b955c51e3

📥 Commits

Reviewing files that changed from the base of the PR and between d707166 and e1c4ee4.

📒 Files selected for processing (17)
  • scripts/__tests__/split-guide-contract.test.ts
  • scripts/__tests__/verify-split-guides.test.ts
  • scripts/lib/split-guide-contract.ts
  • scripts/lib/verify-split-guides.ts
  • scripts/verify-content.ts
  • src/app/[locale]/(marketing)/split/[...path]/page.tsx
  • src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx
  • src/app/[locale]/(marketing)/split/page.tsx
  • src/app/__tests__/split-guides-route.test.tsx
  • src/app/sitemap.ts
  • src/components/Marketing/LocaleSwitcher.tsx
  • src/components/Marketing/__tests__/locale-switcher.test.ts
  • src/constants/__tests__/routes.test.ts
  • src/constants/routes.ts
  • src/i18n/config.ts
  • src/lib/__tests__/split-guides.test.ts
  • src/lib/split-guides.ts

Comment thread scripts/lib/verify-split-guides.ts
Comment thread scripts/lib/verify-split-guides.ts
@0xkkonrad

Copy link
Copy Markdown
Contributor Author

CodeRabbit summary nitpick disposition (0e58e80):

  1. Default MDX compiler test — fixed. The suite now invokes the real tsx/ESM production loader without injecting validateMdx and proves a nested H1 is rejected.
  2. Fenced-code behavior — fixed and explicitly decided: authored forbidden syntax is blocked, but examples inside valid backtick/tilde fences are allowed. The source scanner preserves offsets (including CRLF), and the real compiler acceptance path covers ATX/setext/HTML/Hero examples.
  3. Duplicate slug helper — fixed. Both route discovery and sitemap coverage use publishedSplitGuideSlugs().
  4. Exact locale loop — fixed via the shared exported SPLIT_GUIDE_LOCALES source (en, es-419, pt-br). The suggestion to include es-ar is intentionally declined: this canary contract is exact-file-only and es-ar is explicitly unsupported; manufacturing it would violate the task.
  5. Locale-switcher boundaries — fixed. Tests pin /en/split/guides => false and /en/split/guides/a/b => true.

Additional runtime/release hardening: removed empty generateStaticParams from the Split namespace catch-all (the Next production soft-404 trigger), verified real GET 404 statuses across missing locales/slugs/subtrees, and added required raw-source SHA-256 provenance plus optional source-root recomputation/frontmatter comparison for content/release audits. Mirrored UI CI remains source-checkout-independent.

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@0xkkonrad
0xkkonrad marked this pull request as ready for review August 10, 2026 18:26
@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/__tests__/verify-split-guides.test.ts (1)

181-202: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the subprocess collector parse only the verifier payload, with a clear timeout failure.

completed.stdout is consumed directly in scripts/__tests__/verify-split-guides.test.ts:201, so any transitive stdout after a successful exit would break JSON.parse. The MDX compile path also has no child timeout in scripts/__tests__/verify-split-guides.test.ts:194; add a bounded timeout to spawnSync and an explicit error when it times out.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/__tests__/verify-split-guides.test.ts` around lines 181 - 202, Update
runDefaultCompilerVerifier to give spawnSync a bounded timeout and explicitly
throw a timeout-specific error when the subprocess expires. Parse only the JSON
verifier payload from completed.stdout, tolerating unrelated trailing stdout
while preserving the existing diagnostics/result return shape; continue
reporting nonzero subprocess failures with stderr/stdout context.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/__tests__/verify-split-guides.test.ts`:
- Around line 181-202: Update runDefaultCompilerVerifier to give spawnSync a
bounded timeout and explicitly throw a timeout-specific error when the
subprocess expires. Parse only the JSON verifier payload from completed.stdout,
tolerating unrelated trailing stdout while preserving the existing
diagnostics/result return shape; continue reporting nonzero subprocess failures
with stderr/stdout context.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 997ffc55-a274-40b3-be65-9ba33c00f647

📥 Commits

Reviewing files that changed from the base of the PR and between e1c4ee4 and 73296dc.

📒 Files selected for processing (14)
  • scripts/__tests__/split-guide-contract.test.ts
  • scripts/__tests__/verify-split-guides.test.ts
  • scripts/lib/split-guide-contract.ts
  • scripts/lib/verify-split-guides.ts
  • scripts/verify-content.ts
  • src/app/[locale]/(marketing)/layout.tsx
  • src/app/[locale]/(marketing)/split/[...path]/page.tsx
  • src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx
  • src/app/__tests__/split-guides-route.test.tsx
  • src/components/Marketing/__tests__/html-lang.test.tsx
  • src/components/Marketing/__tests__/locale-switcher.test.ts
  • src/components/Marketing/mdx/CTA.tsx
  • src/components/Marketing/mdx/__tests__/CTA.test.tsx
  • src/i18n/app/AppIntlProvider.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/components/Marketing/tests/locale-switcher.test.ts
  • src/app/tests/split-guides-route.test.tsx
  • src/app/[locale]/(marketing)/split/guides/[slug]/page.tsx
  • scripts/verify-content.ts

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

CodeRabbit final nitpick fixed in 638fb43ad: the default-compiler subprocess now has a 15-second timeout with an explicit timeout error, emits a sentinel-framed JSON payload, and parses only the last framed payload so incidental stdout cannot corrupt the result. Focused verifier: 17/17; TypeScript, formatting, and diff checks pass.

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@0xkkonrad
0xkkonrad requested a review from jjramirezn August 10, 2026 18:50
@0xkkonrad
0xkkonrad marked this pull request as draft August 10, 2026 19:10
@0xkkonrad
0xkkonrad removed the request for review from jjramirezn August 10, 2026 19:10
@0xkkonrad

Copy link
Copy Markdown
Contributor Author

Architecture update (2026-08-11): this native-renderer implementation is superseded and must not be merged as written.

The locked seam is now:

  • mono/split-content/** owns Split truths, messaging, localization, briefs, and generated Markdown;
  • PeanutSplit owns rendering, layouts, SEO/schema machinery, and calculators;
  • peanut-ui owns only the thin public routing and credential-sanitizing boundary for peanut.me/{locale}/split/*.

Durable contract and recovery map: https://github.com/peanutprotocol/mono/pull/75
Umbrella task: TASK-21256 — https://app.notion.com/p/3b783811757981b481f1d9528c6f0600

Keeping this PR draft temporarily so genuinely generic i18n fixes can be evaluated separately. The Split route/loader/verifier implementation here should not be carried forward.

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.

1 participant