diff --git a/docs/javascript-application-workflows.md b/docs/javascript-application-workflows.md index c257464164..0093710351 100644 --- a/docs/javascript-application-workflows.md +++ b/docs/javascript-application-workflows.md @@ -91,16 +91,18 @@ mapped candidate, but structural reachability, semantic influence, runtime observation, and causal proof remain separate claims. Semantic literal nodes keep their complete value in `properties.value`; literal -queries match that field. String labels read `string literal` rather than -repeating the payload. A literal's `identity.role_key` commits its canonical -JSON value as `value-sha256:`, together with its binding and property -role. This keeps large values out of identity and display metadata without +queries match that field. String labels use `string literal` when that is +shorter than the complete JSON value. A literal's `identity.role_key` commits +its canonical JSON value as `value-sha256:` when the digest key is +shorter; smaller values keep their existing JSON key. This keeps large values +out of identity and display metadata without expanding short values or truncating their Evidence. -New analyses therefore produce different literal node IDs from the earlier -payload-bearing role keys. Use IDs returned by the selected parent graph and -read literal values from `properties.value`, rather than decoding role keys or -labels. Previously stored graphs and their original IDs remain valid inputs. +New analyses therefore produce different IDs for hashed literals from the +earlier payload-bearing role keys. Use IDs returned by the selected parent +graph and read literal values from `properties.value`, rather than decoding +role keys or labels. Previously stored graphs and their original IDs remain +valid inputs. ## Version comparison diff --git a/src/application/javascript/JavaScriptSemanticGraphValueProjection.ts b/src/application/javascript/JavaScriptSemanticGraphValueProjection.ts index dfe8267b6f..febe23d247 100644 --- a/src/application/javascript/JavaScriptSemanticGraphValueProjection.ts +++ b/src/application/javascript/JavaScriptSemanticGraphValueProjection.ts @@ -154,18 +154,27 @@ const addLiteralNode = ( binding: JavaScriptSemanticBinding, value: string | number | boolean | null, role: string, -) => - retainSemanticGraphNode(context.state, context.file, { +) => { + const encodedValue = JSON.stringify(value); + const valueDigest = `value-sha256:${digestCanonicalValue(value, "Semantic literal")}`; + const valueKey = + encodedValue.length <= valueDigest.length ? encodedValue : valueDigest; + const stringLabel = "string literal"; + return retainSemanticGraphNode(context.state, context.file, { kind: "literal", // Identity needs an exact value commitment, not another payload copy. // Keep the complete literal in properties for queries and Evidence export. - roleKey: `literal:${binding.bindingId}:${role}:value-sha256:${digestCanonicalValue(value, "Semantic literal")}`, + roleKey: `literal:${binding.bindingId}:${role}:${valueKey}`, location: binding.definitions[0]?.location ?? null, - label: typeof value === "string" ? "string literal" : JSON.stringify(value), + label: + typeof value === "string" && encodedValue.length > stringLabel.length + ? stringLabel + : encodedValue, functionNodeId: context.bindingNodes.get(binding.bindingId)?.function_node_id ?? null, properties: { value }, }); +}; /** Create one canonical slot for a root binding and exact static property path. */ export const semanticPropertySlot = (