fix(javascript): reconcile Node targets with entry assets (#8670)

* fix(javascript): reconcile Node targets with entry assets

* test(inspector): read reconciled evidence payload

* Update tests/boundary/inspector/javascriptRuntimeNodeTarget.test.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* test(inspector): read the workflow evidence payload

* Update tests/boundary/inspector/javascriptRuntimeNodeTarget.test.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* test(javascript): restore Evidence workflow result access

---------

Co-authored-by: morluto <[email protected]>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-11-03 08:54:39 +08:00
1 parent 9bea563e30
commit 2d11fd92d2
6 files changed
+174 -2

No files matched your search

@@ -93,6 +93,10 @@ coverage. It does not print captured source text.
Runtime targets, frames, scripts, and workers become capture-scoped graph
nodes. REA evaluates compatible static candidates conservatively:
V8 Inspector targets whose protocol type is `node` use JavaScript asset/module
candidates for their verified entry location. A target-only correspondence does
not mark that script loaded; load-state evidence requires a script observation.
1. A captured-source SHA-256 plus one matching mapped location yields
a content-and-location match.
2. When no static candidate exists at a mapped location, one unique exact
@@ -57,7 +57,10 @@ const classifyLayer = (
const direct = new Map<string, string[]>();
const ambiguous = new Set<string>();
const incomplete = new Set<string>();
for (const match of matches)
// A target's entry location establishes correspondence, not script presence.
for (const match of matches.filter(
({ entity_kind }) => entity_kind === "script",
))
if (
match.status === "matched" &&
match.static_layer_id === layer.layerId &&
@@ -94,7 +94,10 @@ const targetEntity = (
frameKey: null,
scriptKey: null,
location,
staticKind: "renderer",
staticKind:
capture.kind === "v8-inspector" && target.type === "node"
? "javascript"
: "renderer",
sourceSha256: null,
label: target.title,
properties: {
@@ -0,0 +1,52 @@
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { javascriptRuntimeReconciliationResultSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
import { nodeReconciliationFixture } from "../../fixtures/nodeRuntimeReconciliation.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest.for(["CLI", "stdio MCP"] as const)(
"reconciles synthetic Node target entry Evidence through %s",
async (surface, { cli }) => {
const input = nodeReconciliationFixture(false);
let document: unknown;
if (surface === "CLI") {
const root = await createTestTempDirectory(
"rea-node-reconciliation-cli-",
);
const path = join(root, "input.json");
await writeFile(path, JSON.stringify(input));
const response = await cli.run({
arguments: ["reconcile-javascript-runtime", path, "--format", "json"],
});
expect(response.exitCode, response.stderr).toBe(0);
document = response.json;
} else {
const call = await cli.sharedMcpCall!();
const response = await call("reconcile_javascript_runtime", input);
expect(response.isError, JSON.stringify(response)).not.toBe(true);
document = response.structuredContent;
}
const result = javascriptRuntimeReconciliationResultSchema.parse(
(document as { normalized_result: unknown }).normalized_result,
);
expect(result.reconciliations).toEqual([
expect.objectContaining({
entity_kind: "target",
status: "matched",
reason: "unique-location-match",
confidence: "medium",
candidate_static_count: 1,
}),
]);
expect(result.summary).toMatchObject({
runtime_scripts: 0,
static_loaded: 0,
static_not_observed: 0,
});
expect(
result.graph.edges.filter(({ relation }) => relation === "observed_as"),
).toHaveLength(1);
},
);
@@ -0,0 +1,37 @@
import { expect, test } from "vitest";
import { reconcileJavaScriptRuntimeEvidence } from "../../../src/application/javascript/JavaScriptRuntimeReconciliationService.js";
import { javascriptRuntimeReconciliationResultSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
import { nodeReconciliationFixture } from "../../fixtures/nodeRuntimeReconciliation.js";
test.each([false, true])(
"matches a synthetic Node entry target without inventing script presence: %s",
(scriptObserved) => {
const reconciled = reconcileJavaScriptRuntimeEvidence(
nodeReconciliationFixture(scriptObserved),
);
if (!reconciled.ok) throw reconciled.error;
const result = javascriptRuntimeReconciliationResultSchema.parse(
reconciled.value.evidence.normalized_result,
);
const target = result.reconciliations.find(
({ entity_kind }) => entity_kind === "target",
);
expect(target).toMatchObject({
status: "matched",
basis: "artifact-path",
confidence: "medium",
reason: "unique-location-match",
candidate_static_count: 1,
});
expect(
result.graph.nodes.find(
({ node_id }) => node_id === target?.static_node_id,
)?.kind,
).toBe("javascript-asset");
expect(result.summary).toMatchObject({
runtime_scripts: scriptObserved ? 1 : 0,
static_loaded: scriptObserved ? 1 : 0,
static_not_observed: 0,
});
},
);
+73
View File
@@ -0,0 +1,73 @@
import { createJavaScriptRuntimeObservationEvidence } from "../../src/application/javascript/JavaScriptRuntimeObservationEvidence.js";
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js";
import { javascriptRuntimeObservationSchema } from "../../src/domain/javascript/javascriptRuntimeObservation.js";
import { V8_INSPECTOR_PROVIDER_IDENTITY } from "../../src/inspector/providerIdentity.js";
/** Synthetic, schema-validated capture; this is not a live Inspector observation. */
export const nodeReconciliationFixture = (scriptObserved: boolean) => {
const location = {
kind: "file",
file_path: "/Applications/Example.app/Contents/Resources/app/renderer.js",
};
const runtime = javascriptRuntimeObservationSchema.parse({
runtime: {
product: "node.js/v24.22.1",
protocol_version: "1.3",
v8_version: null,
},
target: {
target_id: "synthetic-node",
protocol_type: "node",
attached: null,
location,
runtime_kind: "unknown",
runtime_kind_authority: "not-declared",
},
capture: {
observation_ms: 100,
events_observed: scriptObserved ? 1 : 0,
events_retained: scriptObserved ? 1 : 0,
events_dropped: 0,
metadata_bytes_retained: 0,
truncated: false,
truncation_reasons: [],
},
scripts: {
items: scriptObserved
? [
{
script_key: `v8_script_${"4".repeat(64)}`,
location,
execution_context_key: null,
cdp_hash: null,
length: null,
is_module: null,
status: "observed-loaded",
},
]
: [],
observed_total: scriptObserved ? 1 : 0,
excluded: { unsupported_location: 0, invalid_protocol_value: 0 },
},
execution_contexts: [],
directly_observed: [],
unavailable_without_instrumentation: [],
unknowns: ["Synthetic bounded capture."],
limitations: ["Synthetic fixture, not a live runtime."],
});
return {
static_layers: [{ analysis: JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE }],
runtime_observations: [
createJavaScriptRuntimeObservationEvidence(
"observe_javascript_runtime",
{
inspector_endpoint: "http://127.0.0.1:9229",
target_id: "synthetic-node",
observation_ms: 100,
},
runtime,
V8_INSPECTOR_PROVIDER_IDENTITY,
),
],
};
};