From 81eb72dae37bfdaef27555951e612ef37759ce08 Mon Sep 17 00:00:00 2001 From: adibarra <93070681+adibarra@users.noreply.github.com> Date: Wed, 27 May 2026 12:23:12 -0500 Subject: [PATCH 01/11] perf(nudges): lazy-load FeedbackForm so 210-line modal leaves landing critical path --- packages/app/src/lib/nudges/registry.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/app/src/lib/nudges/registry.tsx b/packages/app/src/lib/nudges/registry.tsx index e0e84dd5..ff9003ce 100644 --- a/packages/app/src/lib/nudges/registry.tsx +++ b/packages/app/src/lib/nudges/registry.tsx @@ -7,10 +7,18 @@ import { Sparkles, Star, } from 'lucide-react'; +import dynamic from 'next/dynamic'; import { GITHUB_OWNER, GITHUB_REPO } from '@semianalysisai/inferencex-constants'; -import { FEEDBACK_SUBMITTED_EVENT, FeedbackForm } from '@/components/feedback-modal'; +import { FEEDBACK_SUBMITTED_EVENT } from '@/components/feedback-modal'; + +// Keep the ~210-line FeedbackForm out of the landing/dashboard initial JS; +// it only renders after the eligibility event fires (see feedback-modal nudge below). +const FeedbackForm = dynamic( + () => import('@/components/feedback-modal').then((m) => m.FeedbackForm), + { ssr: false }, +); import { GitHubIcon } from '@/components/ui/github-icon'; import { STARRED_EVENT, STARRED_KEY, saveStarred } from '@/lib/star-storage'; import { FEEDBACK_ELIGIBLE_EVENT } from '@/lib/visit-tracking'; From 08219f62dcc761d0d6ab8aa76182406e39df880f Mon Sep 17 00:00:00 2001 From: adibarra <93070681+adibarra@users.noreply.github.com> Date: Wed, 27 May 2026 12:23:40 -0500 Subject: [PATCH 02/11] refactor(compare): drop dead generateStaticParams under force-dynamic --- packages/app/src/app/compare-per-dollar/[slug]/page.tsx | 9 --------- packages/app/src/app/compare/[slug]/page.tsx | 9 --------- 2 files changed, 18 deletions(-) diff --git a/packages/app/src/app/compare-per-dollar/[slug]/page.tsx b/packages/app/src/app/compare-per-dollar/[slug]/page.tsx index deede577..b2b432e2 100644 --- a/packages/app/src/app/compare-per-dollar/[slug]/page.tsx +++ b/packages/app/src/app/compare-per-dollar/[slug]/page.tsx @@ -11,7 +11,6 @@ import { compareModelDisplayLabel, parseCompareSlug, } from '@/lib/compare-slug'; -import { getAllComparableCompareSlugs } from '@/lib/compare-availability'; import { getGpuSpecs } from '@/lib/constants'; import { buildBreadcrumbJsonLd, @@ -36,14 +35,6 @@ interface Props { searchParams: Promise>; } -export async function generateStaticParams() { - // Mirror the /compare route's static params — only (model, pair) combos with - // benchmark data on both sides. Direct URL hits to non-enumerated combos - // still render via the dynamic SSR path (with the empty-state fallback). - const slugs = await getAllComparableCompareSlugs(); - return slugs.map(({ modelSlug, a, b }) => ({ slug: canonicalCompareSlug(modelSlug, a, b) })); -} - export async function generateMetadata({ params }: Props): Promise { const { slug } = await params; const parsed = parseCompareSlug(slug); diff --git a/packages/app/src/app/compare/[slug]/page.tsx b/packages/app/src/app/compare/[slug]/page.tsx index d6c660ec..9e09c691 100644 --- a/packages/app/src/app/compare/[slug]/page.tsx +++ b/packages/app/src/app/compare/[slug]/page.tsx @@ -11,7 +11,6 @@ import { compareModelDisplayLabel, parseCompareSlug, } from '@/lib/compare-slug'; -import { getAllComparableCompareSlugs } from '@/lib/compare-availability'; import { buildBreadcrumbJsonLd, buildJsonLd, @@ -35,14 +34,6 @@ interface Props { searchParams: Promise>; } -export async function generateStaticParams() { - // Only enumerate (model, pair) combos with benchmark data on both sides. - // Direct URL hits to non-enumerated combos still render via the dynamic - // SSR path (with the empty-state fallback). - const slugs = await getAllComparableCompareSlugs(); - return slugs.map(({ modelSlug, a, b }) => ({ slug: canonicalCompareSlug(modelSlug, a, b) })); -} - export async function generateMetadata({ params }: Props): Promise { const { slug } = await params; const parsed = parseCompareSlug(slug); From 04da466af91f6773c85addee9cdae8aa38a5d575 Mon Sep 17 00:00:00 2001 From: adibarra <93070681+adibarra@users.noreply.github.com> Date: Wed, 27 May 2026 12:23:49 -0500 Subject: [PATCH 03/11] fix(compare): lowercase slug before canonical-redirect check to stop 308 cache pollution --- packages/app/src/app/compare-per-dollar/[slug]/page.tsx | 4 +++- packages/app/src/app/compare/[slug]/page.tsx | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/app/src/app/compare-per-dollar/[slug]/page.tsx b/packages/app/src/app/compare-per-dollar/[slug]/page.tsx index b2b432e2..b5feb98c 100644 --- a/packages/app/src/app/compare-per-dollar/[slug]/page.tsx +++ b/packages/app/src/app/compare-per-dollar/[slug]/page.tsx @@ -75,7 +75,9 @@ export default async function ComparePerDollarPage({ params, searchParams }: Pro // alias model resolution, GPU alphabetical order — but redirect target lives // under /compare-per-dollar/. Query string is preserved across the hop. const canonical = canonicalCompareSlug(parsed.model.slug, parsed.a, parsed.b); - if (canonical !== slug) { + // canonical is always lowercase; compare against lowercased input so mixed-case + // URLs don't emit a fresh 308 + CDN cache entry every hit. + if (canonical !== slug.toLowerCase()) { const qs = Object.entries(sp) .flatMap(([k, v]) => { if (Array.isArray(v)) return v.map((vv) => [k, vv] as const); diff --git a/packages/app/src/app/compare/[slug]/page.tsx b/packages/app/src/app/compare/[slug]/page.tsx index 9e09c691..b957028e 100644 --- a/packages/app/src/app/compare/[slug]/page.tsx +++ b/packages/app/src/app/compare/[slug]/page.tsx @@ -79,7 +79,10 @@ export default async function ComparePage({ params, searchParams }: Props) { // redirect — the original PR #351 redirect dropped these, but with bare slugs // now redirecting unconditionally we need to keep them. const canonical = canonicalCompareSlug(parsed.model.slug, parsed.a, parsed.b); - if (canonical !== slug) { + // canonical is always lowercase; compare against lowercased input so mixed-case + // URLs (e.g. /compare/H100-vs-H200) don't emit a fresh 308 + CDN cache entry + // every hit when they actually match the canonical content. + if (canonical !== slug.toLowerCase()) { const qs = Object.entries(sp) .flatMap(([k, v]) => { if (Array.isArray(v)) return v.map((vv) => [k, vv] as const); From 73d558b7e85074338192caecd73950f53816a6fd Mon Sep 17 00:00:00 2001 From: adibarra <93070681+adibarra@users.noreply.github.com> Date: Wed, 27 May 2026 12:23:58 -0500 Subject: [PATCH 04/11] fix(json-ld): escape >, & in addition to < per HTML5 script-content spec --- packages/app/src/components/json-ld.test.ts | 18 ++++++++++++++++++ packages/app/src/components/json-ld.tsx | 10 +++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/app/src/components/json-ld.test.ts b/packages/app/src/components/json-ld.test.ts index 0cc9c819..34feaa4b 100644 --- a/packages/app/src/components/json-ld.test.ts +++ b/packages/app/src/components/json-ld.test.ts @@ -47,6 +47,24 @@ describe('JsonLd', () => { expect(JSON.parse(body)).toEqual(data); }); + it('escapes > so an HTML parser cannot mistake a literal > for the end of a comment/CDATA', () => { + const data = { note: 'a > b' }; + const html = render(data); + const body = scriptBody(html); + expect(body).toContain(String.raw`\u003e`); + expect(body).not.toContain('>'); + expect(JSON.parse(body)).toEqual(data); + }); + + it('escapes & so the payload cannot smuggle entity references through the parser', () => { + const data = { note: 'Tom & Jerry' }; + const html = render(data); + const body = scriptBody(html); + expect(body).toContain(String.raw`\u0026`); + expect(body).not.toContain('&'); + expect(JSON.parse(body)).toEqual(data); + }); + it('does NOT HTML-escape quotes (Google would reject " in JSON-LD)', () => { const html = render({ name: 'GB200' }); const body = scriptBody(html); diff --git a/packages/app/src/components/json-ld.tsx b/packages/app/src/components/json-ld.tsx index dc02e327..10b4e055 100644 --- a/packages/app/src/components/json-ld.tsx +++ b/packages/app/src/components/json-ld.tsx @@ -1,6 +1,7 @@ // Inline JSON-LD ` -// breakout if any string field ever contains one. +// children would HTML-escape the payload). Escapes `<`, `>`, and `&` per the +// HTML5 spec for `` breakout and +// keeps the payload valid if any string field ever contains one of those. export function JsonLd({ data }: { data: object }) { const json = JSON.stringify(data); if (!json) return null; @@ -8,7 +9,10 @@ export function JsonLd({ data }: { data: object }) {