diff --git a/README.md b/README.md index 0365ad8..0ed63df 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ empty, and it would have cost the whole gate the day one was written. The four decision files under `_project/` are the same idea applied to structure. Each holds a decision that would otherwise be spread across the document — sixty-odd -`servers` blocks, eleven tag groups' worth of operations, 203 page URLs — where +`servers` blocks, nine tag groups' worth of operations, 207 page URLs — where it can be read, reviewed and changed in one place. `scripts/build.py` applies them back onto `openapi.yaml` and CI fails if the document and the decisions disagree. @@ -62,21 +62,26 @@ disagree. | | | |---|---| | OpenAPI | 3.0.0 | -| Paths / operations | 131 / 203 | -| Components | 521, of which 479 schemas | -| Tags | 46, across 6 navigation groups | -| Servers | 5 hosts across 4 planes — managed and self-hosted gateway, control plane, admin, admin-in-path | +| Paths / operations | 133 / 207 | +| Components | 535, of which 486 schemas | +| Tags | 47, across 6 navigation groups | +| Servers | 6 hosts across 5 planes — managed and self-hosted gateway, control plane, admin, admin-in-path, Workspace Service | | Security | 1 scheme: `Authorization: Bearer` | -| Docs URLs | 203 — one `x-mint.href` per operation, all unique | +| Docs URLs | 207 — one `x-mint.href` per operation, all unique | | Prose fields stripped | 4,221 | | Written descriptions | 0 — blocked on KB access | -Eleven capability groups the base carried are **not shipped** — Audit Logs, -Collections, Labels, Log Exports, Prompts, Prompt Partials, User Invites, Users, -Virtual Keys, Workspaces and Workspaces > Members. That is 63 operations and 34 -paths, declared by tag in `_project/drops.yaml`. +Nine capability groups the base carried are **not shipped** — Audit Logs, +Collections, Labels, Log Exports, Prompts, Prompt Partials, User Invites, Users +and Virtual Keys. That is 50 operations and 28 paths, declared by tag in +`_project/drops.yaml`. -Deployments was a twelfth until Phase 2, when it turned out to be exposed on the +**Workspaces** is the Prisma AIRS Workspace Service (`/workspaces`, +`/workspaces/{id}`) on its own host, `api.sase.paloaltonetworks.com/airs/workspace/v1`, +from engineering's Workspace Service API 1.0.0 specification. It is where a +caller finds the UUID that every `workspace_id` parameter asks for. + +Deployments was a tenth until Phase 2, when it turned out to be exposed on the admin plane after all. Un-dropping is recovery rather than a flag flip: the base was retired at the end of Phase 1, so removing the line brought nothing back and the six operations were recovered from the pre-drop revision. What came back is @@ -310,7 +315,7 @@ domain and not subordinate to the KB (recorded exemption, Q6, 2026-09-07). The reconciliation loop is therefore three-node — KB ↔ spec ↔ docs — and drift from *either* side is a defect, with no authoritative side to fall back on. -`x-airs-provenance` is scaffolded on all 203 operations with `claims` empty. It +`x-airs-provenance` is scaffolded on all 207 operations with `claims` empty. It is not only "which claim supports this description"; it is the **join key that makes drift detectable**. Without a claim reference on an operation, nothing can tell that the KB moved and the spec did not. @@ -550,11 +555,10 @@ wanted. Until then the generated sample is correct but verbose. cURL only is the intended end state — a single `x-codeSamples` entry suppresses the other language tabs, and other languages are a separate decision. -- **`required` is unfilled on five request bodies** — `POST /configs`, - `POST /admin/workspaces`, and the `PUT`s for configs, providers and - workspaces. `required` is a claim about the API contract and nothing here - establishes it; getting it wrong means a reader omits a field the API rejects. - For the three `PUT`s, requiring nothing may already be correct, since a +- **`required` is unfilled on three request bodies** — `POST /configs` + and the `PUT`s for configs and providers. `required` is a claim about the API + contract and nothing here establishes it; getting it wrong means a reader omits a field the API rejects. + For the two `PUT`s, requiring nothing may already be correct, since a partial update where every field is optional is a normal design. Wants engineering. - **117 lint findings are baselined**, all inherited or carried in with ported diff --git a/_project/drops.yaml b/_project/drops.yaml index 6340824..b24c8f4 100644 --- a/_project/drops.yaml +++ b/_project/drops.yaml @@ -14,8 +14,8 @@ # Vrushank, 2026-09-15, marked [DROPPED] on the Phase 1 drop list. # -# Control-plane capabilities that Prisma AIRS does not expose. Ten of the -# eleven are control plane throughout. `Prompts` is the exception: it spans +# Control-plane capabilities that Prisma AIRS does not expose. Eight of the +# nine are control plane throughout. `Prompts` is the exception: it spans # both planes, and dropping only the control-plane side would ship an API # where a prompt can be executed but never created, listed or versioned, so # the two gateway paths under it go as well. @@ -34,15 +34,6 @@ tags: - User Invites - Users - Virtual Keys - - Workspaces > Members - -# Engineering, 2026-09-15. Their list named seven capabilities as dropped; -# six were already gone above. `Workspaces` is the one that was still -# shipping. Their list also named "SCIM Workspace Mappings" separately, but -# the base did not tag it separately: /scim/workspaces{,/{id}} carries the -# `Workspaces` tag too, so this one line removes both surfaces -- five -# /admin/workspaces operations and three /scim/workspaces ones. - - Workspaces # Individual operations to drop where the whole tag stays. Empty today: every # current removal is a clean tag boundary. Entries are "METHOD /path". diff --git a/_project/hrefs.yaml b/_project/hrefs.yaml index 5d3d40b..2dc70d7 100644 --- a/_project/hrefs.yaml +++ b/_project/hrefs.yaml @@ -227,5 +227,9 @@ hrefs: DELETE /policies/access/{accessPolicyId}: /aigw/api-reference/access-policies/delete-access-policy POST /messages: /aigw/api-reference/messages/create-message POST /messages/count_tokens: /aigw/api-reference/messages/count-message-tokens + GET /workspaces: /aigw/api-reference/workspaces/list-workspaces + POST /workspaces: /aigw/api-reference/workspaces/create-workspace + GET /workspaces/{id}: /aigw/api-reference/workspaces/get-workspace + PUT /workspaces/{id}: /aigw/api-reference/workspaces/update-workspace pinned: - POST /threads/{thread_id}/messages diff --git a/_project/planes.yaml b/_project/planes.yaml index db0d912..0da03b2 100644 --- a/_project/planes.yaml +++ b/_project/planes.yaml @@ -17,6 +17,7 @@ # admin /ai_gw/admin/v2 # admin-in-path also /ai_gw/admin/v2, but the prefix is in the path key # rather than the server URL -- see servers.yaml for why +# workspace the Workspace Service, api.sase.paloaltonetworks.com # # `how` records where the call came from: # classification.yaml -- a human decided, see that file for the reasoning @@ -32,6 +33,8 @@ # linkage closed (upstream commits up to adfd74b); # the plane was decided by Vrushank, not read off # Portkey's server overrides +# workspace-service-1.0.0 -- engineering's Workspace Service API spec +# (2026-11-03); its own host, not an AI Gateway plane # Tags whose operations are deliberately not all on one plane. `check.py` fails # on any other tag that spans two, because the split was decided by capability @@ -197,3 +200,7 @@ gateway: "/vector_stores/{vector_store_id}/file_batches/{batch_id}/files": classification.yaml "/vector_stores/{vector_store_id}/files": classification.yaml "/vector_stores/{vector_store_id}/files/{file_id}": classification.yaml + +workspace: + "/workspaces": workspace-service-1.0.0 + "/workspaces/{id}": workspace-service-1.0.0 diff --git a/_project/servers.yaml b/_project/servers.yaml index a8f0c54..85e506c 100644 --- a/_project/servers.yaml +++ b/_project/servers.yaml @@ -97,3 +97,14 @@ admin: admin-in-path: - url: https://api.apps.paloaltonetworks.com/ai_gw description: Managed + +# Workspace Service. A different host and a different service from the AI +# Gateway planes: workspaces are a Prisma AIRS core resource, bound to an SCM +# scope, and every workspace-level call on /ai_gw/v2 names one by the `id` this +# service returns (`workspace_id`, a UUID). Same SCM bearer token. +# +# Vrushank, 2026-11-03, from engineering's Workspace Service API 1.0.0 +# specification. Not yet live-verified. +workspace: + - url: https://api.sase.paloaltonetworks.com/airs/workspace/v1 + description: Managed diff --git a/build-report.txt b/build-report.txt index 5a16067..1d8d605 100644 --- a/build-report.txt +++ b/build-report.txt @@ -1,22 +1,22 @@ Generated by scripts/build.py from openapi.yaml. -operations 203 -paths 131 -schemas 479 -tags 46 +operations 207 +paths 133 +schemas 486 +tags 47 -docs URLs 203 +docs URLs 207 x-mint.href on every operation, from _project/hrefs.yaml. These are public URLs: the build re-derives each one and fails if it has moved, because a tag rename changes them silently and links point at them. -prose 0 written of 453 fields +prose 0 written of 462 fields Authored in overlays/docs-prose.yaml under the grounding gate and merged into openapi.yaml by this script. Every prose field here is stripped and reapplied on each build, so nothing reaches the published document without passing that gate. -servers 1 root + 76 path override(s) +servers 1 root + 78 path override(s) Every URL comes from _project/servers.yaml; which plane a path is on comes from _project/planes.yaml. Edit a host there and rebuild. The first entry in a plane is the one Mintlify builds its sample from; @@ -31,6 +31,8 @@ servers 1 root + 76 path override(s) https://api.apps.paloaltonetworks.com/ai_gw/admin/v2 -- Managed admin-in-path 4 path(s) https://api.apps.paloaltonetworks.com/ai_gw -- Managed + workspace 2 path(s) + https://api.sase.paloaltonetworks.com/airs/workspace/v1 -- Managed security 1 scheme One Authorization bearer token, declared once at the root. Six schemes @@ -114,7 +116,5 @@ not shipped User Invites Users Virtual Keys - Workspaces - Workspaces > Members parameters, on any operation: organisation_id diff --git a/docs-navigation.json b/docs-navigation.json index 1db9b30..a717212 100644 --- a/docs-navigation.json +++ b/docs-navigation.json @@ -565,6 +565,19 @@ "GET /policies/usage-limits/{policyUsageLimitsId}/entities", "PUT /policies/usage-limits/{policyUsageLimitsId}/entities/{entityId}/reset" ] + }, + { + "group": "Workspaces", + "openapi": { + "source": "https://raw.githubusercontent.com/PaloAltoNetworks/openapi/refs/heads/main/openapi.yaml", + "directory": "api-reference" + }, + "pages": [ + "GET /workspaces", + "POST /workspaces", + "GET /workspaces/{id}", + "PUT /workspaces/{id}" + ] } ] }, diff --git a/openapi.yaml b/openapi.yaml index 2a1de0f..b24147a 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -103,6 +103,8 @@ tags: description: '' - name: Usage Limit Policies description: '' +- name: Workspaces + description: '' - name: Analytics > Graphs description: '' - name: Analytics > Groups @@ -8807,6 +8809,132 @@ paths: text_digest: '' x-mint: href: /aigw/api-reference/messages/count-message-tokens + /workspaces: + get: + operationId: listWorkspaces + tags: &id001 + - Workspaces + parameters: + - $ref: '#/components/parameters/WorkspaceLimit' + - $ref: '#/components/parameters/WorkspaceOffset' + - name: name + in: query + required: false + schema: + type: string + - name: exact_name + in: query + required: false + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ListWorkspacesResponse' + '400': + $ref: '#/components/responses/WorkspaceBadRequest' + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' + x-mint: + href: /aigw/api-reference/workspaces/list-workspaces + post: + operationId: createWorkspace + tags: *id001 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateWorkspaceRequest' + responses: + '201': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Workspace' + '400': + $ref: '#/components/responses/WorkspaceBadRequest' + '409': + $ref: '#/components/responses/WorkspaceConflict' + '500': + $ref: '#/components/responses/WorkspaceInternalServerError' + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' + x-mint: + href: /aigw/api-reference/workspaces/create-workspace + servers: + - url: https://api.sase.paloaltonetworks.com/airs/workspace/v1 + description: Managed + /workspaces/{id}: + get: + operationId: getWorkspace + tags: *id001 + parameters: + - $ref: '#/components/parameters/WorkspaceIdPath' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Workspace' + '404': + $ref: '#/components/responses/WorkspaceNotFound' + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' + x-mint: + href: /aigw/api-reference/workspaces/get-workspace + put: + operationId: updateWorkspace + tags: *id001 + parameters: + - $ref: '#/components/parameters/WorkspaceIdPath' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateWorkspaceRequest' + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Workspace' + '400': + $ref: '#/components/responses/WorkspaceBadRequest' + '404': + $ref: '#/components/responses/WorkspaceNotFound' + '409': + $ref: '#/components/responses/WorkspaceConflict' + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' + x-mint: + href: /aigw/api-reference/workspaces/update-workspace + servers: + - url: https://api.sase.paloaltonetworks.com/airs/workspace/v1 + description: Managed components: securitySchemes: Authorization: @@ -9055,6 +9183,30 @@ components: schema: type: string format: uuid + WorkspaceLimit: + name: limit + in: query + required: false + schema: + type: integer + minimum: 1 + maximum: 100 + default: 20 + WorkspaceOffset: + name: offset + in: query + required: false + schema: + type: integer + minimum: 0 + default: 0 + WorkspaceIdPath: + name: id + in: path + required: true + schema: + type: string + format: uuid schemas: ModelPricingConfig: type: object @@ -10158,7 +10310,7 @@ components: default: standard response_format: type: string - enum: &id001 + enum: &id002 - url - b64_json default: url @@ -10461,7 +10613,7 @@ components: nullable: true size: type: string - enum: &id002 + enum: &id003 - 256x256 - 512x512 - 1024x1024 @@ -10469,7 +10621,7 @@ components: nullable: true response_format: type: string - enum: *id001 + enum: *id002 default: url nullable: true user: @@ -10500,12 +10652,12 @@ components: nullable: true response_format: type: string - enum: *id001 + enum: *id002 default: url nullable: true size: type: string - enum: *id002 + enum: *id003 default: 1024x1024 nullable: true user: @@ -20863,3 +21015,153 @@ components: type: string thinking: $ref: '#/components/schemas/AnthropicThinkingConfig' + Workspace: + type: object + required: + - id + - name + - description + - scope_name + - is_default + - status + - tsg_id + - created_at + - updated_at + - created_by + properties: + id: + type: string + format: uuid + name: + type: string + maxLength: 128 + description: + type: string + maxLength: 500 + nullable: true + scope_name: + type: string + is_default: + type: boolean + status: + $ref: '#/components/schemas/WorkspaceStatus' + tsg_id: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + nullable: true + created_by: + type: string + WorkspaceStatus: + type: string + enum: + - pending + - active + - broken + - failed + - deleting + CreateWorkspaceRequest: + type: object + required: + - name + - scope_name + properties: + name: + type: string + minLength: 1 + maxLength: 128 + description: + type: string + maxLength: 500 + scope_name: + type: string + minLength: 1 + maxLength: 64 + UpdateWorkspaceRequest: + type: object + required: + - name + - description + properties: + name: + type: string + minLength: 1 + maxLength: 128 + description: + type: string + maxLength: 500 + nullable: true + ListWorkspacesResponse: + type: object + required: + - workspaces + - total_count + - limit + - offset + properties: + workspaces: + type: array + items: + $ref: '#/components/schemas/Workspace' + total_count: + type: integer + limit: + type: integer + offset: + type: integer + WorkspaceError: + type: object + required: + - error + properties: + error: + type: object + required: + - code + - message + properties: + code: + $ref: '#/components/schemas/WorkspaceErrorCode' + message: + type: string + details: + type: array + items: + type: object + WorkspaceErrorCode: + type: string + enum: + - VALIDATION_ERROR + - DEFAULT_WORKSPACE + - NOT_FOUND + - CONFLICT + - INTERNAL_ERROR + responses: + WorkspaceBadRequest: + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceError' + WorkspaceConflict: + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceError' + WorkspaceInternalServerError: + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceError' + WorkspaceNotFound: + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/WorkspaceError' diff --git a/overlays/docs-prose.yaml b/overlays/docs-prose.yaml index e6f835c..9f55553 100644 --- a/overlays/docs-prose.yaml +++ b/overlays/docs-prose.yaml @@ -1773,3 +1773,38 @@ actions: claims: [] origin_kind: human text_digest: '' +- target: $.tags[?(@.name=='Workspaces')] + update: + description: '' +- target: $.paths['/workspaces'].get + update: + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' +- target: $.paths['/workspaces'].post + update: + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' +- target: $.paths['/workspaces/{id}'].get + update: + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' +- target: $.paths['/workspaces/{id}'].put + update: + summary: '' + description: '' + x-airs-provenance: + claims: [] + origin_kind: human + text_digest: '' diff --git a/tags-map.yaml b/tags-map.yaml index 376463f..1cbb979 100644 --- a/tags-map.yaml +++ b/tags-map.yaml @@ -13,7 +13,7 @@ # entries mapping to one `to` is how a merge is documented. A tag introduced # here rather than inherited has no `from` at all. # -# Only shipped tags are listed. The eleven groups dropped in Phase 1 were +# Only shipped tags are listed. The groups dropped in Phase 1 were # removed from this file when the base linkage was retired; the record of what # is not shipped, and why, is `_project/drops.yaml`. # @@ -193,6 +193,11 @@ tags: # Title Case, space-separated convention above. - to: Egress Allowlist group: administration + # The Prisma AIRS Workspace Service (engineering's spec, 2026-11-03), on its + # own host. No `from`: it was never in the base. This is where a reader + # finds the UUID every `workspace_id` parameter asks for. + - to: Workspaces + group: administration # --- Observability ----------------------------------------------------- - from: Analytics > Graphs