diff --git a/src/javascript/analysis/JavaScriptAnalysisWorkerSchemas.ts b/src/javascript/analysis/JavaScriptAnalysisWorkerSchemas.ts index b8358ec47..63ad24b62 100644 --- a/src/javascript/analysis/JavaScriptAnalysisWorkerSchemas.ts +++ b/src/javascript/analysis/JavaScriptAnalysisWorkerSchemas.ts @@ -328,6 +328,7 @@ export const javaScriptWorkerStaticAnalysisSchema = z kind: z.enum(["route", "network"]), value: z.string(), mechanism: z.string(), + interpretation: z.literal("candidate").exactOptional(), }), ), storage: z.array( diff --git a/tests/acceptance/applications/applicationWorkflowCli.test.ts b/tests/acceptance/applications/applicationWorkflowCli.test.ts index ed1ca8d16..eefa8a7f9 100644 --- a/tests/acceptance/applications/applicationWorkflowCli.test.ts +++ b/tests/acceptance/applications/applicationWorkflowCli.test.ts @@ -485,6 +485,7 @@ it("preserves complete line-comment source-map URLs through CLI and MCP", async declared_url: declaredUrl, declared_url_sha256: digest, resolved_path: "app.js.map", + resolution_status: "resolved", available: true, }, evidence: expect.objectContaining({ @@ -507,6 +508,7 @@ it("preserves complete line-comment source-map URLs through CLI and MCP", async properties: { declared_url_sha256: digest, resolved_path: "app.js.map", + resolution_status: "resolved", }, }), ); @@ -565,6 +567,7 @@ it("resolves source-map URL paths once without changing their declarations", asy declared_url: declaredUrl, declared_url_sha256: digest, resolved_path: path, + resolution_status: "resolved", available: true, }, evidence: expect.objectContaining({ @@ -587,7 +590,11 @@ it("resolves source-map URL paths once without changing their declarations", asy expect.objectContaining({ relation: "maps_to", target_node_id: map?.node_id, - properties: { declared_url_sha256: digest, resolved_path: path }, + properties: { + declared_url_sha256: digest, + resolved_path: path, + resolution_status: "resolved", + }, }), ); } @@ -1576,8 +1583,11 @@ it("retains bundled isolated-world contextBridge APIs through dedicated and gene world: "isolated", world_id: { status: "literal", value: 1001, expression: null }, api_key: "isolatedApi", + api_status: "object-literal", members: ["ping"], - resolution_basis: "wrapper-substitution", + unknown_members: 0, + // The proven Webpack bootstrap resolves `load(2)` directly. + resolution_basis: "direct-syntax", }), evidence: expect.objectContaining({ location: expect.objectContaining({ diff --git a/tests/acceptance/applications/blockSourceMapCli.test.ts b/tests/acceptance/applications/blockSourceMapCli.test.ts index 957cd49c2..4e7cb7e11 100644 --- a/tests/acceptance/applications/blockSourceMapCli.test.ts +++ b/tests/acceptance/applications/blockSourceMapCli.test.ts @@ -73,6 +73,7 @@ cliTest.for(["CLI", "stdio MCP"] as const)( declared_url: url, declared_url_sha256: digest, resolved_path: url, + resolution_status: "resolved", available: true, }, evidence: expect.objectContaining({ @@ -92,7 +93,11 @@ cliTest.for(["CLI", "stdio MCP"] as const)( expect.objectContaining({ relation: "maps_to", target_node_id: map?.node_id, - properties: { declared_url_sha256: digest, resolved_path: url }, + properties: { + declared_url_sha256: digest, + resolved_path: url, + resolution_status: "resolved", + }, }), ); }, diff --git a/tests/acceptance/applications/javascriptEndpointPayload.test.ts b/tests/acceptance/applications/javascriptEndpointPayload.test.ts index 6a980aa7a..75b54e26e 100644 --- a/tests/acceptance/applications/javascriptEndpointPayload.test.ts +++ b/tests/acceptance/applications/javascriptEndpointPayload.test.ts @@ -108,7 +108,9 @@ cliTest( ), ).toHaveLength(1); expect(repeatedNode.observations).toHaveLength(2); - expect(repeatedNode.identity).toMatchObject({ key: "/ok" }); + expect(repeatedNode.identity).toMatchObject({ + key: JSON.stringify(["literal", "/ok"]), + }); expect( repeatedNode.observations.every(({ label }) => label === "/ok"), ).toBe(true); diff --git a/tests/boundary/filesystem/javascript-applications/javascriptApplicationEmptyLiterals.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptApplicationEmptyLiterals.test.ts index 0490ae211..8387acdaa 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptApplicationEmptyLiterals.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptApplicationEmptyLiterals.test.ts @@ -79,6 +79,10 @@ it("retains empty literal evidence across the application boundary surfaces", as ); }); +/** Endpoint identity keys tag literal values apart from candidates. */ +const literalEndpointKey = (value: string): string => + JSON.stringify(["literal", value]); + it("keeps bridge entry paths stable through worker validation and API seed matching", async () => { const output = await analyzeSource(` const { contextBridge, ipcRenderer } = require("electron"); @@ -144,7 +148,7 @@ it("analyzes a plain long-line loader without package metadata", async () => { for (const node of nodes) { expect(node.identity).toMatchObject({ strategy: "artifact-local-key", - key: "", + key: node.kind === "endpoint" ? literalEndpointKey("") : "", }); expect(node.observations.map(({ label }) => label)).toEqual([null]); } @@ -165,9 +169,9 @@ it("keeps exact values for empty literals without synthetic application labels", // a literal two-quote endpoint; both keep exact identities. expect(endpoints).toEqual( expect.arrayContaining([ - { key: "", labels: [null], values: [""] }, - { key: '""', labels: ['""'], values: ['""'] }, - { key: "/api", labels: ["/api"], values: ["/api"] }, + { key: literalEndpointKey(""), labels: [null], values: [""] }, + { key: literalEndpointKey('""'), labels: ['""'], values: ['""'] }, + { key: literalEndpointKey("/api"), labels: ["/api"], values: ["/api"] }, ]), ); expect(endpoints).toHaveLength(3); @@ -252,7 +256,7 @@ it("does not match an empty endpoint with a literal two-quote seed", async () => case_sensitive: true, }).filter(({ node_id: nodeId }) => endpoints.has(nodeId)); expect(matches.map(({ node_id: nodeId }) => endpoints.get(nodeId))).toEqual([ - '""', + literalEndpointKey('""'), ]); });