perf(domain): avoid duplicate readiness bundle validation
Avoid reparsing the already validated Evidence bundle in readiness reports; retain semantic ID, graph and manifest authentication. Reuse canonical digest ownership and remove an unused verifier temporary directory. Refs #1065.
This commit is contained in:
parent
693ed332b5
commit
29ff887f65
|
|
@ -1,7 +1,6 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { access, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { access, writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
|
|
@ -25,8 +24,6 @@ const electronPath = join(fixtureRoot, "electron");
|
|||
const environment = {
|
||||
...process.env,
|
||||
};
|
||||
const temporaryRoot = await mkdtemp(join(tmpdir(), "rea-readiness-"));
|
||||
|
||||
await access(nativePath);
|
||||
const nativeEvidence = await runCli(["inspect-artifact", nativePath, "--json"]);
|
||||
const javascriptCliEvidence = await runCli([
|
||||
|
|
@ -135,7 +132,6 @@ try {
|
|||
);
|
||||
} finally {
|
||||
await client.close();
|
||||
await rm(temporaryRoot, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
async function runCli(arguments_) {
|
||||
|
|
|
|||
|
|
@ -238,7 +238,13 @@ export const parseEvidenceBundle = (input: unknown): EvidenceBundle => {
|
|||
const owned = immutableBundles.get(input);
|
||||
if (owned !== undefined) return owned;
|
||||
}
|
||||
const parsed = evidenceBundleSchema.parse(input);
|
||||
return authenticateParsedEvidenceBundle(evidenceBundleSchema.parse(input));
|
||||
};
|
||||
|
||||
/** Authenticate evidence and bundle invariants after the bundle shape is parsed. */
|
||||
export const authenticateParsedEvidenceBundle = (
|
||||
parsed: EvidenceBundle,
|
||||
): EvidenceBundle => {
|
||||
const recordIds = parsed.records.map(({ evidence_id: id }) => id);
|
||||
if (new Set(recordIds).size !== recordIds.length)
|
||||
throw new TypeError("Evidence bundle contains duplicate record IDs");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,45 @@ const input = (
|
|||
...overrides,
|
||||
});
|
||||
|
||||
describe("readiness bundle authentication", () => {
|
||||
it("authenticates each Evidence record after parsing the readiness contract", () => {
|
||||
const value = input();
|
||||
const record = value.evidence_bundle.records[0];
|
||||
if (record === undefined) throw new TypeError("Missing Evidence record");
|
||||
value.evidence_bundle.records[0] = {
|
||||
...record,
|
||||
evidence_id: `ev_${"0".repeat(64)}`,
|
||||
};
|
||||
|
||||
expect(() => createReconstructionReadinessReport(value)).toThrow(
|
||||
/Evidence semantic identifier does not match its record/u,
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects a noncanonical bundle manifest after readiness parsing", () => {
|
||||
const value = input();
|
||||
const provider = value.evidence_bundle.providers[0];
|
||||
if (provider === undefined)
|
||||
throw new TypeError("Missing provider manifest");
|
||||
value.evidence_bundle.providers.push(provider);
|
||||
|
||||
expect(() => createReconstructionReadinessReport(value)).toThrow(
|
||||
/Evidence bundle manifests are not canonical/u,
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects duplicate Evidence record IDs after readiness parsing", () => {
|
||||
const value = input();
|
||||
const record = value.evidence_bundle.records[0];
|
||||
if (record === undefined) throw new TypeError("Missing Evidence record");
|
||||
value.evidence_bundle.records.push(record);
|
||||
|
||||
expect(() => createReconstructionReadinessReport(value)).toThrow(
|
||||
/Evidence bundle contains duplicate record IDs/u,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("reconstruction readiness report", () => {
|
||||
it("accepts every caller supplied capability", () => {
|
||||
const capability = RECONSTRUCTION_READINESS_EXAMPLE.capabilities[0];
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { createHash } from "node:crypto";
|
||||
|
||||
import canonicalize from "canonicalize";
|
||||
|
||||
import { parseEvidenceBundle } from "./evidenceBundle.js";
|
||||
import { digestCanonicalValue } from "./canonicalDigest.js";
|
||||
import { authenticateParsedEvidenceBundle } from "./evidenceBundle.js";
|
||||
import { readinessFindingOrder } from "./reconstructionReadinessFindingHelpers.js";
|
||||
import {
|
||||
READINESS_STAGE_IDS,
|
||||
|
|
@ -24,7 +21,7 @@ export const createReconstructionReadinessReport = (
|
|||
const input = reconstructionReadinessInputSchema.parse(inputValue);
|
||||
const sourceDigest = digest(sourceValue(input));
|
||||
const evidenceIds = new Set(
|
||||
parseEvidenceBundle(input.evidence_bundle).records.map(
|
||||
authenticateParsedEvidenceBundle(input.evidence_bundle).records.map(
|
||||
({ evidence_id: evidenceId }) => evidenceId,
|
||||
),
|
||||
);
|
||||
|
|
@ -185,8 +182,5 @@ const ratio = (numerator: number, denominator: number): number =>
|
|||
denominator === 0 ? 1 : numerator / denominator;
|
||||
|
||||
const digest = (value: unknown): string => {
|
||||
const encoded = canonicalize(value);
|
||||
if (encoded === undefined)
|
||||
throw new TypeError("Reconstruction readiness value is not canonical JSON");
|
||||
return createHash("sha256").update(encoded).digest("hex");
|
||||
return digestCanonicalValue(value, "Reconstruction readiness");
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue