[GH-ISSUE #2024] [Bug] A null source name drops all known originals from a retained source map #674

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

Originally created by @xu91102 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2024

Before submitting

  • Searched open/closed issues and recent/open PRs; this is a different behavior from #1939 and the open package-pattern work #2018.
  • Uses source-owned fixtures with no credentials or private target data.

Area

Evidence, artifacts, or reconstruction — JavaScript application analysis.

Observed behavior

REA reports partial coverage and drops every original-source node. The map is structurally valid: null is an unknown source-name placeholder, and the second mapping/source/content entry identifies original.ts. The trace decoder resolves that mapping to original.ts.

Reproduction

In a built source checkout, materialize the fixture:

node --input-type=module <<'JS'
import { mkdirSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
const root = resolve("fixture");
const files = {
  "bundle.js": "export const answer = 42;\n//# sourceMappingURL=bundle.js.map\n",
  "bundle.js.map": "{\"version\":3,\"sources\":[null,\"original.ts\"],\"sourcesContent\":[null,\"export const answer: number = 42;\"],\"names\":[],\"mappings\":\"ACAA\"}"
};
for (const [path, text] of Object.entries(files)) {
 const target = resolve(root,path);
 mkdirSync(dirname(target),{recursive:true});
 writeFileSync(target,text);
}
JS
node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --format json > observed.json

Inspect normalized_result.graph.edges for specifier, resolved_path, and resolution_status, or source-map-original nodes and the graph coverage. The affected source checkout was built and the public CLI was executed on these exact fixture shapes before this report.

Expected behavior

Keep named source declarations and their correctly indexed embedded-content hashes even when another source name is null. Preserve an explicit unknown for unnamed declarations rather than inventing a filename or discarding all known originals. Continue rejecting other non-string source values.

Format/loader reference. Runtime/decoder controls were executed rather than inferred from documentation.

Impact and scope

Static application reconstruction loses known original-source evidence. No live browser or native engine is required to reproduce the local directory-analysis failure.

Version and runtime

  • Source revision: 2ff850de68dc9b05c6faf2bbfd26d56bc2d5d27c (main at investigation start).
  • Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64.
  • Interface: compiled CLI.
  • Target: source-owned local directory.

Source-derived analysis

collectSourceMapOriginals treats null as a malformed non-string name and immediately returns an empty invalid observation, discarding subsequent known entries.

Originally created by @xu91102 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2024 ### Before submitting - [x] Searched open/closed issues and recent/open PRs; this is a different behavior from #1939 and the open package-pattern work #2018. - [x] Uses source-owned fixtures with no credentials or private target data. ### Area Evidence, artifacts, or reconstruction — JavaScript application analysis. ### Observed behavior REA reports partial coverage and drops every original-source node. The map is structurally valid: null is an unknown source-name placeholder, and the second mapping/source/content entry identifies original.ts. The trace decoder resolves that mapping to original.ts. ### Reproduction In a built source checkout, materialize the fixture: ```sh node --input-type=module <<'JS' import { mkdirSync, writeFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; const root = resolve("fixture"); const files = { "bundle.js": "export const answer = 42;\n//# sourceMappingURL=bundle.js.map\n", "bundle.js.map": "{\"version\":3,\"sources\":[null,\"original.ts\"],\"sourcesContent\":[null,\"export const answer: number = 42;\"],\"names\":[],\"mappings\":\"ACAA\"}" }; for (const [path, text] of Object.entries(files)) { const target = resolve(root,path); mkdirSync(dirname(target),{recursive:true}); writeFileSync(target,text); } JS node scripts/rea.mjs analyze-javascript-application "$(pwd)/fixture" --format json > observed.json ``` Inspect `normalized_result.graph.edges` for `specifier`, `resolved_path`, and `resolution_status`, or source-map-original nodes and the graph coverage. The affected source checkout was built and the public CLI was executed on these exact fixture shapes before this report. ### Expected behavior Keep named source declarations and their correctly indexed embedded-content hashes even when another source name is null. Preserve an explicit unknown for unnamed declarations rather than inventing a filename or discarding all known originals. Continue rejecting other non-string source values. [Format/loader reference](https://tc39.es/ecma426/#sec-DecodeSourceMapSources). Runtime/decoder controls were executed rather than inferred from documentation. ### Impact and scope Static application reconstruction loses known original-source evidence. No live browser or native engine is required to reproduce the local directory-analysis failure. ### Version and runtime - Source revision: `2ff850de68dc9b05c6faf2bbfd26d56bc2d5d27c` (main at investigation start). - Node 24.18.0, npm 11.16.0, macOS 27.0.1 arm64. - Interface: compiled CLI. - Target: source-owned local directory. ### Source-derived analysis collectSourceMapOriginals treats null as a malformed non-string name and immediately returns an empty invalid observation, discarding subsequent known entries.
bsakaguchi 2026-10-15 18:27:16 +00:00
Author
Owner

@CassieFox23 commented on GitHub (Oct 12, 2026):

TL;DR: I could not reproduce this on main. I did see the bug on the commit just before the fix. The fix is ee50ed121.

Thanks, xu91102, for the clear report. I ran your fixture on Linux.

Run Graph coverage Node for original.ts
REA before the fix partial missing
REA on main complete kept

REA before the fix is c0904b4c1. REA on main is d96550f2f. The older commit d9d2a1738 gave the same result as c0904b4c1.

On main, the node for original.ts has source index 1, and its content hash matches the embedded text. The null name is kept as an unknown node. That node says source_name_available is false.

The map agrees with this. The ECMA-426 draft of 11 September 2026 allows a null source name (section 9). The mapping ACAA points at source 1, which is original.ts.

Not run

  • Other bad source values, such as numbers (your "keep rejecting" case).
  • The browser collection path and the MCP interface.
  • macOS and Windows.
Commands

Fixture files, as in your issue, under /tmp/nodebatch/fx/2024:

bundle.js      export const answer = 42;
               //# sourceMappingURL=bundle.js.map
bundle.js.map  {"version":3,"sources":[null,"original.ts"],"sourcesContent":[null,"export const answer: number = 42;"],"names":[],"mappings":"ACAA"}
# build each tree (Node 24.18.0 first on PATH, npm 11.16.0)
npm ci && npm run build && npm run test:prepare

# REA, once per tree (mid is c0904b4c1, base is d9d2a1738)
node /tmp/nodebatch/main/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > main-2024.json
node /tmp/nodebatch/mid/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > mid-2024.json
node /tmp/nodebatch/base/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > base-2024.json

REA fields on main, from the graph:

graph.coverage.status    "complete" (before the fix: "partial")
source-module node       original.ts, source_index 1, source_name_available true, content_available true
                         content_sha256 26a8680bbf0c861168714585a9facbb8dda5378b24d70451e9cb11495e71d37a
unknown node             source_index 0, source_name_available false, content_available false

The content hash above is the same as sha256sum of the string export const answer: number = 42; with no newline.

All three trees print 6.4.0 for --version, so the version string does not tell them apart. The shas do.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 24.18.0 (REA ran under this version only)
  • Head / base: d96550f2f (main) / c0904b4c1 (the parent of ee50ed121)
  • Other: d9d2a1738, the parent of c0904b4c1, was also run

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6129432416 --> @CassieFox23 commented on GitHub (Oct 12, 2026): **TL;DR:** I could not reproduce this on main. I did see the bug on the commit just before the fix. The fix is ee50ed121. Thanks, xu91102, for the clear report. I ran your fixture on Linux. | Run | Graph coverage | Node for original.ts | |---|---|---| | REA before the fix | partial | missing | | REA on main | complete | kept | REA before the fix is c0904b4c1. REA on main is d96550f2f. The older commit d9d2a1738 gave the same result as c0904b4c1. On main, the node for original.ts has source index 1, and its content hash matches the embedded text. The null name is kept as an unknown node. That node says `source_name_available` is false. The map agrees with this. The ECMA-426 draft of 11 September 2026 allows a null source name (section 9). The mapping ACAA points at source 1, which is original.ts. ### Not run - Other bad source values, such as numbers (your "keep rejecting" case). - The browser collection path and the MCP interface. - macOS and Windows. <details> <summary>Commands</summary> Fixture files, as in your issue, under /tmp/nodebatch/fx/2024: ``` bundle.js export const answer = 42; //# sourceMappingURL=bundle.js.map bundle.js.map {"version":3,"sources":[null,"original.ts"],"sourcesContent":[null,"export const answer: number = 42;"],"names":[],"mappings":"ACAA"} ``` ```sh # build each tree (Node 24.18.0 first on PATH, npm 11.16.0) npm ci && npm run build && npm run test:prepare # REA, once per tree (mid is c0904b4c1, base is d9d2a1738) node /tmp/nodebatch/main/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > main-2024.json node /tmp/nodebatch/mid/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > mid-2024.json node /tmp/nodebatch/base/scripts/rea.mjs analyze-javascript-application /tmp/nodebatch/fx/2024 --format json > base-2024.json ``` REA fields on main, from the graph: ``` graph.coverage.status "complete" (before the fix: "partial") source-module node original.ts, source_index 1, source_name_available true, content_available true content_sha256 26a8680bbf0c861168714585a9facbb8dda5378b24d70451e9cb11495e71d37a unknown node source_index 0, source_name_available false, content_available false ``` The content hash above is the same as sha256sum of the string export const answer: number = 42; with no newline. All three trees print 6.4.0 for --version, so the version string does not tell them apart. The shas do. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 24.18.0 (REA ran under this version only) - Head / base: d96550f2f (main) / c0904b4c1 (the parent of ee50ed121) - Other: d9d2a1738, the parent of c0904b4c1, was also run </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
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#674
No description provided.