fix(evidence): preserve JSON ownership across metadata rebinding (#7036)

This commit is contained in:
gensokyo-dev
2026-10-25 03:11:38 +08:00
committed by GitHub
parent a834ed1cab
commit 03ed0c63d9
2 changed files with 68 additions and 10 deletions
+51 -1
View File
@@ -13,8 +13,15 @@ import {
parseEvidence,
immutableEvidence,
withEvidenceCallerInputPath,
rebindEvidenceToTargetPath,
} from "./evidence.js";
import { MAX_JSON_DEPTH, type JsonValue } from "./jsonValue.js";
import {
MAX_JSON_DEPTH,
jsonValueSchema,
type JsonValue,
} from "./jsonValue.js";
import { AnalysisResourceConstraintError } from "./analysisErrorCore.js";
import { projectAnalysisError } from "./analysisErrorProjection.js";
import { createEvidenceBundle } from "./evidenceBundle.js";
import { freezeJsonSnapshot } from "./immutableJson.js";
@@ -183,6 +190,49 @@ it("retains verbatim caller input without changing semantic identity or copying
expect(() => withEvidenceCallerInputPath(second, "invalid\0path")).toThrow();
});
it.each(["caller selection", "subject display"])(
"preserves sealed JSON ownership when rebinding %s metadata",
(metadata) => {
const original = createEvidence(
TARGET,
PROVIDER,
{
operation: "inspect",
parameters: {},
result: { rows: [{ value: "observed" }] },
rawResult: { source: ["provider"] },
},
{ immutable: true },
);
const rebound =
metadata === "caller selection"
? withEvidenceCallerInputPath(original, "./selected/../alias")
: rebindEvidenceToTargetPath(original, {
...TARGET,
path: "/tmp/selected-alias",
});
const projected = projectAnalysisError(
new AnalysisResourceConstraintError(
"inspect",
"memory",
"low heap",
null,
{
partialObservation: rebound,
},
),
);
expect(rebound).not.toBe(original);
expect(rebound.evidence_id).toBe(original.evidence_id);
expect(rebound.normalized_result).toBe(original.normalized_result);
expect(rebound.raw_result).toBe(original.raw_result);
expect(projected.details?.partial_observation).toBe(rebound);
expect(jsonValueSchema.parse(rebound)).toBe(rebound);
expect(original.caller_input_path).toBeUndefined();
expect(original.subject?.local_path).toBe(TARGET.path);
},
);
it("applies the JSON depth boundary to owned immutable results", () => {
let result: JsonValue = 1;
for (let index = 0; index <= MAX_JSON_DEPTH; index += 1)
+17 -9
View File
@@ -26,6 +26,7 @@ import {
freezeJsonSnapshot,
freezeOwnedJsonTreeSnapshot,
canBorrowParsedJsonSnapshot,
immutableJsonSnapshotMember,
isImmutableJsonSnapshot,
} from "./immutableJson.js";
import { digestSchema } from "./../domain/digests.js";
@@ -355,11 +356,7 @@ export const rebindEvidenceToTargetPath = (
// The original authenticated Evidence owns immutable payloads. Only the
// small display subject and envelope are new, so preserve those payloads
// without reparsing a potentially large analysis result.
Object.freeze(reboundSubject.digest);
Object.freeze(reboundSubject);
Object.freeze(reboundEvidence);
immutableEvidenceSnapshots.set(reboundEvidence, reboundEvidence);
return reboundEvidence;
return rememberReboundEvidence(evidence, reboundEvidence);
};
/** Bind the exact selected request path without changing semantic identity or stored history. */
@@ -372,12 +369,23 @@ export const withEvidenceCallerInputPath = (
if (owned.caller_input_path === callerInputPath) return owned;
// The authenticated source owns its immutable payloads. Only this small
// envelope changes, so replay does not copy a document-sized result.
const rebound = Object.freeze({
const rebound = {
...owned,
caller_input_path: callerInputPath,
});
immutableEvidenceSnapshots.set(rebound, rebound);
return rebound;
};
return rememberReboundEvidence(owned, rebound);
};
/** Carry the source's sealing proof before sealing only the changed envelope. */
const rememberReboundEvidence = (
source: Evidence,
rebound: Evidence,
): Evidence => {
// Each own member belongs to an authenticated immutable source. Register
// these shared roots so sealing the envelope never walks their payloads.
for (const key of Object.keys(source))
immutableJsonSnapshotMember(source, key);
return rememberImmutableEvidence(rebound);
};
/** Recognize authenticated Evidence whose complete reachable JSON data is immutable. */