@openwop/spec-artifacts 2.35.1 → 2.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CORPUS-STAMP.json +103 -89
- package/api/openapi.yaml +325 -4
- package/api/seams-v2.yaml +342 -1
- package/api/v2/asyncapi.yaml +1 -1
- package/api/v2/openapi.yaml +564 -8
- package/package.json +1 -1
- package/schemas/a2a-task-state.schema.json +3 -3
- package/schemas/artifact-type-pack-manifest.schema.json +3 -3
- package/schemas/capabilities.schema.json +34 -1
- package/schemas/connection-pack-manifest.schema.json +14 -0
- package/schemas/debug-bundle.schema.json +20 -0
- package/schemas/dispatch-config.schema.json +1 -1
- package/schemas/localized-content-language-settings.schema.json +3 -3
- package/schemas/localized-content-page.schema.json +2 -2
- package/schemas/localized-content-section.schema.json +3 -3
- package/schemas/run-event-payloads.schema.json +4 -2
- package/schemas/suspend-request.schema.json +61 -4
- package/schemas/v2/a2a-task-state.schema.json +10 -9
- package/schemas/v2/agent-deployment-transition.schema.json +4 -4
- package/schemas/v2/agent-deployment.schema.json +7 -7
- package/schemas/v2/agent-eval-suite.schema.json +10 -10
- package/schemas/v2/agent-inventory-response.schema.json +8 -2
- package/schemas/v2/artifact-type-pack-manifest.schema.json +3 -3
- package/schemas/v2/artifact.schema.json +84 -0
- package/schemas/v2/capabilities.schema.json +82 -8
- package/schemas/v2/certification-bundle.schema.json +1 -1
- package/schemas/v2/channel-presence-payload.schema.json +3 -3
- package/schemas/v2/connection-pack-manifest.schema.json +14 -0
- package/schemas/v2/conversation-event.schema.json +9 -2
- package/schemas/v2/conversation-turn.schema.json +19 -12
- package/schemas/v2/dispatch-config.schema.json +1 -1
- package/schemas/v2/envelopes/ui.a2ui-surface.schema.json +920 -22
- package/schemas/v2/error-envelope.schema.json +11 -1
- package/schemas/v2/eval-summary.schema.json +1 -2
- package/schemas/v2/goal.schema.json +4 -4
- package/schemas/v2/localized-content-language-settings.schema.json +3 -3
- package/schemas/v2/localized-content-page.schema.json +2 -2
- package/schemas/v2/localized-content-section.schema.json +3 -3
- package/schemas/v2/node-pack-manifest.schema.json +105 -0
- package/schemas/v2/part.schema.json +81 -0
- package/schemas/v2/proposal.schema.json +6 -6
- package/schemas/v2/run-event-payloads.schema.json +5 -3
- package/schemas/v2/self-hosted-runner-dispatch-frame.schema.json +2 -2
- package/schemas/v2/self-hosted-runner-result-frame.schema.json +1 -1
- package/schemas/v2/suspend-request.schema.json +251 -6
- package/schemas/v2/tool-descriptor.schema.json +246 -2
- package/schemas/v2/trigger-event.schema.json +1 -2
- package/schemas/v2/trigger-subscription.schema.json +1 -2
- package/schemas/v2/webhook-verification.schema.json +22 -0
- package/schemas/v2/workflow-definition.schema.json +25 -25
- package/spec/v1/alias-detectors.json +13 -1
- package/spec/v1/core-standard-manifest.json +2 -2
- package/spec/v1/deprecations.json +45 -1
- package/spec/v1/deprecations.schema.json +119 -4
- package/spec/v1/gaps.json +1925 -4
- package/spec/v2/README.md +5 -2
- package/spec/v2/core/capabilities.md +13 -26
- package/spec/v2/core/conformance.md +5 -8
- package/spec/v2/core/connection-packs.md +1 -1
- package/spec/v2/core/conversation.md +1 -1
- package/spec/v2/core/errors.md +8 -3
- package/spec/v2/core/events.md +8 -20
- package/spec/v2/core/form-content-packs.md +2 -2
- package/spec/v2/core/headers.md +5 -4
- package/spec/v2/core/host-services.md +6 -2
- package/spec/v2/core/idempotency.md +1 -1
- package/spec/v2/core/identity.md +23 -12
- package/spec/v2/core/interop.md +34 -4
- package/spec/v2/core/interrupt.md +6 -3
- package/spec/v2/core/node-pack-runtimes.md +20 -0
- package/spec/v2/core/oauth.md +32 -0
- package/spec/v2/core/overview.md +19 -6
- package/spec/v2/core/packs.md +4 -6
- package/spec/v2/core/persistence.md +20 -55
- package/spec/v2/core/replay.md +5 -11
- package/spec/v2/core/runs.md +9 -8
- package/spec/v2/core/security-defaults.md +18 -20
- package/spec/v2/core/tool-catalog.md +22 -0
- package/spec/v2/core/versioning.md +10 -28
- package/spec/v2/core/webhooks.md +16 -4
- package/spec/v2/core/workflow-chain-packs.md +1 -1
- package/spec/v2/corrections.json +32 -0
- package/spec/v2/corrections.schema.json +49 -0
- package/spec/v2/declaration.json +18 -13
- package/spec/v2/declaration.schema.json +3 -1
- package/spec/v2/errors.json +46 -1
- package/spec/v2/ext/a2uiSurface/README.md +131 -17
- package/spec/v2/ext/dataIntegration/README.md +5 -0
- package/spec/v2/facets/a2a.schema.json +4 -0
- package/spec/v2/facets/auth.schema.json +24 -0
- package/spec/v2/facets/mcp.schema.json +4 -0
- package/spec/v2/facets/oauth.schema.json +70 -0
- package/spec/v2/facets/webhooks.schema.json +23 -2
- package/spec/v2/id-field-bindings.json +2 -0
- package/spec/v2/interop-map.json +639 -0
- package/spec/v2/interop-map.schema.json +458 -0
- package/spec/v2/migrations.json +7 -0
- package/spec/v2/migrations.schema.json +58 -0
- package/spec/v2/path-manifest.json +6 -1
- package/spec/v2/release.json +3 -3
- package/spec/v2/surface-baseline.json +7981 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Security Defaults
|
|
2
2
|
|
|
3
3
|
> **Status: Stable · RFC 0173 (§A–§E), 0164 §22, 0170 §B.**
|
|
4
|
-
> **Normative home:** `sandbox`, `compensation`.
|
|
4
|
+
> **Normative home:** `sandbox`, `compensation`, `purposePropagation`.
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
RFC 0173 replaces v1's opt-in security flags (RFC 0164 §22). This document is the obligation table: which surface binds which behavior, the invariant, and the witness.
|
|
9
9
|
|
|
10
10
|
## The rule
|
|
11
11
|
|
|
@@ -25,22 +25,24 @@ A host MUST NOT advertise a surface whose obligation it has relaxed (§A.2).
|
|
|
25
25
|
| `packs` (pack execution) | isolation: the eight `node-pack-sandbox-*` invariants bind for pack code; `sandbox.isolationModel` names the mechanism and never relaxes the property (replaces `sandbox.supported`) | witnessable-gated (eight `sandbox-*` scenarios) | `node-pack-sandbox-*` |
|
|
26
26
|
| `compensation` | the plan, attempt, and inverse-action obligations with the read projection `GET /runs/{runId}/compensation` and the operator action family as canonical wire (replaces `compensation.supported` with seam-only evidence) | witnessable-gated (reads) + seam-gated (operator actions) | `compensation-replay-no-refire`, `compensation-effect-id-retry-stable` |
|
|
27
27
|
| `idempotency` | Layer-2 effect identity keyed on business identity; the activity recipe is the fallback; `GET /runs/{runId}/effects` is the read | witnessable-gated (fixture provider) | `logical-effect-id-retry-stable` |
|
|
28
|
+
| an `oauth2` or `oidc` lane | protected-resource metadata and challenges (identity.md §2.5) | witnessable-gated | `auth-challenge-no-oracle` |
|
|
29
|
+
| any outbound request | no inbound credential on an onward hop (§Onward hops) | seam-gated | `inbound-credential-no-passthrough` |
|
|
28
30
|
|
|
29
31
|
### Auth lanes
|
|
30
32
|
|
|
31
|
-
The
|
|
33
|
+
The obligations are identity.md §2 and bind on advertisement.
|
|
32
34
|
|
|
33
35
|
### Replay suppression
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
Stated in replay.md §Suppression and §"The effect-seam manifest"; the `replay-side-effect-suppression` scenario witnesses it.
|
|
36
38
|
|
|
37
39
|
### Webhook durability
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
Stated in webhooks.md §Durability; the `webhook-durable-delivery` scenario witnesses it.
|
|
40
42
|
|
|
41
43
|
### Approver enforcement
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
Stated in interrupt.md §"Approver enforcement"; the `approver-enforced` scenario witnesses it.
|
|
44
46
|
|
|
45
47
|
### Sandbox isolation
|
|
46
48
|
|
|
@@ -50,13 +52,19 @@ The remaining `sandbox` facets name the bound each invariant already carries: `a
|
|
|
50
52
|
|
|
51
53
|
### Compensation
|
|
52
54
|
|
|
53
|
-
A host that advertises `compensation` MUST serve `GET /runs/{runId}/compensation` (`schemas/v2/compensation-projection.schema.json`)
|
|
55
|
+
A host that advertises `compensation` MUST serve `GET /runs/{runId}/compensation` (`schemas/v2/compensation-projection.schema.json`), keyed on the node and attempt the operator family uses; a host that does not advertise `compensation` has no obligation.
|
|
54
56
|
|
|
55
57
|
The facets bind the policy shape (`schemas/v2/compensation-policy.schema.json`): `compensation.orderingModels` MUST list `reverse-completion` and MAY add `dependency-graph`, and a policy naming a model outside it MUST be refused at registration; `compensation.profileVersion` participates in the inverse-action identity, so a policy naming a different one MUST be refused; `compensation.manualIntervention` is the `manual` status above — a host advertising it records the unwind rather than abandoning it.
|
|
56
58
|
|
|
57
59
|
### Layer-2 effect identity
|
|
58
60
|
|
|
59
|
-
A host that advertises `idempotency` MUST
|
|
61
|
+
A host that advertises `idempotency` MUST serve `GET /runs/{runId}/effects`; the keying, provider-key, retention and projection rules are idempotency.md §"Layer 2: effect identity" (RFC 0150 §B).
|
|
62
|
+
|
|
63
|
+
### Onward hops
|
|
64
|
+
|
|
65
|
+
A host MUST NOT attach a credential it received inbound (an `Authorization`, `Cookie` or `Proxy-Authorization` value, a DPoP proof, an interrupt token, a peer's bearer, or credential material carried in a body) to any outbound request: A2A, MCP, webhook, callback, `httpClient` or connector. Outbound authentication uses only credentials the host holds for that destination (oauth.md). A verified delegation chain is not a passthrough: it carries provenance, never the inbound credential (identity.md §2.4).
|
|
66
|
+
|
|
67
|
+
A host advertising `purposePropagation` MUST re-emit a `permittedPurposes` label it received (A2A `metadata.openwop.permittedPurposes`, `TriggerEvent.permittedPurposes`) on every onward hop of the same data, narrowing and never widening, and MUST treat `[]` as no onward use; `purposePropagation.propagatesOnward` is `false` only on a host with no onward hop. The family advertises propagation, not enforcement.
|
|
60
68
|
|
|
61
69
|
## Relaxations
|
|
62
70
|
|
|
@@ -68,7 +76,7 @@ A relaxation, where one is legitimate — a development deployment, a single-ten
|
|
|
68
76
|
| `deployment` | Set at deploy time. |
|
|
69
77
|
| `persisted` | Survives restarts and is auditable. |
|
|
70
78
|
|
|
71
|
-
A bundle that records a relaxation MUST NOT certify the profile the relaxed obligation belongs to; the `relaxation-recorded` scenario verifies it unaided (conformance.md).
|
|
79
|
+
A bundle that records a relaxation MUST NOT certify the profile the relaxed obligation belongs to; the `relaxation-recorded` scenario verifies it unaided (conformance.md).
|
|
72
80
|
|
|
73
81
|
## Three dispositions
|
|
74
82
|
|
|
@@ -97,16 +105,6 @@ The following threat-model artifacts are required:
|
|
|
97
105
|
|
|
98
106
|
## Migration
|
|
99
107
|
|
|
100
|
-
|
|
101
|
-
| --- | --- | --- |
|
|
102
|
-
| `C6.1` | fourteen `auth.*` gate flags | obligations of the lane; `auth.lanes[]` facets |
|
|
103
|
-
| `C6.2` | `replay.sideEffectSuppression: none \| recorded-outcome` | suppression is the only replay behavior; the manifest is the witness |
|
|
104
|
-
| `C6.3` | `webhooks.durable` opt-in | durable delivery binds with `webhooks`; undelivered best-effort deliveries are not translated |
|
|
105
|
-
| `C6.4` | `interrupt.approverRouting` gate | enforcement binds with the fields |
|
|
106
|
-
| `C6.5` | `sandbox.supported` gate | isolation binds with pack execution; `node:vm` not a value |
|
|
107
|
-
| `C6.6` | `compensation.supported` with seam-only evidence | core obligation with the read projection; persisted plans and attempts unchanged |
|
|
108
|
-
| `C6.7` | unimplemented activity recipe | business-identity keying; `GET /runs/{runId}/effects` |
|
|
109
|
-
| `C6.8` | none | `host.relaxations[]` in bundle v3 |
|
|
110
|
-
| `C6.9` | five-section replay threat model; no interop model | sibling sections; `threat-model-interop.md` |
|
|
108
|
+
Rows `C6.1`–`C6.9` are `spec/v1/migrations.json` entries.
|
|
111
109
|
|
|
112
110
|
See also: identity.md, replay.md, webhooks.md, capabilities.md, conformance.md.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Tool catalog
|
|
2
|
+
|
|
3
|
+
> **Status: Stable · RFC 0078, RFC 0112.**
|
|
4
|
+
> **Normative home:** `toolCatalog`.
|
|
5
|
+
|
|
6
|
+
## Why this exists
|
|
7
|
+
|
|
8
|
+
v2 carried the catalog only by pointing at `spec/v1/tool-catalog.md`. This is its v2 contract, plus a projection onto MCP `ToolAnnotations` (RFC 0204). The shapes are `schemas/v2/tool-descriptor.schema.json` and `schemas/v2/compact-tool-descriptor.schema.json`.
|
|
9
|
+
|
|
10
|
+
## The catalog
|
|
11
|
+
|
|
12
|
+
A host advertising `toolCatalog` MUST serve `GET /tools` (a `ToolDescriptor[]`) and `GET /tools/{toolId}`, both read-only. The list MUST hold only tools the caller may invoke in its tenant, and an unknown or unauthorized `toolId` MUST return `404`. `toolCatalog.sources` names the sources projected; a consumer MUST tolerate any subset. A host SHOULD return tools sorted by `toolId`, so an unchanged catalog reads identically.
|
|
13
|
+
|
|
14
|
+
## The descriptor
|
|
15
|
+
|
|
16
|
+
`toolId` MUST be unique in the catalog and stable for a host version. `safetyTier: "exec"` MUST carry `source: "host-extension"`. A descriptor MUST NOT carry credential material. The host MUST assign `safetyTier`, `replayPolicy` and `egress` itself and MUST NOT copy them from an MCP server's `annotations`, which are untrusted; a `source: "mcp"` tool it has not classified MUST be `safetyTier: "write"`.
|
|
17
|
+
|
|
18
|
+
`annotations`, when present, MUST carry all four MCP hints, derived from those fields and not from MCP defaults (`destructiveHint` and `openWorldHint` default to `true` upstream): `readOnlyHint` is true iff `safetyTier` is `pure` or `read`, `destructiveHint` iff it is `write` or `exec`, `idempotentHint` iff `replayPolicy` is `deterministic` or `idempotent`, and `openWorldHint` unless `egress` is `none`.
|
|
19
|
+
|
|
20
|
+
## Views and sessions
|
|
21
|
+
|
|
22
|
+
A host advertising `toolCatalog.compactView` MUST answer `?view=compact` on both endpoints with `CompactToolDescriptor`s (the list as `{ tools: [...] }`) carrying the standard view's `toolId` set; a compact `inputSchema` MUST NOT use `$ref`, `oneOf`, `allOf`, `anyOf`, `not`, `patternProperties` or `dependentSchemas` at any depth. Any other `view`, or a host not advertising it, yields the standard view. A host advertising `toolCatalog.sessionLifecycle` MAY bracket calls with content-free `tool.session.opened` and `tool.session.closed`; a consumer MUST tolerate their absence.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Why this exists
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
How a v2 host selects a major, what each version axis means, and what a release is.
|
|
8
8
|
|
|
9
9
|
## 1. Major negotiation (RFC 0172 §A)
|
|
10
10
|
|
|
@@ -12,23 +12,21 @@ v1 negotiated on one scalar, could not advertise two majors, split `engineVersio
|
|
|
12
12
|
|
|
13
13
|
A v2 host MUST advertise `protocolVersions[]` (grammar `^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$` per member) containing every `<major>.<minor>` it serves, and a root `preferredVersion` that MUST be a member of `protocolVersions[]`. Both are REQUIRED root metadata in `schemas/v2/capabilities.schema.json` (see `capabilities.md`). Through the overlap a host serves `["1.<n>", "2.<m>"]`; after v1 end-of-support it serves `["2.<m>"]`.
|
|
14
14
|
|
|
15
|
-
**Through the overlap `preferredVersion` MUST name a 1.x member
|
|
15
|
+
**Through the overlap `preferredVersion` MUST name a 1.x member**, because a header-less request is a v1 client's (`capabilities.md` §1; §1.3). A host that drops v1 from `protocolVersions[]` advertises a `2.x` `preferredVersion` and its header-less representation becomes the closed v2 root. On a host serving a single major, `preferredVersion` MUST equal `protocolVersion` (RFC 0179 §A.1). A v2 consumer reads `preferredVersion` as the header-less default; when it is absent on a v1 document the consumer's default is `max(protocolVersions[])`, else `protocolVersion` (RFC 0179 §A.2). The suite's `--target-major` defaults from it (RFC 0168 §D.3).
|
|
16
16
|
|
|
17
17
|
### 1.2 Paths
|
|
18
18
|
|
|
19
19
|
v1 operations keep their `/v1/…` path keys unchanged through the overlap. v2 operations are unversioned path keys on a bare origin (`servers[].url = https://{host}`): `/runs`, `/runs/{runId}`, `/.well-known/openwop`. There is no `/v2/` path space. An unversioned path is the v2 surface; the v1 MUST that servers answer `400` for unversioned roots is retracted for v2.
|
|
20
20
|
|
|
21
|
-
A host that advertises a major in `protocolVersions[]` MUST reach, under that major, every operation **named in `spec/v2/path-manifest.json`** that it serves under the other
|
|
21
|
+
A host that advertises a major in `protocolVersions[]` MUST reach, under that major, every operation **named in `spec/v2/path-manifest.json`** that it serves under the other: advertising a major is a claim about the **path space**, not about `/.well-known/openwop` alone (§1.3 selects that resource's representation). If `/v1/<op>` answers and the unversioned `/<op>` returns `404` under the advertised major, the host MUST NOT advertise that major until the surface is reachable.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
paths are not manifest operations and do not require a per-major twin. The
|
|
25
|
-
canonical OpenAPI therefore contains no conformance-seam operation.
|
|
23
|
+
Seam and proprietary paths are not manifest operations and need no per-major twin.
|
|
26
24
|
|
|
27
|
-
`spec/v2/path-manifest.json` (generated) carries operations (`method`, `path`, `operationId`) and channels (`name`, `address`) on a bare origin, and **every path in it is unversioned** — there are no `/v1` rows. The `/v1` twin of a manifest row is derived by prefixing, which is what the pairing above compares. OpenAPI (`api/v2/openapi.yaml`), AsyncAPI (`api/v2/asyncapi.yaml`), and any kept proto MUST resolve to identical absolute paths for the shared event stream (`scripts/check-path-parity.mjs`)
|
|
25
|
+
`spec/v2/path-manifest.json` (generated) carries operations (`method`, `path`, `operationId`) and channels (`name`, `address`) on a bare origin, and **every path in it is unversioned** — there are no `/v1` rows. The `/v1` twin of a manifest row is derived by prefixing, which is what the pairing above compares. OpenAPI (`api/v2/openapi.yaml`), AsyncAPI (`api/v2/asyncapi.yaml`), and any kept proto MUST resolve to identical absolute paths for the shared event stream (`scripts/check-path-parity.mjs`) (seams: `conformance.md`).
|
|
28
26
|
|
|
29
27
|
### 1.3 The request header
|
|
30
28
|
|
|
31
|
-
A request on an unversioned path MAY carry `OpenWOP-Version: <major>` or `OpenWOP-Version: <major>.<minor>` — `2` and `2.0` select the same major and a host MUST accept both. Only the major selects; a minor in the header is informational, and what pins a minor is `minClientVersion` plus the additive rules.
|
|
29
|
+
A request on an unversioned path MAY carry `OpenWOP-Version: <major>` or `OpenWOP-Version: <major>.<minor>` — `2` and `2.0` select the same major and a host MUST accept both. Only the major selects; a minor in the header is informational, and what pins a minor is `minClientVersion` plus the additive rules (`COMPATIBILITY.md` §2.4).
|
|
32
30
|
|
|
33
31
|
| Condition | Host behavior |
|
|
34
32
|
| --- | --- |
|
|
@@ -62,10 +60,6 @@ Otherwise the page MUST move off the shared name.
|
|
|
62
60
|
|
|
63
61
|
When both majors are advertised, a v2 client MUST select the highest major it implements that the host lists; a v1 client (no header, `/v1/` paths) is unaffected. `minClientVersion` (axis 15, grammar as axis 1) is a MUST: a host MAY refuse a client below it with `426` `client_version_unsupported`.
|
|
64
62
|
|
|
65
|
-
`OpenWOP-Version` selects by major. The `<major>.<minor>` spelling is accepted so
|
|
66
|
-
a client may echo a `protocolVersions[]` member. Minor compatibility is governed
|
|
67
|
-
by `minClientVersion` and the additive-change rules.
|
|
68
|
-
|
|
69
63
|
## 2. The 18 version axes (RFC 0172 §B; RFC 0167 §E.1)
|
|
70
64
|
|
|
71
65
|
`unify` = one type and grammar with a codemod; `first-class` = own schema-enforced grammar and negotiation rule; `retire` = absorbed into the capability record's `{status, since, until?}`; `delete` = removed with a register row.
|
|
@@ -99,7 +93,7 @@ One grammar covers protocol, envelope-kind, and pack axes wherever a version is
|
|
|
99
93
|
|
|
100
94
|
### 2.2 `eventLogSchemaVersion` (axis 4; RFC 0176 §A.2)
|
|
101
95
|
|
|
102
|
-
`eventLogSchemaVersion` is the era key
|
|
96
|
+
`eventLogSchemaVersion` is the era key; the schema floor is `minimum 2`. Its stamping, absent-⇒-`2` and discovery rules are `persistence.md` §"The era key"; the reader contract is `persistence.md`.
|
|
103
97
|
|
|
104
98
|
## 3. Where v2 lives (RFC 0172 §C)
|
|
105
99
|
|
|
@@ -117,12 +111,11 @@ Through the overlap a host MUST advertise both majors (§1.1), MUST emit `OpenWO
|
|
|
117
111
|
|
|
118
112
|
**A run minted under major 1 and read under major 2 MUST use the tenant-bound
|
|
119
113
|
projection** `<tenantId>/<v1-id>` (`identity.md` §5). A host MUST NOT return a
|
|
120
|
-
bare v1 id in a major-2 response.
|
|
121
|
-
`id_tenant_mismatch` check; `ids.schema.json` has no legacy unprefixed branch.
|
|
114
|
+
bare v1 id in a major-2 response.
|
|
122
115
|
|
|
123
116
|
The overlap ends at v1 end-of-support (`overview.md`), when `protocolVersions[]` drops the `1.<n>` member and every alias carrying the `v1-end-of-support` trigger is removed.
|
|
124
117
|
|
|
125
|
-
**Retirement is atomic
|
|
118
|
+
**Retirement is atomic.** §1.1 admits no state in which both majors are advertised and `2.x` is preferred, so dropping v1 retires the whole `/v1` path space at once.
|
|
126
119
|
|
|
127
120
|
**Retirement changes every header-less request's default contract.** Before
|
|
128
121
|
end-of-support, a header-less unversioned request uses major 1; afterward it uses
|
|
@@ -134,15 +127,4 @@ colliding route or apply §1.4 content negotiation.
|
|
|
134
127
|
|
|
135
128
|
## 6. Migration rows (RFC 0172)
|
|
136
129
|
|
|
137
|
-
|
|
138
|
-
| --- | --- | --- |
|
|
139
|
-
| `C5.1` | `engineVersion` integer at root, string on five carriers | integer everywhere; codemod `engine-version-unify` |
|
|
140
|
-
| `C5.3` | — | root `preferredVersion` |
|
|
141
|
-
| `C5.4` | — | `OpenWOP-Version` request/response header; three error codes |
|
|
142
|
-
| `C5.5` | `/v1/<op>` path keys | unversioned `/<op>` keys (v1 keys retained through the overlap) |
|
|
143
|
-
| `C5.6` | `400` for unversioned roots | unversioned roots are the v2 surface |
|
|
144
|
-
| `C5.7` | `$id` base `/spec/v1/` | `/spec/v2/` (new files; v1 `$id`s immutable) |
|
|
145
|
-
| `C5.8` | `minClientVersion` advisory | MUST (§1.5) |
|
|
146
|
-
| `C5.9` | `info.version` hand-maintained | generated from the corpus tag |
|
|
147
|
-
|
|
148
|
-
Row `C5.2` (channel state-key prefixes → typed channels) is owned by `events.md`. Every row is a `spec/v1/migrations.json` entry; the persisted-data disposition for each is `not-persisted` except `C5.1` (legacy-stamped) and `C5.7` (never-upgraded).
|
|
130
|
+
Rows `C5.1`–`C5.9` are `spec/v1/migrations.json` entries (`C5.2` is owned by `events.md`); the persisted-data disposition for each is `not-persisted` except `C5.1` (legacy-stamped) and `C5.7` (never-upgraded).
|
package/spec/v2/core/webhooks.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
A client registers a URL and an event filter once; the host POSTs matching events, signed, as they happen. In v2 durable delivery binds with the surface — a signed event that may be dropped is not a delivery contract.
|
|
9
9
|
|
|
10
10
|
## Surfaces
|
|
11
11
|
|
|
@@ -13,14 +13,14 @@ A host that advertises `webhooks` (capabilities.md) serves `registerWebhook` (`P
|
|
|
13
13
|
|
|
14
14
|
| Operation | Request | Response |
|
|
15
15
|
| --- | --- | --- |
|
|
16
|
-
| `registerWebhook` | `{ url, events[], secret?, tags? }`; `url` MUST be `https://`; `events[]` MUST be non-empty v2 event type names (events.md) | `201 { webhookId }` |
|
|
16
|
+
| `registerWebhook` | `{ url, events[], secret?, tags?, signatureAlgorithms? }`; `url` MUST be `https://`; `events[]` MUST be non-empty v2 event type names (events.md) | `201 { webhookId }` |
|
|
17
17
|
| `unregisterWebhook` | path `webhookId` | `204`; `404` when unknown; `403` when the caller is outside the subscription's tenant |
|
|
18
18
|
|
|
19
19
|
A subscription MUST receive only events from runs within its tenant scope; cross-tenant delivery is a protocol violation whatever the filter says (invariant `webhook-cross-tenant-isolation`). `tags` narrows delivery to runs whose options carry an overlapping tag.
|
|
20
20
|
|
|
21
21
|
## Delivery
|
|
22
22
|
|
|
23
|
-
The delivery envelope is generated from the
|
|
23
|
+
The delivery envelope is generated from the event's payload definition (events.md §Payloads). The body is `{ runId, workspaceId?, event }` where `event` is the verbatim run event (events.md), and it MUST validate against `schemas/v2/webhook-delivery.schema.json`. `workspaceId` is present exactly when `RunSnapshot.owner.workspace` is (`identity.md` §1) — a host MUST NOT substitute its tenant id for an absent workspace.
|
|
24
24
|
|
|
25
25
|
The envelope's `runId` MUST use the tenant-bound v2 form defined by
|
|
26
26
|
`identity.md` §5, matching the nested event and every response representation.
|
|
@@ -43,6 +43,18 @@ A host MUST send all five on every delivery. The signed bytes are `{timestamp}.{
|
|
|
43
43
|
|
|
44
44
|
A subscriber MUST verify before acting: reject a timestamp more than ±5 minutes from its clock; compute `HMAC-SHA256({timestamp}.{rawBody}, secret)`; compare in constant time. A subscriber MUST reject an unrecognized `OpenWOP-Signature-Algorithm` value. Subscribers SHOULD track `(OpenWOP-Webhook-Id, runId, sequence)` for at-least-once deduplication. A host MUST NOT log the secret.
|
|
45
45
|
|
|
46
|
+
### Standard Webhooks
|
|
47
|
+
|
|
48
|
+
`standard-webhooks-1` names the symmetric scheme of Standard Webhooks 1.0.0 (RFC 0201). Its in-header `v1,` token is that standard's, not the OpenWOP scheme id `v1`; neither is read as the other, and `OpenWOP-Signature-Algorithm` stays `v1`.
|
|
49
|
+
|
|
50
|
+
**Opt-in.** A subscription carries the scheme only when `registerWebhook` sends `signatureAlgorithms` listing it and `v1`, with a `secret` of the form `whsec_<base64 of 24–64 bytes>`; otherwise, or when the host does not advertise the id, `400 validation_error`. The `201` echoes the applied list. Every other subscription is unchanged.
|
|
51
|
+
|
|
52
|
+
**Endpoint verification.** Before answering `201`, the host MUST send the request of `schemas/v2/webhook-verification.schema.json` to `url` under §Egress, signed as below, and MUST refuse `400 webhook_endpoint_unverified`, persisting nothing, unless a `2xx` arrives within 10 s whose JSON `challenge` equals the one sent. A host MUST NOT verify a subscription that did not opt in.
|
|
53
|
+
|
|
54
|
+
**Delivery.** Each delivery to an opted-in subscription adds `webhook-id`, `webhook-timestamp` (equal to `OpenWOP-Timestamp`) and `webhook-signature`: space-separated `v1,<base64 HMAC-SHA256>` entries over `{webhook-id}.{webhook-timestamp}.{rawBody}`, keyed by the decoded secret. `webhook-id` matches `^[A-Za-z0-9_-]{16,128}$`, MUST be identical on every attempt of one `(webhookId, runId, sequence)` and MUST differ across them.
|
|
55
|
+
|
|
56
|
+
**Rotation.** A host advertising `webhooks.secretRotation` serves `rotateWebhookSecret`. For `overlapSeconds` after a rotation, `webhook-signature` MUST carry one entry per secret and `OpenWOP-Signature` stays on the previous secret; afterwards only the new secret signs.
|
|
57
|
+
|
|
46
58
|
### Dual emission through the overlap
|
|
47
59
|
|
|
48
60
|
A host advertising both majors MUST send, on every delivery, the `X-openwop-*` family alongside the `OpenWOP-*` family with identical values (RFC 0165 §C.1, RFC 0176 §D.2). A v2 receiver MUST accept a delivery carrying only the `X-openwop-*` family under scheme `v1`, verifying the same bytes. This adds no signature scheme. Per-subscription secrets are unchanged across the cut; deliveries queued before the cut are drained under their own retry policy with the payload they were serialized with (persistence.md). The `X-openwop-*` family is removed on its register date.
|
|
@@ -64,6 +76,6 @@ A host MUST NOT deliver events a `replay` fork re-emits as fixed history; replay
|
|
|
64
76
|
|
|
65
77
|
## Egress
|
|
66
78
|
|
|
67
|
-
At registration a host MUST reject (`400 webhook_url_rejected`) non-`https://` URLs, RFC 1918 and loopback and link-local ranges, IPv6 ULA, cloud metadata hosts, and `localhost`. At delivery time a host MUST re-resolve the hostname, validate every resolved address against the same denied ranges plus its own denylist, connect to the validated address without re-resolving, and refuse to follow redirects (invariant `webhook-delivery-egress-revalidation`, reference-impl tier). An IPv4-mapped IPv6 address (`::ffff:0:0/96`) MUST be judged by the IPv4 address it embeds, whatever its spelling
|
|
79
|
+
At registration a host MUST reject (`400 webhook_url_rejected`) non-`https://` URLs, RFC 1918 and loopback and link-local ranges, IPv6 ULA, cloud metadata hosts, and `localhost`. At delivery time a host MUST re-resolve the hostname, validate every resolved address against the same denied ranges plus its own denylist, connect to the validated address without re-resolving, and refuse to follow redirects (invariant `webhook-delivery-egress-revalidation`, reference-impl tier). An IPv4-mapped IPv6 address (`::ffff:0:0/96`) MUST be judged by the IPv4 address it embeds, whatever its spelling. An address embedding IPv4 in another standard translation form (IPv4-compatible `::/96`, NAT64 `64:ff9b::/96`, 6to4 `2002::/16`) SHOULD be judged the same way, and those prefixes SHOULD NOT be denied wholesale. A host SHOULD refuse every destination the IANA special-purpose address registries mark not globally reachable (RFC 0196 §B).
|
|
68
80
|
|
|
69
81
|
See also: events.md, replay.md, persistence.md, security-defaults.md.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
A workflow-chain pack ships a reusable fragment a host expands into a concrete definition, and may compose other chains as co-registered children.
|
|
8
|
+
A workflow-chain pack ships a reusable fragment a host expands into a concrete definition, and may compose other chains as co-registered children. The manifest is `schemas/v2/workflow-chain-pack-manifest.schema.json`; installation and signing follow packs.md.
|
|
9
9
|
|
|
10
10
|
## Exact pins
|
|
11
11
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./corrections.schema.json",
|
|
3
|
+
"$comment": "RFC 0197 §A.4 — v2 Class-3 corrections. Seeded with P3 only. The 2.8.2 removal of `workflowChainPacks.deferredParameters` and `.hostExpansionSeam` (P1) is deliberately NOT seeded: a committed bundle carried `deferredParameters` and then failed `capabilities-root-closed`, so the row would fail R3 — which is the point. P1 is recorded as the motivating defect in COMPATIBILITY.md §3a, not laundered into this register.",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"updated": "2026-09-22",
|
|
6
|
+
"rows": [
|
|
7
|
+
{
|
|
8
|
+
"id": "openwop.correction.v2.1",
|
|
9
|
+
"date": "2026-09-20",
|
|
10
|
+
"class": "w3c-class-3",
|
|
11
|
+
"releasedIn": "2.32.0",
|
|
12
|
+
"rfc": "0177",
|
|
13
|
+
"pointers": [
|
|
14
|
+
"schemas/v2/artifact-type-pack-manifest.schema.json#/signing",
|
|
15
|
+
"schemas/v2/chat-card-pack-manifest.schema.json#/signing",
|
|
16
|
+
"schemas/v2/connection-pack-manifest.schema.json#/signing",
|
|
17
|
+
"schemas/v2/form-content-pack-manifest.schema.json#/signing",
|
|
18
|
+
"schemas/v2/node-pack-manifest.schema.json#/signing",
|
|
19
|
+
"schemas/v2/prompt-pack-manifest.schema.json#/signing",
|
|
20
|
+
"schemas/v2/workflow-chain-pack-manifest.schema.json#/signing",
|
|
21
|
+
"schemas/v2/workflow-chain-pack-manifest.schema.json#/chains/[]/dag/nodes/[]/config"
|
|
22
|
+
],
|
|
23
|
+
"compatibilityEntry": "the v2 bare pack-manifest `signing` block and `FragmentNode.config`",
|
|
24
|
+
"priorShapeCensus": {
|
|
25
|
+
"bundles": 0,
|
|
26
|
+
"manifests": 0,
|
|
27
|
+
"manifestsScanned": 190,
|
|
28
|
+
"note": "The prior shape is a manifest shape, not a discovery shape, so no bundle could carry it and the bundle leg is 0 by construction. The registry leg was measured at the correction: 0 of 190 published v2 pack.json documents validated against the schemas BEFORE the change and 185 of 190 after, so no published document carried the `{ publicKeyRef, signatureRef, method }` block the schemas described. `spec/v2/core/packs.md` §Signing, RFC 0177 §C.3 and migration row openwop.migration.C10.1 had already replaced it with `{ keyId, scheme }`; the schemas were the outlier against the prose, the Accepted RFC and the registry at once. `signing` stays OPTIONAL on a bare manifest, so no previously-valid unsigned document is invalidated. FragmentNode.config was closed by the v1→v2 seed against its own description, failing 73 of 81 published chain packs; reopening it narrows nothing."
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v2/corrections.schema.json",
|
|
4
|
+
"title": "OpenWOP v2 Class-3 corrections register",
|
|
5
|
+
"description": "Shape of spec/v2/corrections.json (RFC 0197 §A.4). A W3C Process Class 3 correction — one that MAY affect conformance but adds no feature — MAY change a v2 shape outside the §A.2 retirement predicate only when nothing conforming stops conforming AND R3 holds for the prior shape (no committed v2 host bundle and no published registry manifest carries it). This register is the machine-readable half of the COMPATIBILITY.md §3 entry: scripts/check-v2-retirement.mjs re-runs the bundle and registry scan over every row, so `priorShapeCensus` is a claim the gate falsifies rather than prose nobody re-reads. scripts/check-v2-surface-monotone.mjs admits a baseline removal whose pointer a row names. Data, not a wire artifact.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["$schema", "version", "updated", "rows"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"$schema": { "type": "string", "const": "./corrections.schema.json" },
|
|
11
|
+
"$comment": { "type": "string" },
|
|
12
|
+
"version": { "type": "integer", "const": 1 },
|
|
13
|
+
"updated": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
|
|
14
|
+
"rows": { "type": "array", "minItems": 0, "items": { "$ref": "#/$defs/row" } }
|
|
15
|
+
},
|
|
16
|
+
"$defs": {
|
|
17
|
+
"row": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"required": ["id", "date", "class", "pointers", "compatibilityEntry", "priorShapeCensus"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"id": { "type": "string", "pattern": "^openwop\\.correction\\.v2\\.[0-9]+$" },
|
|
23
|
+
"date": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", "description": "The date the correction landed, matching its COMPATIBILITY.md §3 entry." },
|
|
24
|
+
"class": { "type": "string", "const": "w3c-class-3", "description": "Only Class 3 belongs here. A Class 2 editorial change moves no shape and needs no row; anything that invalidates a conforming document is a major (§A.1), not a correction." },
|
|
25
|
+
"releasedIn": { "type": "string", "pattern": "^2\\.[0-9]+(\\.[0-9]+)?$", "description": "The corpus release that carried the correction." },
|
|
26
|
+
"rfc": { "type": ["string", "null"], "pattern": "^[0-9]{4}$", "description": "The RFC under which the correction landed, or null when it landed under an already-Accepted RFC with no new filing." },
|
|
27
|
+
"pointers": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"minItems": 1,
|
|
30
|
+
"description": "Every schema pointer the correction moved, as `<repo-relative file>#<INSTANCE pointer>` \u2014 the document-shaped path scripts/generate-v2-surface-baseline.mjs prints (`#/signing`, `#/chains/[]/dag/nodes/[]/config`), never the schema-shaped one (`#/properties/signing`), because a `$defs` name is not a surface. scripts/check-v2-surface-monotone.mjs matches a baseline removal against this list, so a pointer left out is a removal the monotone gate refuses.",
|
|
31
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9_./-]+#(/[^#|]*)?$" }
|
|
32
|
+
},
|
|
33
|
+
"compatibilityEntry": { "type": "string", "minLength": 1, "description": "A literal substring of the COMPATIBILITY.md §3 \"correction on record\" entry. The gate fails when it drifts — a register row whose prose entry has been reworded away is an unrecorded shape change." },
|
|
34
|
+
"priorShapeCensus": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": ["bundles", "manifests", "note"],
|
|
38
|
+
"description": "RFC 0197 R3, evaluated for the PRIOR shape at the time of the correction. Both counts MUST be 0; `manifests: null` is not an absence of evidence that may be read as evidence of absence — the gate refuses it.",
|
|
39
|
+
"properties": {
|
|
40
|
+
"bundles": { "type": "integer", "minimum": 0, "description": "Committed evidence/v2-host-bundles/*.json whose discovery.document carried the prior shape." },
|
|
41
|
+
"manifests": { "type": ["integer", "null"], "minimum": 0, "description": "Published registry manifests that carried it. null means no census was run." },
|
|
42
|
+
"manifestsScanned": { "type": ["integer", "null"], "minimum": 0, "description": "How many manifests the census read. A count of 0 out of 0 witnesses nothing." },
|
|
43
|
+
"note": { "type": "string", "minLength": 1, "description": "How the census was taken and why nothing conforming stopped conforming." }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
package/spec/v2/declaration.json
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"key": "implementation",
|
|
62
62
|
"kind": "metadata",
|
|
63
63
|
"schema": "metadata/implementation",
|
|
64
|
-
"note":
|
|
64
|
+
"note": "RFC 0208 §G",
|
|
65
65
|
"disposition": "kept"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
{
|
|
324
324
|
"key": "nodePackRuntimes",
|
|
325
325
|
"kind": "family",
|
|
326
|
-
"normativeText": ["spec/
|
|
326
|
+
"normativeText": ["spec/v2/core/node-pack-runtimes.md"],
|
|
327
327
|
"anchor": "core",
|
|
328
328
|
"section": "core/capabilities.md#nodePackRuntimes",
|
|
329
329
|
"peerDependencyId": "nodePackRuntimes",
|
|
@@ -405,7 +405,7 @@
|
|
|
405
405
|
{
|
|
406
406
|
"key": "purposePropagation",
|
|
407
407
|
"kind": "family",
|
|
408
|
-
"normativeText": ["spec/
|
|
408
|
+
"normativeText": ["spec/v2/core/security-defaults.md"],
|
|
409
409
|
"anchor": "core",
|
|
410
410
|
"section": "core/capabilities.md#purposePropagation",
|
|
411
411
|
"peerDependencyId": "purposePropagation",
|
|
@@ -464,7 +464,7 @@
|
|
|
464
464
|
{
|
|
465
465
|
"key": "credentials",
|
|
466
466
|
"kind": "family",
|
|
467
|
-
"normativeText": ["spec/
|
|
467
|
+
"normativeText": ["spec/v2/core/oauth.md"],
|
|
468
468
|
"anchor": "core",
|
|
469
469
|
"section": "core/capabilities.md#credentials",
|
|
470
470
|
"peerDependencyId": "credentials",
|
|
@@ -530,7 +530,7 @@
|
|
|
530
530
|
{
|
|
531
531
|
"key": "oauth",
|
|
532
532
|
"kind": "family",
|
|
533
|
-
"normativeText": ["spec/
|
|
533
|
+
"normativeText": ["spec/v2/core/oauth.md"],
|
|
534
534
|
"anchor": "core",
|
|
535
535
|
"section": "core/capabilities.md#oauth",
|
|
536
536
|
"peerDependencyId": "oauth",
|
|
@@ -541,11 +541,13 @@
|
|
|
541
541
|
},
|
|
542
542
|
"facets": [
|
|
543
543
|
"grants",
|
|
544
|
-
"providers"
|
|
544
|
+
"providers",
|
|
545
|
+
"credentialInterrupt"
|
|
545
546
|
],
|
|
546
547
|
"floorScenarios": [],
|
|
547
548
|
"requirementIds": [],
|
|
548
|
-
"owningRfc": "0047"
|
|
549
|
+
"owningRfc": "0047",
|
|
550
|
+
"facetsFrom": "spec/v2/facets/oauth.schema.json"
|
|
549
551
|
},
|
|
550
552
|
{
|
|
551
553
|
"key": "authorization",
|
|
@@ -990,7 +992,7 @@
|
|
|
990
992
|
"requirementIds": [],
|
|
991
993
|
"owningRfc": "0078",
|
|
992
994
|
"normativeText": [
|
|
993
|
-
"spec/
|
|
995
|
+
"spec/v2/core/tool-catalog.md"
|
|
994
996
|
]
|
|
995
997
|
},
|
|
996
998
|
{
|
|
@@ -1146,6 +1148,7 @@
|
|
|
1146
1148
|
"facets": [
|
|
1147
1149
|
"deadLetter",
|
|
1148
1150
|
"retryPolicy",
|
|
1151
|
+
"secretRotation",
|
|
1149
1152
|
"signatureAlgorithms"
|
|
1150
1153
|
],
|
|
1151
1154
|
"floorScenarios": [],
|
|
@@ -1200,7 +1203,8 @@
|
|
|
1200
1203
|
"agentCardUrl",
|
|
1201
1204
|
"streaming",
|
|
1202
1205
|
"pushNotifications",
|
|
1203
|
-
"durableTasks"
|
|
1206
|
+
"durableTasks",
|
|
1207
|
+
"agentCards"
|
|
1204
1208
|
],
|
|
1205
1209
|
"floorScenarios": [],
|
|
1206
1210
|
"requirementIds": [],
|
|
@@ -1458,7 +1462,7 @@
|
|
|
1458
1462
|
{
|
|
1459
1463
|
"key": "mcp",
|
|
1460
1464
|
"kind": "family",
|
|
1461
|
-
"normativeText": ["spec/v2/core/interop.md"],
|
|
1465
|
+
"normativeText": ["spec/v2/core/interop.md", "spec/v2/core/host-services.md"],
|
|
1462
1466
|
"anchor": "core",
|
|
1463
1467
|
"section": "core/capabilities.md#mcp",
|
|
1464
1468
|
"peerDependencyId": "mcp",
|
|
@@ -1476,7 +1480,8 @@
|
|
|
1476
1480
|
"features",
|
|
1477
1481
|
"serverUrls",
|
|
1478
1482
|
"serverMount",
|
|
1479
|
-
"mrtr"
|
|
1483
|
+
"mrtr",
|
|
1484
|
+
"client"
|
|
1480
1485
|
],
|
|
1481
1486
|
"floorScenarios": [],
|
|
1482
1487
|
"requirementIds": [],
|
|
@@ -1759,8 +1764,8 @@
|
|
|
1759
1764
|
],
|
|
1760
1765
|
"floorScenarios": [],
|
|
1761
1766
|
"requirementIds": [],
|
|
1762
|
-
"owningRfc": "
|
|
1763
|
-
"reason": "RFC 0169 \u00a7C.5 (
|
|
1767
|
+
"owningRfc": "0209",
|
|
1768
|
+
"reason": "RFC 0169 \u00a7C.5 (claims-check; ext/); RFC 0209: the ext README is the v2 contract for `ui.a2ui-surface` schema version 2; facet `deltaTransport` deprecated for v2 (RFC 0197 retirement path)"
|
|
1764
1769
|
},
|
|
1765
1770
|
{
|
|
1766
1771
|
"key": "brand",
|
|
@@ -212,7 +212,9 @@
|
|
|
212
212
|
]
|
|
213
213
|
},
|
|
214
214
|
"until": {
|
|
215
|
-
"type": "string"
|
|
215
|
+
"type": "string",
|
|
216
|
+
"pattern": "^2\\.[0-9]+$",
|
|
217
|
+
"description": "RFC 0197 \u00a7C.8 \u2014 the CORPUS shape-hold: no surface of this family is retired before this 2.x minor. scripts/check-v2-retirement.mjs R5 refuses a removal whose `removeIn` is not later than it. This is NOT the wire record\u2019s `until` (spec/v2/core/capabilities.md \u00a72), which is the host\u2019s own timeline for its own offer \u2014 two fields with one name and different owners, which is why the distinction is written here. No declaration row sets it today."
|
|
216
218
|
}
|
|
217
219
|
}
|
|
218
220
|
},
|
package/spec/v2/errors.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://openwop.dev/spec/v2/errors.schema.json",
|
|
3
3
|
"$comment": "RFC 0171 §B.1 — the error registry: one row per code {code, httpStatus, retriable, details, since, deprecated?}. schemas/v2/error-envelope.schema.json is GENERATED from it (scripts/generate-error-envelope.mjs). Retry timing lives in Retry-After only (§B.2). statusSource records whether the status was stated in v1 prose, a v1 convention, or decided here. details is null until a code's details schema is registered (a null row means details is an open object for that code — closure over details is the RFC 0171 Phase 3 follow-up G-row).",
|
|
4
4
|
"version": "2.0",
|
|
5
|
-
"updated": "2026-09-
|
|
5
|
+
"updated": "2026-09-23",
|
|
6
6
|
"vendorCodePattern": "^(?!openwop\\.)[a-z][a-z0-9]*(-[a-z0-9]+)*\\.[a-z][a-z0-9_]*$",
|
|
7
7
|
"rows": [
|
|
8
8
|
{
|
|
@@ -167,6 +167,15 @@
|
|
|
167
167
|
"since": "1.0",
|
|
168
168
|
"source": "spec/v1/node-packs.md"
|
|
169
169
|
},
|
|
170
|
+
{
|
|
171
|
+
"code": "unsupported_runtime",
|
|
172
|
+
"httpStatus": 400,
|
|
173
|
+
"statusSource": "v1 convention (node-packs.md)",
|
|
174
|
+
"retriable": false,
|
|
175
|
+
"details": null,
|
|
176
|
+
"since": "1.0",
|
|
177
|
+
"source": "spec/v1/node-packs.md"
|
|
178
|
+
},
|
|
170
179
|
{
|
|
171
180
|
"code": "protocol_version_mismatch",
|
|
172
181
|
"httpStatus": 400,
|
|
@@ -261,6 +270,33 @@
|
|
|
261
270
|
"since": "2.0",
|
|
262
271
|
"source": "spec/v2/core/webhooks.md §Egress"
|
|
263
272
|
},
|
|
273
|
+
{
|
|
274
|
+
"code": "webhook_endpoint_unverified",
|
|
275
|
+
"httpStatus": 400,
|
|
276
|
+
"statusSource": "v2 decision",
|
|
277
|
+
"retriable": false,
|
|
278
|
+
"details": null,
|
|
279
|
+
"since": "2.36",
|
|
280
|
+
"source": "RFC 0201 §D"
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"code": "connector_auth_declined",
|
|
284
|
+
"httpStatus": 401,
|
|
285
|
+
"statusSource": "v2 decision",
|
|
286
|
+
"retriable": false,
|
|
287
|
+
"details": null,
|
|
288
|
+
"since": "2.36",
|
|
289
|
+
"source": "RFC 0199 §C.4"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"code": "connection_auth_metadata_mismatch",
|
|
293
|
+
"httpStatus": 422,
|
|
294
|
+
"statusSource": "v2 decision",
|
|
295
|
+
"retriable": false,
|
|
296
|
+
"details": null,
|
|
297
|
+
"since": "2.36",
|
|
298
|
+
"source": "RFC 0199 §B.3"
|
|
299
|
+
},
|
|
264
300
|
{
|
|
265
301
|
"code": "audience_mismatch",
|
|
266
302
|
"httpStatus": 401,
|
|
@@ -288,6 +324,15 @@
|
|
|
288
324
|
"since": "2.0",
|
|
289
325
|
"source": "RFC 0170 §B.3"
|
|
290
326
|
},
|
|
327
|
+
{
|
|
328
|
+
"code": "credential_lifetime_exceeded",
|
|
329
|
+
"httpStatus": 401,
|
|
330
|
+
"statusSource": "v2 decision",
|
|
331
|
+
"retriable": false,
|
|
332
|
+
"details": null,
|
|
333
|
+
"since": "2.36",
|
|
334
|
+
"source": "RFC 0210 §B"
|
|
335
|
+
},
|
|
291
336
|
{
|
|
292
337
|
"code": "delegation_expired",
|
|
293
338
|
"httpStatus": 401,
|