Fix stepper SSR/hydration flash: server reads cookie, cache bypass

Three changes to eliminate the stepper flash:

1. home-stepper.sx: server path reads cookie via (get-cookie) for
   step-idx initial value. Client path reads document.cookie via
   def-store. Both default to 0 when no cookie exists.

2. sx_server.ml: bypass response cache when sx-home-stepper cookie
   is present. Render on main thread (not worker) so get-cookie
   sees the parsed request cookies.

3. site-full.spec.js: flash detection test sets cookie=7 via
   Playwright context, checks SSR HTML matches hydrated state.

Test: "No flash: SSR=7 hydrated=7 (cookie=7)" — passes.
Tested on fresh stack=site server subprocess.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 07:28:47 +00:00
parent 32fd3ef7d3
commit 79ba9c2d40
3 changed files with 31 additions and 3 deletions

View File

@@ -159,6 +159,12 @@ test('home', async ({ page }) => {
const errors = trackErrors(page);
const entries = [];
// Set cookie to step 7, then load page — SSR should render at 7
await page.context().addCookies([{
name: 'sx-home-stepper', value: '7',
url: server.baseUrl,
}]);
// Capture SSR state before JS runs — detect hydration flash
const ssrResponse = await page.goto(server.baseUrl + '/sx/', { waitUntil: 'commit', timeout: 30000 });
const ssrHtml = await ssrResponse.text();
@@ -174,7 +180,7 @@ test('home', async ({ page }) => {
return m ? m[1] : null;
});
const noFlash = ssrIndex === hydratedIndex;
entries.push({ ok: noFlash, label: `No flash: SSR=${ssrIndex} hydrated=${hydratedIndex}`, feature: 'no-flash' });
entries.push({ ok: noFlash, label: `No flash: SSR=${ssrIndex} hydrated=${hydratedIndex} (cookie=7)`, feature: 'no-flash' });
const info = await discoverPage(page);
entries.push({ ok: true, label: 'Boot: data-sx-ready', feature: 'boot' });