[GH-ISSUE #5420] [Bug] Browser scenarios silently skip storage seeds with an empty Chromium execution-context origin #3287

Closed
opened 2026-10-31 00:38:48 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5420

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Process capture or runtime observation

Observed behavior

node scripts/rea.mjs capture-browser-scenario <scenario-file> --json exits 0 in launch mode with the caller-selected Chrome for Testing 145.0.7632.6, but the first page script and a later read see neither declared local nor session storage seed. The final storage artifact is empty, yet completeness is complete and equality_eligible is true, with no limitation identifying unapplied seeds.

An independent verifier reproduced this in both affected-build runs. Changing only the executable to Chrome for Testing 153.0.8010.12 applied both seeds before the first script in both control runs. REA does not install or automatically select either browser.

Reproduction

The verifier ran the public CLI twice per executable against a disposable loopback HTTP fixture, once normally and once with DEBUG=pw:protocol. The fixture's first inline script was:

<script>
const read = () => ({local:Object.entries(localStorage),session:Object.entries(sessionStorage)});
console.log("seed-first", JSON.stringify(read()));
setTimeout(() => console.log("seed-later", JSON.stringify(read())), 300);
</script>

The executed scenario had this shape. Replace PORT with the fixture server's allocated port and BROWSER_EXECUTABLE with the installed executable for each run; those are redacted runtime-specific substitutions, not literal request values.

{
  "browser": {"mode": "launch", "executable_path": "BROWSER_EXECUTABLE"},
  "start_url": {"url": "http://127.0.0.1:PORT/seed.html"},
  "actions": [{"step_id": "settle", "action": "wait_for_timeout", "duration_ms": 600}],
  "storage": {
    "local_storage": [{"origin": "http://127.0.0.1:PORT", "entries": [{"name": "seed", "value": {"source": "literal", "value": "local-value"}}]}],
    "session_storage": [{"origin": "http://127.0.0.1:PORT", "entries": [{"name": "seed", "value": {"source": "literal", "value": "session-value"}}]}]
  },
  "capture": {"at_end": ["storage"], "events": ["console"]}
}

From the baseline checkout with its locked dependencies and built runtime, serve the fixture on 127.0.0.1, save the scenario, and run:

node scripts/rea.mjs capture-browser-scenario <scenario-file> --json

Use Chrome for Testing 145.0.7632.6, Playwright Chromium revision 1208, for the failing run. Repeat with the identical input except for executable selection using Chrome for Testing 153.0.8010.12, revision 1243, as the passing control. The verifier isolated home/configuration/data/cache/state/temporary directories and terminated and awaited each fixture server. No external site or API was used.

Expected behavior

docs/browser-scenario-contract.md:195-205 promises local storage seeds once per storage partition and session storage seeds once per origin in each top-level browsing context, before the first document scripts. Lines 32-56 accept a caller-selected installed Chrome-family executable without an applicable version exception for this build.

Both page reads should contain the declared values, and the final storage artifact should contain both entries with hashed values. Successful capture evidence should not conceal a failure to establish the requested initial state.

Impact and scope

The tested launch scenario silently runs with incorrect initial state and returns complete, equality-eligible evidence. Failure reproduced 2/2 times on the affected executable; the control passed 2/2 times. Selecting the already-installed passing executable preserves the requested result for this fixture.

Observed scope is one loopback origin, one local storage entry, one session storage entry, launch mode, and the two browser builds above. Other origins, partitions, popup contexts, and builds were not tested. No security boundary crossing or user data loss was observed.

REA version

6.7.0, source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8, using its existing built runtime and locked dependencies. Upstream recheck at 1417bf943bf49e49b414e8a508bf28a31304be83 found no subsequent changes to the cited storage implementation, session setup, or contract; no new runtime reproduction is claimed for that head.

Runtime and platform

Node v26.12.0; macOS arm64; playwright-core 1.58.2. Affected: Chrome for Testing 145.0.7632.6, Chromium revision 1208 associated with the pinned Playwright dependency. Passing control: Chrome for Testing 153.0.8010.12, installed revision 1243.

Target and artifact context

Disposable HTML page on a local HTTP server with literal test seeds. Captured console events and the final storage artifact establish the result. Empty cookies are expected because the scenario declares none.

Interface

CLI

Earliest failure stage

Capture or observation

Relevant output or evidence

Both affected-build runs exited 0 and logged:

seed-first {"local":[],"session":[]}
seed-later {"local":[],"session":[]}

Final storage artifact:

{"state":"captured","value":{"cookies":[],"local_storage":[],"session_storage":[]}}

Overall completeness:

{"status":"complete","equality_eligible":true,"missing_sections":[],"truncated_sections":[]}

Both control runs logged the following values at both reads and captured both entries with hashed values:

{"local":[["seed","local-value"]],"session":[["seed","session-value"]]}

The protocol-logged pair showed Runtime.executionContextCreated reporting origin: "" for REA's private isolated storage world on the affected build and the actual loopback origin on the control. Both had a frame ID. Both browsers reported provider-owned process cleanup.

Typed outcome or recovery expected

Apply both seeds before the first script and retain them at final capture when the page has made no changes. An explicit initialization failure would prevent false success, but would not itself restore the promised seed behavior. Applying values only before final capture would also miss the first-script requirement.

Analysis or suspected cause

Source-derived reasoning: src/browser/PlaywrightScenarioStorage.ts:339-354 retains private execution contexts and script associations. Lines 413-425 look up the seed by context.origin and return without applying storage when no seed matches. The observed empty origin therefore skips the declared HTTP-origin seeds. Lines 477-510 resume the private paused frame. src/browser/PlaywrightScenarioSession.ts:285-296 installs this mechanism before initial navigation. This source explanation is bounded by the runtime observations above.

Additional context

This report was prepared with AI assistance and independently reproduced through the public CLI. No last-known-good REA release or broader browser compatibility range was established. The upstream recheck compared current main against the verified baseline; the browser reproductions remain those performed by the independent verifier at that baseline.

Prior mention: https://github.com/morluto/rea/pull/4956 (closed unmerged; stated it targeted the wrong repository)

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5420 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Process capture or runtime observation ### Observed behavior `node scripts/rea.mjs capture-browser-scenario <scenario-file> --json` exits 0 in launch mode with the caller-selected Chrome for Testing 145.0.7632.6, but the first page script and a later read see neither declared local nor session storage seed. The final storage artifact is empty, yet completeness is `complete` and `equality_eligible` is `true`, with no limitation identifying unapplied seeds. An independent verifier reproduced this in both affected-build runs. Changing only the executable to Chrome for Testing 153.0.8010.12 applied both seeds before the first script in both control runs. REA does not install or automatically select either browser. ### Reproduction The verifier ran the public CLI twice per executable against a disposable loopback HTTP fixture, once normally and once with `DEBUG=pw:protocol`. The fixture's first inline script was: ```html <script> const read = () => ({local:Object.entries(localStorage),session:Object.entries(sessionStorage)}); console.log("seed-first", JSON.stringify(read())); setTimeout(() => console.log("seed-later", JSON.stringify(read())), 300); </script> ``` The executed scenario had this shape. Replace `PORT` with the fixture server's allocated port and `BROWSER_EXECUTABLE` with the installed executable for each run; those are redacted runtime-specific substitutions, not literal request values. ```json { "browser": {"mode": "launch", "executable_path": "BROWSER_EXECUTABLE"}, "start_url": {"url": "http://127.0.0.1:PORT/seed.html"}, "actions": [{"step_id": "settle", "action": "wait_for_timeout", "duration_ms": 600}], "storage": { "local_storage": [{"origin": "http://127.0.0.1:PORT", "entries": [{"name": "seed", "value": {"source": "literal", "value": "local-value"}}]}], "session_storage": [{"origin": "http://127.0.0.1:PORT", "entries": [{"name": "seed", "value": {"source": "literal", "value": "session-value"}}]}] }, "capture": {"at_end": ["storage"], "events": ["console"]} } ``` From the baseline checkout with its locked dependencies and built runtime, serve the fixture on `127.0.0.1`, save the scenario, and run: ```sh node scripts/rea.mjs capture-browser-scenario <scenario-file> --json ``` Use Chrome for Testing 145.0.7632.6, Playwright Chromium revision 1208, for the failing run. Repeat with the identical input except for executable selection using Chrome for Testing 153.0.8010.12, revision 1243, as the passing control. The verifier isolated home/configuration/data/cache/state/temporary directories and terminated and awaited each fixture server. No external site or API was used. ### Expected behavior `docs/browser-scenario-contract.md:195-205` promises local storage seeds once per storage partition and session storage seeds once per origin in each top-level browsing context, before the first document scripts. Lines 32-56 accept a caller-selected installed Chrome-family executable without an applicable version exception for this build. Both page reads should contain the declared values, and the final storage artifact should contain both entries with hashed values. Successful capture evidence should not conceal a failure to establish the requested initial state. ### Impact and scope The tested launch scenario silently runs with incorrect initial state and returns complete, equality-eligible evidence. Failure reproduced 2/2 times on the affected executable; the control passed 2/2 times. Selecting the already-installed passing executable preserves the requested result for this fixture. Observed scope is one loopback origin, one local storage entry, one session storage entry, launch mode, and the two browser builds above. Other origins, partitions, popup contexts, and builds were not tested. No security boundary crossing or user data loss was observed. ### REA version 6.7.0, source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`, using its existing built runtime and locked dependencies. Upstream recheck at `1417bf943bf49e49b414e8a508bf28a31304be83` found no subsequent changes to the cited storage implementation, session setup, or contract; no new runtime reproduction is claimed for that head. ### Runtime and platform Node v26.12.0; macOS arm64; playwright-core 1.58.2. Affected: Chrome for Testing 145.0.7632.6, Chromium revision 1208 associated with the pinned Playwright dependency. Passing control: Chrome for Testing 153.0.8010.12, installed revision 1243. ### Target and artifact context Disposable HTML page on a local HTTP server with literal test seeds. Captured console events and the final storage artifact establish the result. Empty cookies are expected because the scenario declares none. ### Interface CLI ### Earliest failure stage Capture or observation ### Relevant output or evidence Both affected-build runs exited 0 and logged: ```text seed-first {"local":[],"session":[]} seed-later {"local":[],"session":[]} ``` Final storage artifact: ```json {"state":"captured","value":{"cookies":[],"local_storage":[],"session_storage":[]}} ``` Overall completeness: ```json {"status":"complete","equality_eligible":true,"missing_sections":[],"truncated_sections":[]} ``` Both control runs logged the following values at both reads and captured both entries with hashed values: ```json {"local":[["seed","local-value"]],"session":[["seed","session-value"]]} ``` The protocol-logged pair showed `Runtime.executionContextCreated` reporting `origin: ""` for REA's private isolated storage world on the affected build and the actual loopback origin on the control. Both had a frame ID. Both browsers reported provider-owned process cleanup. ### Typed outcome or recovery expected Apply both seeds before the first script and retain them at final capture when the page has made no changes. An explicit initialization failure would prevent false success, but would not itself restore the promised seed behavior. Applying values only before final capture would also miss the first-script requirement. ### Analysis or suspected cause Source-derived reasoning: `src/browser/PlaywrightScenarioStorage.ts:339-354` retains private execution contexts and script associations. Lines 413-425 look up the seed by `context.origin` and return without applying storage when no seed matches. The observed empty origin therefore skips the declared HTTP-origin seeds. Lines 477-510 resume the private paused frame. `src/browser/PlaywrightScenarioSession.ts:285-296` installs this mechanism before initial navigation. This source explanation is bounded by the runtime observations above. ### Additional context This report was prepared with AI assistance and independently reproduced through the public CLI. No last-known-good REA release or broader browser compatibility range was established. The upstream recheck compared current main against the verified baseline; the browser reproductions remain those performed by the independent verifier at that baseline. Prior mention: https://github.com/morluto/rea/pull/4956 (closed unmerged; stated it targeted the wrong repository)
Author
Owner

@coygeek commented on GitHub (Oct 24, 2026):

Checked resolved on main at d87e73f2db.

The empty execution-context origin now falls back to the exact frame's securityOrigin obtained from Page.getFrameTree, before looking up declared seeds. The regression for an empty isolated-world origin passed, along with the control that rejects unknown applicability instead of inferring an origin from a URL. The companion test confirms seed evaluation happens before the document script resumes. These are controlled CDP tests against the producing storage owner; no real-Chromium first-script run is claimed by this closure.

Relevant implementation: PlaywrightScenarioStorage.ts, PlaywrightScenarioStorage.ts.

Closing as completed on main.

<!-- gh-comment-id:6380759196 --> @coygeek commented on GitHub (Oct 24, 2026): Checked resolved on `main` at d87e73f2db50be72d33a4b3c7199af35518b441c. The empty execution-context origin now falls back to the exact frame's `securityOrigin` obtained from `Page.getFrameTree`, before looking up declared seeds. The regression for an empty isolated-world origin passed, along with the control that rejects unknown applicability instead of inferring an origin from a URL. The companion test confirms seed evaluation happens before the document script resumes. These are controlled CDP tests against the producing storage owner; no real-Chromium first-script run is claimed by this closure. Relevant implementation: [PlaywrightScenarioStorage.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/browser/PlaywrightScenarioStorage.ts#L490), [PlaywrightScenarioStorage.ts](https://github.com/morluto/rea/blob/d87e73f2db50be72d33a4b3c7199af35518b441c/src/browser/PlaywrightScenarioStorage.ts#L550). Closing as completed on main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3287
No description provided.