[GH-ISSUE #2650] fix(electron): dropped preload observation yields a false limitation #951

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

Summary

An active capture can record that a window exposes preload configuration, lose the event to the retention budget, and tell the caller that the window metadata did not expose configuration. The same result still records the dropped preload event and includes its family in observed coverage; this does not establish that its configuration-versus-context classification is correct. The defect is the false exposure statement in the capture's limitations; retained paths and preload execution remain unavailable.

Steps to reproduce

In the source checkout identified below, use the following focused source test. It runs the unchanged active recording script against in-memory app/process/window stand-ins. Unrelated patch families are no-op stubs. No Electron runtime launches. The first window emits 10,000 short window events before a second window supplies a short preload path. The hook-generated snapshot passes through the real snapshot parser and public result projection. Two controls distinguish retained configuration and absent configuration. The fixture was run with the repository's focused source-test launcher; the conventional source-test command below exercises the same test entry point.

Save this as src/browser/electronPreloadRetentionRepro.test.ts:

import { readFileSync } from "node:fs";
import { EventEmitter } from "node:events";
import { runInNewContext } from "node:vm";
import { expect, it } from "vitest";
import { readApplicationState } from "./PlaywrightElectronActiveActions.js";
import { projectElectronActiveCapture } from "./PlaywrightElectronActiveProjection.js";

type FixtureWindow = EventEmitter & { id: number; webContents: { id: number; getLastWebPreferences(): { preload?: string } } };

async function fixture(ticks: number, preload?: string) {
  const app = new EventEmitter();
  const mockProcess = Object.assign(new EventEmitter(), { pid: 123, type: "browser" });
  const context: Record<string, unknown> = {
    process: mockProcess,
    require: (name: string) => {
      if (name === "electron") return { app };
      if (name === "./electron-active-hook-boundaries.cjs") return {
        createElectronActiveBoundaryPatches: () => new Proxy({}, { get: () => () => undefined }),
      };
      throw new Error(`Unexpected module ${name}`);
    },
  };
  runInNewContext(readFileSync(new URL("../../scripts/electron-active-hook.cjs", import.meta.url), "utf8"), context);
  let metadataReads = 0;
  const makeWindow = (id: number, selectedPreload?: string) => {
    const window = Object.assign(new EventEmitter(), {
      id,
      webContents: { id, getLastWebPreferences: () => { if (id === 2) metadataReads++; return selectedPreload === undefined ? {} : { preload: selectedPreload }; } },
    }) as FixtureWindow;
    app.emit("browser-window-created", {}, window);
    return window;
  };
  const first = makeWindow(1);
  for (let index = 0; index < ticks; index++) first.emit("fixture-tick");
  makeWindow(2, preload);
  const snapshot = (context.__reaElectronActiveSnapshot as () => unknown)();
  // Exercise the real hook-snapshot parser without connecting to a provider.
  let evaluation = 0;
  const values = [[], [], "fixture-electron", snapshot];
  const state = await readApplicationState({ evaluate: async () => values[evaluation++] } as never);
  const result = projectElectronActiveCapture({ executable: "/opt/electron", application: "/opt/fixture/main.cjs" }, [], state);
  return { state, result, metadataReads };
}

it("reproduces a dropped configured preload and the contrary public limitation", async () => {
  const { state, result, metadataReads } = await fixture(10000, "/opt/fixture/preload.cjs");
  expect(metadataReads).toBe(1);
  expect(state.hookSnapshot.hook_error).toBe(false);
  expect(state.hookSnapshot.events.some(event => event.kind === "preload")).toBe(false);
  expect(result.retention.dropped_event_families).toContainEqual({ family: "preload", count: 1 });
  expect(result.coverage.observed_event_families).toContain("preload");
  expect(result.limitations).toContain("Preload configuration was not exposed by the observed Electron window metadata. Preload paths and execution remain unavailable.");
  console.log(JSON.stringify({ metadata_reads: metadataReads, retained: result.retention.retained, dropped: result.retention.dropped, dropped_preload: result.retention.dropped_event_families.find(x => x.family === "preload"), preload_in_coverage: result.coverage.observed_event_families.includes("preload"), contrary_limitation: result.limitations.find(x => x.startsWith("Preload configuration")) }));
});

it("distinguishes retained configuration and absent configuration controls", async () => {
  const retained = await fixture(0, "/opt/fixture/preload.cjs");
  expect(retained.result.timeline.events.some(event => event.kind === "preload")).toBe(true);
  expect(retained.result.limitations.some(x => x.startsWith("Preload configuration"))).toBe(false);
  const absent = await fixture(0);
  expect(absent.result.timeline.events.some(event => event.kind === "preload")).toBe(false);
  expect(absent.result.limitations.some(x => x.startsWith("Preload configuration"))).toBe(true);
  expect(absent.result.retention.dropped_event_families).toEqual([]);
});

Run:

npm run test:local -- src/browser/electronPreloadRetentionRepro.test.ts

Expected behavior

The active tool's existing contract identifies observed and unavailable event families and truncation. Its documentation says preload configuration comes from window runtime metadata. For a configuration event observed and then dropped, limitations must describe the loss without saying the metadata failed to expose configuration. This does not require preserving the dropped path or asserting that a preload executed.

Actual behavior

Baseline verification observed both focused tests passing when checking the incorrect result and its controls. An independent final-review replay against current upstream source reproduced the same output and controls through a Node assertion adapter rather than the Vitest runner. The second window's metadata getter ran once. The configuration event was dropped, its family remained in observed coverage, and the false limitation appeared. The meaningful output was:

{"metadata_reads":1,"retained":9706,"dropped":299,"dropped_preload":{"family":"preload","count":1},"preload_in_coverage":true,"contrary_limitation":"Preload configuration was not exposed by the observed Electron window metadata. Preload paths and execution remain unavailable."}

With no preceding window events, configuration is retained and this limitation is absent. With neither configured preload nor preceding events, the limitation is present and there are no dropped families. The runtime observation covers the inert producer/parser/projection fixture. Public CLI/MCP and a real Electron runtime were not executed. Public-operation applicability was checked in source only.

Evidence

  • Expected source: src/contracts/javascript/electronToolContracts.ts:139-146 defines the exact active tool and its observed/unavailable-family and truncation contract; docs/electron-observation.md:105-110 defines the metadata source for configuration and distinguishes it from execution; AGENTS.md:5, :19, and :21 require preserving observations, omission, and uncertainty.
  • Failure source: The inline producer/parser/projection fixture and its quoted output. Relevant production boundaries are scripts/electron-active-hook.cjs:543-590, :165-302, and :649-673; the snapshot schema and parser are in src/browser/PlaywrightElectronActiveActions.ts:14-38 and :314-336. The contrary limitation is in src/browser/PlaywrightElectronActiveProjection.ts:169-173.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The documented public operation is capture_electron_scenario, also exposed through the CLI. For valid existing absolute executable/application paths, empty actions, successful capture and successful cleanup, the returned Evidence preserves these projected limitations. Window-event counts and retention loss do not reject the snapshot. These applicability checks were source-only; the executed fixture does not establish real-provider compatibility or cleanup behavior.

Restoration check

Using the generated dropped-configuration snapshot, the result should retain the dropped-family accounting and observed configuration coverage, while its limitations must not assert that window metadata failed to expose configuration. Any replacement wording must keep the dropped path unavailable and must not imply preload execution. The no-configuration control must still communicate unavailable configuration, and the retained-configuration control must continue to expose its event without the false sentence.

Runtime or environment

Source revision a2d8b94dd50dab8d966239dd63ab84718aa8b4b4. Focused source tests used Node 24.18.0 and npm 11.16.0. Electron was represented by inert fixtures; no released package or actual Electron version was tested. Current upstream source recheck at 3ae826ceba6f25b08bce50bcb51001209bc16b57 found the hook, parser, projection, active input/result contracts, and successful public entry path unchanged; the false limitation is still present. The source recheck did not rerun the fixture, launch Electron, invoke CLI/MCP, or execute the latest published rea-agents 6.4.0 release. Final review subsequently replayed the inline fixture against current upstream source on Node.js v26.10.0, using the locked TypeScript transpiler and a node:assert adapter for its assertions. Both cases passed and reproduced the quoted output. This replay used the unchanged hook, real snapshot parser and real result projection; it did not run Vitest, CLI/MCP, the released package or Electron.

Additional context

The Electron lifecycle tracker covers broader capture capabilities. This report concerns the existing active result's treatment of a dropped configuration observation.

Related: #2594 concerns loss of the entire initial snapshot after a failed final read; #64 is the broader Electron instrumentation parent. Neither covers this retained-result limitation.

Triage assessment

  • Impact level: P3
  • Assessment status: supported
  • Impact basis: The verified defect is a false limitation sentence. The result still records the dropped preload event and includes its family in observed coverage; no downstream behavior change was established for this sentence. This assessment does not endorse the separate coverage classification.
  • Workaround status: available
  • Workaround basis: Inspect the dropped preload family together with its browser role and the retention counters to recognize lost main-process configuration evidence instead of trusting the non-exposure sentence. These records were verified in the fixture. This does not validate the coverage labels or recover the dropped path.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2650 ## Summary An active capture can record that a window exposes preload configuration, lose the event to the retention budget, and tell the caller that the window metadata did not expose configuration. The same result still records the dropped preload event and includes its family in observed coverage; this does not establish that its configuration-versus-context classification is correct. The defect is the false exposure statement in the capture's limitations; retained paths and preload execution remain unavailable. ## Steps to reproduce In the source checkout identified below, use the following focused source test. It runs the unchanged active recording script against in-memory app/process/window stand-ins. Unrelated patch families are no-op stubs. No Electron runtime launches. The first window emits 10,000 short window events before a second window supplies a short preload path. The hook-generated snapshot passes through the real snapshot parser and public result projection. Two controls distinguish retained configuration and absent configuration. The fixture was run with the repository's focused source-test launcher; the conventional source-test command below exercises the same test entry point. Save this as `src/browser/electronPreloadRetentionRepro.test.ts`: ```ts import { readFileSync } from "node:fs"; import { EventEmitter } from "node:events"; import { runInNewContext } from "node:vm"; import { expect, it } from "vitest"; import { readApplicationState } from "./PlaywrightElectronActiveActions.js"; import { projectElectronActiveCapture } from "./PlaywrightElectronActiveProjection.js"; type FixtureWindow = EventEmitter & { id: number; webContents: { id: number; getLastWebPreferences(): { preload?: string } } }; async function fixture(ticks: number, preload?: string) { const app = new EventEmitter(); const mockProcess = Object.assign(new EventEmitter(), { pid: 123, type: "browser" }); const context: Record<string, unknown> = { process: mockProcess, require: (name: string) => { if (name === "electron") return { app }; if (name === "./electron-active-hook-boundaries.cjs") return { createElectronActiveBoundaryPatches: () => new Proxy({}, { get: () => () => undefined }), }; throw new Error(`Unexpected module ${name}`); }, }; runInNewContext(readFileSync(new URL("../../scripts/electron-active-hook.cjs", import.meta.url), "utf8"), context); let metadataReads = 0; const makeWindow = (id: number, selectedPreload?: string) => { const window = Object.assign(new EventEmitter(), { id, webContents: { id, getLastWebPreferences: () => { if (id === 2) metadataReads++; return selectedPreload === undefined ? {} : { preload: selectedPreload }; } }, }) as FixtureWindow; app.emit("browser-window-created", {}, window); return window; }; const first = makeWindow(1); for (let index = 0; index < ticks; index++) first.emit("fixture-tick"); makeWindow(2, preload); const snapshot = (context.__reaElectronActiveSnapshot as () => unknown)(); // Exercise the real hook-snapshot parser without connecting to a provider. let evaluation = 0; const values = [[], [], "fixture-electron", snapshot]; const state = await readApplicationState({ evaluate: async () => values[evaluation++] } as never); const result = projectElectronActiveCapture({ executable: "/opt/electron", application: "/opt/fixture/main.cjs" }, [], state); return { state, result, metadataReads }; } it("reproduces a dropped configured preload and the contrary public limitation", async () => { const { state, result, metadataReads } = await fixture(10000, "/opt/fixture/preload.cjs"); expect(metadataReads).toBe(1); expect(state.hookSnapshot.hook_error).toBe(false); expect(state.hookSnapshot.events.some(event => event.kind === "preload")).toBe(false); expect(result.retention.dropped_event_families).toContainEqual({ family: "preload", count: 1 }); expect(result.coverage.observed_event_families).toContain("preload"); expect(result.limitations).toContain("Preload configuration was not exposed by the observed Electron window metadata. Preload paths and execution remain unavailable."); console.log(JSON.stringify({ metadata_reads: metadataReads, retained: result.retention.retained, dropped: result.retention.dropped, dropped_preload: result.retention.dropped_event_families.find(x => x.family === "preload"), preload_in_coverage: result.coverage.observed_event_families.includes("preload"), contrary_limitation: result.limitations.find(x => x.startsWith("Preload configuration")) })); }); it("distinguishes retained configuration and absent configuration controls", async () => { const retained = await fixture(0, "/opt/fixture/preload.cjs"); expect(retained.result.timeline.events.some(event => event.kind === "preload")).toBe(true); expect(retained.result.limitations.some(x => x.startsWith("Preload configuration"))).toBe(false); const absent = await fixture(0); expect(absent.result.timeline.events.some(event => event.kind === "preload")).toBe(false); expect(absent.result.limitations.some(x => x.startsWith("Preload configuration"))).toBe(true); expect(absent.result.retention.dropped_event_families).toEqual([]); }); ``` Run: ```bash npm run test:local -- src/browser/electronPreloadRetentionRepro.test.ts ``` ## Expected behavior The active tool's existing contract identifies observed and unavailable event families and truncation. Its documentation says preload configuration comes from window runtime metadata. For a configuration event observed and then dropped, limitations must describe the loss without saying the metadata failed to expose configuration. This does not require preserving the dropped path or asserting that a preload executed. ## Actual behavior Baseline verification observed both focused tests passing when checking the incorrect result and its controls. An independent final-review replay against current upstream source reproduced the same output and controls through a Node assertion adapter rather than the Vitest runner. The second window's metadata getter ran once. The configuration event was dropped, its family remained in observed coverage, and the false limitation appeared. The meaningful output was: ```json {"metadata_reads":1,"retained":9706,"dropped":299,"dropped_preload":{"family":"preload","count":1},"preload_in_coverage":true,"contrary_limitation":"Preload configuration was not exposed by the observed Electron window metadata. Preload paths and execution remain unavailable."} ``` With no preceding window events, configuration is retained and this limitation is absent. With neither configured preload nor preceding events, the limitation is present and there are no dropped families. The runtime observation covers the inert producer/parser/projection fixture. Public CLI/MCP and a real Electron runtime were not executed. Public-operation applicability was checked in source only. ## Evidence - Expected source: `src/contracts/javascript/electronToolContracts.ts:139-146` defines the exact active tool and its observed/unavailable-family and truncation contract; `docs/electron-observation.md:105-110` defines the metadata source for configuration and distinguishes it from execution; `AGENTS.md:5`, `:19`, and `:21` require preserving observations, omission, and uncertainty. - Failure source: The inline producer/parser/projection fixture and its quoted output. Relevant production boundaries are `scripts/electron-active-hook.cjs:543-590`, `:165-302`, and `:649-673`; the snapshot schema and parser are in `src/browser/PlaywrightElectronActiveActions.ts:14-38` and `:314-336`. The contrary limitation is in `src/browser/PlaywrightElectronActiveProjection.ts:169-173`. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The documented public operation is `capture_electron_scenario`, also exposed through the CLI. For valid existing absolute executable/application paths, empty actions, successful capture and successful cleanup, the returned Evidence preserves these projected limitations. Window-event counts and retention loss do not reject the snapshot. These applicability checks were source-only; the executed fixture does not establish real-provider compatibility or cleanup behavior. ## Restoration check Using the generated dropped-configuration snapshot, the result should retain the dropped-family accounting and observed configuration coverage, while its limitations must not assert that window metadata failed to expose configuration. Any replacement wording must keep the dropped path unavailable and must not imply preload execution. The no-configuration control must still communicate unavailable configuration, and the retained-configuration control must continue to expose its event without the false sentence. ## Runtime or environment Source revision `a2d8b94dd50dab8d966239dd63ab84718aa8b4b4`. Focused source tests used Node 24.18.0 and npm 11.16.0. Electron was represented by inert fixtures; no released package or actual Electron version was tested. Current upstream source recheck at `3ae826ceba6f25b08bce50bcb51001209bc16b57` found the hook, parser, projection, active input/result contracts, and successful public entry path unchanged; the false limitation is still present. The source recheck did not rerun the fixture, launch Electron, invoke CLI/MCP, or execute the latest published `rea-agents` 6.4.0 release. Final review subsequently replayed the inline fixture against current upstream source on Node.js v26.10.0, using the locked TypeScript transpiler and a `node:assert` adapter for its assertions. Both cases passed and reproduced the quoted output. This replay used the unchanged hook, real snapshot parser and real result projection; it did not run Vitest, CLI/MCP, the released package or Electron. ## Additional context [The Electron lifecycle tracker](https://github.com/morluto/rea/issues/375) covers broader capture capabilities. This report concerns the existing active result's treatment of a dropped configuration observation. Related: #2594 concerns loss of the entire initial snapshot after a failed final read; #64 is the broader Electron instrumentation parent. Neither covers this retained-result limitation. ## Triage assessment - Impact level: P3 - Assessment status: supported - Impact basis: The verified defect is a false limitation sentence. The result still records the dropped preload event and includes its family in observed coverage; no downstream behavior change was established for this sentence. This assessment does not endorse the separate coverage classification. - Workaround status: available - Workaround basis: Inspect the dropped preload family together with its browser role and the retention counters to recognize lost main-process configuration evidence instead of trusting the non-exposure sentence. These records were verified in the fixture. This does not validate the coverage labels or recover the dropped path.
bsakaguchi 2026-10-15 18:29:50 +00:00
Author
Owner

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

Addressed on main in bffdd91053fb5d076b762cf1b325e8dcb5ab2d8c.

Dropped preload-family observations still establish observed configuration, avoiding a false absence warning.

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:6159213878 --> @morluto commented on GitHub (Oct 14, 2026): Addressed on main in [bffdd91053fb5d076b762cf1b325e8dcb5ab2d8c](https://github.com/morluto/rea/commit/bffdd91053fb5d076b762cf1b325e8dcb5ab2d8c). Dropped preload-family observations still establish observed configuration, avoiding a false absence warning. 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#951
No description provided.