You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue remains OPEN. The supported-UI ensureWelcomePortalEntry() harness hardening reduced the original precondition problem but has not fully eliminated this nondeterministic startup/navigation failure class.
A recurrence was observed on unrelated docs-only PR #564 at exact head bf684034afe82d838dcd9bc62bfd9de0aecafbe6 in CI/CD run 33478269659 / Playwright job 99764976401:
117 passed
9 skipped
2 failed
2 flaky
The failures/flakes again converged on ensureWelcomePortalEntry() / WelcomePortal startup navigation in onboarding-entry-precondition.spec.ts and export.spec.ts, across Chromium and Mobile Chrome. PR #564 changes only the R-15 design contract / migration-ledger documentation, so there is no demonstrated S5/R-15 source relationship.
Current classification:
startup/harness determinism owner = #532
settings-only seed-authority ambiguity = RESOLVED by #546
underlying double-boot / unexpected startup-state root cause = OPEN
#527 regression = NO evidence
Preserve first-attempt failures as evidence. A same-head targeted rerun may classify intermittent behavior, but repeated retries must not substitute for root-cause analysis.
Summary
export.spec.ts's beforeEach originally assumed waitForSpaReady(page) always resolves via WelcomePortal, and clicked "Start a New Project" unconditionally. waitForSpaReady() actually races three success conditions (#sidebar, [data-tour="nav-mobile"], or the "Start a New Project" button) and succeeds on any of them — it does not distinguish a fresh boot from a returning-user boot. On the main post-merge run for PR #530 (run 33088546994, job 98579015311), all 3 Playwright retries of this test failed identically (byte-identical screenshot/error-context hashes) waiting on that locator, because the app had already booted into the main shell (Outline Generator view) instead of WelcomePortal. A same-SHA rerun (job 98582879363) passed cleanly, establishing a startup-state determinism gap rather than the already-fixed #527 portal-activation auto-seed race.
This is not a regression of #527/#530. Do not reopen #527 unless its exact mechanism is independently reproduced.
Evidence gathered from the original failure
From the failed job's attached Playwright trace (retry 1, chromium):
waitForSpaReady()'s internal action log shows the #sidebar wait resolving successfully before the "Start a New Project" wait ever got its own resolution — i.e. the race resolved via the main-chrome branch, not WelcomePortal.
Frame-snapshot URLs recorded across the trace: the page loaded at http://127.0.0.1:3000/WorldScript-Studio/ with no hash, then ~700ms later the hash became #/outline and stayed there for the remainder of the 20s timeout — i.e. the app's own in-app router (deepLinkService.pushHash) navigated to Outline Generator on its own, which per useApp.ts's readInitialView() priority (URL hash → ?view= → localStorage['worldscript-last-view'] → dashboard) only happens when one of the first three sources was already non-empty.
Console log timeline shows the full boot sequence (Vite HMR connect, Using IndexedDB storage backend, SW registration, WorkerBus init) occurring twice within this single trace, with [WorldScript:DEBUG:app] Hydrating flat project state into Redux-Undo envelope. appearing only on the second occurrence. Per index.tsx's bootApp(), this log line only fires when preloadedState.project is truthy and in flat (non-envelope) format — i.e. a real, non-blank persisted project existed in IndexedDB by the second boot cycle, not merely a default/blank placeholder.
export.spec.ts is a single-test file using Playwright's stock, fully-isolated per-test browser context (no custom fixtures, no storageState, no globalSetup in playwright.config.ts) — cross-test-file storage leakage is ruled out as the mechanism.
Open root cause
The exact trigger for the double-boot cycle and/or unexpected WelcomePortal-entry state is not yet pinned down.
Candidate mechanisms requiring evidence include:
register-sw.ts's unconditional controllerchange → location.reload() (the existing DA-02 finding), which can explain a mid-boot reload but does not by itself explain every persisted-state observation.
Early autosave / project persistence during boot, including whether a project can become durable before the WelcomePortal flow is semantically settled.
A separate startup/navigation race in the supported-UI reset/entry helper itself, now made more plausible by the docs(core): define R-15 secure storage contract (#445) #564 recurrence where the helper sometimes fails to reach nav-mobile or welcome-portal.
The previously noted settings-only isNewUser ambiguity is no longer an outstanding candidate: PR #546 changed seed authority to depend on an actually hydratable/normalized persisted project rather than any truthy preloaded state. That correction does not explain or close the remaining double-boot / startup-navigation behavior.
Harness hardening already landed
ensureWelcomePortalEntry() in tests/e2e/helpers.ts establishes the WelcomePortal entry through supported UI: if "Start a New Project" is not visible after waitForSpaReady(), it uses Settings → Data & Backups → Factory Reset rather than touching storage/React internals directly. tests/e2e/onboarding-entry-precondition.spec.ts regression-tests multiple startup shapes.
This remains the correct direction for deterministic preconditions, but the #564 recurrence proves the current helper is not yet a complete closure of the startup/navigation failure class. Any further remediation should be performed in a dedicated #532 scope, not opportunistically inside unrelated PRs.
Recommended investigation / acceptance criteria
A dedicated #532 remediation should establish which of these is authoritative:
a real application startup-state/double-boot defect;
Current status — 2026-09-01
This issue remains OPEN. The supported-UI
ensureWelcomePortalEntry()harness hardening reduced the original precondition problem but has not fully eliminated this nondeterministic startup/navigation failure class.A recurrence was observed on unrelated docs-only PR #564 at exact head
bf684034afe82d838dcd9bc62bfd9de0aecafbe6in CI/CD run33478269659/ Playwright job99764976401:The failures/flakes again converged on
ensureWelcomePortalEntry()/ WelcomePortal startup navigation inonboarding-entry-precondition.spec.tsandexport.spec.ts, across Chromium and Mobile Chrome. PR #564 changes only the R-15 design contract / migration-ledger documentation, so there is no demonstrated S5/R-15 source relationship.Current classification:
Preserve first-attempt failures as evidence. A same-head targeted rerun may classify intermittent behavior, but repeated retries must not substitute for root-cause analysis.
Summary
export.spec.ts'sbeforeEachoriginally assumedwaitForSpaReady(page)always resolves via WelcomePortal, and clicked "Start a New Project" unconditionally.waitForSpaReady()actually races three success conditions (#sidebar,[data-tour="nav-mobile"], or the "Start a New Project" button) and succeeds on any of them — it does not distinguish a fresh boot from a returning-user boot. On themainpost-merge run for PR #530 (run33088546994, job98579015311), all 3 Playwright retries of this test failed identically (byte-identical screenshot/error-context hashes) waiting on that locator, because the app had already booted into the main shell (Outline Generator view) instead of WelcomePortal. A same-SHA rerun (job98582879363) passed cleanly, establishing a startup-state determinism gap rather than the already-fixed #527 portal-activation auto-seed race.This is not a regression of #527/#530. Do not reopen #527 unless its exact mechanism is independently reproduced.
Evidence gathered from the original failure
From the failed job's attached Playwright trace (
retry 1,chromium):waitForSpaReady()'s internal action log shows the#sidebarwait resolving successfully before the "Start a New Project" wait ever got its own resolution — i.e. the race resolved via the main-chrome branch, not WelcomePortal.http://127.0.0.1:3000/WorldScript-Studio/with no hash, then ~700ms later the hash became#/outlineand stayed there for the remainder of the 20s timeout — i.e. the app's own in-app router (deepLinkService.pushHash) navigated to Outline Generator on its own, which peruseApp.ts'sreadInitialView()priority (URL hash →?view=→localStorage['worldscript-last-view']→ dashboard) only happens when one of the first three sources was already non-empty.Using IndexedDB storage backend, SW registration, WorkerBus init) occurring twice within this single trace, with[WorldScript:DEBUG:app] Hydrating flat project state into Redux-Undo envelope.appearing only on the second occurrence. Perindex.tsx'sbootApp(), this log line only fires whenpreloadedState.projectis truthy and in flat (non-envelope) format — i.e. a real, non-blank persisted project existed in IndexedDB by the second boot cycle, not merely a default/blank placeholder.export.spec.tsis a single-test file using Playwright's stock, fully-isolated per-test browser context (no custom fixtures, nostorageState, noglobalSetupinplaywright.config.ts) — cross-test-file storage leakage is ruled out as the mechanism.Open root cause
The exact trigger for the double-boot cycle and/or unexpected WelcomePortal-entry state is not yet pinned down.
Candidate mechanisms requiring evidence include:
register-sw.ts's unconditionalcontrollerchange→location.reload()(the existing DA-02 finding), which can explain a mid-boot reload but does not by itself explain every persisted-state observation.nav-mobileorwelcome-portal.The previously noted settings-only
isNewUserambiguity is no longer an outstanding candidate: PR #546 changed seed authority to depend on an actually hydratable/normalized persisted project rather than any truthy preloaded state. That correction does not explain or close the remaining double-boot / startup-navigation behavior.Harness hardening already landed
ensureWelcomePortalEntry()intests/e2e/helpers.tsestablishes the WelcomePortal entry through supported UI: if "Start a New Project" is not visible afterwaitForSpaReady(), it uses Settings → Data & Backups → Factory Reset rather than touching storage/React internals directly.tests/e2e/onboarding-entry-precondition.spec.tsregression-tests multiple startup shapes.This remains the correct direction for deterministic preconditions, but the #564 recurrence proves the current helper is not yet a complete closure of the startup/navigation failure class. Any further remediation should be performed in a dedicated #532 scope, not opportunistically inside unrelated PRs.
Recommended investigation / acceptance criteria
A dedicated #532 remediation should establish which of these is authoritative:
Before closing #532, require evidence that:
ensureWelcomePortalEntry()reliably reaches its target from each supported startup shape used by CI;nav-mobile/welcome-portalnever becomes reachable;Non-goals