[GH-ISSUE #6588] [Bug] WASM glue analysis rejects source-phase imports supported by Node 24 #3976

Closed
opened 2026-10-31 00:45:44 +00:00 by bsakaguchi · 1 comment
Owner

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

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 real WasmArtifactService.inspect boundary returns a valid WASM inspection but reports parse_status: "failed" and no references for valid .mjs glue using either import source module from "./module.wasm" or await import.source("./module.wasm"). Node's syntax checker accepts both files. Ordinary static and dynamic imports of the identical literal are retained as unique local-path candidates in the same inspection. This is a loss of static literal evidence; no runtime loading or data-flow inference is requested.

Reproduction

Use the source revision and runtime below, locked dependencies, and caller-supplied WABT 1.0.42. Save this as reproduce.mts at the checkout root and run:

REA_WABT_BIN_DIRECTORY=/absolute/wabt/bin node node_modules/tsx/dist/cli.mjs reproduce.mts ./wasm-source-phase-fixture

The script uses real WABT and the shared production inspection boundary used by CLI/MCP. It writes only synthetic fixtures. node --check validates glue syntax without evaluating it, and no WASM module is instantiated or executed. One inspection with the four glue files below produced both failures and both successful controls.

import { mkdir, writeFile } from 'node:fs/promises';
import { resolve, basename } from 'node:path';
import { pathToFileURL } from 'node:url';
import { spawnSync } from 'node:child_process';
const { WasmArtifactService } = await import(pathToFileURL(resolve('src/application/wasm/WasmArtifactService.ts')).href);
const { WabtArtifactProvider } = await import(pathToFileURL(resolve('src/wasm/WabtArtifactProvider.ts')).href);
const root = resolve(process.argv[2] ?? 'wasm-source-phase-fixture');
const toolDirectory = process.env.REA_WABT_BIN_DIRECTORY;
if (!toolDirectory) throw new Error('Set REA_WABT_BIN_DIRECTORY to WABT 1.0.42 bin');
await mkdir(root, { recursive: true });
const path = resolve(root, 'module.wasm');
await writeFile(path, Buffer.from('0061736d01000000', 'hex'));
const sources = {
  static_source: 'import source module from "./module.wasm";\n',
  dynamic_source: 'const module = await import.source("./module.wasm");\n',
  static_control: 'import * as module from "./module.wasm";\n',
  dynamic_control: 'const module = await import("./module.wasm");\n',
};
const glue_paths = [];
const syntax = [];
for (const [name, source] of Object.entries(sources)) {
  const glue = resolve(root, name + '.mjs');
  await writeFile(glue, source);
  const checked = spawnSync(process.execPath, ['--check', glue], { encoding: 'utf8' });
  syntax.push({ file: basename(glue), exit_status: checked.status, stderr: checked.stderr });
  glue_paths.push(glue);
}
const service = new WasmArtifactService(new WabtArtifactProvider({ ...process.env, REA_WABT_BIN_DIRECTORY: toolDirectory }));
try {
  const result = await service.inspect({ path, glue_paths });
  if (!result.ok) throw result.error;
  const report = result.value.normalized_result;
  console.log(JSON.stringify({
    runtime: { node: process.version, platform: process.platform, arch: process.arch },
    syntax,
    validation: report.validation,
    module_sha256: report.artifact.sha256,
    wabt_release: report.tool_profile.release,
    glue: report.glue.map(g => ({ file: basename(g.artifact.path), parse_status: g.parse_status, references: g.references.map(r => ({ value: r.value, line: r.line, column: r.column, association: r.association, candidate_paths: r.candidate_paths.map(p => basename(p)) })) })),
  }, null, 2));
} finally {
  await service.close();
}

Expected behavior

Retain the literal ./module.wasm and its coordinates from valid source-phase import glue, with association: "local-path-candidate" pointing to the selected module. Preserve the distinction between an AST-observed literal and a proven runtime load.

The WASM glue contract promises .wasm string literals, source coordinates, parser status, and relative filesystem associations. Node 24.22.1's documented WASM source-phase imports support both reproduced syntax forms. The ordinary-import controls establish that these literal associations are otherwise supported.

Impact and scope

Both selected source-phase glue files lose their complete reference inventory. The primary WASM validation and WAT remain available, and the failure is explicitly marked in parse_status; this is not a claim of falsely complete glue coverage or a broken entire WASM inspection. The observed scope is two valid source-phase import forms on the recorded runtime. Other hosts and packaged CLI/MCP delivery were not exercised. No equivalent workaround preserving typed Evidence for the original glue was verified.

REA version

Source main 0154141304028645d767bad32a1f7568b5d4815b, whose package version is 6.7.0. This is not the published rea-agents-6.7.0 revision 27dc42d10249f0410904a75c0997842eb03b931c; that release was not tested.

Runtime and platform

Node.js v24.22.1; Linux 7.2.8-9-omarchy, x86_64; Omarchy 4.0.6; locked @babel/parser 8.0.4; official WABT 1.0.42 Linux x64 executables. The WABT release archive SHA-256 was 84895407a6bbb80e918f33b16b2fb2206021c150b6bc9ff6f761263a745ab131, matching release metadata. No native decompiler provider was involved.

Target and artifact context

An empty valid WebAssembly core module, bytes 0061736d01000000, SHA-256 93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476, and four synthetic .mjs glue files. The source-phase forms are the only relevant difference from their ordinary-import controls.

Interface

Other — directly exercised the shared WasmArtifactService.inspect production boundary with the real WABT provider; public CLI/MCP transport was not exercised.

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: the linked WASM glue contract and Node runtime documentation above.
  • Failure source: the executed production-boundary reproduction printed the records below.
  • Evidence provenance: observed.
  • Local verification: reproduced.
  • Reproduction completeness: complete for the shared application/provider boundary.

Smallest useful output, with candidate paths displayed as fixture basenames by the script:

Node v24.22.1, linux x64; all four node --check exit statuses: 0; stderr: ""
validation: valid; wabt_release: 1.0.42
static_source.mjs:  parse_status=failed, references=[]
dynamic_source.mjs: parse_status=failed, references=[]
static_control.mjs: parse_status=complete, value=./module.wasm, line=1, column=24, association=local-path-candidate, candidate_paths=[module.wasm]
dynamic_control.mjs: parse_status=complete, value=./module.wasm, line=1, column=28, association=local-path-candidate, candidate_paths=[module.wasm]

The full JSON emitted by the inline script contains these same fields. The baseline and revision apply to this observed output.

Typed outcome or recovery expected

Each source-phase glue record should retain its literal reference with parser coverage matching the accepted syntax. Restoration should preserve the successful ordinary-import controls and avoid executing glue or WASM to obtain static associations.

Analysis or suspected cause

Source-derived explanation: the glue adapter returns an empty failed result when the shared JavaScript parser returns null. The parser's JavaScript plugin selection does not enable Babel's source-phase import grammar. This is explanatory source evidence, separate from the observed real-provider result.

Additional context

The static and dynamic source-phase forms are grouped as one grammar-compatibility defect. Published 6.7.0, other JavaScript syntax proposals, other operating systems, and end-to-end CLI/MCP delivery are untested.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Two runtime-valid glue forms lose all static references in an otherwise successful inspection; the optional glue facet explicitly reports failed parsing, while WASM validation and decoded output remain available.
  • Workaround status: unverified
  • Workaround basis: Ordinary imports work as controls but changing a source-phase import changes program semantics; no equivalent method preserving the original glue's typed reference Evidence was verified.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6588 ### 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 real `WasmArtifactService.inspect` boundary returns a valid WASM inspection but reports `parse_status: "failed"` and no references for valid `.mjs` glue using either `import source module from "./module.wasm"` or `await import.source("./module.wasm")`. Node's syntax checker accepts both files. Ordinary static and dynamic imports of the identical literal are retained as unique local-path candidates in the same inspection. This is a loss of static literal evidence; no runtime loading or data-flow inference is requested. ### Reproduction Use the source revision and runtime below, locked dependencies, and caller-supplied WABT 1.0.42. Save this as `reproduce.mts` at the checkout root and run: ```sh REA_WABT_BIN_DIRECTORY=/absolute/wabt/bin node node_modules/tsx/dist/cli.mjs reproduce.mts ./wasm-source-phase-fixture ``` The script uses real WABT and the shared production inspection boundary used by CLI/MCP. It writes only synthetic fixtures. `node --check` validates glue syntax without evaluating it, and no WASM module is instantiated or executed. One inspection with the four glue files below produced both failures and both successful controls. ```ts import { mkdir, writeFile } from 'node:fs/promises'; import { resolve, basename } from 'node:path'; import { pathToFileURL } from 'node:url'; import { spawnSync } from 'node:child_process'; const { WasmArtifactService } = await import(pathToFileURL(resolve('src/application/wasm/WasmArtifactService.ts')).href); const { WabtArtifactProvider } = await import(pathToFileURL(resolve('src/wasm/WabtArtifactProvider.ts')).href); const root = resolve(process.argv[2] ?? 'wasm-source-phase-fixture'); const toolDirectory = process.env.REA_WABT_BIN_DIRECTORY; if (!toolDirectory) throw new Error('Set REA_WABT_BIN_DIRECTORY to WABT 1.0.42 bin'); await mkdir(root, { recursive: true }); const path = resolve(root, 'module.wasm'); await writeFile(path, Buffer.from('0061736d01000000', 'hex')); const sources = { static_source: 'import source module from "./module.wasm";\n', dynamic_source: 'const module = await import.source("./module.wasm");\n', static_control: 'import * as module from "./module.wasm";\n', dynamic_control: 'const module = await import("./module.wasm");\n', }; const glue_paths = []; const syntax = []; for (const [name, source] of Object.entries(sources)) { const glue = resolve(root, name + '.mjs'); await writeFile(glue, source); const checked = spawnSync(process.execPath, ['--check', glue], { encoding: 'utf8' }); syntax.push({ file: basename(glue), exit_status: checked.status, stderr: checked.stderr }); glue_paths.push(glue); } const service = new WasmArtifactService(new WabtArtifactProvider({ ...process.env, REA_WABT_BIN_DIRECTORY: toolDirectory })); try { const result = await service.inspect({ path, glue_paths }); if (!result.ok) throw result.error; const report = result.value.normalized_result; console.log(JSON.stringify({ runtime: { node: process.version, platform: process.platform, arch: process.arch }, syntax, validation: report.validation, module_sha256: report.artifact.sha256, wabt_release: report.tool_profile.release, glue: report.glue.map(g => ({ file: basename(g.artifact.path), parse_status: g.parse_status, references: g.references.map(r => ({ value: r.value, line: r.line, column: r.column, association: r.association, candidate_paths: r.candidate_paths.map(p => basename(p)) })) })), }, null, 2)); } finally { await service.close(); } ``` ### Expected behavior Retain the literal `./module.wasm` and its coordinates from valid source-phase import glue, with `association: "local-path-candidate"` pointing to the selected module. Preserve the distinction between an AST-observed literal and a proven runtime load. The [WASM glue contract](https://github.com/morluto/rea/blob/0154141304028645d767bad32a1f7568b5d4815b/docs/wasm-artifacts.md#L123-L130) promises `.wasm` string literals, source coordinates, parser status, and relative filesystem associations. [Node 24.22.1's documented WASM source-phase imports](https://github.com/nodejs/node/blob/v24.22.1/doc/api/esm.md#wasm-source-phase-imports) support both reproduced syntax forms. The ordinary-import controls establish that these literal associations are otherwise supported. ### Impact and scope Both selected source-phase glue files lose their complete reference inventory. The primary WASM validation and WAT remain available, and the failure is explicitly marked in `parse_status`; this is not a claim of falsely complete glue coverage or a broken entire WASM inspection. The observed scope is two valid source-phase import forms on the recorded runtime. Other hosts and packaged CLI/MCP delivery were not exercised. No equivalent workaround preserving typed Evidence for the original glue was verified. ### REA version Source main `0154141304028645d767bad32a1f7568b5d4815b`, whose package version is `6.7.0`. This is not the published `rea-agents-6.7.0` revision `27dc42d10249f0410904a75c0997842eb03b931c`; that release was not tested. ### Runtime and platform Node.js `v24.22.1`; Linux `7.2.8-9-omarchy`, x86_64; Omarchy `4.0.6`; locked `@babel/parser` `8.0.4`; official WABT `1.0.42` Linux x64 executables. The WABT release archive SHA-256 was `84895407a6bbb80e918f33b16b2fb2206021c150b6bc9ff6f761263a745ab131`, matching release metadata. No native decompiler provider was involved. ### Target and artifact context An empty valid WebAssembly core module, bytes `0061736d01000000`, SHA-256 `93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476`, and four synthetic `.mjs` glue files. The source-phase forms are the only relevant difference from their ordinary-import controls. ### Interface Other — directly exercised the shared `WasmArtifactService.inspect` production boundary with the real WABT provider; public CLI/MCP transport was not exercised. ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence - Expected source: the linked WASM glue contract and Node runtime documentation above. - Failure source: the executed production-boundary reproduction printed the records below. - Evidence provenance: observed. - Local verification: reproduced. - Reproduction completeness: complete for the shared application/provider boundary. Smallest useful output, with candidate paths displayed as fixture basenames by the script: ```text Node v24.22.1, linux x64; all four node --check exit statuses: 0; stderr: "" validation: valid; wabt_release: 1.0.42 static_source.mjs: parse_status=failed, references=[] dynamic_source.mjs: parse_status=failed, references=[] static_control.mjs: parse_status=complete, value=./module.wasm, line=1, column=24, association=local-path-candidate, candidate_paths=[module.wasm] dynamic_control.mjs: parse_status=complete, value=./module.wasm, line=1, column=28, association=local-path-candidate, candidate_paths=[module.wasm] ``` The full JSON emitted by the inline script contains these same fields. The baseline and revision apply to this observed output. ### Typed outcome or recovery expected Each source-phase glue record should retain its literal reference with parser coverage matching the accepted syntax. Restoration should preserve the successful ordinary-import controls and avoid executing glue or WASM to obtain static associations. ### Analysis or suspected cause Source-derived explanation: [the glue adapter](https://github.com/morluto/rea/blob/0154141304028645d767bad32a1f7568b5d4815b/src/wasm/WasmGlueAdapter.ts#L34-L46) returns an empty failed result when the shared JavaScript parser returns null. [The parser's JavaScript plugin selection](https://github.com/morluto/rea/blob/0154141304028645d767bad32a1f7568b5d4815b/src/domain/javascript/javascriptSourceParser.ts#L95-L97) does not enable Babel's source-phase import grammar. This is explanatory source evidence, separate from the observed real-provider result. ### Additional context The static and dynamic source-phase forms are grouped as one grammar-compatibility defect. Published 6.7.0, other JavaScript syntax proposals, other operating systems, and end-to-end CLI/MCP delivery are untested. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Two runtime-valid glue forms lose all static references in an otherwise successful inspection; the optional glue facet explicitly reports failed parsing, while WASM validation and decoded output remain available. - Workaround status: unverified - Workaround basis: Ordinary imports work as controls but changing a source-phase import changes program semantics; no equivalent method preserving the original glue's typed reference Evidence was verified.
Author
Owner

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

Resolved by github.com/morluto/rea@fd08a22742. The owning shared parser enables installed sourcePhaseImports grammar. Four exact source-phase/ordinary import controls retain static literal value, location and association without loading WASM. Validation: src/wasm/WabtOutput.test.ts passed in the recorded round2/3 execution; this review did not rerun tests. Coverage is limited to the cited control; no broader real-provider, Windows or performance claim.

<!-- gh-comment-id:6376107407 --> @morluto commented on GitHub (Oct 23, 2026): Resolved by https://github.com/morluto/rea/commit/fd08a2274247e62086cbcbdaf0df3ed09c2e76c9. The owning shared parser enables installed sourcePhaseImports grammar. Four exact source-phase/ordinary import controls retain static literal value, location and association without loading WASM. Validation: `src/wasm/WabtOutput.test.ts` passed in the recorded round2/3 execution; this review did not rerun tests. Coverage is limited to the cited control; no broader real-provider, Windows or performance claim.
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#3976
No description provided.