fix(graphs): separate source identities from display representations

Validation: integrated changes passed formatting, typecheck, lint, resolved module-boundary verification and git diff --check. Tests and real-provider workflows were not run.
This commit is contained in:
morluto
2026-10-11 00:03:20 +08:00
parent 2ca3ad2386
commit a6f76f5da9
9 changed files with 156 additions and 70 deletions
@@ -8,6 +8,7 @@ import {
} from "./JavaScriptArtifactGraphContext.js";
import { astObservationEvidence } from "./JavaScriptArtifactGraphEvidence.js";
import { compositeKey } from "../../domain/unicodeCodePointOrder.js";
import { javascriptDisplayText } from "../../domain/javascript/javascriptAstValues.js";
import {
addElectronInferenceEdge,
electronFindingSourceNode,
@@ -51,17 +52,27 @@ const addNativeBinding = (input: NativeBindingInput): void => {
identity: electronObservationIdentity(
context,
"javascript-requested-native-export",
// Members are a variable-length source-derived list: compositeKey keeps
// ["a\0b"] distinct from ["a", "b"] inside the digested identity.
`${file.path}:${value.specifier}:${value.binding_kind}:${compositeKey(value.members)}:${electronRangeKey(value.location)}`,
compositeKey([
file.path,
value.specifier,
value.binding_kind,
value.members,
value.namespace_access ?? null,
value.dynamic_member_access ?? null,
electronRangeKey(value.location),
]),
),
observations: [
{
label: value.members.join(", "),
label:
value.members.map(javascriptDisplayText).join(", ") ||
value.specifier,
properties: {
specifier: value.specifier,
binding_kind: value.binding_kind,
requested_members: value.members,
namespace_access: value.namespace_access ?? null,
dynamic_member_access: value.dynamic_member_access ?? null,
resolved_path: resolved,
native_export_verification: "not-performed",
},
@@ -90,6 +101,8 @@ const addNativeBinding = (input: NativeBindingInput): void => {
specifier: value.specifier,
binding_kind: value.binding_kind,
requested_members: value.members,
namespace_access: value.namespace_access ?? null,
dynamic_member_access: value.dynamic_member_access ?? null,
},
limitations: [
"Requested JavaScript members are not verified native exports.",
@@ -107,6 +120,8 @@ const addNativeBinding = (input: NativeBindingInput): void => {
properties: {
resolved_path: resolved,
requested_members: value.members,
namespace_access: value.namespace_access ?? null,
dynamic_member_access: value.dynamic_member_access ?? null,
verified: false,
},
confidence: "medium",
@@ -1,6 +1,7 @@
import type { ApplicationNode } from "../../domain/javascript/javascriptApplicationGraphSchemas.js";
import type { JavaScriptBundlerRegistration } from "../../domain/javascript/javascriptStaticAnalysisTypes.js";
import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js";
import { compositeKey } from "../../domain/unicodeCodePointOrder.js";
import {
addAstContainsEdge,
artifactLocalIdentity,
@@ -80,7 +81,11 @@ const createBundlerChunkNode = (
const chunkKey = `${registration.runtime}:${registration.chunk_keys.join(",")}`;
return context.accumulator.addNode({
kind: "javascript-chunk",
identity: artifactLocalIdentity(file.sha256, "bundler-chunk", chunkKey),
identity: artifactLocalIdentity(
file.sha256,
"bundler-chunk",
compositeKey([registration.runtime, registration.chunk_keys]),
),
observations: [
{
label: chunkKey,
@@ -1,4 +1,5 @@
import type { ArtifactInventorySnapshot } from "../../domain/artifactInventorySnapshot.js";
import { compositeKey } from "../../domain/unicodeCodePointOrder.js";
import {
completeApplicationCoverage,
partialApplicationCoverage,
@@ -330,7 +331,7 @@ export const chunkLookupKey = (
path: string,
runtime: string,
chunkKey: string,
): string => `${path}\0${runtime}\0${chunkKey}`;
): string => compositeKey([path, runtime, chunkKey]);
/** Resolve a relative static specifier without escaping the artifact root. */
export const resolveArtifactPath = (
@@ -1,6 +1,9 @@
import { posix } from "node:path";
import { compareUnicodeCodePoints } from "../../domain/unicodeCodePointOrder.js";
import {
compareUnicodeCodePoints,
compositeKey,
} from "../../domain/unicodeCodePointOrder.js";
import type { ApplicationNode } from "../../domain/javascript/javascriptApplicationGraphSchemas.js";
import {
completeApplicationCoverage,
@@ -177,7 +180,7 @@ const addExportRelationship = (
identity: artifactLocalIdentity(
file.sha256,
"module-export",
`${file.container_sha256}:${file.path}:${link.exportedName}`,
compositeKey([file.container_sha256, file.path, link.exportedName]),
),
observations: [
{