feat: harden test and registry evidence

This commit is contained in:
donghyeon-ka
2026-07-26 17:15:26 +09:00
parent 3f634eb655
commit 98d4fd4960
68 changed files with 6167 additions and 250 deletions
+102
View File
@@ -0,0 +1,102 @@
import { describe, expect, it } from "vitest";
import {
canonicalRegistryJson,
diffRegistrySnapshots,
registrySnapshotDigest,
validateBreakingEvidence,
verifyRegistryBaselineApproval,
} from "../../scripts/lib/registry-compatibility.mjs";
function snapshot(
rows: Readonly<Record<string, Readonly<Record<string, unknown>>>>,
) {
return {
schemaVersion: 2,
registries: [
{
registryId: "FE-REG-TEST",
contract: { breakingFields: ["path"] },
rows,
},
],
};
}
describe("registry compatibility evidence", () => {
it("canonicalizes object and primitive-array ordering", () => {
expect(
canonicalRegistryJson({
second: ["b", "a"],
first: { z: 1, a: 2 },
}),
).toBe('{"first":{"a":2,"z":1},"second":["a","b"]}');
});
it("classifies additive, behavioral and breaking actual diffs", () => {
expect(
diffRegistrySnapshots(
snapshot({ A: { path: "/a" } }),
snapshot({ A: { path: "/a" }, B: { path: "/b" } }),
).impact,
).toBe("additive");
expect(
diffRegistrySnapshots(
snapshot({ A: { path: "/a", owner: "one" } }),
snapshot({ A: { path: "/a", owner: "two" } }),
).impact,
).toBe("behavior-change");
expect(
diffRegistrySnapshots(
snapshot({ A: { path: "/a" } }),
snapshot({ A: { path: "/moved" } }),
).impact,
).toBe("breaking");
expect(
diffRegistrySnapshots(
snapshot({ A: { path: "/a" } }),
snapshot({}),
).impact,
).toBe("breaking");
});
it("verifies the approved digest and complete breaking evidence", () => {
const before = snapshot({ A: { path: "/before" } });
const after = snapshot({ A: { path: "/after" } });
const digest = registrySnapshotDigest(before);
expect(
verifyRegistryBaselineApproval(before, {
schemaVersion: 1,
snapshotDigest: digest,
owner: "platform",
approvedAt: "2026-07-26T00:00:00.000Z",
}).passed,
).toBe(true);
expect(
verifyRegistryBaselineApproval(before, {
schemaVersion: 1,
snapshotDigest: "tampered",
owner: "platform",
approvedAt: "2026-07-26T00:00:00.000Z",
}).passed,
).toBe(false);
const diff = diffRegistrySnapshots(before, after);
expect(validateBreakingEvidence(diff, { changes: [] }).passed).toBe(false);
const changeId = diff.changes[0]?.changeId;
expect(
validateBreakingEvidence(diff, {
changes: [
{
changeId,
versionBump: "2",
migration: "dual-read",
compatibilityWindow: "one release",
rollback: "restore previous registry snapshot",
owner: "platform",
},
],
}).passed,
).toBe(true);
});
});
+18 -10
View File
@@ -2,24 +2,32 @@ import { readFile } from "node:fs/promises";
import { describe, expect, it } from "vitest";
describe("registry governance manifest", () => {
it("declares exactly nine single-owner registries and impact labels", async () => {
it("declares ten typed, single-owner executable registries", async () => {
const governance = JSON.parse(
await readFile("config/contracts/registry-governance.json", "utf8"),
);
const registries =
/** @type {Array<{registryId: string, owner: string}>} */ (
/** @type {Array<{
* registryId: string,
* owner: string,
* requiredFields: string[],
* fieldTypes: Record<string, string>
* }>} */ (
governance.registries
);
expect(governance.registries).toHaveLength(9);
expect(governance.registries).toHaveLength(10);
expect(new Set(registries.map((entry) => entry.registryId)).size).toBe(
9,
10,
);
expect(registries.every((entry) => entry.owner)).toBe(true);
expect(governance.compatibilityImpact.allowed).toEqual([
"none",
"additive",
"behavior-change",
"breaking",
]);
expect(
registries.every(
(entry) =>
Array.isArray(entry.requiredFields) &&
entry.requiredFields.length > 0 &&
entry.fieldTypes &&
Object.keys(entry.fieldTypes).length > 0,
),
).toBe(true);
});
});