Skip to content

fix(web): rescue pricing and legal routes - #5647

Merged
Hmbown merged 4 commits into
mainfrom
codex/pr5639-rescue-20260827
Aug 29, 2026
Merged

Hmbown merged 4 commits into
mainfrom
codex/pr5639-rescue-20260827

Conversation

@Hmbown

@Hmbown Hmbown commented Aug 27, 2026

Copy link
Copy Markdown
Owner

No-Issue: rescues the Codewhale half of Hmbown/cwc#262 from #5639 with CI-clean commit metadata

Supersedes #5639.

Summary

  • makes the localized pricing route a real, honest page: open source is free and hosted Member is described without exposing a buy action while production billing is dormant
  • adds localized legal, terms, and privacy routes using the same Shannon Labs legal body as the managed app
  • redirects the short privacy, terms, and legal paths to their canonical routes
  • adds Pricing, Terms, and Privacy to the footer and public discovery surfaces

Verification

  • web tests: 339 passed
  • ESLint passed
  • production Next build passed and generated all 621 static pages, including the new routes
  • contributor/agent credit check passed
  • formatting diff check passed

No deployment is included in this PR.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 1s —— View job


Review: fix(web): rescue pricing and legal routes

  • Gather context (PR diff, changed files)
  • Understand the request (code review of the pricing/legal route rescue)
  • Review correctness / logic
  • Review provider/model/route safety
  • Review reuse & simplification
  • Review test coverage
  • Review security
  • Post final review summary

