Registers the TECH_LOG_STUDIO_SESSION SAME_ORIGIN_COOKIE auth profile and declares the tech-log-studio-http-v1 contribution covering all 18 JSON Studio operations (everything except the multipart uploadStudioAsset), built from two shared builders (safeOperation/keyedOperation) so every KEYED command gets IDEMPOTENCY_REPLAY recovery and a zero retry budget, and every SAFE read gets a plain retry budget, without repeating the declaration shape 18 times. Rescopes the canonical package identity from "tech-log-studio-contract" to "@tech-log/studio-contract" (generator, canonical-source.json, contract-generation.test.ts) because the platform's contribution composer requires an npm-scoped packageId; the unscoped form failed composition. Updates the release-manifest test fixture, which hardcoded an empty expected contract set, to derive its expected packages from the real installed set now that TechLog is always installed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "vitest";
|
|
|
|
import canonicalSource from "../../../src/features/tech-log/contracts/studio/canonical-source.json" with { type: "json" };
|
|
import {
|
|
TECH_LOG_STUDIO_CONTRIBUTION,
|
|
TECH_LOG_STUDIO_OPERATION_IDS,
|
|
} from "../../../src/features/tech-log/contracts/tech-log-studio-contract-contribution.ts";
|
|
import { composeContractContributions } from "../../../src/contracts/external-contract-runtime.ts";
|
|
|
|
const UPLOAD = "uploadStudioAsset";
|
|
|
|
test("declares every canonical operation except the multipart upload", () => {
|
|
const expected = canonicalSource.operationIds.filter((id) => id !== UPLOAD);
|
|
assert.equal(expected.length, 18);
|
|
assert.deepEqual(
|
|
[...TECH_LOG_STUDIO_OPERATION_IDS].sort(),
|
|
[...expected].sort(),
|
|
);
|
|
});
|
|
|
|
test("pins the canonical digest and revision as external package provenance", () => {
|
|
const source = TECH_LOG_STUDIO_CONTRIBUTION.source;
|
|
assert.equal(source.kind, "EXTERNAL_PACKAGE");
|
|
if (source.kind !== "EXTERNAL_PACKAGE") return;
|
|
assert.equal(source.package.packageId, canonicalSource.packageId);
|
|
assert.equal(source.package.version, canonicalSource.version);
|
|
assert.equal(source.package.digest, canonicalSource.digest);
|
|
assert.equal(source.package.sourceRevision, canonicalSource.sourceRevision);
|
|
assert.equal(source.package.runtimeProtocolVersion, 1);
|
|
});
|
|
|
|
test("composes without violating the platform contract runtime", () => {
|
|
const composed = composeContractContributions([TECH_LOG_STUDIO_CONTRIBUTION]);
|
|
assert.equal(composed.externalPackages.length, 1);
|
|
});
|
|
|
|
test("every mutating operation replays by idempotency key and never auto-retries", () => {
|
|
for (const entry of TECH_LOG_STUDIO_CONTRIBUTION.http) {
|
|
if (entry.contract.retrySemantics !== "KEYED") continue;
|
|
assert.deepEqual(
|
|
entry.contract.commandRecovery,
|
|
{
|
|
mode: "IDEMPOTENCY_REPLAY",
|
|
operationIdentityField: "idempotencyKey",
|
|
},
|
|
`${entry.contract.operationId} recovery`,
|
|
);
|
|
assert.equal(
|
|
entry.frontend.retryBudget,
|
|
0,
|
|
`${entry.contract.operationId} budget`,
|
|
);
|
|
}
|
|
});
|
|
|
|
test("path templates match the canonical /api/v1/studio prefix", () => {
|
|
for (const entry of TECH_LOG_STUDIO_CONTRIBUTION.http) {
|
|
assert.ok(
|
|
entry.contract.pathTemplate.startsWith("/api/v1/studio/"),
|
|
`${entry.contract.operationId}: ${entry.contract.pathTemplate}`,
|
|
);
|
|
}
|
|
});
|