[PR #4585] fix(browser): record dedicated worker requests through attached sessions #6322

Open
opened 2026-10-31 01:13:34 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/4585
Author: @jayinvers
Created: 10/16/2026
Status: 🔄 Open

Base: main ← Head: fix/cdp-worker-request-recording


📝 Commits (4)

  • 9f332a5 fix(browser): record dedicated worker requests through attached sessions
  • 6407793 fix(browser): harden worker session cleanup and completion attribution
  • d362639 test(ci): fit the shared cli-boundary worker heap to current main
  • 4f5cbe2 fix(browser): bound worker admission and record nested workers

📊 Changes

17 files changed (+1759 additions, -35 deletions)

View changed files

📝 docs/browser-observation.md (+20 -2)
📝 scripts/fixtures/browser-verifier-site.mjs (+41 -0)
📝 scripts/verify-real-browser.mjs (+33 -0)
📝 src/browser/CdpCaptureEventHandlers.ts (+3 -0)
📝 src/browser/CdpCaptureEventTypes.ts (+8 -0)
📝 src/browser/CdpCaptureEvents.ts (+34 -5)
➕ src/browser/CdpCaptureEvents.workerAttribution.test.ts (+138 -0)
📝 src/browser/CdpPageCapture.ts (+116 -26)
➕ src/browser/CdpPageCaptureWorkerSessions.ts (+392 -0)
📝 src/domain/browserObservationSchemas.ts (+7 -0)
➕ tests/boundary/browser/cdpWorkerNetworkRecording.test.ts (+713 -0)
📝 tests/fixtures/fakeCdpBrowser.ts (+8 -0)
📝 tests/fixtures/fakeCdpBrowserEvents.ts (+196 -0)
📝 tests/fixtures/fakeCdpBrowserResults.ts (+1 -0)
📝 tests/fixtures/fakeCdpBrowserTargets.ts (+23 -0)
📝 tests/fixtures/fakeCdpBrowserTypes.ts (+21 -0)
📝 vitest.config.ts (+5 -2)

📄 Description

Summary

rea inspect-web-page reported dedicated web workers in its worker inventory but recorded none of the requests they issued, because the capture only listened for Network events on the page's own CDP session. This PR flattens the page's dedicated-worker sessions onto the connection, multiplexes their Network events into the capture, and retains every worker-issued request with the issuing worker's target ID. Fixes #4425.

Problem and expected behavior

Smallest trigger: attach inspect-web-page to a page whose dedicated worker fetches observable URLs during the observation window. Violated invariant: recorded network traffic claimed attach-window coverage while an entire attached issuer (the worker) contributed a silent zero.

Expected behavior (per the issue): requests issued by dedicated workers appear in network.requests with worker attribution preserved, instead of a false zero count.

Executed reproduction (real Chrome 155, local Windows host, headless, local fixture site; markers fetched every 500 ms by the page and by one long-lived new Worker('/worker.js')):

  • Before (base revision, CLI inspect-web-page --observation-ms 6000): page markers 5/5 recorded, worker markers 0 recorded, worker not listed in the terminal inventory.
  • After (this branch, same fixture): page markers 4/4 with worker_target_id: null; worker markers 4/4, all with worker_target_id: "6B77…715"; the same target ID appears in workers[] with type: "worker", attached: true; the worker request's initiator.url is the worker script (/worker.js).

Change and scope

  • src/browser/CdpPageCaptureWorkerSessions.ts (new): owns worker-session multiplexing for one page capture. Sends Target.setAutoAttach (autoAttach, flatten, waitForDebuggerOnStart: false, filter limited to this page's worker children) on the page session; admits worker child sessions from Target.attachedToTarget; sends only Network.enable to each worker session; stops admitting on Target.detachedFromTarget; settles pending enables after the observation window (rethrowing the first real failure with its original error semantics; a worker that vanished between attach and enable is tolerated because its session no longer exists); releases admitted sessions (Network.disable, Target.detachFromTarget, then Target.setAutoAttach { autoAttach: false }) best effort in the capture's finally, before the owning page-session detach and socket close.
  • src/browser/CdpPageCapture.ts: ingests events from the page session and from admitted worker sessions; response-body reads for worker requests target the issuing worker session (a detached worker is reported as an unavailable body with an explicit limitation instead of being read through the page session, which cannot see the request).
  • CdpCaptureEvents/CdpCaptureEventHandlers: multiplexed ingest carries a worker source so Network.requestWillBeSent (and redirect continuations, which rebuild the record) persist attribution.
  • src/domain/browserObservationSchemas.ts: network.requests[].worker_target_id (string | null, default null), additive; null means the page session issued the request. Historical captures parse unchanged via the default.
  • Fixtures/verification: the fake CDP browser can flatten one dedicated worker (with a rogue never-admitted session, and an optional mid-window worker termination plus a stale post-detach event); the real-browser verifier's fixture page now runs one long-lived dedicated worker issuing /worker-api traffic, and the verifier asserts worker requests are recorded with attribution.

Intentionally not included: merging auto-attached workers into the terminal workers[] inventory (owned by Target.getTargets at teardown; terminated workers can therefore be referenced by worker_target_id without appearing in the terminal inventory — documented), and any change for the malformed-inventory sibling issues #3376/#3378.

Follow the contribution scope.
Unresolved scope, authority, side effects, or required verification block
integration. Link the required maintainer scope decision for new providers or
capabilities involving target execution, injection, mutation, or protection
recovery; ordinary fixes within existing boundaries may state "not applicable".
Draft PRs may leave the scope decision pending and the readiness and merge checklists
unchecked. Maintainers can help resolve open questions.

Not applicable: this is a bug fix inside the existing passive inspect_web_page observation boundary. Attaching a flattened read-only session is the same class of action DevTools performs; no script evaluation, injection, mutation, or worker pausing is added (waitForDebuggerOnStart is explicitly disabled).

Contract and boundary impact

  • Semantic owner and earliest changed stage: CdpPageCapture/CdpPageCaptureWorkerSessions (browser adapter); domain schema only gains the additive nullable field.
  • Contribution scope fit and linked maintainer decision: not applicable (ordinary fix within the existing passive-observation boundary; read-only target inspection).
  • CLI and MCP/tool-catalog contract: network.requests[] gains worker_target_id: string | null (default null). Additive; generated catalogs are regenerated by CI. Existing diff projections use explicit field lists and are unchanged.
  • Provider, bridge, target-format, or platform compatibility: Target.setAutoAttach unavailability degrades to an explicit limitation plus workers attach-limited coverage instead of failing the capture.
  • Evidence, artifact, provenance, or reconstruction contract: worker requests keep Evidence provenance rules (URL sanitization, allowlisted origins, redaction) identical to page requests; attribution is preserved per request.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): workers of the selected page only (CDP filter plus a type guard); worker sessions are released by this capture before the page-session detach; the socket close remains the definitive boundary.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none beyond CI-regenerated catalogs; no committed generated outputs changed.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process. (Attaches one flattened read-only CDP session per dedicated worker of the already-selected page; never pauses or mutates the worker.)
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services. (Local verification contacted only the locally launched browser, the local fixture HTTP site, and the loopback CDP endpoint; no non-local network services were contacted.)
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated:
    • tests/boundary/browser/cdpWorkerNetworkRecording.test.ts (4 tests, real HTTP/WS wire fixture): worker request recorded with attribution; page request stays null; never-admitted session ignored; Network.enable/cleanup commands asserted; worker JSON body read through the worker session; mid-window worker termination retains attributed requests, ignores post-detach events, and reports the body unavailable without a dead-session command; unavailable Target.setAutoAttach keeps the capture working with an explicit limitation and workers attach-limited coverage.
    • src/browser/CdpCaptureEvents.workerAttribution.test.ts (2 tests): ingest-source attribution semantics, including preservation across redirect continuation/response/loading events.
    • Real-browser verifier (scripts/verify-real-browser.mjs + site fixture): one long-lived dedicated worker issues /worker-api traffic; the verifier fails if worker requests are missing, unattributed, or recorded as page traffic.
  • Base reproduction or other evidence: executed, see Problem section (before: 0/5 worker markers on base revision; after: 4/4 attributed). Red-green: on the base revision the 4 boundary tests fail (worker requests absent, no Target.setAutoAttach sent) and the real-browser verifier aborts with "Real Chrome dedicated worker requests were not recorded with worker attribution"; both pass with this branch.
  • User-visible CLI/MCP output (if applicable): see the before/after JSON summaries in the Problem section; worker requests now carry worker_target_id linking to workers[].target_id.
  • Remaining proof gaps: the pre-merge runs of the fork/upstream CI lanes (including the ubuntu real-browser lane) are pending on this PR; the local real-browser evidence used Chrome 155 on Windows and the CI lane uses the ubuntu Chrome build.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

All commands executed on the rebase base morluto/rea main 060587b4 plus this branch's single commit, Windows 11 host, Node 24.18.0:

  • npx tsc --noEmit — pass.
  • npm run check:fast — pass (typecheck + lint + module boundaries).
  • npx knip — pass.
  • npx oxfmt --check <changed files> — pass (after npx oxfmt <files>).
  • npm run verify:test-discovery — pass ("Discovered all 1441 test files exactly once").
  • npx vitest run tests/boundary/browser/cdpWorkerNetworkRecording.test.ts src/browser/CdpCaptureEvents.workerAttribution.test.ts — 6/6 pass. npm run test:focused -- src/browser/CdpCaptureEvents.workerAttribution.test.ts — pass. npm run test:focused on the boundary path cannot run on this Windows source checkout because its run-exclusive prerequisite needs the Windows native artifact; the native files were restored from the published rea-agents@6.5.0 tarball (uncommitted, per native/windows/README.md) for the real-browser verification below, after which the equivalent steps (turbo run artifacts:skills, direct vitest) were used for the boundary path.
  • npx vitest run --project boundary tests/boundary/browser — 560 passed, 36 failed; the same 36 tests fail identically on clean upstream/main on this host (browserProcessStartup, historicalCaptureDecoder, historicalWebCapture, sazWebCapture; Windows python/signal/CLI-subprocess environment, plus the known Doctor.test.ts failure in the source-project run below).
  • npx vitest run --project domain --project services --project adapters --project composition — 8112 passed, 78 failed; the same 78 tests fail identically on clean upstream/main on this host (Ghidra/Hopper/WABT/adb/Electron toolchain and Doctor host quirks; none browser-related).
  • npx vitest run --project cli-boundary tests/boundary/cli/httpCaptureComparison.test.ts and --project mcp-boundary tests/boundary/mcp/browserMcp.test.ts — pass.
  • Real browser, executed: node scripts/verify-real-browser.mjs (Chrome 155.0.8059.84, headless, REA_BROWSER_EXECUTABLE set) — full verifier verified: true, report includes workerNetworkRequests: 5; on the base revision the same verifier aborts at the new worker-attribution assertion.
  • Standalone CLI reproduction (before/after summaries above) via scripts/rea.mjs inspect-web-page against a locally launched headless Chrome and a local fixture site.
  • Fork CI on this exact commit: https://github.com/jayinvers/rea/actions/runs/38953675531 — completed, conclusion success (all jobs, including the ubuntu browser / real-browser lane running the extended worker verification).

Compatibility, safety, and release

  • Breaking changes or migration steps: none. worker_target_id is additive with a null default; previously exported captures re-parse unchanged. Comparisons ignore the new field unless callers project it.
  • Real Hopper/Ghidra, browser, or OS coverage: real-browser verification executed locally (Chrome 155, Windows) and covered by the existing ubuntu real-browser CI lane with the extended verifier fixture. No Hopper/Ghidra impact.
  • Package or release metadata impact: none; no committed generated outputs changed.
  • Security, privacy, process, or containment review: worker requests pass the same origin sanitization and redaction as page requests; worker script URLs (including blob: workers, whose fetch initiators sanitize to null) are not retained beyond existing rules; no credentials, headers, or bodies are retained beyond the existing allowlisted projections; attaching a worker session never pauses it and adds no script execution.

Review follow-up (2026-10-17)

Addressed the four Greptile inline findings in commit 7da329d9 (tests included for each, red-green verified; real-browser re-run verified: worker attribution intact):

  • P1 worker exit vs pending commands: each admitted worker session now carries a detach AbortController; Network.enable and worker-session Network.getResponseBody bind to it, so Chromium-unanswerable commands settle immediately on Target.detachedFromTarget instead of failing the inspection at the transport deadline. A body read aborted by worker exit reports body_shapes: unavailable plus the existing limitation.
  • P1 cancellation vs worker cleanup: release() now uses one shared short cleanup deadline combined with the capture AbortSignal (mirroring cleanupCdpTargetCommands); cancellation skips optional shutdown, still detaches sessions under the bounded signal, never throws.
  • P2 late worker failures: settle() runs again immediately before the result is built, so a worker admitted during later page reads surfaces its enable failure with its own cause.
  • P2 false worker-startup warnings: Network.loadingFinished is only applied when the finishing event's session attribution matches the session that announced the request; the page-to-worker script handoff keeps encoded_data_length: null instead of marking the request unavailable.

Commit f7718c01 (separate, drop-friendly) raises the shared cli-boundary vitest worker heap budget 384->512 MiB: on current main the coverage-instrumented CLI module graph no longer fits 384 MiB and CI workers OOMed after all their files had passed (no test failure). This branch's CI cannot pass without it; if maintainers prefer fixing main's budget separately, that commit can be dropped after.

New head: f7718c01 (base fb146bf4). Fork CI: https://github.com/jayinvers/rea/actions/runs/39004504606 — success (37 jobs).

Review follow-up round 2 (2026-10-17)

Addressed the second Greptile round in commit 4f5cbe2f (rebased onto main 79d2b718):

  • P1 mixed documents: the navigation/origin guard was extracted at its owner into assertDocumentUnchanged and now also runs after the final worker settle, so a navigation landing while that settle drains fails the inspection (target_changed / target_not_allowed) exactly like an earlier navigation.
  • P1 worker churn: admission closes when the final settle begins (later attaches record attachLimited("workers") plus a one-time limitation), and the settle drain is bounded by a 1s deadline combined with the capture AbortSignal (same pattern as release). A settled enable failure still rethrows first; on deadline the capture proceeds with an honest limitation.
  • P1 nested workers: each admitted worker's enable sequence also sends Target.setAutoAttach on that worker session (auto-attach does not recurse); attach/detach events are honored only from the page session or sessions this capture already admitted, so nested workers are recorded recursively under the same cutoff with worker_target_id attribution, and join settle/release/cleanup. Verified on real Chrome with a nested worker fixture (grandchild requests attributed).

New head: 4f5cbe2f. Fork CI: https://github.com/jayinvers/rea/actions/runs/39014739326 — success (37 jobs, incl. browser / real-browser).

Author readiness

Human owner: @jayinvers

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/4585 **Author:** [@jayinvers](https://github.com/jayinvers) **Created:** 10/16/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/cdp-worker-request-recording` --- ### 📝 Commits (4) - [`9f332a5`](https://github.com/morluto/rea/commit/9f332a52a366bf72ceed8a411e716e08ddc10cbf) fix(browser): record dedicated worker requests through attached sessions - [`6407793`](https://github.com/morluto/rea/commit/6407793b96c5a4d4cd571a6aae287e8276a58147) fix(browser): harden worker session cleanup and completion attribution - [`d362639`](https://github.com/morluto/rea/commit/d362639686b679647798065104c2e9da8b255093) test(ci): fit the shared cli-boundary worker heap to current main - [`4f5cbe2`](https://github.com/morluto/rea/commit/4f5cbe2f3a8ba51cea4bff30f0575641b9adad0c) fix(browser): bound worker admission and record nested workers ### 📊 Changes **17 files changed** (+1759 additions, -35 deletions) <details> <summary>View changed files</summary> 📝 `docs/browser-observation.md` (+20 -2) 📝 `scripts/fixtures/browser-verifier-site.mjs` (+41 -0) 📝 `scripts/verify-real-browser.mjs` (+33 -0) 📝 `src/browser/CdpCaptureEventHandlers.ts` (+3 -0) 📝 `src/browser/CdpCaptureEventTypes.ts` (+8 -0) 📝 `src/browser/CdpCaptureEvents.ts` (+34 -5) ➕ `src/browser/CdpCaptureEvents.workerAttribution.test.ts` (+138 -0) 📝 `src/browser/CdpPageCapture.ts` (+116 -26) ➕ `src/browser/CdpPageCaptureWorkerSessions.ts` (+392 -0) 📝 `src/domain/browserObservationSchemas.ts` (+7 -0) ➕ `tests/boundary/browser/cdpWorkerNetworkRecording.test.ts` (+713 -0) 📝 `tests/fixtures/fakeCdpBrowser.ts` (+8 -0) 📝 `tests/fixtures/fakeCdpBrowserEvents.ts` (+196 -0) 📝 `tests/fixtures/fakeCdpBrowserResults.ts` (+1 -0) 📝 `tests/fixtures/fakeCdpBrowserTargets.ts` (+23 -0) 📝 `tests/fixtures/fakeCdpBrowserTypes.ts` (+21 -0) 📝 `vitest.config.ts` (+5 -2) </details> ### 📄 Description ## Summary `rea inspect-web-page` reported dedicated web workers in its worker inventory but recorded none of the requests they issued, because the capture only listened for `Network` events on the page's own CDP session. This PR flattens the page's dedicated-worker sessions onto the connection, multiplexes their `Network` events into the capture, and retains every worker-issued request with the issuing worker's target ID. Fixes #4425. ## Problem and expected behavior Smallest trigger: attach `inspect-web-page` to a page whose dedicated worker fetches observable URLs during the observation window. Violated invariant: recorded network traffic claimed attach-window coverage while an entire attached issuer (the worker) contributed a silent zero. Expected behavior (per the issue): requests issued by dedicated workers appear in `network.requests` with worker attribution preserved, instead of a false zero count. Executed reproduction (real Chrome 155, local Windows host, headless, local fixture site; markers fetched every 500 ms by the page and by one long-lived `new Worker('/worker.js')`): - Before (base revision, CLI `inspect-web-page --observation-ms 6000`): page markers `5/5` recorded, worker markers `0` recorded, worker not listed in the terminal inventory. - After (this branch, same fixture): page markers `4/4` with `worker_target_id: null`; worker markers `4/4`, all with `worker_target_id: "6B77…715"`; the same target ID appears in `workers[]` with `type: "worker"`, `attached: true`; the worker request's `initiator.url` is the worker script (`/worker.js`). ## Change and scope - `src/browser/CdpPageCaptureWorkerSessions.ts` (new): owns worker-session multiplexing for one page capture. Sends `Target.setAutoAttach` (`autoAttach`, `flatten`, `waitForDebuggerOnStart: false`, filter limited to this page's `worker` children) on the page session; admits worker child sessions from `Target.attachedToTarget`; sends only `Network.enable` to each worker session; stops admitting on `Target.detachedFromTarget`; settles pending enables after the observation window (rethrowing the first real failure with its original error semantics; a worker that vanished between attach and enable is tolerated because its session no longer exists); releases admitted sessions (`Network.disable`, `Target.detachFromTarget`, then `Target.setAutoAttach { autoAttach: false }`) best effort in the capture's `finally`, before the owning page-session detach and socket close. - `src/browser/CdpPageCapture.ts`: ingests events from the page session and from admitted worker sessions; response-body reads for worker requests target the issuing worker session (a detached worker is reported as an unavailable body with an explicit limitation instead of being read through the page session, which cannot see the request). - `CdpCaptureEvents`/`CdpCaptureEventHandlers`: multiplexed ingest carries a worker source so `Network.requestWillBeSent` (and redirect continuations, which rebuild the record) persist attribution. - `src/domain/browserObservationSchemas.ts`: `network.requests[].worker_target_id` (`string | null`, default `null`), additive; `null` means the page session issued the request. Historical captures parse unchanged via the default. - Fixtures/verification: the fake CDP browser can flatten one dedicated worker (with a rogue never-admitted session, and an optional mid-window worker termination plus a stale post-detach event); the real-browser verifier's fixture page now runs one long-lived dedicated worker issuing `/worker-api` traffic, and the verifier asserts worker requests are recorded with attribution. Intentionally not included: merging auto-attached workers into the terminal `workers[]` inventory (owned by `Target.getTargets` at teardown; terminated workers can therefore be referenced by `worker_target_id` without appearing in the terminal inventory — documented), and any change for the malformed-inventory sibling issues #3376/#3378. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Unresolved scope, authority, side effects, or required verification block integration. Link the required maintainer scope decision for new providers or capabilities involving target execution, injection, mutation, or protection recovery; ordinary fixes within existing boundaries may state "not applicable". Draft PRs may leave the scope decision pending and the readiness and merge checklists unchecked. Maintainers can help resolve open questions. Not applicable: this is a bug fix inside the existing passive `inspect_web_page` observation boundary. Attaching a flattened read-only session is the same class of action DevTools performs; no script evaluation, injection, mutation, or worker pausing is added (`waitForDebuggerOnStart` is explicitly disabled). ## Contract and boundary impact - Semantic owner and earliest changed stage: `CdpPageCapture`/`CdpPageCaptureWorkerSessions` (browser adapter); domain schema only gains the additive nullable field. - Contribution scope fit and linked maintainer decision: not applicable (ordinary fix within the existing passive-observation boundary; read-only target inspection). - CLI and MCP/tool-catalog contract: `network.requests[]` gains `worker_target_id: string | null` (default `null`). Additive; generated catalogs are regenerated by CI. Existing diff projections use explicit field lists and are unchanged. - Provider, bridge, target-format, or platform compatibility: `Target.setAutoAttach` unavailability degrades to an explicit limitation plus `workers` attach-limited coverage instead of failing the capture. - Evidence, artifact, provenance, or reconstruction contract: worker requests keep Evidence provenance rules (URL sanitization, allowlisted origins, redaction) identical to page requests; attribution is preserved per request. - Target selection, authority, upstream behavior, and cleanup details (if applicable): workers of the selected page only (CDP filter plus a type guard); worker sessions are released by this capture before the page-session detach; the socket close remains the definitive boundary. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none beyond CI-regenerated catalogs; no committed generated outputs changed. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [x] Launch or attach to a process. (Attaches one flattened read-only CDP session per dedicated worker of the already-selected page; never pauses or mutates the worker.) - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. (Local verification contacted only the locally launched browser, the local fixture HTTP site, and the loopback CDP endpoint; no non-local network services were contacted.) - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: - `tests/boundary/browser/cdpWorkerNetworkRecording.test.ts` (4 tests, real HTTP/WS wire fixture): worker request recorded with attribution; page request stays `null`; never-admitted session ignored; `Network.enable`/cleanup commands asserted; worker JSON body read through the worker session; mid-window worker termination retains attributed requests, ignores post-detach events, and reports the body unavailable without a dead-session command; unavailable `Target.setAutoAttach` keeps the capture working with an explicit limitation and `workers` attach-limited coverage. - `src/browser/CdpCaptureEvents.workerAttribution.test.ts` (2 tests): ingest-source attribution semantics, including preservation across redirect continuation/response/loading events. - Real-browser verifier (`scripts/verify-real-browser.mjs` + site fixture): one long-lived dedicated worker issues `/worker-api` traffic; the verifier fails if worker requests are missing, unattributed, or recorded as page traffic. - Base reproduction or other evidence: executed, see Problem section (before: 0/5 worker markers on base revision; after: 4/4 attributed). Red-green: on the base revision the 4 boundary tests fail (worker requests absent, no `Target.setAutoAttach` sent) and the real-browser verifier aborts with "Real Chrome dedicated worker requests were not recorded with worker attribution"; both pass with this branch. - User-visible CLI/MCP output (if applicable): see the before/after JSON summaries in the Problem section; worker requests now carry `worker_target_id` linking to `workers[].target_id`. - Remaining proof gaps: the pre-merge runs of the fork/upstream CI lanes (including the ubuntu real-browser lane) are pending on this PR; the local real-browser evidence used Chrome 155 on Windows and the CI lane uses the ubuntu Chrome build. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed All commands executed on the rebase base `morluto/rea` main `060587b4` plus this branch's single commit, Windows 11 host, Node 24.18.0: - `npx tsc --noEmit` — pass. - `npm run check:fast` — pass (typecheck + lint + module boundaries). - `npx knip` — pass. - `npx oxfmt --check <changed files>` — pass (after `npx oxfmt <files>`). - `npm run verify:test-discovery` — pass ("Discovered all 1441 test files exactly once"). - `npx vitest run tests/boundary/browser/cdpWorkerNetworkRecording.test.ts src/browser/CdpCaptureEvents.workerAttribution.test.ts` — 6/6 pass. `npm run test:focused -- src/browser/CdpCaptureEvents.workerAttribution.test.ts` — pass. `npm run test:focused` on the boundary path cannot run on this Windows source checkout because its `run-exclusive` prerequisite needs the Windows native artifact; the native files were restored from the published `rea-agents@6.5.0` tarball (uncommitted, per `native/windows/README.md`) for the real-browser verification below, after which the equivalent steps (`turbo run artifacts:skills`, direct vitest) were used for the boundary path. - `npx vitest run --project boundary tests/boundary/browser` — 560 passed, 36 failed; the same 36 tests fail identically on clean `upstream/main` on this host (`browserProcessStartup`, `historicalCaptureDecoder`, `historicalWebCapture`, `sazWebCapture`; Windows python/signal/CLI-subprocess environment, plus the known `Doctor.test.ts` failure in the source-project run below). - `npx vitest run --project domain --project services --project adapters --project composition` — 8112 passed, 78 failed; the same 78 tests fail identically on clean `upstream/main` on this host (Ghidra/Hopper/WABT/adb/Electron toolchain and Doctor host quirks; none browser-related). - `npx vitest run --project cli-boundary tests/boundary/cli/httpCaptureComparison.test.ts` and `--project mcp-boundary tests/boundary/mcp/browserMcp.test.ts` — pass. - Real browser, executed: `node scripts/verify-real-browser.mjs` (Chrome 155.0.8059.84, headless, `REA_BROWSER_EXECUTABLE` set) — full verifier `verified: true`, report includes `workerNetworkRequests: 5`; on the base revision the same verifier aborts at the new worker-attribution assertion. - Standalone CLI reproduction (before/after summaries above) via `scripts/rea.mjs inspect-web-page` against a locally launched headless Chrome and a local fixture site. - Fork CI on this exact commit: https://github.com/jayinvers/rea/actions/runs/38953675531 — completed, conclusion `success` (all jobs, including the ubuntu `browser / real-browser` lane running the extended worker verification). ## Compatibility, safety, and release - Breaking changes or migration steps: none. `worker_target_id` is additive with a `null` default; previously exported captures re-parse unchanged. Comparisons ignore the new field unless callers project it. - Real Hopper/Ghidra, browser, or OS coverage: real-browser verification executed locally (Chrome 155, Windows) and covered by the existing ubuntu real-browser CI lane with the extended verifier fixture. No Hopper/Ghidra impact. - Package or release metadata impact: none; no committed generated outputs changed. - Security, privacy, process, or containment review: worker requests pass the same origin sanitization and redaction as page requests; worker script URLs (including `blob:` workers, whose fetch initiators sanitize to `null`) are not retained beyond existing rules; no credentials, headers, or bodies are retained beyond the existing allowlisted projections; attaching a worker session never pauses it and adds no script execution. ## Review follow-up (2026-10-17) Addressed the four Greptile inline findings in commit `7da329d9` (tests included for each, red-green verified; real-browser re-run verified: worker attribution intact): - P1 worker exit vs pending commands: each admitted worker session now carries a detach `AbortController`; `Network.enable` and worker-session `Network.getResponseBody` bind to it, so Chromium-unanswerable commands settle immediately on `Target.detachedFromTarget` instead of failing the inspection at the transport deadline. A body read aborted by worker exit reports `body_shapes: unavailable` plus the existing limitation. - P1 cancellation vs worker cleanup: `release()` now uses one shared short cleanup deadline combined with the capture `AbortSignal` (mirroring `cleanupCdpTargetCommands`); cancellation skips optional shutdown, still detaches sessions under the bounded signal, never throws. - P2 late worker failures: `settle()` runs again immediately before the result is built, so a worker admitted during later page reads surfaces its enable failure with its own cause. - P2 false worker-startup warnings: `Network.loadingFinished` is only applied when the finishing event's session attribution matches the session that announced the request; the page-to-worker script handoff keeps `encoded_data_length: null` instead of marking the request unavailable. Commit `f7718c01` (separate, drop-friendly) raises the shared `cli-boundary` vitest worker heap budget 384->512 MiB: on current main the coverage-instrumented CLI module graph no longer fits 384 MiB and CI workers OOMed after all their files had passed (no test failure). This branch's CI cannot pass without it; if maintainers prefer fixing main's budget separately, that commit can be dropped after. New head: `f7718c01` (base `fb146bf4`). Fork CI: https://github.com/jayinvers/rea/actions/runs/39004504606 — success (37 jobs). ## Review follow-up round 2 (2026-10-17) Addressed the second Greptile round in commit `4f5cbe2f` (rebased onto main `79d2b718`): - P1 mixed documents: the navigation/origin guard was extracted at its owner into `assertDocumentUnchanged` and now also runs after the final worker settle, so a navigation landing while that settle drains fails the inspection (`target_changed` / `target_not_allowed`) exactly like an earlier navigation. - P1 worker churn: admission closes when the final settle begins (later attaches record `attachLimited("workers")` plus a one-time limitation), and the settle drain is bounded by a 1s deadline combined with the capture AbortSignal (same pattern as release). A settled enable failure still rethrows first; on deadline the capture proceeds with an honest limitation. - P1 nested workers: each admitted worker's enable sequence also sends `Target.setAutoAttach` on that worker session (auto-attach does not recurse); attach/detach events are honored only from the page session or sessions this capture already admitted, so nested workers are recorded recursively under the same cutoff with `worker_target_id` attribution, and join settle/release/cleanup. Verified on real Chrome with a nested worker fixture (grandchild requests attributed). New head: `4f5cbe2f`. Fork CI: https://github.com/jayinvers/rea/actions/runs/39014739326 — success (37 jobs, incl. `browser / real-browser`). ## Author readiness <!-- The human owner completes these declarations before requesting review. The PR author is the owner by default. A different owner must explicitly accept ownership on this PR. AI agents must leave these declarations to a human to dictate to them or there could be catastrophic consequences for many users of REA. Draft PRs may leave them unchecked. These declarations record initial readiness when opening the PR for review; later pushes do not require a new human sign-off. Keep the description and validation evidence current as work changes. See CONTRIBUTING.md#pull-request-ownership-and-readiness. --> Human owner: @jayinvers - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge <!-- Draft PRs may leave pending items unchecked. Resolve material scope and authority questions before integration. --> - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
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#6322
No description provided.