Spaces:
Running
Running
File size: 9,122 Bytes
518343a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | /**
* th1_composition.test.ts
*
* Vitest tests for the Lutar.Composition.TH1_Composition gate.
*
* Tests:
* 1. 1000-input random doctrine preservation test
* 2. Lattice order (labelLE) edge cases
* 3. Compatible / incompatible system pairs
* 4. composeList across all label combinations
* 5. Receipt emission with mock signer
*
* Lean commit: c4d13795689601324fce0236351bfe0ade990a43
*/
import { describe, it, expect } from "vitest";
import {
labelLE,
doctrinePredicate,
isDoctrineLockedSystem,
compatible,
compose,
composeList,
verifyCompositionPreservesDoctrine,
emitTH1CompositionReceipt,
th1CompositionGate,
type LutarSystem,
type DoctrineLabel,
type Signer,
} from "../../src/gates/th1_composition";
// ---------------------------------------------------------------------------
// Seeded LCG
// ---------------------------------------------------------------------------
function seedRandom(seed: number) {
let s = seed >>> 0;
return () => {
s = (Math.imul(1664525, s) + 1013904223) >>> 0;
return s / 0x100000000;
};
}
const LABELS: DoctrineLabel[] = ["Bot", "L1", "L2", "Top"];
function pickLabel(rand: () => number): DoctrineLabel {
return LABELS[Math.floor(rand() * 4)];
}
const mockSigner: Signer = (p: string) =>
`mock-sig::${Buffer.from(p).slice(0, 16).toString("hex")}`;
// ---------------------------------------------------------------------------
// 1. 1000-input random doctrine preservation test
// ---------------------------------------------------------------------------
describe("th1_composition: 1000-input random composition_preserves_doctrine", () => {
it("composed system is doctrine-locked for all valid compatible pairs", () => {
const rand = seedRandom(0xabcdef12);
let failures = 0;
for (let i = 0; i < 1000; i++) {
const th = pickLabel(rand);
// Build valid S1: threshold ≤ inputLabel ≤ outputLabel, threshold ≤ outputLabel
const thRank = ["Bot", "L1", "L2", "Top"].indexOf(th);
const validLabels = LABELS.slice(thRank); // all labels ≥ th
if (validLabels.length < 2) continue;
const inLabel1 = validLabels[Math.floor(rand() * validLabels.length)];
const inRank1 = LABELS.indexOf(inLabel1);
const validOut1 = LABELS.slice(Math.max(inRank1, thRank));
const outLabel1 = validOut1[Math.floor(rand() * validOut1.length)];
// S2 must have inputLabel ≥ outLabel1
const s2MinInRank = LABELS.indexOf(outLabel1);
const validIn2 = LABELS.slice(Math.max(s2MinInRank, thRank));
if (validIn2.length === 0) continue;
const inLabel2 = validIn2[Math.floor(rand() * validIn2.length)];
const inRank2 = LABELS.indexOf(inLabel2);
const validOut2 = LABELS.slice(Math.max(inRank2, thRank));
const outLabel2 = validOut2[Math.floor(rand() * validOut2.length)];
const s1: LutarSystem = { threshold: th, inputLabel: inLabel1, outputLabel: outLabel1 };
const s2: LutarSystem = { threshold: th, inputLabel: inLabel2, outputLabel: outLabel2 };
if (!verifyCompositionPreservesDoctrine(s1, s2)) failures++;
}
expect(failures).toBe(0);
});
});
// ---------------------------------------------------------------------------
// 2. Lattice order (labelLE) edge cases
// ---------------------------------------------------------------------------
describe("th1_composition: labelLE lattice order", () => {
it("labelLE is reflexive", () => {
for (const l of LABELS) {
expect(labelLE(l, l)).toBe(true);
}
});
it("labelLE is transitive", () => {
const pairs: [DoctrineLabel, DoctrineLabel, DoctrineLabel][] = [
["Bot", "L1", "L2"],
["Bot", "L1", "Top"],
["Bot", "L2", "Top"],
["L1", "L2", "Top"],
];
for (const [a, b, c] of pairs) {
expect(labelLE(a, b) && labelLE(b, c) && labelLE(a, c)).toBe(true);
}
});
it("Bot ≤ everything", () => {
for (const l of LABELS) expect(labelLE("Bot", l)).toBe(true);
});
it("everything ≤ Top", () => {
for (const l of LABELS) expect(labelLE(l, "Top")).toBe(true);
});
it("L2 > L1 (not L2 ≤ L1)", () => {
expect(labelLE("L2", "L1")).toBe(false);
});
it("Top > L2 (not Top ≤ L2)", () => {
expect(labelLE("Top", "L2")).toBe(false);
});
});
// ---------------------------------------------------------------------------
// 3. Compatible / incompatible system pairs
// ---------------------------------------------------------------------------
describe("th1_composition: compatible and compose", () => {
it("compatible: L1 output → L1 input → true", () => {
const s1: LutarSystem = { threshold: "Bot", inputLabel: "Bot", outputLabel: "L1" };
const s2: LutarSystem = { threshold: "Bot", inputLabel: "L1", outputLabel: "L2" };
expect(compatible(s1, s2)).toBe(true);
});
it("incompatible: L2 output → L1 input → false", () => {
const s1: LutarSystem = { threshold: "Bot", inputLabel: "Bot", outputLabel: "L2" };
const s2: LutarSystem = { threshold: "Bot", inputLabel: "L1", outputLabel: "L2" };
expect(compatible(s1, s2)).toBe(false);
});
it("compose produces correct input/output labels", () => {
const s1: LutarSystem = { threshold: "L1", inputLabel: "L1", outputLabel: "L2" };
const s2: LutarSystem = { threshold: "L1", inputLabel: "L2", outputLabel: "Top" };
const result = compose(s1, s2);
expect(result.inputLabel).toBe("L1");
expect(result.outputLabel).toBe("Top");
expect(result.threshold).toBe("L1");
});
it("compose throws on threshold mismatch", () => {
const s1: LutarSystem = { threshold: "L1", inputLabel: "L1", outputLabel: "L2" };
const s2: LutarSystem = { threshold: "L2", inputLabel: "L2", outputLabel: "Top" };
expect(() => compose(s1, s2)).toThrow("threshold mismatch");
});
it("compose throws when incompatible (output > input)", () => {
const s1: LutarSystem = { threshold: "Bot", inputLabel: "Bot", outputLabel: "L2" };
const s2: LutarSystem = { threshold: "Bot", inputLabel: "L1", outputLabel: "L2" };
expect(() => compose(s1, s2)).toThrow("incompatible");
});
});
// ---------------------------------------------------------------------------
// 4. composeList
// ---------------------------------------------------------------------------
describe("th1_composition: composeList", () => {
it("composeList of single system returns it unchanged", () => {
const s: LutarSystem = { threshold: "L1", inputLabel: "L1", outputLabel: "L2" };
const result = composeList([s]);
expect(result).toEqual(s);
});
it("composeList of chain [Bot→L1] → [L1→L2] → [L2→Top]", () => {
const chain: LutarSystem[] = [
{ threshold: "Bot", inputLabel: "Bot", outputLabel: "L1" },
{ threshold: "Bot", inputLabel: "L1", outputLabel: "L2" },
{ threshold: "Bot", inputLabel: "L2", outputLabel: "Top" },
];
const result = composeList(chain);
expect(result.inputLabel).toBe("Bot");
expect(result.outputLabel).toBe("Top");
expect(isDoctrineLockedSystem(result)).toBe(true);
});
it("composeList throws on empty list", () => {
expect(() => composeList([])).toThrow("empty list");
});
});
// ---------------------------------------------------------------------------
// 5. Receipt emission
// ---------------------------------------------------------------------------
describe("th1_composition: DSSE receipt emission", () => {
const s1: LutarSystem = { threshold: "L1", inputLabel: "L1", outputLabel: "L2" };
const s2: LutarSystem = { threshold: "L1", inputLabel: "L2", outputLabel: "Top" };
it("emits receipt with correct theorem and commit SHA", () => {
const receipt = emitTH1CompositionReceipt(s1, s2, mockSigner);
expect(receipt.theorem).toBe(
"Lutar.Composition.composition_preserves_doctrine"
);
expect(receipt.lean_commit_sha).toBe("c4d13795689601324fce0236351bfe0ade990a43");
expect(receipt.output).toBe(true);
expect(receipt.inputs_hash).toMatch(/^[0-9a-f]{64}$/);
expect(receipt.sig).toContain("mock-sig::");
});
it("receipt output = false for incompatible systems", () => {
const bad: LutarSystem = { threshold: "L1", inputLabel: "L1", outputLabel: "L1" };
const incompatible: LutarSystem = { threshold: "L1", inputLabel: "L2", outputLabel: "Top" };
const receipt = emitTH1CompositionReceipt(bad, incompatible, mockSigner);
expect(receipt.output).toBe(false);
});
it("gate returns composedSystem and doctrinePreserved=true", () => {
const { composedSystem, doctrinePreserved, receipt } = th1CompositionGate(s1, s2, mockSigner);
expect(composedSystem).not.toBeNull();
expect(composedSystem?.inputLabel).toBe("L1");
expect(composedSystem?.outputLabel).toBe("Top");
expect(doctrinePreserved).toBe(true);
expect(receipt.output).toBe(true);
});
it("deterministic inputs_hash", () => {
const r1 = emitTH1CompositionReceipt(s1, s2, mockSigner);
const r2 = emitTH1CompositionReceipt(s1, s2, mockSigner);
expect(r1.inputs_hash).toBe(r2.inputs_hash);
});
});
|