[GH-ISSUE #2573] fix(javascript-semantic-calls): computed keys create false method captures #889

Closed
opened 2026-10-15 18:29:20 +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/2573

Summary

Analyzing an object method and a class method whose computed names read a local variable reports that both methods capture that variable, even though neither method body reads it. The result gives consumers incorrect closure ownership for supported JavaScript syntax.

Steps to reproduce

Use the source revision and installed dependencies listed under Runtime or environment. Add a test named javascriptSemanticAnalysis.computed_key_capture.regression.test.ts beside the semantic analysis module, then run the focused command below. The following fixture reproduces the observed empty-list assertion failure.

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

it("computed keys do not create method captures", () => {
  const source = `function outer() { const name = "m"; const obj = { [name]() { return 1; } }; class C { [name]() { return 2; } } }`;
  const ir = analyzeJavaScriptSemantics(source);
  expect(ir.closureCaptures).toEqual([]);
});
npm run test:focused -- src/domain/javascript/javascriptSemanticAnalysis.computed_key_capture.regression.test.ts

Expected behavior

The capture list should be empty. JavaScript evaluates these computed names while creating the object and class, outside the method parameter and body environments. The variable is local to the enclosing function, and neither method references it from its body, so no nested callable captures it in this input.

Actual behavior

The local focused run returned two captures of the same name binding. Their owners were the object method and class method, labeled [computed@51] and [computed@87] for this source string. Both reference locations point to the computed names rather than the method bodies. The assertion failed with exit code 1. In the same run, a method whose body returns an outer variable correctly produced one capture, and literal computed names produced none.

Evidence

  • Expected source: src/domain/javascript/javascriptSemanticIr.ts:152 defines a capture as an outer lexical binding referenced by a nested callable; src/domain/javascript/javascriptSemanticAnalysis.ts:584 explicitly handles computed object/class method keys outside the method parameter and body scopes.
  • Failure source: The focused semantic analysis fixture above returned two false capture records. src/domain/javascript/javascriptSemanticCalls.ts:94 enters the method before visiting its key, and src/domain/javascript/javascriptSemanticCalls.ts:304 resolves the key identifier and records it against that method.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The primary evidence is the returned capture list and failing assertion from the focused run. One failing case and two passing controls ran in one focused file; the public CLI was not run.

The returned records were callable:method:51:73 and callable:method:87:109, each referencing scope:function:0:113:binding:name. Their reference spans were line 1, columns 52-56 and 88-92. Source inspection also confirms that semantic graph projection turns these capture records into resolved captures relationships at src/application/javascript/JavaScriptSemanticGraphFlowProjection.ts:229; that downstream result was not executed locally.

Restoration check

The same object/class fixture must return an empty capture list. A method body that returns an outer variable must still produce exactly one capture owned by that method, and literal computed names must still produce none. These checks distinguish correct computed-key ownership from disabling closure capture collection.

Runtime or environment

  • The failure was verified at source revision: a2d8b94dd5 and is still present at 8b181716ac.
  • REA package manifest: 6.4.0; Node.js: v26.10.0; npm: 11.19.1; Vitest: 5.0.3; macOS arm64.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The focused run demonstrates incorrect closure facts for computed names in both object and class methods. Graph consumers use these records as capture relationships, so this is a consequential semantic analysis error bounded to the demonstrated syntax; a public CLI failure was not tested.
  • Workaround status: unverified
  • Workaround basis: Literal computed names avoid the failure in the control, but they do not establish a practical workaround for shipped source that requires computed names. No consumer-side workaround was tested.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2573 ## Summary Analyzing an object method and a class method whose computed names read a local variable reports that both methods capture that variable, even though neither method body reads it. The result gives consumers incorrect closure ownership for supported JavaScript syntax. ## Steps to reproduce Use the source revision and installed dependencies listed under Runtime or environment. Add a test named `javascriptSemanticAnalysis.computed_key_capture.regression.test.ts` beside the semantic analysis module, then run the focused command below. The following fixture reproduces the observed empty-list assertion failure. ```ts import { expect, it } from "vitest"; import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js"; it("computed keys do not create method captures", () => { const source = `function outer() { const name = "m"; const obj = { [name]() { return 1; } }; class C { [name]() { return 2; } } }`; const ir = analyzeJavaScriptSemantics(source); expect(ir.closureCaptures).toEqual([]); }); ``` ```sh npm run test:focused -- src/domain/javascript/javascriptSemanticAnalysis.computed_key_capture.regression.test.ts ``` ## Expected behavior The capture list should be empty. JavaScript evaluates these computed names while creating the object and class, outside the method parameter and body environments. The variable is local to the enclosing function, and neither method references it from its body, so no nested callable captures it in this input. ## Actual behavior The local focused run returned two captures of the same `name` binding. Their owners were the object method and class method, labeled `[computed@51]` and `[computed@87]` for this source string. Both reference locations point to the computed names rather than the method bodies. The assertion failed with exit code 1. In the same run, a method whose body returns an outer variable correctly produced one capture, and literal computed names produced none. ## Evidence - Expected source: `src/domain/javascript/javascriptSemanticIr.ts:152` defines a capture as an outer lexical binding referenced by a nested callable; `src/domain/javascript/javascriptSemanticAnalysis.ts:584` explicitly handles computed object/class method keys outside the method parameter and body scopes. - Failure source: The focused semantic analysis fixture above returned two false capture records. `src/domain/javascript/javascriptSemanticCalls.ts:94` enters the method before visiting its key, and `src/domain/javascript/javascriptSemanticCalls.ts:304` resolves the key identifier and records it against that method. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The primary evidence is the returned capture list and failing assertion from the focused run. One failing case and two passing controls ran in one focused file; the public CLI was not run. The returned records were `callable:method:51:73` and `callable:method:87:109`, each referencing `scope:function:0:113:binding:name`. Their reference spans were line 1, columns 52-56 and 88-92. Source inspection also confirms that semantic graph projection turns these capture records into resolved `captures` relationships at `src/application/javascript/JavaScriptSemanticGraphFlowProjection.ts:229`; that downstream result was not executed locally. ## Restoration check The same object/class fixture must return an empty capture list. A method body that returns an outer variable must still produce exactly one capture owned by that method, and literal computed names must still produce none. These checks distinguish correct computed-key ownership from disabling closure capture collection. ## Runtime or environment - The failure was verified at source revision: a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and is still present at 8b181716aca2cb467be499cba226abfb5ae19141. - REA package manifest: 6.4.0; Node.js: v26.10.0; npm: 11.19.1; Vitest: 5.0.3; macOS arm64. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The focused run demonstrates incorrect closure facts for computed names in both object and class methods. Graph consumers use these records as capture relationships, so this is a consequential semantic analysis error bounded to the demonstrated syntax; a public CLI failure was not tested. - Workaround status: unverified - Workaround basis: Literal computed names avoid the failure in the control, but they do not establish a practical workaround for shipped source that requires computed names. No consumer-side workaround was tested.
bsakaguchi 2026-10-15 18:29:20 +00:00
Author
Owner

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

Addressed on main in 896696b2e761e34c267977bb5c6982c607a622d0.

Computed method keys belong to the enclosing evaluation context rather than the method body; nested functions retain their own lexical ownership.

Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit.

Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.

<!-- gh-comment-id:6159198779 --> @morluto commented on GitHub (Oct 14, 2026): Addressed on main in [896696b2e761e34c267977bb5c6982c607a622d0](https://github.com/morluto/rea/commit/896696b2e761e34c267977bb5c6982c607a622d0). Computed method keys belong to the enclosing evaluation context rather than the method body; nested functions retain their own lexical ownership. Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit. Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.
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#889
No description provided.