Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/openapi-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ restart with the remaining valid catalogs. Config requires at least one catalog;
leave the server stopped if disabling the last one. Removing a file while the
process is using it is not a reliable disable procedure.

## Complete release admission

`admitCatalogRelease(options, catalogId, releaseId)` from
`@knitli/openapi-mcp/runtime` verifies every signed inventory operation and
schema before admitting the generation through the configured `GenerationStore`.
It revalidates the manifest and inventory around generation CAS retries. Use
this supported portable API when activating an executable catalog; `admitManifest`
retains its signed-envelope-only contract. Storage must preserve immutable release
identities. Admission does not guarantee future availability, so runtime reads
continue verifying records at use time.

## Recover from a bad release

Before release, record the prior **observed package version**, its tarball digest,
Expand Down
24 changes: 24 additions & 0 deletions packages/openapi-mcp/src/runtime/admission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { AdmittedManifest } from "./manifest.ts";
import {
admitExecutableRelease,
type OpenApiRuntimeOptions,
verifyExecutableRelease,
} from "./runtime.ts";
import type { CatalogId, ReleaseId } from "./types.ts";

/** Verify the complete release inventory before atomically admitting its generation.
* Storage must preserve immutable release identities; later runtime reads still
* verify records because this check cannot guarantee future storage availability.
*/
export async function admitCatalogRelease(
options: OpenApiRuntimeOptions,
catalogId: CatalogId,
releaseId: ReleaseId,
): Promise<AdmittedManifest> {
const preflight = await verifyExecutableRelease(
options,
catalogId,
releaseId,
);
return admitExecutableRelease(options, preflight);
}
1 change: 1 addition & 0 deletions packages/openapi-mcp/src/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type { ActionDispatchPermit } from "./action-permit.ts";
export { admitCatalogRelease } from "./admission.ts";
export {
classifyOperation,
type OperationClassification,
Expand Down
7 changes: 6 additions & 1 deletion packages/openapi-mcp/test-consumers/node.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { runRuntimeConformanceSuite } from "@knitli/openapi-mcp/conformance";
import {
ARTIFACT_FORMAT_VERSION,
type AuthorizedTransport,
admitCatalogRelease,
admitManifest,
type CredentialSnapshot,
canonicalJson,
Expand Down Expand Up @@ -146,7 +147,11 @@ try {
);
assert.ok(envelope);
assert.ok(nextEnvelope);
const admitted = await admitManifest(envelope, trust, generations);
const admitted = await admitCatalogRelease(
{ store, trust, generations },
prior.manifest.catalogId,
prior.manifest.releaseId,
);
const runtime = createOpenApiRuntime({
store,
trust,
Expand Down
2 changes: 2 additions & 0 deletions packages/openapi-mcp/test-consumers/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
} from "@knitli/openapi-mcp/runtime";
import {
ARTIFACT_FORMAT_VERSION,
admitCatalogRelease,
createD1CatalogStore,
PREPARED_CALL_VERSION,
RUNTIME_CONTRACT_VERSION,
Expand Down Expand Up @@ -100,6 +101,7 @@ type _workerConformanceAdapter = Assert<
>;

export const portableContract = [
admitCatalogRelease,
ARTIFACT_FORMAT_VERSION,
PREPARED_CALL_VERSION,
RUNTIME_CONTRACT_VERSION,
Expand Down
Loading