fix(javascript): retain bridge conditions on IPC joins (#2747)

* fix(javascript): retain bridge conditions on IPC joins

* fix(javascript): retain IPC condition ownership

* style(javascript): format bridge path regression

* fix(process): report no remaining time after a provider deadline fires

Node timers can fire while performance.now() is still a fraction of a
millisecond short of the monotonic deadline. ProviderStartupDeadline then
reported interruption "timeout" and an aborted signal while remainingMs()
returned ceil(0.x) = 1, so polling loops guarded by remainingMs() > 0
(Hopper and Ghidra startup) could run past an elapsed deadline, and the
real-timer test "aborts a bounded wait when its real monotonic deadline
expires" failed intermittently in CI (expected 1 to be 0).

Once the deadline's own timer has classified a timeout, report zero
remaining time. A deterministic regression test fires the timer with the
monotonic clock 0.4 ms short of the deadline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(javascript): preserve Electron join condition coverage

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Codex <codex@users.noreply.github.com>
This commit is contained in:
Avocado 2026-10-14 09:39:27 +11:00 committed by GitHub
parent 3a4d49406a
commit c6166d4b56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 2 deletions

View File

@ -165,7 +165,8 @@ export const addElectronCallPaths = (
pairing_basis: "unique-exact-literal-channel",
resolution: "candidate",
handler_path: to.file.path,
conditions: to.path.conditions,
bridge_conditions: from.path.conditions,
handler_conditions: to.path.conditions,
},
limitations: [
"The unique static channel match does not establish runtime registration, sender acceptance, or dispatch.",

View File

@ -55,7 +55,8 @@ cliTest(
expect(
byId.get(edge.target_node_id)?.observations[0]?.properties.channel,
).toBe(edge.properties.channel);
expect(edge.properties.conditions).toEqual([
expect(edge.properties.bridge_conditions).toEqual([]);
expect(edge.properties.handler_conditions).toEqual([
expect.objectContaining({ expression: "allowed(event)" }),
]);
}
@ -495,3 +496,44 @@ cliTest(
).toEqual(["empty:key"]);
},
);
cliTest(
"retains bridge and handler conditions on Electron IPC join edges",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-electron-join-conditions-");
await writeFixtureFiles(root, {
"preload.js": `const e=require("electron");
e.contextBridge.exposeInMainWorld("desktop", {
choose: flag
? () => e.ipcRenderer.send("test:copy")
: () => e.ipcRenderer.send("test:cut")
});`,
"main.js": `const e=require("electron");
if(!flag)e.ipcMain.on("test:copy",event=>allowed(event)&&event.sender.copy());
if(flag)e.ipcMain.on("test:cut",event=>allowed(event)&&event.sender.cut());`,
});
const { graph } = await analyzeJavaScriptDirectory("CLI", cli, root);
const joins = graph.edges.filter(
(edge) =>
edge.evidence.extractor.operation === "join-electron-wrapper-paths",
);
expect(joins).toHaveLength(2);
for (const [channel, bridgeCondition] of [
["test:copy", "flag"],
["test:cut", "!(flag)"],
]) {
const edge = joins.find(
(candidate) => candidate.properties.channel === channel,
);
expect(edge?.properties.bridge_conditions).toEqual([
expect.objectContaining({ expression: bridgeCondition }),
]);
expect(edge?.properties.handler_conditions).toEqual([
expect.objectContaining({
expression: channel === "test:copy" ? "!flag" : "flag",
}),
expect.objectContaining({ expression: "allowed(event)" }),
]);
}
},
);