From c2fcd754ee54c9f2bc07ea7ce1132bcbeeb72856 Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 09:55:08 -0400 Subject: [PATCH 1/6] =?UTF-8?q?feat(spec):=20console-management=20operatio?= =?UTF-8?q?ns=20=E2=80=94=20pricing=20manifests,=20custody,=20engine=20cap?= =?UTF-8?q?abilities,=20gpu=20infer/status=20(rendering-completeness-epic?= =?UTF-8?q?=20P3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MCP product-tool plane is a DERIVED projection (openapi-spec ops ∩ enforcedV1Groups) — spec-coverage is the bottleneck, so these four paths/ops unlock derived wave_* tools: - /pricing/manifests GET+POST (pricing:read/write) — shapes from src/pricing-manifests.ts - /custody/{op} POST grant|revoke|inspect|exercise (custody:write, operator-plane) — from src/capability-custody.ts (receipt-only responses; secrets never in payloads) - /engine/capabilities GET (engine:read) — media-engine capability contract - /gpu/infer POST + GET status (gpu:read/write) — wave-gpu-edge EXCLUDED with receipts: members (console-plane — Supabase org_members behind the session, NOT a gateway-enforced group; the derivation would drop it) and mail/timeline (spoke-direct, mail is not in EDGE_SPOKE_GROUPS so /v1/mail is not gateway-enforced). Gateway deploy follows the merge; the derived tool list regenerates on deploy. --- openapi.yaml | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index da8ade7..9714301 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2043,6 +2043,185 @@ paths: '429': $ref: '#/components/responses/RateLimitError' + /pricing/manifests: + get: + tags: [Pricing] + summary: List the caller-org's pricing tier manifests + operationId: pricingManifestsList + description: | + Gateway-native read (pricing-pages E0). Returns every pricing manifest the + authenticated org has published, newest-first. Requires `pricing:read`. + Org is the VALIDATED principal only — no cross-org reads. + responses: + '200': + description: The org's manifests + content: + application/json: + schema: + type: object + required: [org, manifests] + properties: + org: { type: string } + manifests: + type: array + items: { $ref: '#/components/schemas/PricingManifest' } + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + post: + tags: [Pricing] + summary: Validate + upsert the caller-org's tier manifest + operationId: pricingManifestsCreate + description: | + Gateway-native write (pricing-pages E0). Validates the tier manifest against the + rail law server-side and upserts it for the caller-org. Requires `pricing:write`. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [slug, tiers] + properties: + slug: { type: string } + tiers: { type: array, items: { type: object, additionalProperties: true } } + responses: + '200': + description: The upserted manifest + content: + application/json: + schema: { $ref: '#/components/schemas/PricingManifest' } + '400': + description: Manifest fails the rail-law validation + content: + application/json: + schema: { $ref: '#/components/schemas/ValidationError' } + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + + /custody/{op}: + post: + tags: [Custody] + summary: Held-fund capability operation (grant / revoke / inspect / exercise) + operationId: custodyOperation + description: | + The money-engine custody surface (capability-custody). `op` is one of + grant | revoke | inspect | exercise. Every operation is scoped to the + authenticated principal's org; grants persist METADATA in the CapabilityAccount DO and + the secret envelope ciphertext-only in KV (crypto-shreddable on revoke). Requires + `custody:write` — deliberately NOT in UNIFORM_CUSTOMER_SCOPES (operator-plane). + parameters: + - name: op + in: path + required: true + description: The custody operation + schema: { type: string, enum: [grant, revoke, inspect, exercise] } + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [grantId] + properties: + grantId: { type: string } + provider: { type: string } + scopes: { type: array, items: { type: string } } + ttlSeconds: { type: number } + responses: + '200': + description: The operation receipt (metadata only — never a secret field) + content: + application/json: + schema: + type: object + additionalProperties: true + '400': + description: INVALID_JSON / unknown op / bad grant id + content: + application/json: + schema: { $ref: '#/components/schemas/ValidationError' } + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '503': + description: CUSTODY_UNCONFIGURED — bindings/flag absent + content: + application/json: + schema: { $ref: '#/components/schemas/ValidationError' } + + /engine/capabilities: + get: + tags: [Engine] + summary: The media-engine capability contract + operationId: engineCapabilities + description: | + Served by wave-media-engine (engine.wave.online) through the gateway (engine:read). + Returns the engine's capability JSON — the codecs/operations this deployment accepts. + responses: + '200': + description: The capability contract + content: + application/json: + schema: + type: object + additionalProperties: true + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + + /gpu/infer: + post: + tags: [Gpu] + summary: Dispatch a GPU inference job on the WAVE-hosted GPU plane + operationId: gpuInfer + description: | + wave-gpu-edge (Phase C, RunPod-backed). Requires `gpu:write`. The gateway stamps + x-wave-gateway-secret; the edge emits x-wave-meter: wave_edge_gpu_hours billed verbatim. + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + model: { type: string } + input: { type: object, additionalProperties: true } + responses: + '200': + description: The job receipt + content: + application/json: + schema: + type: object + additionalProperties: true + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + get: + tags: [Gpu] + summary: GPU plane status + operationId: gpuStatus + description: Requires `gpu:read`. + responses: + '200': + description: Plane status + content: + application/json: + schema: + type: object + additionalProperties: true + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + components: securitySchemes: BearerAuth: @@ -3921,6 +4100,26 @@ components: additionalProperties: true description: Scheme-specific metadata (e.g. settlement mode, session id). + PricingManifest: + type: object + properties: + slug: { type: string } + org: { type: string } + tiers: { type: array, items: { type: object, additionalProperties: true } } + createdAt: { type: string } + updatedAt: { type: string } + additionalProperties: true + + ValidationError: + type: object + properties: + ok: { type: boolean } + error: + type: object + properties: + code: { type: string } + message: { type: string } + IdentityResolveResponse: description: > The resolved fleet directory entry, DISCRIMINATED on the outer `agent` value: From 76146bf91cc34515dab7d032fec972774aaa9220 Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 10:01:10 -0400 Subject: [PATCH 2/6] chore: regenerate api-types.d.ts for the new console-management ops (the sdk-types gate compares the committed artifact) --- generated/api-types.d.ts | 315 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/generated/api-types.d.ts b/generated/api-types.d.ts index 8c5aef5..31d9833 100644 --- a/generated/api-types.d.ts +++ b/generated/api-types.d.ts @@ -910,6 +910,103 @@ export interface paths { patch?: never; trace?: never; }; + "/pricing/manifests": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List the caller-org's pricing tier manifests + * @description Gateway-native read (pricing-pages E0). Returns every pricing manifest the + * authenticated org has published, newest-first. Requires `pricing:read`. + * Org is the VALIDATED principal only — no cross-org reads. + */ + get: operations["pricingManifestsList"]; + put?: never; + /** + * Validate + upsert the caller-org's tier manifest + * @description Gateway-native write (pricing-pages E0). Validates the tier manifest against the + * rail law server-side and upserts it for the caller-org. Requires `pricing:write`. + */ + post: operations["pricingManifestsCreate"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/custody/{op}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Held-fund capability operation (grant / revoke / inspect / exercise) + * @description The money-engine custody surface (capability-custody). `op` is one of + * grant | revoke | inspect | exercise. Every operation is scoped to the + * authenticated principal's org; grants persist METADATA in the CapabilityAccount DO and + * the secret envelope ciphertext-only in KV (crypto-shreddable on revoke). Requires + * `custody:write` — deliberately NOT in UNIFORM_CUSTOMER_SCOPES (operator-plane). + */ + post: operations["custodyOperation"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/engine/capabilities": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * The media-engine capability contract + * @description Served by wave-media-engine (engine.wave.online) through the gateway (engine:read). + * Returns the engine's capability JSON — the codecs/operations this deployment accepts. + */ + get: operations["engineCapabilities"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/gpu/infer": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * GPU plane status + * @description Requires `gpu:read`. + */ + get: operations["gpuStatus"]; + put?: never; + /** + * Dispatch a GPU inference job on the WAVE-hosted GPU plane + * @description wave-gpu-edge (Phase C, RunPod-backed). Requires `gpu:write`. The gateway stamps + * x-wave-gateway-secret; the edge emits x-wave-meter: wave_edge_gpu_hours billed verbatim. + */ + post: operations["gpuInfer"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { @@ -1853,6 +1950,24 @@ export interface components { [key: string]: unknown; }; }; + PricingManifest: { + slug?: string; + org?: string; + tiers?: { + [key: string]: unknown; + }[]; + createdAt?: string; + updatedAt?: string; + } & { + [key: string]: unknown; + }; + ValidationError: { + ok?: boolean; + error?: { + code?: string; + message?: string; + }; + }; /** @description The resolved fleet directory entry, DISCRIMINATED on the outer `agent` value: `agent: "telephony"` serves the TelephonyResolveResponse variant; every other directory key serves the AgentResolveResponse variant. Generated clients can narrow on `agent`. */ IdentityResolveResponse: components["schemas"]["AgentResolveResponse"] | components["schemas"]["TelephonyResolveResponse"]; AgentResolveResponse: { @@ -4013,4 +4128,204 @@ export interface operations { 429: components["responses"]["RateLimitError"]; }; }; + pricingManifestsList: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The org's manifests */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + org: string; + manifests: components["schemas"]["PricingManifest"][]; + }; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + }; + }; + pricingManifestsCreate: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + slug: string; + tiers: { + [key: string]: unknown; + }[]; + }; + }; + }; + responses: { + /** @description The upserted manifest */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PricingManifest"]; + }; + }; + /** @description Manifest fails the rail-law validation */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ValidationError"]; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + }; + }; + custodyOperation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The custody operation */ + op: "grant" | "revoke" | "inspect" | "exercise"; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + grantId: string; + provider?: string; + scopes?: string[]; + ttlSeconds?: number; + }; + }; + }; + responses: { + /** @description The operation receipt (metadata only — never a secret field) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: unknown; + }; + }; + }; + /** @description INVALID_JSON / unknown op / bad grant id */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ValidationError"]; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + /** @description CUSTODY_UNCONFIGURED — bindings/flag absent */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ValidationError"]; + }; + }; + }; + }; + engineCapabilities: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The capability contract */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: unknown; + }; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + }; + }; + gpuStatus: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Plane status */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: unknown; + }; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + }; + }; + gpuInfer: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + model?: string; + input?: { + [key: string]: unknown; + }; + }; + }; + }; + responses: { + /** @description The job receipt */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + [key: string]: unknown; + }; + }; + }; + 401: components["responses"]["Unauthorized"]; + 403: components["responses"]["Forbidden"]; + }; + }; } From 6c6db8dd3162d074272152f6848643d781489c81 Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 10:07:31 -0400 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20scrub=20private-repo=20names=20from?= =?UTF-8?q?=20the=20public=20spec=20descriptions=20(content=20gate)=20?= =?UTF-8?q?=E2=80=94=20regenerate=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generated/api-types.d.ts | 8 ++++---- openapi.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/generated/api-types.d.ts b/generated/api-types.d.ts index 31d9833..05021d2 100644 --- a/generated/api-types.d.ts +++ b/generated/api-types.d.ts @@ -970,8 +970,8 @@ export interface paths { }; /** * The media-engine capability contract - * @description Served by wave-media-engine (engine.wave.online) through the gateway (engine:read). - * Returns the engine's capability JSON — the codecs/operations this deployment accepts. + * @description Served through the WAVE gateway (engine:read). Returns the engine's capability + * JSON — the codecs/operations this deployment accepts. */ get: operations["engineCapabilities"]; put?: never; @@ -997,8 +997,8 @@ export interface paths { put?: never; /** * Dispatch a GPU inference job on the WAVE-hosted GPU plane - * @description wave-gpu-edge (Phase C, RunPod-backed). Requires `gpu:write`. The gateway stamps - * x-wave-gateway-secret; the edge emits x-wave-meter: wave_edge_gpu_hours billed verbatim. + * @description The WAVE-hosted GPU inference plane (RunPod-backed). Requires `gpu:write`. Metered + * as wave_edge_gpu_hours, billed verbatim. */ post: operations["gpuInfer"]; delete?: never; diff --git a/openapi.yaml b/openapi.yaml index 9714301..f05043e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2160,8 +2160,8 @@ paths: summary: The media-engine capability contract operationId: engineCapabilities description: | - Served by wave-media-engine (engine.wave.online) through the gateway (engine:read). - Returns the engine's capability JSON — the codecs/operations this deployment accepts. + Served through the WAVE gateway (engine:read). Returns the engine's capability + JSON — the codecs/operations this deployment accepts. responses: '200': description: The capability contract @@ -2181,8 +2181,8 @@ paths: summary: Dispatch a GPU inference job on the WAVE-hosted GPU plane operationId: gpuInfer description: | - wave-gpu-edge (Phase C, RunPod-backed). Requires `gpu:write`. The gateway stamps - x-wave-gateway-secret; the edge emits x-wave-meter: wave_edge_gpu_hours billed verbatim. + The WAVE-hosted GPU inference plane (RunPod-backed). Requires `gpu:write`. Metered + as wave_edge_gpu_hours, billed verbatim. requestBody: required: true content: From 25b8dedaf2725b8d3e625c8cbde51226ed83e790 Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 10:22:54 -0400 Subject: [PATCH 4/6] =?UTF-8?q?fix(spec):=20reuse=20the=20existing=20norma?= =?UTF-8?q?lized=20error=20envelope=20=E2=80=94=20gitar=20review=20(respon?= =?UTF-8?q?ses/ValidationError=20ref,=20drop=20the=20duplicate=20schema);?= =?UTF-8?q?=20declare=20the=20new=20tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openapi.yaml | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index f05043e..57ad5c5 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2093,10 +2093,7 @@ paths: application/json: schema: { $ref: '#/components/schemas/PricingManifest' } '400': - description: Manifest fails the rail-law validation - content: - application/json: - schema: { $ref: '#/components/schemas/ValidationError' } + $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '403': @@ -2140,10 +2137,7 @@ paths: type: object additionalProperties: true '400': - description: INVALID_JSON / unknown op / bad grant id - content: - application/json: - schema: { $ref: '#/components/schemas/ValidationError' } + $ref: '#/components/responses/ValidationError' '401': $ref: '#/components/responses/Unauthorized' '403': @@ -4110,15 +4104,6 @@ components: updatedAt: { type: string } additionalProperties: true - ValidationError: - type: object - properties: - ok: { type: boolean } - error: - type: object - properties: - code: { type: string } - message: { type: string } IdentityResolveResponse: description: > From f8d20afdc21835ede11555f75543ae272e138b82 Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 10:27:03 -0400 Subject: [PATCH 5/6] fix: 503 custody response inlines the Error schema (no reusable component for it) --- generated/api-types.d.ts | 29 +++-------------------------- openapi.yaml | 2 +- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/generated/api-types.d.ts b/generated/api-types.d.ts index 05021d2..4916b8d 100644 --- a/generated/api-types.d.ts +++ b/generated/api-types.d.ts @@ -1961,13 +1961,6 @@ export interface components { } & { [key: string]: unknown; }; - ValidationError: { - ok?: boolean; - error?: { - code?: string; - message?: string; - }; - }; /** @description The resolved fleet directory entry, DISCRIMINATED on the outer `agent` value: `agent: "telephony"` serves the TelephonyResolveResponse variant; every other directory key serves the AgentResolveResponse variant. Generated clients can narrow on `agent`. */ IdentityResolveResponse: components["schemas"]["AgentResolveResponse"] | components["schemas"]["TelephonyResolveResponse"]; AgentResolveResponse: { @@ -4180,15 +4173,7 @@ export interface operations { "application/json": components["schemas"]["PricingManifest"]; }; }; - /** @description Manifest fails the rail-law validation */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ValidationError"]; - }; - }; + 400: components["responses"]["ValidationError"]; 401: components["responses"]["Unauthorized"]; 403: components["responses"]["Forbidden"]; }; @@ -4225,15 +4210,7 @@ export interface operations { }; }; }; - /** @description INVALID_JSON / unknown op / bad grant id */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ValidationError"]; - }; - }; + 400: components["responses"]["ValidationError"]; 401: components["responses"]["Unauthorized"]; 403: components["responses"]["Forbidden"]; /** @description CUSTODY_UNCONFIGURED — bindings/flag absent */ @@ -4242,7 +4219,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["ValidationError"]; + "application/json": components["schemas"]["Error"]; }; }; }; diff --git a/openapi.yaml b/openapi.yaml index 57ad5c5..bb3f5dd 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -2146,7 +2146,7 @@ paths: description: CUSTODY_UNCONFIGURED — bindings/flag absent content: application/json: - schema: { $ref: '#/components/schemas/ValidationError' } + schema: { $ref: '#/components/schemas/Error' } /engine/capabilities: get: From 456737414164f26d060a50ea271fb25308c1023b Mon Sep 17 00:00:00 2001 From: Jake Fineman Date: Tue, 1 Sep 2026 10:38:50 -0400 Subject: [PATCH 6/6] fix: declare the Pricing/Custody/Engine/Gpu tags at top level (gitar review) --- openapi.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index bb3f5dd..e865763 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -38,6 +38,14 @@ security: - BearerAuth: [] tags: + - name: Pricing + description: Seller-facing pricing tier manifests (pricing-pages). + - name: Custody + description: Money-engine held-fund capability operations (operator-plane). + - name: Engine + description: The media-engine capability contract. + - name: Gpu + description: The WAVE-hosted GPU inference plane. - name: Agent Auth description: >- The OAuth Device Authorization Grant (RFC 8628) ceremony that lets a self-hosted