Skip to content

perf(viewer): deduce spaces lazily instead of the full database in SSR#251

Draft
jamesdabbs wants to merge 1 commit into
mainfrom
perf/viewer-ssr-deduction
Draft

perf(viewer): deduce spaces lazily instead of the full database in SSR#251
jamesdabbs wants to merge 1 commit into
mainfrom
perf/viewer-ssr-deduction

Conversation

@jamesdabbs

@jamesdabbs jamesdabbs commented Jun 28, 2026

Copy link
Copy Markdown
Member

Stacked on #254 (perf/viewer-ssr-isolate-cache) — this PR's base is that branch, so the diff here is only the deduction change. Merge #254 first.

What & why

The universal layout load runs during SSR, and refresh() ran the full deduction engine over every space on each request — then the client discarded it and recomputed the same thing after hydration. One logged invocation spent 440 ms of CPU rendering a single static reference page. Only 3 routes are prerendered, so every detail page (exactly what crawlers and deep links hit) paid this.

Gate the eager full-database deduction to the browser, and have checked(spaceId) deduce only the space it needs, on demand — so SSR of the trait page still renders the data it references. Side effect: removes the duplicate deduction passes the old test documented as a FIXME.

Instrumentation

Adds a deduce_space Workers Logs event (space id + derived count). After this change an SSR page render emits exactly one deduce_space (the requested space), and deduce_run (the full-database pass) disappears from runtime logs.

Tradeoff

SSR'd space pages show only asserted traits in the initial HTML; deduced ones fill in after hydration (unchanged from how the client already worked). If SEO on derived traits matters, prerendering all routes is the follow-up.

Validation

  • pnpm --filter viewer tsc and validate (svelte-check) — clean
  • pnpm --filter viewer test — 70 passed, 5 todo (the FIXME duplicate-pass assertions are gone)
  • VITE_SITE=topology pnpm --filter viewer build

Manual deploy + telemetry check (topology worker pi-base-topology):

  1. VITE_SITE=topology pnpm --filter viewer build
  2. pnpm --filter viewer cf:deploy:topology (= wrangler deploy --env topology)
  3. GET a non-prerendered /spaces/<id>/properties/<id> page.
  4. In Workers Logs / observability:
    • Expect: exactly one deduce_space per render (the requested space), and no deduce_run from SSR invocations.
    • Compare the platform cpuTimeMs on the detail routes (request.routeId) before vs after: should drop from ~440 ms toward low tens of ms.

Reviewing

Easiest commit-by-commit; base is #254.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
pi-base-topology e928786 Commit Preview URL

Branch Preview URL
Jun 28 2026, 08:29 PM

@jamesdabbs jamesdabbs self-assigned this Jun 28, 2026
@jamesdabbs jamesdabbs force-pushed the perf/viewer-ssr-deduction branch from a665198 to 6e44d20 Compare June 28, 2026 04:42
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying topology with  Cloudflare Pages  Cloudflare Pages

Latest commit: e928786
Status: ✅  Deploy successful!
Preview URL: https://8c7ced7c.topology.pages.dev
Branch Preview URL: https://perf-viewer-ssr-deduction.topology.pages.dev

View logs

@jamesdabbs jamesdabbs force-pushed the perf/viewer-ssr-deduction branch 3 times, most recently from 81d7c67 to cb950ba Compare June 28, 2026 16:02
@jamesdabbs jamesdabbs changed the title perf(viewer): eliminate per-request prover work in SSR + Workers Logs telemetry perf(viewer): deduce spaces lazily instead of the full database in SSR Jun 28, 2026
@jamesdabbs jamesdabbs changed the base branch from main to perf/viewer-ssr-isolate-cache June 28, 2026 16:04
Base automatically changed from perf/viewer-ssr-isolate-cache to main June 28, 2026 20:24
The universal layout load runs during SSR, and refresh() ran the full
deduction engine over every space on each request — then the client threw it
away and recomputed it after hydration. One logged invocation spent 440ms of
CPU rendering a single static reference page; only 3 routes are prerendered,
so every detail page (exactly what crawlers and deep links hit) paid this.

Gate the eager full-database deduction to the browser, and have
checked(spaceId) deduce only the space it needs on demand so SSR of the trait
page still renders the data it references. As a side effect this removes the
duplicate deduction passes the old test documented as a FIXME.

Instrumentation: add a `deduce_space` Workers Logs event (space id + derived
count). After this change an SSR page render should emit exactly one
`deduce_space` for the requested space, and `deduce_run` (the full-database
pass) should disappear from runtime logs entirely — the signal, alongside the
platform's per-invocation cpuTimeMs, that the per-request prover work is gone.

Stacked on the isolate bundle cache so a warm isolate now reuses both the
parse/transform and skips the full prover.
@jamesdabbs jamesdabbs force-pushed the perf/viewer-ssr-deduction branch from cb950ba to e928786 Compare June 28, 2026 20:28
@jamesdabbs

Copy link
Copy Markdown
Member Author

Telemetry validation — deployed to pi-base-topology (version bc73d93f)

Deployed this branch (rebased onto main after #254 merged) to the topology worker and validated against live traffic + a controlled request batch.

✅ Eager full-database deduction eliminated from SSR

deduce_run events: 52 in the hour before deploy → 0 after. The full-database prover no longer runs during SSR.

✅ Lazy per-space deduction works, and SSR renders correctly

Raw SSR HTML for /spaces/S000001/properties/P000016 (server-rendered, pre-hydration) contains the deduced verdict and its proof:

Space S1 | Property P16 is Automatically deduced from the following: … Theorems T430, T431, ¬T782 ∧ T795, T650

So checked() deduces the one requested space on demand and the deduced trait + proof are in the initial HTML — not asserted-only. deduce_space fires ~once per SSR render (the instrumentation), and the response is compact (~9 KB). Valid pages return 200; nonexistent ones (e.g. /spaces/S000600/properties/P000200) correctly 404.

✅ Heavy-route CPU dropped sharply

$workers.cpuTimeMs on /spaces/[id]/properties/[propertyId]:

percentile baseline (#254) #251
p50 889 ms 265 ms (~3.4× lower)
p90 2621 ms 404 ms
p99 3654 ms 404 ms (~9× lower)

The residual ~265 ms is base SSR render + occasional cold-isolate bundle transform; the 0.6–3.6 s of per-request prover work is gone.

Caveats / honesty on the sample

  • The post-deploy window is a low-traffic evening lull (~6–22 SSR invocations in 41 min), so the p90/p99 above rest on a small sample (p90≈p99 because there are only a handful of points). The median and the deduce_run→0 result are robust; the tail magnitude should be re-confirmed over a busier soak.
  • That cuts in our favor: low traffic means a higher cold-isolate fraction (more cold parses), so a busy-traffic window should land at or below these numbers, not above.
  • The baseline row is the perf(viewer): cache the parsed SSR bundle per isolate #254 afternoon busy window (13:00–16:00 UTC, thousands of samples).

Reproduce

Verdict: behaves correctly (deduced traits SSR'd with proofs), eager deduction eliminated, and per-render CPU down ~3.4× median / ~9× p99. Recommend one more soak through a busy-traffic window to firm up the tail percentiles before merge.

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