[GH-ISSUE #2575] fix(javascript): retain configuration reads followed by member access #892

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

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

Summary

When REA analyzes JavaScript that reads an environment variable or command-line argument and immediately accesses a property of the value, its configuration results omit the read. For example, inspecting the length of an environment value loses the known environment key, although reading the same value directly retains it. This leaves configuration-source recovery incomplete for ordinary JavaScript expressions.

Steps to reproduce

Use the source baseline and installed dependencies listed under Runtime or environment. Add a test at src/domain/javascript/configurationMemberAccess.test.ts with the following fixture, then run the focused test command.

import { expect, it } from "vitest";
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";

it("retains configuration reads consumed by member access", () => {
  const ir = analyzeJavaScriptSemantics(`
    const length = process.env.API_URL.length;
    const endpoint = process.env.API_URL;
    const argumentLength = process.argv[2].length;
  `);
  expect(ir.configurationOperations.map(({ kind, key }) => ({ kind, key }))).toEqual([
    { kind: "environment", key: "API_URL" },
    { kind: "environment", key: "API_URL" },
    { kind: "argv", key: "2" },
  ]);
});
npm run test:focused -- src/domain/javascript/configurationMemberAccess.test.ts

The verifier ran this fixture with equivalent variable names in a temporary test. The analyzer inspects inert syntax; the fixture does not need an environment value or an actual command-line argument.

Expected behavior

All three expressions read a configuration source. The analysis should retain an environment operation for each API_URL read and an argument operation for index 2. Accessing .length on a source value should preserve the known source key, even though the value itself is unknown.

Actual behavior

The focused reproduction returned only one operation, the direct environment read shown below. It omitted both reads followed by .length, while reporting complete semantic coverage. The test command exited with status 1 because the expected three-operation assertion failed. Two additional control tests passed: direct reads remained detectable, local lookalikes remained excluded, and a method-access case returned no argument operation while a split-expression control retained it.

[{"kind":"environment","key":"API_URL"}]

Evidence

  • Expected source: docs/javascript-application-workflows.md:60 documents recovery of configuration sources; src/domain/javascript/javascriptSemanticIr.ts:291 defines configuration-source operations; src/domain/javascript/javascriptSemanticAnalysis.native_bindings.test.ts:65 checks direct environment and argument reads.
  • Failure source: The focused reproduction above observed the omitted operations. src/domain/javascript/javascriptSemanticDataEffects.ts:114 excludes a configuration read when its parent uses it as a member object; src/domain/javascript/javascriptSemanticDataEffects.ts:145 prevents the outer member expression from replacing the lost read.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The global process identifier was unshadowed, the environment key was static, and argument index 2 met the existing index guard. Direct-read controls recovered both source kinds. A function parameter named process and an unrelated local object produced no configuration operations, which rules out expanding recovery to arbitrary lookalikes.

The method-access fixture const mode = process.argv[2].trim(); also returned an empty configuration-operation list. The control const argument = process.argv[2]; const mode = argument.trim(); retained the argument source. These observations establish configuration-operation recovery; binding-flow restoration and public CLI or MCP output were not tested.

Restoration check

The reproduction should return both environment operations and the argument operation with their exact keys. The method-access fixture should also retain its argument source. Direct reads must remain detectable, while shadowed process parameters and unrelated local objects must remain excluded. Check source recovery without requiring the analyzer to evaluate configuration values or asserting an unsupported direct binding flow.

Runtime or environment

  • Failure verified at a2d8b94dd5 and still present at 8b181716ac
  • Node.js: v26.10.0.
  • npm: 11.19.1.
  • Vitest: 5.0.3, from the installed locked dependencies.
  • Entry point: the source JavaScript semantic analyzer, with a focused domain test.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Configuration recovery silently omits known environment and argument sources for the tested member-access expressions. This affects analysis correctness for a bounded input pattern while direct configuration reads still work; no crash or data loss was observed.
  • Workaround status: unverified
  • Workaround basis: Assigning the configuration read to a temporary variable before accessing its value restored detection in a control. This changes the analyzed artifact, so its suitability for an existing artifact that must retain its original source remains unverified.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2575 ## Summary When REA analyzes JavaScript that reads an environment variable or command-line argument and immediately accesses a property of the value, its configuration results omit the read. For example, inspecting the length of an environment value loses the known environment key, although reading the same value directly retains it. This leaves configuration-source recovery incomplete for ordinary JavaScript expressions. ## Steps to reproduce Use the source baseline and installed dependencies listed under Runtime or environment. Add a test at `src/domain/javascript/configurationMemberAccess.test.ts` with the following fixture, then run the focused test command. ```ts import { expect, it } from "vitest"; import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js"; it("retains configuration reads consumed by member access", () => { const ir = analyzeJavaScriptSemantics(` const length = process.env.API_URL.length; const endpoint = process.env.API_URL; const argumentLength = process.argv[2].length; `); expect(ir.configurationOperations.map(({ kind, key }) => ({ kind, key }))).toEqual([ { kind: "environment", key: "API_URL" }, { kind: "environment", key: "API_URL" }, { kind: "argv", key: "2" }, ]); }); ``` ```sh npm run test:focused -- src/domain/javascript/configurationMemberAccess.test.ts ``` The verifier ran this fixture with equivalent variable names in a temporary test. The analyzer inspects inert syntax; the fixture does not need an environment value or an actual command-line argument. ## Expected behavior All three expressions read a configuration source. The analysis should retain an environment operation for each `API_URL` read and an argument operation for index `2`. Accessing `.length` on a source value should preserve the known source key, even though the value itself is unknown. ## Actual behavior The focused reproduction returned only one operation, the direct environment read shown below. It omitted both reads followed by `.length`, while reporting complete semantic coverage. The test command exited with status 1 because the expected three-operation assertion failed. Two additional control tests passed: direct reads remained detectable, local lookalikes remained excluded, and a method-access case returned no argument operation while a split-expression control retained it. ```json [{"kind":"environment","key":"API_URL"}] ``` ## Evidence - Expected source: `docs/javascript-application-workflows.md:60` documents recovery of configuration sources; `src/domain/javascript/javascriptSemanticIr.ts:291` defines configuration-source operations; `src/domain/javascript/javascriptSemanticAnalysis.native_bindings.test.ts:65` checks direct environment and argument reads. - Failure source: The focused reproduction above observed the omitted operations. `src/domain/javascript/javascriptSemanticDataEffects.ts:114` excludes a configuration read when its parent uses it as a member object; `src/domain/javascript/javascriptSemanticDataEffects.ts:145` prevents the outer member expression from replacing the lost read. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The global `process` identifier was unshadowed, the environment key was static, and argument index `2` met the existing index guard. Direct-read controls recovered both source kinds. A function parameter named `process` and an unrelated local object produced no configuration operations, which rules out expanding recovery to arbitrary lookalikes. The method-access fixture `const mode = process.argv[2].trim();` also returned an empty configuration-operation list. The control `const argument = process.argv[2]; const mode = argument.trim();` retained the argument source. These observations establish configuration-operation recovery; binding-flow restoration and public CLI or MCP output were not tested. ## Restoration check The reproduction should return both environment operations and the argument operation with their exact keys. The method-access fixture should also retain its argument source. Direct reads must remain detectable, while shadowed `process` parameters and unrelated local objects must remain excluded. Check source recovery without requiring the analyzer to evaluate configuration values or asserting an unsupported direct binding flow. ## Runtime or environment - Failure verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and still present at 8b181716aca2cb467be499cba226abfb5ae19141 - Node.js: v26.10.0. - npm: 11.19.1. - Vitest: 5.0.3, from the installed locked dependencies. - Entry point: the source JavaScript semantic analyzer, with a focused domain test. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Configuration recovery silently omits known environment and argument sources for the tested member-access expressions. This affects analysis correctness for a bounded input pattern while direct configuration reads still work; no crash or data loss was observed. - Workaround status: unverified - Workaround basis: Assigning the configuration read to a temporary variable before accessing its value restored detection in a control. This changes the analyzed artifact, so its suitability for an existing artifact that must retain its original source remains unverified.
bsakaguchi 2026-10-15 18:29:21 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@xu91102 commented on GitHub (Oct 13, 2026):

Reproduced on main d13c9f840d36a321a56917e75c48afcb8d72920e through both the compiled CLI and production stdio MCP.

A test-owned Node program verifies real environment/argv reads followed by .length, .trim() and optional member access. Both public graph cases then fail: only the direct environment read is retained, while the other four known sources disappear. The regression checks source identities and keeps their values unknown; it also excludes a shadowed process parameter and an unrelated local lookalike.

Preparing a fix at the configuration-source producer's admission rule. The public regression does not claim direct value flow through the later member transform.

<!-- gh-comment-id:6143407070 --> @xu91102 commented on GitHub (Oct 13, 2026): Reproduced on main `d13c9f840d36a321a56917e75c48afcb8d72920e` through both the compiled CLI and production stdio MCP. A test-owned Node program verifies real environment/argv reads followed by `.length`, `.trim()` and optional member access. Both public graph cases then fail: only the direct environment read is retained, while the other four known sources disappear. The regression checks source identities and keeps their values unknown; it also excludes a shadowed `process` parameter and an unrelated local lookalike. Preparing a fix at the configuration-source producer's admission rule. The public regression does not claim direct value flow through the later member transform.
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#892
No description provided.