[GH-ISSUE #3217] [Bug] Source-map fetching marks a fully parsed bundle partial when no maps are declared #1154

Closed
opened 2026-10-15 18:31:34 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

The public analyze-web-bundle CLI returns partial completeness when --fetch-source-maps is selected for a captured script that declares no source map. It reports zero requested maps, zero processed maps, no map items, and a source-map unknown saying that requested maps were unavailable or incomplete. The script itself is successfully parsed with zero parse failures.

The independent reproduction exercised the built CLI against the repository's simulated CDP peer over real loopback HTTP/WebSocket connections. No map HTTP request occurred. Omitting the option for identical script content returned complete completeness and no unknowns. A separate declared-map control returned HTTP 404 and correctly produced partial completeness with a failed map item and one affected script key. All three CLI processes exited successfully. Real Chrome behavior was not independently exercised.

Reproduction

  1. Use a clean checkout at 58300885207133422af235e0f2b10658cf958b03 and its pinned development toolchain. Install dependencies and build the CLI with an isolated home:
mkdir -p .repro-home
run_isolated() {
  env HOME="$PWD/.repro-home" \
    XDG_CONFIG_HOME="$PWD/.repro-home/config" \
    XDG_CACHE_HOME="$PWD/.repro-home/cache" \
    XDG_DATA_HOME="$PWD/.repro-home/data" "$@"
}
run_isolated npm ci
run_isolated npm run build:cached
  1. Create the input fixture inline. It supplies one script with window.plain = 1; fetch("/api/plain"); and compares source-map selection, omission, and a declared map returning HTTP 404. Each case starts its own loopback CDP fixture endpoint.
cat > src/browser/repro.test.ts <<'TS'
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { expect, it } from 'vitest';
import { startFakeCdpBrowser } from '../../tests/fixtures/fakeCdpBrowser.js';

const run = promisify(execFile);

it('compares map-less selection with omission and an HTTP-404 map', async () => {
  for (const [label, declared, selected] of [
    ['map-less selected', false, true],
    ['map-less unselected', false, false],
    ['declared map HTTP 404', true, true],
  ] as const) {
    const browser = await startFakeCdpBrowser({
      commandResult: ({ method }) => method === 'Debugger.getScriptSource'
        ? { scriptSource: 'window.plain = 1; fetch("/api/plain");' }
        : undefined,
      commandEvents: (command, origin) =>
        command.method === 'Debugger.enable' ? [{
          method: 'Debugger.scriptParsed',
          ...(command.sessionId ? { sessionId: command.sessionId } : {}),
          params: {
            scriptId: 'plain-script', url: `${origin}/plain.js`,
            hash: 'plain-hash', length: 38, isModule: false,
            executionContextId: 1, scriptLanguage: 'JavaScript',
            ...(declared ? { sourceMapURL: '/missing.map' } : {}),
          },
        }] : undefined,
    });
    try {
      const { stdout } = await run(process.execPath, [
        'scripts/rea.mjs', 'analyze-web-bundle', browser.endpoint,
        'allowed-page', '--observation-ms', '0', '--format', 'json',
        ...(selected ? ['--fetch-source-maps'] : []),
      ], { env: process.env });
      const result = JSON.parse(stdout).normalized_result;
      console.log(label, JSON.stringify({
        source_maps: result.observations.source_maps,
        completeness: result.completeness,
        unknowns: result.unknowns,
      }));
      expect(result.capture.scripts_analyzed).toBe(1);
      expect(result.completeness.parse_failures).toBe(0);
      if (!declared && selected) {
        expect(result.observations.source_maps).toEqual({
          status: 'unavailable', requested: 0, processed: 0, items: [],
        });
        expect(result.completeness.status).toBe('partial');
        expect(result.unknowns).toEqual([{
          dimension: 'source_maps',
          reason: 'One or more requested source maps were unavailable or incomplete',
          affected_script_keys: [],
        }]);
        expect(browser.httpRequests.every(r => r.url.startsWith('/json/'))).toBe(true);
      } else if (!declared) {
        expect(result.observations.source_maps.status).toBe('not_requested');
        expect(result.completeness.status).toBe('complete');
        expect(result.unknowns).toEqual([]);
      } else {
        expect(result.observations.source_maps.requested).toBe(1);
        expect(result.observations.source_maps.items[0].status).toBe('fetch_failed');
        expect(result.completeness.status).toBe('partial');
        expect(result.unknowns[0].affected_script_keys).toHaveLength(1);
      }
    } finally {
      await browser.close();
    }
  }
}, 30000);
TS
  1. Run the diagnostic test and remove the files it creates:
run_isolated npm run test:local -- src/browser/repro.test.ts
rm src/browser/repro.test.ts
rm -r .repro-home

The fixture invokes node scripts/rea.mjs analyze-web-bundle <loopback endpoint> allowed-page --observation-ms 0 --format json, adding --fetch-source-maps for the selected cases. Its assertions describe the observed baseline behavior and controls. A passing diagnostic test demonstrates the defect rather than restoration.

Expected behavior

The CLI help describes --fetch-source-maps as "Fetch source maps referenced by captured scripts". docs/browser-observation.md:309 documents optional source-map fetching and failure coverage. AGENTS.md:75 requires completeness to derive from examined coverage, and src/domain/webBundleAnalyzerResult.ts:205 states that complete describes examination of captured source.

When a captured script has no map declaration, no map fetch is requested or lost. If its source is fully parsed and no declarations were omitted, selecting map fetching should preserve complete bundle coverage and should not introduce an unknown asserting unavailable requested maps. This does not require a particular replacement status for the empty source-map collection.

Impact and scope

The verified impact is P2. Consumers that use machine-readable completeness and unknowns receive a false missing-coverage signal, while successfully parsed script findings remain available. No data loss or blocked analysis workflow was observed.

Omitting --fetch-source-maps demonstrably avoids the false signal for this map-less input. That workaround is practical when the caller knows there are no maps to fetch; it does not preserve optional map evidence in captures that also contain declared maps. The reproduction establishes public CLI behavior with a simulated CDP producer, rather than real-browser or independent MCP coverage.

REA version

6.4.0 (main at 5830088520)

Runtime and platform

Node 26.10.0; macOS 27.0 arm64

Target and artifact context

A caller-written 38-byte JavaScript script supplied by the repository's tests/fixtures/fakeCdpBrowser.ts over loopback HTTP/WebSocket connections. The map-less input declares no sourceMapURL; the control declares /missing.map and receives HTTP 404. No external website, Chrome installation, or private target artifact is required for the CLI calls.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

The selected map-less CLI result contains these fields under normalized_result:

observations.source_maps = {"status":"unavailable","requested":0,"processed":0,"items":[]}
completeness = {"status":"partial","parsed_scripts":1,"parse_failures":0,"visited_ast_nodes":12}
unknowns = [{"dimension":"source_maps","reason":"One or more requested source maps were unavailable or incomplete","affected_script_keys":[]}]

Typed outcome or recovery expected

For the same map-less input with source-map selection enabled, retain zero requested maps, complete bundle completeness, no source-map unknown, and the captured script and endpoint finding. Keep the option-omitted control complete. A declared map returning HTTP 404 must remain partial, retain its failed item, and identify its affected script. Suppressing source-map failures globally would hide real missing coverage.

The schema at src/domain/webBundleAnalysis.ts:134-145 permits both not_requested and unavailable for an empty completed collection. The required correction is accurate completeness and unknowns, rather than a prescribed collection-status value.

Analysis or suspected cause

Source-derived at the reported baseline: src/cli/browserCommands.ts:132-172 parses the option and calls the shared application service. src/application/BrowserObservationService.ts:71-92 reaches the browser provider, and src/browser/CdpBrowserProvider.ts:138-169 passes the captured request list to the fetcher whenever selection is true, even if the list is empty.

A missing declaration produces null map fields at src/browser/CdpCaptureEventHandlers.ts:165-172, and src/browser/CdpPageCaptureScripts.ts:154-159 creates no map request. src/browser/WebSourceMapFetcher.ts:163-190 returns unavailable for that empty collection. src/domain/webBundleAnalyzerResult.ts:25-32 treats that status as incomplete, and src/domain/webBundleAnalyzerResult.ts:150-164 emits the source-map unknown with no affected script keys. These locators explain the observed result; the independent violation proof came from the public CLI fixture, rather than a direct helper call.

Additional context

Related reports are #2954 and #2625. They concern filename-dependent original-source parsing and attribution of real JavaScript parse gaps, respectively; this report concerns invented source-map coverage loss when no map was declared or requested.

Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3217 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior The public `analyze-web-bundle` CLI returns partial completeness when `--fetch-source-maps` is selected for a captured script that declares no source map. It reports zero requested maps, zero processed maps, no map items, and a source-map unknown saying that requested maps were unavailable or incomplete. The script itself is successfully parsed with zero parse failures. The independent reproduction exercised the built CLI against the repository's simulated CDP peer over real loopback HTTP/WebSocket connections. No map HTTP request occurred. Omitting the option for identical script content returned complete completeness and no unknowns. A separate declared-map control returned HTTP 404 and correctly produced partial completeness with a failed map item and one affected script key. All three CLI processes exited successfully. Real Chrome behavior was not independently exercised. ### Reproduction 1. Use a clean checkout at `58300885207133422af235e0f2b10658cf958b03` and its pinned development toolchain. Install dependencies and build the CLI with an isolated home: ```sh mkdir -p .repro-home run_isolated() { env HOME="$PWD/.repro-home" \ XDG_CONFIG_HOME="$PWD/.repro-home/config" \ XDG_CACHE_HOME="$PWD/.repro-home/cache" \ XDG_DATA_HOME="$PWD/.repro-home/data" "$@" } run_isolated npm ci run_isolated npm run build:cached ``` 2. Create the input fixture inline. It supplies one script with `window.plain = 1; fetch("/api/plain");` and compares source-map selection, omission, and a declared map returning HTTP 404. Each case starts its own loopback CDP fixture endpoint. ```sh cat > src/browser/repro.test.ts <<'TS' import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; import { expect, it } from 'vitest'; import { startFakeCdpBrowser } from '../../tests/fixtures/fakeCdpBrowser.js'; const run = promisify(execFile); it('compares map-less selection with omission and an HTTP-404 map', async () => { for (const [label, declared, selected] of [ ['map-less selected', false, true], ['map-less unselected', false, false], ['declared map HTTP 404', true, true], ] as const) { const browser = await startFakeCdpBrowser({ commandResult: ({ method }) => method === 'Debugger.getScriptSource' ? { scriptSource: 'window.plain = 1; fetch("/api/plain");' } : undefined, commandEvents: (command, origin) => command.method === 'Debugger.enable' ? [{ method: 'Debugger.scriptParsed', ...(command.sessionId ? { sessionId: command.sessionId } : {}), params: { scriptId: 'plain-script', url: `${origin}/plain.js`, hash: 'plain-hash', length: 38, isModule: false, executionContextId: 1, scriptLanguage: 'JavaScript', ...(declared ? { sourceMapURL: '/missing.map' } : {}), }, }] : undefined, }); try { const { stdout } = await run(process.execPath, [ 'scripts/rea.mjs', 'analyze-web-bundle', browser.endpoint, 'allowed-page', '--observation-ms', '0', '--format', 'json', ...(selected ? ['--fetch-source-maps'] : []), ], { env: process.env }); const result = JSON.parse(stdout).normalized_result; console.log(label, JSON.stringify({ source_maps: result.observations.source_maps, completeness: result.completeness, unknowns: result.unknowns, })); expect(result.capture.scripts_analyzed).toBe(1); expect(result.completeness.parse_failures).toBe(0); if (!declared && selected) { expect(result.observations.source_maps).toEqual({ status: 'unavailable', requested: 0, processed: 0, items: [], }); expect(result.completeness.status).toBe('partial'); expect(result.unknowns).toEqual([{ dimension: 'source_maps', reason: 'One or more requested source maps were unavailable or incomplete', affected_script_keys: [], }]); expect(browser.httpRequests.every(r => r.url.startsWith('/json/'))).toBe(true); } else if (!declared) { expect(result.observations.source_maps.status).toBe('not_requested'); expect(result.completeness.status).toBe('complete'); expect(result.unknowns).toEqual([]); } else { expect(result.observations.source_maps.requested).toBe(1); expect(result.observations.source_maps.items[0].status).toBe('fetch_failed'); expect(result.completeness.status).toBe('partial'); expect(result.unknowns[0].affected_script_keys).toHaveLength(1); } } finally { await browser.close(); } } }, 30000); TS ``` 3. Run the diagnostic test and remove the files it creates: ```sh run_isolated npm run test:local -- src/browser/repro.test.ts rm src/browser/repro.test.ts rm -r .repro-home ``` The fixture invokes `node scripts/rea.mjs analyze-web-bundle <loopback endpoint> allowed-page --observation-ms 0 --format json`, adding `--fetch-source-maps` for the selected cases. Its assertions describe the observed baseline behavior and controls. A passing diagnostic test demonstrates the defect rather than restoration. ### Expected behavior The CLI help describes `--fetch-source-maps` as "Fetch source maps referenced by captured scripts". `docs/browser-observation.md:309` documents optional source-map fetching and failure coverage. `AGENTS.md:75` requires completeness to derive from examined coverage, and `src/domain/webBundleAnalyzerResult.ts:205` states that complete describes examination of captured source. When a captured script has no map declaration, no map fetch is requested or lost. If its source is fully parsed and no declarations were omitted, selecting map fetching should preserve complete bundle coverage and should not introduce an unknown asserting unavailable requested maps. This does not require a particular replacement status for the empty source-map collection. ### Impact and scope The verified impact is P2. Consumers that use machine-readable completeness and unknowns receive a false missing-coverage signal, while successfully parsed script findings remain available. No data loss or blocked analysis workflow was observed. Omitting `--fetch-source-maps` demonstrably avoids the false signal for this map-less input. That workaround is practical when the caller knows there are no maps to fetch; it does not preserve optional map evidence in captures that also contain declared maps. The reproduction establishes public CLI behavior with a simulated CDP producer, rather than real-browser or independent MCP coverage. ### REA version 6.4.0 (main at 58300885207133422af235e0f2b10658cf958b03) ### Runtime and platform Node 26.10.0; macOS 27.0 arm64 ### Target and artifact context A caller-written 38-byte JavaScript script supplied by the repository's `tests/fixtures/fakeCdpBrowser.ts` over loopback HTTP/WebSocket connections. The map-less input declares no `sourceMapURL`; the control declares `/missing.map` and receives HTTP 404. No external website, Chrome installation, or private target artifact is required for the CLI calls. ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence The selected map-less CLI result contains these fields under `normalized_result`: ```text observations.source_maps = {"status":"unavailable","requested":0,"processed":0,"items":[]} completeness = {"status":"partial","parsed_scripts":1,"parse_failures":0,"visited_ast_nodes":12} unknowns = [{"dimension":"source_maps","reason":"One or more requested source maps were unavailable or incomplete","affected_script_keys":[]}] ``` ### Typed outcome or recovery expected For the same map-less input with source-map selection enabled, retain zero requested maps, complete bundle completeness, no source-map unknown, and the captured script and endpoint finding. Keep the option-omitted control complete. A declared map returning HTTP 404 must remain partial, retain its failed item, and identify its affected script. Suppressing source-map failures globally would hide real missing coverage. The schema at `src/domain/webBundleAnalysis.ts:134-145` permits both `not_requested` and `unavailable` for an empty completed collection. The required correction is accurate completeness and unknowns, rather than a prescribed collection-status value. ### Analysis or suspected cause Source-derived at the reported baseline: `src/cli/browserCommands.ts:132-172` parses the option and calls the shared application service. `src/application/BrowserObservationService.ts:71-92` reaches the browser provider, and `src/browser/CdpBrowserProvider.ts:138-169` passes the captured request list to the fetcher whenever selection is true, even if the list is empty. A missing declaration produces null map fields at `src/browser/CdpCaptureEventHandlers.ts:165-172`, and `src/browser/CdpPageCaptureScripts.ts:154-159` creates no map request. `src/browser/WebSourceMapFetcher.ts:163-190` returns `unavailable` for that empty collection. `src/domain/webBundleAnalyzerResult.ts:25-32` treats that status as incomplete, and `src/domain/webBundleAnalyzerResult.ts:150-164` emits the source-map unknown with no affected script keys. These locators explain the observed result; the independent violation proof came from the public CLI fixture, rather than a direct helper call. ### Additional context Related reports are #2954 and #2625. They concern filename-dependent original-source parsing and attribution of real JavaScript parse gaps, respectively; this report concerns invented source-map coverage loss when no map was declared or requested.
bsakaguchi 2026-10-15 18:31:34 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Delivered on main in fffb07419.

A selected source-map pass with no declarations was classified unavailable. The fetcher now reports not_requested for an empty declared set, retaining partial coverage for actual map failures.

Validation: Source-map fetcher, browser CLI and real-browser qualification. Full exact-revision qualification passed.

<!-- gh-comment-id:6177649925 --> @morluto commented on GitHub (Oct 14, 2026): Delivered on main in [fffb07419](https://github.com/morluto/rea/commit/fffb0741936067530d1ce9777461cd53e87398c2). A selected source-map pass with no declarations was classified unavailable. The fetcher now reports not_requested for an empty declared set, retaining partial coverage for actual map failures. Validation: Source-map fetcher, browser CLI and real-browser qualification. Full exact-revision [qualification](https://github.com/morluto/rea/actions/runs/38629313022) passed.
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#1154
No description provided.