fix: restore contract-set regression coverage and mirror canonical problem bounds
release-manifest.test.ts's fixture derived manifest.contractSet.packages from EXPECTED_CONTRACT_SET_PACKAGES itself, so the equality it checked was satisfied by construction and CONTRACT_SET_PACKAGE_MISSING became unreachable from any test in the repo. Adds two independent checks: a literal (not derived) assertion that EXPECTED_CONTRACT_SET_PACKAGES really contains @tech-log/studio-contract@2.0.0, and a negative test with a manifest that omits a package the real expected set requires, asserting CONTRACT_SET_PACKAGE_MISSING. Confirmed the negative test has teeth by temporarily disabling the missing-package branch in verifyContractSet (src/contracts/contract-set.ts) and observing the test fail before reverting. Also narrows tech-log-studio-contract-contribution.ts's problemSchema to match canonical ProblemDetails exactly: title max 200 (was 240) and type unbounded (was max 512; canonical only constrains it as format: uri-reference). Both prior values were over-permissive, so no previously-accepted document is now rejected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
66c047cec8
commit
9313018ef5
@@ -47,8 +47,9 @@ const passthrough = <T>(schemaId: string) =>
|
|||||||
|
|
||||||
const problemSchema = z
|
const problemSchema = z
|
||||||
.object({
|
.object({
|
||||||
type: z.string().min(1).max(512),
|
// canonical: `format: uri-reference` only, no length bound.
|
||||||
title: z.string().min(1).max(240),
|
type: z.string().min(1),
|
||||||
|
title: z.string().min(1).max(200),
|
||||||
status: z.int().min(400).max(599),
|
status: z.int().min(400).max(599),
|
||||||
detail: z.string().min(1).max(5000),
|
detail: z.string().min(1).max(5000),
|
||||||
code: z.enum(STUDIO_ERROR_CODES as unknown as [string, ...string[]]),
|
code: z.enum(STUDIO_ERROR_CODES as unknown as [string, ...string[]]),
|
||||||
|
|||||||
@@ -96,6 +96,26 @@ function jsonResponse(body: unknown): Response {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Round 2 review finding: a fixture built entirely from
|
||||||
|
* `EXPECTED_CONTRACT_SET_PACKAGES` proves the manifest matches itself, not
|
||||||
|
* that composition actually produced the TechLog package. This assertion is
|
||||||
|
* independent of that derivation — the expected value is a literal written
|
||||||
|
* here, not read back from `EXPECTED_PACKAGES`/`EXPECTED_SET_DIGEST` above —
|
||||||
|
* so if the unconditional install in `installed-contract-contributions.ts`
|
||||||
|
* is ever reverted and `EXPECTED_CONTRACT_SET_PACKAGES` silently shrinks to
|
||||||
|
* empty, this fails on its own regardless of what the fixture below does.
|
||||||
|
*/
|
||||||
|
describe("expected contract set composition", () => {
|
||||||
|
it("actually contains the TechLog Studio contract, not just an empty set matching itself", () => {
|
||||||
|
const techLog = EXPECTED_CONTRACT_SET_PACKAGES.find(
|
||||||
|
(entry) => entry.packageId === "@tech-log/studio-contract",
|
||||||
|
);
|
||||||
|
expect(techLog).toBeTruthy();
|
||||||
|
expect(techLog?.version).toBe("2.0.0");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("release manifest boot boundary", () => {
|
describe("release manifest boot boundary", () => {
|
||||||
it("loads a coherent release tuple", async () => {
|
it("loads a coherent release tuple", async () => {
|
||||||
await expect(
|
await expect(
|
||||||
@@ -192,6 +212,33 @@ describe("release manifest boot boundary", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Round 2 review finding: deriving the fixture's `contractSet.packages`
|
||||||
|
* from `EXPECTED_CONTRACT_SET_PACKAGES` made `CONTRACT_SET_PACKAGE_MISSING`
|
||||||
|
* unreachable from any test — the equality was satisfied by construction.
|
||||||
|
* This restores that failure path with an independently built manifest
|
||||||
|
* that omits a package the real expected set actually requires, mirroring
|
||||||
|
* the shape of "rejects a contract set the build did not compile" above.
|
||||||
|
*/
|
||||||
|
it("rejects a manifest that omits a package the build actually compiled in", async () => {
|
||||||
|
await expect(
|
||||||
|
loadReleaseManifest(runtime, {
|
||||||
|
fetcher: async () =>
|
||||||
|
jsonResponse({
|
||||||
|
...manifest,
|
||||||
|
contractSet: {
|
||||||
|
setAlgorithm: "CA_CONTRACT_SET_V1",
|
||||||
|
setDigest: EMPTY_SET_DIGEST,
|
||||||
|
packages: [],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
).rejects.toMatchObject({
|
||||||
|
kind: "CONTRACT_SET_MISMATCH",
|
||||||
|
code: "CONTRACT_SET_PACKAGE_MISSING",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("still reads a V1 manifest during the compatibility window", async () => {
|
it("still reads a V1 manifest during the compatibility window", async () => {
|
||||||
await expect(
|
await expect(
|
||||||
loadReleaseManifest(
|
loadReleaseManifest(
|
||||||
|
|||||||
Reference in New Issue
Block a user