test: gate the dev release manifest against the compiled contract set
Nothing in the gate set read `public/*.json`. Every static gate passed and the whole suite passed while `pnpm dev` rendered the boot-error screen instead of the app, which is the only reason the drift survived two contract changes. `check:dev-release-manifest` compares the fixture's `setAlgorithm`, `setDigest` and package set against what `generate-contract-set.ts` composes, and is registered on FE-GATE-010 next to `check-tech-log-contract` so CI executes it. Unlike the refresh wired into contract generation, this observes the composed set directly, so it also catches a contribution added to or removed from `installed-contract-contributions.ts`. `CANONICAL_GATE_SHAPE_SHA256` recomputed by hand, as always: the committed constant 98d19911... was first reproduced from the committed `gates.json` with an independent transcription of `canonicalGateShapeSha256`, and only then was b4096244... hashed from the new one. Command counts move 84/96 -> 85/97; artifacts stay at 130 because the gate publishes no evidence file, matching `check-tech-log-contract`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b75c9d0956
commit
4090c8681d
@@ -0,0 +1,82 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
DEV_RELEASE_MANIFEST_PATH,
|
||||
checkDevReleaseManifestContractSet,
|
||||
compareDevReleaseManifestContractSet,
|
||||
expectedDevReleaseManifestContractSet,
|
||||
readDevReleaseManifest,
|
||||
} from "../../scripts/lib/dev-release-manifest.ts";
|
||||
|
||||
/**
|
||||
* `corepack pnpm dev` serves `public/release-manifest.json` verbatim and
|
||||
* `verifyContractSet` runs unconditionally at boot, so a fixture that does not
|
||||
* declare the compiled contract set is a hard `pnpm dev` boot failure in the
|
||||
* default `MOCK` mode. Nothing else in the gate set reads `public/*.json`.
|
||||
*/
|
||||
describe("dev release manifest contract set", () => {
|
||||
it("declares exactly the contract set the build compiles", async () => {
|
||||
await expect(checkDevReleaseManifestContractSet()).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps the fixture algorithm and digest identical to the compiled set", async () => {
|
||||
const document = await readDevReleaseManifest();
|
||||
const expected = expectedDevReleaseManifestContractSet();
|
||||
expect(document["contractSet"]).toEqual(expected);
|
||||
expect(expected.packages.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("reports the missing package that fails boot closed", () => {
|
||||
const expected = expectedDevReleaseManifestContractSet();
|
||||
const failures = compareDevReleaseManifestContractSet(
|
||||
{ ...expected, packages: [] },
|
||||
expected,
|
||||
);
|
||||
expect(failures.join("\n")).toMatch(/CONTRACT_SET_PACKAGE_MISSING/u);
|
||||
});
|
||||
|
||||
it("reports a stale set digest", () => {
|
||||
const expected = expectedDevReleaseManifestContractSet();
|
||||
const failures = compareDevReleaseManifestContractSet(
|
||||
{ ...expected, setDigest: `sha256:${"a".repeat(64)}` },
|
||||
expected,
|
||||
);
|
||||
expect(failures.join("\n")).toMatch(/setDigest drift/u);
|
||||
});
|
||||
|
||||
it("reports a package the manifest declares but the build never compiled", () => {
|
||||
const expected = expectedDevReleaseManifestContractSet();
|
||||
const stranger = {
|
||||
packageId: "@tech-log/not-installed",
|
||||
version: "1.0.0",
|
||||
digest: `sha256:${"0".repeat(64)}` as const,
|
||||
runtimeProtocolVersion: 1 as const,
|
||||
sourceRevision: "abcdef0",
|
||||
};
|
||||
const failures = compareDevReleaseManifestContractSet(
|
||||
{ ...expected, packages: [...expected.packages, stranger] },
|
||||
expected,
|
||||
);
|
||||
expect(failures.join("\n")).toMatch(/CONTRACT_SET_PACKAGE_UNEXPECTED/u);
|
||||
});
|
||||
|
||||
it("reports a stale version left behind by a regenerated contract", () => {
|
||||
const expected = expectedDevReleaseManifestContractSet();
|
||||
const [first] = expected.packages;
|
||||
expect(first).toBeDefined();
|
||||
const failures = compareDevReleaseManifestContractSet(
|
||||
{ ...expected, packages: [{ ...first!, version: "999.0.0" }] },
|
||||
expected,
|
||||
);
|
||||
expect(failures.join("\n")).toMatch(/package drift for/u);
|
||||
});
|
||||
|
||||
it("rejects a fixture whose contractSet block is absent altogether", () => {
|
||||
const failures = compareDevReleaseManifestContractSet(
|
||||
undefined,
|
||||
expectedDevReleaseManifestContractSet(),
|
||||
);
|
||||
expect(failures).toHaveLength(1);
|
||||
expect(failures[0]).toContain(DEV_RELEASE_MANIFEST_PATH);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user