[GH-ISSUE #2574] fix(javascript-semantics): event dispatch data appears as a listener #890

Closed
opened 2026-10-15 18:29:20 +00:00 by bsakaguchi · 0 comments
Owner

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

Summary

When JavaScript semantic analysis reads an EventEmitter call that emits a bound data value, the returned dispatch operation identifies that value as a listener and assigns it a listener source range. The value is data passed to existing listeners. This gives consumers of the semantic IR a false listener fact. The current semantic graph projection ignores listener fields for dispatch operations, which limits the demonstrated effect.

Steps to reproduce

Use the source baseline under Runtime or environment with its dependencies installed. Save this focused test as src/domain/javascript/eventDispatchData.test.ts, then run the command below. The analyzed program explicitly constructs a Node EventEmitter, so emitter applicability does not depend on an undeclared receiver.

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

it("keeps emitted data out of listener fields", () => {
  const ir = analyzeJavaScriptSemantics(
    'import { EventEmitter } from "node:events"; const bus = new EventEmitter(); const data = 1; bus.emit("ready", data);',
  );
  expect(ir.eventOperations).toHaveLength(1);
  expect(ir.eventOperations[0]).toMatchObject({
    kind: "dispatch",
    method: "emit",
    eventName: "ready",
    listenerBindingId: null,
    listenerLocation: null,
  });
});
npm run test:focused -- src/domain/javascript/eventDispatchData.test.ts

Expected behavior

Analyzing this program should retain a ready event dispatch with no listener binding or listener location. EventEmitter emit passes its additional arguments to existing listeners. Listener-specific fields should describe listener arguments on operations that accept them, such as registration with on or removal with off.

Actual behavior

The focused verification reproduced the failure for both the explicit EventEmitter fixture above and the simpler const data = 1; bus.emit("ready", data); input. Both null-field assertions failed. The explicit fixture returned these fields on its complete dispatch operation:

{
  "listenerBindingId": "scope:program:0:116:binding:data",
  "listenerLocation": {
    "start": { "line": 1, "column": 110 },
    "end": { "line": 1, "column": 114 }
  }
}

The location identifies the data argument. A separate control passed for on and off using a bound handler, and an emit call with no data retained null listener fields. The run exited 1 with two failing assertions and one passing control. The analyzed programs were parsed as inert source; no target program was executed by the analyzer.

Evidence

  • Expected source: src/domain/javascript/javascriptSemanticIr.ts:217-238 defines EventEmitter-style operations and nullable listener fields; docs/javascript-application-workflows.md:60-67 documents support for registration, removal, and dispatch candidates. The distinct role of emit data is also established by Node EventEmitter behavior.
  • Failure source: The focused analyzer fixture above returned the data binding and data range. src/domain/javascript/javascriptSemanticAsyncEffects.ts:138-155 reads argument index 1 as a listener for every event method, including dispatch, and publishes its binding and range.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Source inspection shows that the current graph projection handles dispatch separately and does not use these listener fields. The verified failure is in the semantic IR returned by the analyzer. A direct Node event control delivered data value 1 to a pre-existing listener and retained exactly one listener, confirming the argument's data role. The broader semantic-tracing contract is tracked in the closed feature issue https://github.com/morluto/rea/issues/404; this report concerns a distinct reproduced correctness failure.

Restoration check

With the same explicit emitter fixture, require a retained ready dispatch whose listenerBindingId and listenerLocation are both null. Keep the on and off controls reporting the bound handler and its source location, and keep emit with no data reporting null listener fields. Removing all event operations would fail the dispatch-retention check. Preserve the graph's existing distinction between dispatch and listener operations.

Runtime or environment

  • Failure was verified at a2d8b94dd5 and is still present at 8b181716ac by source recheck
  • Package manifest version: 6.4.0
  • Runtime: Node.js v26.10.0, npm 11.19.1, Vitest 5.0.3; locked dependencies were already installed.
  • Entry point: analyzeJavaScriptSemantics, invoked through a focused domain test. No CLI or MCP failure was observed.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The reproduced dispatch operation contains an incorrect listener binding and location, so consumers that use those facts receive a false semantic association. The demonstrated defect is bounded to the IR; no graph-output or runtime-execution failure was established.
  • Workaround status: unverified
  • Workaround basis: The current graph projection already ignores listener fields for dispatch and preserves the event, but no existing setting or workflow was demonstrated that lets an affected direct IR consumer avoid the false association without changing its code.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2574 ## Summary When JavaScript semantic analysis reads an EventEmitter call that emits a bound data value, the returned dispatch operation identifies that value as a listener and assigns it a listener source range. The value is data passed to existing listeners. This gives consumers of the semantic IR a false listener fact. The current semantic graph projection ignores listener fields for dispatch operations, which limits the demonstrated effect. ## Steps to reproduce Use the source baseline under Runtime or environment with its dependencies installed. Save this focused test as src/domain/javascript/eventDispatchData.test.ts, then run the command below. The analyzed program explicitly constructs a Node EventEmitter, so emitter applicability does not depend on an undeclared receiver. ```ts import { expect, it } from "vitest"; import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js"; it("keeps emitted data out of listener fields", () => { const ir = analyzeJavaScriptSemantics( 'import { EventEmitter } from "node:events"; const bus = new EventEmitter(); const data = 1; bus.emit("ready", data);', ); expect(ir.eventOperations).toHaveLength(1); expect(ir.eventOperations[0]).toMatchObject({ kind: "dispatch", method: "emit", eventName: "ready", listenerBindingId: null, listenerLocation: null, }); }); ``` ```sh npm run test:focused -- src/domain/javascript/eventDispatchData.test.ts ``` ## Expected behavior Analyzing this program should retain a ready event dispatch with no listener binding or listener location. EventEmitter emit passes its additional arguments to existing listeners. Listener-specific fields should describe listener arguments on operations that accept them, such as registration with on or removal with off. ## Actual behavior The focused verification reproduced the failure for both the explicit EventEmitter fixture above and the simpler const data = 1; bus.emit("ready", data); input. Both null-field assertions failed. The explicit fixture returned these fields on its complete dispatch operation: ```json { "listenerBindingId": "scope:program:0:116:binding:data", "listenerLocation": { "start": { "line": 1, "column": 110 }, "end": { "line": 1, "column": 114 } } } ``` The location identifies the data argument. A separate control passed for on and off using a bound handler, and an emit call with no data retained null listener fields. The run exited 1 with two failing assertions and one passing control. The analyzed programs were parsed as inert source; no target program was executed by the analyzer. ## Evidence - Expected source: src/domain/javascript/javascriptSemanticIr.ts:217-238 defines EventEmitter-style operations and nullable listener fields; docs/javascript-application-workflows.md:60-67 documents support for registration, removal, and dispatch candidates. The distinct role of emit data is also established by Node EventEmitter behavior. - Failure source: The focused analyzer fixture above returned the data binding and data range. src/domain/javascript/javascriptSemanticAsyncEffects.ts:138-155 reads argument index 1 as a listener for every event method, including dispatch, and publishes its binding and range. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Source inspection shows that the current graph projection handles dispatch separately and does not use these listener fields. The verified failure is in the semantic IR returned by the analyzer. A direct Node event control delivered data value 1 to a pre-existing listener and retained exactly one listener, confirming the argument's data role. The broader semantic-tracing contract is tracked in the closed feature issue https://github.com/morluto/rea/issues/404; this report concerns a distinct reproduced correctness failure. ## Restoration check With the same explicit emitter fixture, require a retained ready dispatch whose listenerBindingId and listenerLocation are both null. Keep the on and off controls reporting the bound handler and its source location, and keep emit with no data reporting null listener fields. Removing all event operations would fail the dispatch-retention check. Preserve the graph's existing distinction between dispatch and listener operations. ## Runtime or environment - Failure was verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and is still present at 8b181716aca2cb467be499cba226abfb5ae19141 by source recheck - Package manifest version: 6.4.0 - Runtime: Node.js v26.10.0, npm 11.19.1, Vitest 5.0.3; locked dependencies were already installed. - Entry point: analyzeJavaScriptSemantics, invoked through a focused domain test. No CLI or MCP failure was observed. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The reproduced dispatch operation contains an incorrect listener binding and location, so consumers that use those facts receive a false semantic association. The demonstrated defect is bounded to the IR; no graph-output or runtime-execution failure was established. - Workaround status: unverified - Workaround basis: The current graph projection already ignores listener fields for dispatch and preserves the event, but no existing setting or workflow was demonstrated that lets an affected direct IR consumer avoid the false association without changing its code.
bsakaguchi 2026-10-15 18:29:20 +00:00
  • closed this issue
  • added the
    bug
    label
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#890
No description provided.