[GH-ISSUE #6727] [Bug] Mapped arguments writes leave stale exported parameter literals #4092

Closed
opened 2026-10-31 00:46:45 +00:00 by bsakaguchi · 0 comments
Owner

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

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 published analyze-javascript-application CLI reports /value as exact literal 1 for the non-strict CommonJS export below. Calling that same function with one argument returns {value:2}: arguments[0] aliases its simple parameter. The production artifact analyzer and export-return projection reproduce the wrong literal on both current main and published 6.7.0. An alias of arguments also reproduces it. Strict-mode, default-parameter and no-write controls correctly retain 1.

Reproduction

Use the published rea-agents@6.7.0 package root with its dependencies available and Node v24.22.1. The public invocation and fixture below were executed; temporary paths are generalized. REA analyzes the fixture statically. The separate VM oracle executes only this self-authored, local arithmetic fixture.

work="$(mktemp -d)"
mkdir "$work/app" "$work/home" "$work/config" "$work/cache" "$work/temp"
cat > "$work/app/app.cjs" <<'JS'
exports.read=function(value){value=1;arguments[0]=2;return {value};};
JS
env -i PATH="$PATH" HOME="$work/home" XDG_CONFIG_HOME="$work/config" \
  XDG_CACHE_HOME="$work/cache" TMPDIR="$work/temp" \
  node "$PWD/scripts/rea.mjs" analyze-javascript-application "$work/app" \
  --artifact-format directory --json > "$work/result.json"
node --input-type=module - "$work" <<'JS'
import {readFileSync} from 'node:fs';
import {runInNewContext} from 'node:vm';
const root=process.argv[2];
const evidence=JSON.parse(readFileSync(root+'/result.json','utf8'));
for(const node of evidence.normalized_result.graph.nodes)
  for(const {properties:p} of node.observations)
    if(p.semantic_role==='export-return-shapes' && p.exported_name==='read')
      console.log('REA',JSON.stringify(p.static_return_shapes.flatMap(s=>s.fields)));
const source=readFileSync(root+'/app/app.cjs','utf8');
console.log('native',JSON.stringify(runInNewContext('const exports={};'+source+'exports.read(0)')));
JS

The public CLI reproduced the primary fixture once, exited 0, and parsed one JavaScript file with zero parse failures. Five cases were also executed sequentially through analyzeJavaScriptArtifactFiles, projectJavaScriptModuleSemantics and projectJavaScriptExportReturnShapes, once per tested build:

Function body / parameters Native read(0) REA /value
value=1;arguments[0]=2;return {value}; / value 2 literal 1
value=1;const args=arguments;args[0]=2;return {value}; / value 2 literal 1
"use strict";value=1;arguments[0]=2;return {value}; / value 1 literal 1
value=1;arguments[0]=2;return {value}; / value=0 1 literal 1
value=1;return {value}; / value 1 literal 1

Expected behavior

Do not publish literal 1 after a supported write can change a mapped parameter. Retaining caller-dependent uncertainty is sufficient; precise evaluation of arguments is unnecessary. Preserve the strict-mode, non-simple-parameter and no-write controls. ECMAScript's arguments exotic objects specify the parameter mapping for non-strict functions with simple parameters. REA's return-shape contract evaluates rebound values at their read position and retains unknown when ordering or values are unproved.

Impact and scope

Valid non-strict CommonJS source yields an incorrect exact exported return field after a direct or aliased arguments write. The demonstrated consequence is bounded static-analysis incorrectness. No downstream incident or real-application frequency was measured. A source-preserving REA workaround was not verified; adding strict mode or changing the parameter list changes program semantics and serves only as a control.

REA version

Published npm tarball rea-agents@6.7.0: production dist analyzer and public bundled CLI executed. Main source 5d6b8a0ab693c03ab85cf0807d40bedf021e76d8: production artifact analyzer and projection executed with locked dependencies. The unpacked release reused the checkout's dependency directory; it was not a separate clean npm installation.

Runtime and platform

Node.js v24.22.1; Linux x64. No external analysis provider or service was needed.

Target and artifact context

A disposable directory containing one authored CommonJS app.cjs, with an ordinary non-strict function, one simple parameter and no outer declaration named arguments. Every independent oracle calls the function with an explicit argument, which establishes the mapped slot.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Observed published CLI field and independent fixture result:

REA [{"path":"/value","presence":"present","state":"literal","value":1,"reason":null}]
native {"value":2}

Both production-boundary builds retained this same wrong field for the primary and alias fixtures. All five cases on each build reported semantic IR coverage {"status":"complete","omittedCount":0} and return projection coverage:

{"status":"complete","retained_return_sites":1,"omitted_return_sites":0,"omitted_fields":0,"omitted_property_coverage":0,"projection_complete":true}

These coverage fields describe retained semantic/projection facts, not a claim that the whole application has complete runtime knowledge. The overall CLI Evidence retains static-analysis limitations.

  • Evidence provenance: observed.
  • Local verification: reproduced.
  • Reproduction completeness: complete.
  • Missing coverage: MCP transport, other platforms, real-application incidence and implementation restoration were not tested. No full test suite or build was launched for this investigation.

Analysis or suspected cause

Source-derived: bindFunctionLocals registers explicit parameters without their implicit arguments mapping. Assignment registration consequently retains the direct value=1 assignment without representing the index write as another possible write to that parameter. This explains the observed output but is not a proposed implementation.

Related open #6552 concerns resolving an ordinary function's implicit arguments to an unrelated outer binding and emitting a false closure capture. This fixture has no outer arguments binding: shadowing that name alone does not model mapped parameter writes. Closed #2725 concerns incoming parameter provenance, and #2570 concerns TypeScript receiver-parameter positions. Neither demonstrates this write-alias failure. Open/closed searches for mapped arguments, arguments objects and arguments/parameter literals found no matching report.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The public static-analysis workflow emits a demonstrably wrong exact exported literal for bounded valid CommonJS inputs; both current source and the published analyzer reproduce it.
  • Workaround status: unverified
  • Workaround basis: No unchanged-input REA workflow or public option was verified to recover the mapped-write uncertainty. Source edits used as controls change runtime semantics.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6727 ## 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 published `analyze-javascript-application` CLI reports `/value` as exact literal `1` for the non-strict CommonJS export below. Calling that same function with one argument returns `{value:2}`: `arguments[0]` aliases its simple parameter. The production artifact analyzer and export-return projection reproduce the wrong literal on both current main and published 6.7.0. An alias of `arguments` also reproduces it. Strict-mode, default-parameter and no-write controls correctly retain `1`. ## Reproduction Use the published `rea-agents@6.7.0` package root with its dependencies available and Node v24.22.1. The public invocation and fixture below were executed; temporary paths are generalized. REA analyzes the fixture statically. The separate VM oracle executes only this self-authored, local arithmetic fixture. ```sh work="$(mktemp -d)" mkdir "$work/app" "$work/home" "$work/config" "$work/cache" "$work/temp" cat > "$work/app/app.cjs" <<'JS' exports.read=function(value){value=1;arguments[0]=2;return {value};}; JS env -i PATH="$PATH" HOME="$work/home" XDG_CONFIG_HOME="$work/config" \ XDG_CACHE_HOME="$work/cache" TMPDIR="$work/temp" \ node "$PWD/scripts/rea.mjs" analyze-javascript-application "$work/app" \ --artifact-format directory --json > "$work/result.json" node --input-type=module - "$work" <<'JS' import {readFileSync} from 'node:fs'; import {runInNewContext} from 'node:vm'; const root=process.argv[2]; const evidence=JSON.parse(readFileSync(root+'/result.json','utf8')); for(const node of evidence.normalized_result.graph.nodes) for(const {properties:p} of node.observations) if(p.semantic_role==='export-return-shapes' && p.exported_name==='read') console.log('REA',JSON.stringify(p.static_return_shapes.flatMap(s=>s.fields))); const source=readFileSync(root+'/app/app.cjs','utf8'); console.log('native',JSON.stringify(runInNewContext('const exports={};'+source+'exports.read(0)'))); JS ``` The public CLI reproduced the primary fixture once, exited `0`, and parsed one JavaScript file with zero parse failures. Five cases were also executed sequentially through `analyzeJavaScriptArtifactFiles`, `projectJavaScriptModuleSemantics` and `projectJavaScriptExportReturnShapes`, once per tested build: | Function body / parameters | Native `read(0)` | REA `/value` | | --- | --- | --- | | `value=1;arguments[0]=2;return {value};` / `value` | `2` | literal `1` | | `value=1;const args=arguments;args[0]=2;return {value};` / `value` | `2` | literal `1` | | `"use strict";value=1;arguments[0]=2;return {value};` / `value` | `1` | literal `1` | | `value=1;arguments[0]=2;return {value};` / `value=0` | `1` | literal `1` | | `value=1;return {value};` / `value` | `1` | literal `1` | ## Expected behavior Do not publish literal `1` after a supported write can change a mapped parameter. Retaining caller-dependent uncertainty is sufficient; precise evaluation of `arguments` is unnecessary. Preserve the strict-mode, non-simple-parameter and no-write controls. ECMAScript's [arguments exotic objects](https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-arguments-exotic-objects) specify the parameter mapping for non-strict functions with simple parameters. REA's [return-shape contract](https://github.com/morluto/rea/blob/5d6b8a0ab693c03ab85cf0807d40bedf021e76d8/docs/javascript-application-workflows.md#L367-L376) evaluates rebound values at their read position and retains unknown when ordering or values are unproved. ## Impact and scope Valid non-strict CommonJS source yields an incorrect exact exported return field after a direct or aliased `arguments` write. The demonstrated consequence is bounded static-analysis incorrectness. No downstream incident or real-application frequency was measured. A source-preserving REA workaround was not verified; adding strict mode or changing the parameter list changes program semantics and serves only as a control. ## REA version Published npm tarball `rea-agents@6.7.0`: production `dist` analyzer and public bundled CLI executed. Main source `5d6b8a0ab693c03ab85cf0807d40bedf021e76d8`: production artifact analyzer and projection executed with locked dependencies. The unpacked release reused the checkout's dependency directory; it was not a separate clean npm installation. ## Runtime and platform Node.js v24.22.1; Linux x64. No external analysis provider or service was needed. ## Target and artifact context A disposable directory containing one authored CommonJS `app.cjs`, with an ordinary non-strict function, one simple parameter and no outer declaration named `arguments`. Every independent oracle calls the function with an explicit argument, which establishes the mapped slot. ## Interface CLI ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence Observed published CLI field and independent fixture result: ```text REA [{"path":"/value","presence":"present","state":"literal","value":1,"reason":null}] native {"value":2} ``` Both production-boundary builds retained this same wrong field for the primary and alias fixtures. All five cases on each build reported semantic IR coverage `{"status":"complete","omittedCount":0}` and return projection coverage: ```json {"status":"complete","retained_return_sites":1,"omitted_return_sites":0,"omitted_fields":0,"omitted_property_coverage":0,"projection_complete":true} ``` These coverage fields describe retained semantic/projection facts, not a claim that the whole application has complete runtime knowledge. The overall CLI Evidence retains static-analysis limitations. - Evidence provenance: observed. - Local verification: reproduced. - Reproduction completeness: complete. - Missing coverage: MCP transport, other platforms, real-application incidence and implementation restoration were not tested. No full test suite or build was launched for this investigation. ## Analysis or suspected cause Source-derived: [`bindFunctionLocals`](https://github.com/morluto/rea/blob/5d6b8a0ab693c03ab85cf0807d40bedf021e76d8/src/domain/javascript/javascriptSemanticAnalysis.ts#L1716-L1733) registers explicit parameters without their implicit `arguments` mapping. [Assignment registration](https://github.com/morluto/rea/blob/5d6b8a0ab693c03ab85cf0807d40bedf021e76d8/src/domain/javascript/javascriptSemanticAnalysis.ts#L1477-L1524) consequently retains the direct `value=1` assignment without representing the index write as another possible write to that parameter. This explains the observed output but is not a proposed implementation. Related open [#6552](https://github.com/morluto/rea/issues/6552) concerns resolving an ordinary function's implicit `arguments` to an unrelated outer binding and emitting a false closure capture. This fixture has no outer `arguments` binding: shadowing that name alone does not model mapped parameter writes. Closed [#2725](https://github.com/morluto/rea/issues/2725) concerns incoming parameter provenance, and [#2570](https://github.com/morluto/rea/issues/2570) concerns TypeScript receiver-parameter positions. Neither demonstrates this write-alias failure. Open/closed searches for mapped arguments, arguments objects and arguments/parameter literals found no matching report. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The public static-analysis workflow emits a demonstrably wrong exact exported literal for bounded valid CommonJS inputs; both current source and the published analyzer reproduce it. - Workaround status: unverified - Workaround basis: No unchanged-input REA workflow or public option was verified to recover the mapped-write uncertainty. Source edits used as controls change runtime semantics.
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#4092
No description provided.