diff --git a/src/app/page.tsx b/src/app/page.tsx index f2b0ab75b..6da5b170f 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -120,8 +120,8 @@ function getHourForTimeZone(timeZone?: string): number { * v1.7.0 — first-paint gate for the dashboard tile strip. * * `primaryLoading` must come from whichever query actually drives the - * tiles: the snapshot cell under `NEXT_PUBLIC_DASHBOARD_SNAPSHOT=true`, - * the slim analytics cell otherwise. A disabled TanStack query reports + * tiles: the snapshot cell by default, the slim analytics cell when + * `NEXT_PUBLIC_DASHBOARD_SNAPSHOT=false`. A disabled TanStack query reports * `isLoading: false` (idle fetch status), so keying off the wrong * source flashes the empty state for the whole fetch. Pure + exported * so the gate has direct unit coverage without mounting the page. @@ -245,12 +245,12 @@ export default function DashboardPage() { // Both queries share `caches.analytics` server-side so warm hits // stay free, and TanStack's parallel-mounting keeps the network fan- // out flat. - // v1.7.0 W6 — unified first-paint snapshot (reversible rollout flag). - // When `NEXT_PUBLIC_DASHBOARD_SNAPSHOT=true`, every tile hydrates from - // ONE un-gated `/api/dashboard/snapshot` cell so the whole strip - // shares one completion moment and the `/api/auth/me` round-trip - // leaves the cold critical path. Flag OFF keeps the legacy four - // independent cells (today's behaviour, byte-identical). + // Unified first-paint snapshot (reversible rollout flag, default ON). + // Every tile hydrates from ONE un-gated `/api/dashboard/snapshot` cell + // so the whole strip shares one completion moment and the + // `/api/auth/me` round-trip leaves the cold critical path. Set + // `NEXT_PUBLIC_DASHBOARD_SNAPSHOT=false` to fall back to the legacy + // four independent cells. const snapshotEnabled = isDashboardSnapshotEnabled(); const snapshotQuery = useDashboardSnapshot(snapshotEnabled); diff --git a/src/lib/dashboard/snapshot-flag.ts b/src/lib/dashboard/snapshot-flag.ts index 74e824c6d..019db330f 100644 --- a/src/lib/dashboard/snapshot-flag.ts +++ b/src/lib/dashboard/snapshot-flag.ts @@ -1,18 +1,21 @@ /** - * v1.7.0 W6 — reversible rollout flag for the unified dashboard - * snapshot consumption (R-firstpaint §6 rollout). + * Reversible rollout flag for the unified dashboard snapshot + * consumption. * - * The `GET /api/dashboard/snapshot` endpoint and the - * `insight-pregenerate` cron ship inert in step 1. This flag controls - * step 2 — whether the dashboard page reads every tile from the single - * snapshot cell (flag ON) or keeps the legacy four independent cells - * (flag OFF, today's behaviour, zero risk). Default OFF so the swap is - * opt-in until the stagger is verified gone in production. + * Controls whether the dashboard page reads every above-the-fold tile + * from the single `GET /api/dashboard/snapshot` cell (default) or falls + * back to the legacy four independent cells (slim analytics + thick + * analytics + mood + widget layout). The snapshot path is the desired + * behaviour: one un-gated request hydrates the whole strip so every + * tile shares one completion moment, instead of four parallel cells + * where the mood cache resolves fastest and pops in ahead of the rest. * - * Build-time `NEXT_PUBLIC_*` env var so the bundle is statically - * branched; flipping it is a redeploy, not a runtime toggle, which - * keeps the off-path bundle identical to today's. + * Default ON. Set `NEXT_PUBLIC_DASHBOARD_SNAPSHOT=false` to fall back + * to the legacy multi-cell path. Defaulting on (rather than gating on + * `=== "true"`) avoids the `NEXT_PUBLIC_*` build-time-baking trap: the + * snapshot path is exercised in dev / e2e without a special build + * flag, and the production image gets it without a Dockerfile ARG. */ export function isDashboardSnapshotEnabled(): boolean { - return process.env.NEXT_PUBLIC_DASHBOARD_SNAPSHOT === "true"; + return process.env.NEXT_PUBLIC_DASHBOARD_SNAPSHOT !== "false"; }