This is a web-only (Next.js) marketing-site diff — no Rust core code, so category 2 (provider/model/route safety, the v0.8.65 EPIC #2608 invariant) doesn't apply here.

Findings

1. Footer legal links bypass the localization contractweb/lib/i18n/links.ts:83-90

export function footerLegalLinks(locale: string): ChromeLink[] {
  return [
    { href: `/${locale}/pricing`, label: "Pricing" },
    { href: `/${locale}/legal/terms`, label: "Terms" },
    { href: `/${locale}/legal/privacy`, label: "Privacy" },
  ];
}

Every sibling generator in this file (footerProductLinks, footerProjectLinks) takes a chrome: ChromeDict and sources its labels from the dictionary — the file's own header comment says "labels come from ChromeDict... every routed locale gets the identical route shape," with locale-swap parity enforced by docs-ia.test.ts. footerLegalLinks instead hardcodes English strings, so these three new footer links render as "Pricing / Terms / Privacy" in every non-English locale, including zh, which config.ts documents as requiring "full website parity with English on first-class pages" (chrome/footer is explicitly in scope for that parity, unlike page bodies). The new test (docs-ia.test.ts) only asserts on href, not label, so it doesn't catch this. Worth adding footerPricing/footerTerms/footerPrivacy keys to ChromeDict and threading chrome through like the other two generators.
Fix this →

2. Alias redirects use a temporary (307) redirectweb/app/[locale]/legal/page.tsx, privacy/page.tsx, terms/page.tsx
These call redirect() from next/navigation, which is a temporary redirect. Since /privacy, /terms, and /legal are intended as permanent canonical aliases onto /legal/privacy and /legal/terms (per the PR description and the new test public-billing-legal-routes.test.ts), permanentRedirect() would be the more correct choice for SEO/link-equity purposes. Low severity — not a bug, just a signal mismatch with stated intent.

What looks good

  • The pricing page correctly avoids a non-functional "Buy" button while billing is dormant, matching the PR's stated intent.
  • contentLocalesForPath already defaults to ["en", "zh"] for unregistered routes, so the new bilingual pages didn't need any registry changes — verified the sitemap math checks out exactly (78 → 84 entries = 3 new paths × 2 content locales).
  • Test coverage is thorough and consistent across sitemap, llms-txt, page-meta, and the new public-billing-legal-routes.test.ts; the docs-ia.test.ts footer-string assertion (footer.toContain("footerLegalLinks(locale)")) is a nice guard against silently dropping the call site.
  • No dead/duplicate CSS — new .legal-doc* / .pricing-* classes in globals.css are all consumed by the new pages.

Note: I wasn't able to execute npm test/vitest in this sandboxed environment (command execution was blocked), so the "339 passed" claim in the PR description is not independently re-verified here, but the diffs to the test files are internally consistent with the implementation changes.

@Hmbown
Hmbown force-pushed the codex/pr5639-rescue-20260827 branch from 1e9c915 to f3660ed Compare August 27, 2026 13:30
@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 18s —— View job


Review: fix(web): rescue pricing and legal routes

  • Gather context (PR diff, changed files)
  • Understand the request
  • Review correctness / logic
  • Review provider/model/route safety
  • Review reuse & simplification
  • Review test coverage
  • Review security
  • Post final review summary

This sync adds one commit (f3660ed, CI/persistence-backlog measurement fix) on top of the previously-reviewed web commit (95224f9). No Rust core/provider-selection code is touched, so category 2 (provider/model/route safety) doesn't apply.

Findings (carried over, still unresolved)

1. footerLegalLinks bypasses the localization contractweb/lib/i18n/links.ts:83-90

export function footerLegalLinks(locale: string): ChromeLink[] {
  return [
    { href: `/${locale}/pricing`, label: "Pricing" },
    { href: `/${locale}/legal/terms`, label: "Terms" },
    { href: `/${locale}/legal/privacy`, label: "Privacy" },
  ];
}

Every sibling generator (footerProductLinks, footerProjectLinks) takes chrome: ChromeDict and sources labels from the dictionary. ChromeDict (web/lib/i18n/dictionaries/types.ts:24-175) has no footerPricing/footerTerms/footerPrivacy keys, and config.ts:12 documents that "shipped" locales (zh included) get "full website parity with English on first-class pages," which covers chrome/footer, not just page bodies. As written, these three footer links render hardcoded English ("Pricing"/"Terms"/"Privacy") for every non-English locale. docs-ia.test.ts only asserts on href, not label, so nothing catches this today.
Fix this →

2. Alias redirects still use temporary (307) redirectsweb/app/[locale]/legal/page.tsx, privacy/page.tsx, terms/page.tsx
These call redirect() from next/navigation (temporary). /privacy, /terms, /legal are meant as permanent canonical aliases per the PR description, so permanentRedirect() is more correct for SEO/link-equity. Low severity, not a functional bug.

New commit in this sync (f3660ed, unrelated to pricing/legal)

Reviewed scripts/measure-persistence-backlog.py, scripts/test_measure_persistence_backlog.py, scripts/persistence-backlog-budget.json, and crates/tui/src/tui/persistence_actor/tests.rs:

  • The switch from -p codewhale-tui --all-features to --workspace --all-features correctly matches CI's feature unification, and the new zero-tests regex (test {TEST_NAME} \.\.\. (ok|FAILED|ignored)) correctly targets the specific test's outcome instead of treating any "running 0 tests" line (now common across workspace packages that don't contain the test) as a failure — good fix, and test_workspace_zero_test_packages_do_not_hide_the_exact_test covers the regression it fixes.
  • The warmup try_send/drain added in tests.rs before rss_before_bytes/the timed loop is correctly drained (while receiver.try_recv().is_ok() {}) before the counted section starts, so it doesn't pollute accepted_requests or retained_queued_requests. No bug found.
  • enqueue_elapsed_ns ceiling raised 25ms → 50ms with a documented rationale (observed 28ms after relinking on a clean macOS runner) — a calibration change, not a logic issue.

What still looks good

  • Pricing page correctly avoids a non-functional "Buy" button while billing is dormant.
  • contentLocalesForPath already defaults to ["en", "zh"], so no registry changes were needed for the new pages; sitemap math checks out (78 → 84 = 3 new paths × 2 locales).
  • Test coverage across sitemap, llms-txt, page-meta, and the new public-billing-legal-routes.test.ts is thorough and internally consistent with the implementation.
  • No dead/duplicate CSS — new .legal-doc*/.pricing-* classes are all consumed by the new pages.

Note: command execution (npm test/vitest/cargo) was not run in this session; findings are based on static review of the diff.

@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 10s —— View job


Review: fix(web): rescue pricing and legal routes

  • Gather context (PR diff, changed files, prior review comments)
  • Verify latest commit addresses prior findings (localized footer links, permanent redirects)
  • Review remaining diff for new issues
  • Attempt to run tests/lint
  • Post final review summary

This is a web-only (Next.js) marketing-site diff — no Rust core/provider-selection code, so category 2 (provider/model/route safety) doesn't apply.

Both previously open findings are now resolved (commit 6b384dd)

1. Footer legal links now localizedweb/lib/i18n/links.ts:83-90. footerLegalLinks takes chrome: ChromeDict like its sibling generators and sources labels from new footerPricing/footerTerms/footerPrivacy keys. Verified:

  • ChromeDict (web/lib/i18n/dictionaries/types.ts:156-161) declares the three keys, and every one of the 19 locale chrome.ts files defines all three (checked with a grep across dictionaries/*/chrome.ts — none missing).
  • web/components/footer.tsx:24 passes chrome through at the call site.
  • docs-ia.test.ts:217-221 now asserts legal.map(l => l.label) equals the dictionary values per locale (closing the gap the earlier review flagged), and docs-ia.test.ts:305-309 pins the zh labels to 价格/服务条款/隐私政策 — real localized strings, not English fallbacks.

2. Alias redirects are now permanentweb/app/[locale]/legal/page.tsx, privacy/page.tsx, terms/page.tsx all use permanentRedirect() from next/navigation instead of the temporary redirect(). Correct for the stated intent (canonical permanent aliases).

Other changes in this diff — no issues found

  • pricing/page.tsx: correctly avoids a non-functional "Buy" button while billing is dormant; copy is honest and consistent in both locales shown (isZh ternaries).
  • legal-copy.ts: shared terms/privacy body reused from the hosted app, reasonable structure, no placeholder/lorem content.
  • sitemap.ts / llms-txt.ts: new /pricing, /legal/terms, /legal/privacy entries follow the exact existing pattern (contentLocalesForPath, EXTRA_PAGES) — no duplication, no dead code.
  • public-billing-legal-routes.test.ts and the docs-ia.test.ts additions give solid coverage: page existence, alias hrefs, per-locale label parity, and legal-copy content assertions.
  • No stray/unconsumed CSS — new .legal-doc*/.pricing-* classes in globals.css are all used by the new pages.

Note

Command execution (npm test / tsc / vitest / git fetch) was blocked in this sandboxed session, consistent with the prior two review passes on this PR, so the "339 passed" test claim and a fresh build/typecheck are not independently re-executed here. The diffs to test files are internally consistent with the implementation, and the specific line-level claims above (dictionary keys, call sites, test assertions) were verified by reading the actual source, not inferred.

No further changes needed — this PR is in good shape.

CodeWhale Bot added 4 commits August 28, 2026 20:07
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
`cargo test -p codewhale-tui --all-features` does not unify features
the same way as `cargo nextest run --workspace --all-features`. The
budget step relinked codewhale-tui for ~13 minutes on macos-latest and
then recorded enqueue_elapsed_ns=28092535 against a 25ms ceiling after
the suite had already passed.

Run the measurement with `--workspace --all-features`, treat sibling
"running 0 tests" output as expected, page in try_send before the timed
sample, and raise the enqueue noise ceiling to 50ms. RSS, retained
count, and payload ratchets are unchanged.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
The persistence-backlog measurement rework (tests.rs warmup, the
workspace-wide measurement invocation, the 50ms enqueue ceiling, and
its python test updates) belongs to the persistence lane, not the
pricing/legal route rescue. Restore those four files to their main
state so this PR carries only the pricing and legal rescue.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Address the two open review findings on the pricing/legal rescue:

- footerLegalLinks now takes the ChromeDict like its sibling generators
  and sources labels from new footerPricing/footerTerms/footerPrivacy
  keys, added to ChromeDict and all 18 locale dictionaries, so the
  footer legal links render localized for every routed locale (zh
  included) instead of hardcoded English. docs-ia.test.ts now asserts
  the labels match the dictionary per locale, closing the test gap.
- The /legal, /privacy, and /terms alias pages use permanentRedirect
  instead of the temporary redirect: these are canonical permanent
  aliases for the moved pricing/legal home.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@Hmbown
Hmbown force-pushed the codex/pr5639-rescue-20260827 branch from 6b384dd to 67916a9 Compare August 29, 2026 03:08
@claude

claude Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 48s —— View job


Review: fix(web): rescue pricing and legal routes

  • Gather context (PR diff, changed files, prior review comments)
  • Identify what changed in this sync vs. the last reviewed commit
  • Verify persistence-backlog files were cleanly reverted out of scope
  • Re-verify previously-fixed findings are still fixed
  • Post final review summary

This sync (d039002, "chore: drop stray files from another lane") is the only new commit since the last review. 67916a9 is a rebase of the previously-reviewed 6b384dd (same content, new hash) — no new web changes to review there.

This sync's change: scope cleanup — looks correct

d039002 reverts crates/tui/src/tui/persistence_actor/tests.rs, scripts/measure-persistence-backlog.py, scripts/persistence-backlog-budget.json, and scripts/test_measure_persistence_backlog.py to their origin/main state. These four files had been carried in by the earlier CI commit (5168737/f3660ed) but belong to an unrelated persistence-backlog lane, not this pricing/legal rescue. I confirmed with git diff origin/main -- <those 4 files> that they are now byte-identical to main — this PR's diff is exactly the 37 web files described in the PR body, with no unrelated Rust/CI carry-over. Good cleanup; this is the kind of scope discipline the repo guidance asks for.

Both previously-flagged findings remain fixed

  • Footer legal links are localizedweb/lib/i18n/links.ts:84-90, footerLegalLinks still takes chrome: ChromeDict and reads chrome.footerPricing/footerTerms/footerPrivacy, matching the pattern of footerProductLinks/footerProjectLinks.
  • Alias redirects are permanent — verified web/app/[locale]/legal/page.tsx still uses permanentRedirect() from next/navigation, not the temporary redirect().

No new issues found

No further changes needed — this PR is in good shape.

Note: command execution (npm test / vitest / cargo) was not run in this session; the scope-cleanup verification above was done via direct git diff against origin/main, which is authoritative for "are these files unchanged."

@Hmbown
Hmbown merged commit 5def7f1 into main Aug 29, 2026
27 checks passed
@Hmbown
Hmbown deleted the codex/pr5639-rescue-20260827 branch August 29, 2026 04:15
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