@openwop/spec-artifacts 2.42.5 → 2.42.7

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.
Files changed (63) hide show
  1. package/CORPUS-STAMP.json +64 -63
  2. package/api/seams-v2.yaml +238 -316
  3. package/api/v2/asyncapi.yaml +83 -113
  4. package/api/v2/openapi.yaml +339 -724
  5. package/package.json +1 -1
  6. package/schemas/audit-verify-result.schema.json +2 -2
  7. package/schemas/v2/audit-verify-result.schema.json +2 -2
  8. package/schemas/v2/capabilities.schema.json +2 -5
  9. package/spec/v1/core-standard-manifest.json +2 -2
  10. package/spec/v1/gaps.json +171 -1
  11. package/spec/v2/README.md +34 -36
  12. package/spec/v2/core/capabilities.md +186 -119
  13. package/spec/v2/core/conformance.md +78 -27
  14. package/spec/v2/core/connection-packs.md +8 -3
  15. package/spec/v2/core/conversation.md +10 -4
  16. package/spec/v2/core/errors.md +30 -9
  17. package/spec/v2/core/events.md +116 -80
  18. package/spec/v2/core/form-content-packs.md +11 -13
  19. package/spec/v2/core/headers.md +22 -14
  20. package/spec/v2/core/host-services.md +22 -5
  21. package/spec/v2/core/idempotency.md +48 -36
  22. package/spec/v2/core/identity.md +110 -42
  23. package/spec/v2/core/interop.md +82 -21
  24. package/spec/v2/core/interrupt.md +79 -40
  25. package/spec/v2/core/node-pack-runtimes.md +18 -4
  26. package/spec/v2/core/oauth.md +40 -6
  27. package/spec/v2/core/overview.md +61 -33
  28. package/spec/v2/core/packs.md +53 -28
  29. package/spec/v2/core/persistence.md +61 -80
  30. package/spec/v2/core/replay.md +56 -42
  31. package/spec/v2/core/runs.md +198 -60
  32. package/spec/v2/core/security-defaults.md +57 -33
  33. package/spec/v2/core/tool-catalog.md +29 -6
  34. package/spec/v2/core/versioning.md +95 -49
  35. package/spec/v2/core/webhooks.md +59 -20
  36. package/spec/v2/core/workflow-chain-packs.md +16 -14
  37. package/spec/v2/corrections.json +17 -1
  38. package/spec/v2/corrections.schema.json +1 -1
  39. package/spec/v2/declaration.json +24 -7
  40. package/spec/v2/declaration.schema.json +10 -0
  41. package/spec/v2/errors.json +109 -2
  42. package/spec/v2/errors.schema.json +38 -0
  43. package/spec/v2/ext/README.md +36 -23
  44. package/spec/v2/ext/a2uiSurface/README.md +75 -89
  45. package/spec/v2/ext/brand/README.md +15 -15
  46. package/spec/v2/ext/canvas/README.md +15 -15
  47. package/spec/v2/ext/chat/README.md +15 -15
  48. package/spec/v2/ext/coordination/README.md +15 -15
  49. package/spec/v2/ext/dataIntegration/README.md +17 -20
  50. package/spec/v2/ext/entities/README.md +15 -15
  51. package/spec/v2/ext/grpc-transport/README.md +6 -8
  52. package/spec/v2/ext/kanban/README.md +15 -15
  53. package/spec/v2/ext/knowledge/README.md +15 -15
  54. package/spec/v2/ext/launchStudio/README.md +16 -16
  55. package/spec/v2/ext/messaging/README.md +15 -15
  56. package/spec/v2/ext/portability/README.md +3 -17
  57. package/spec/v2/ext/provider-idempotency/README.md +7 -10
  58. package/spec/v2/ext/restTransport/README.md +30 -19
  59. package/spec/v2/ext/sandbox-runtime-notes/README.md +7 -9
  60. package/spec/v2/ext/webResearch/README.md +16 -16
  61. package/spec/v2/profiles.json +6 -2
  62. package/spec/v2/release.json +2 -2
  63. package/spec/v2/surface-baseline.json +542 -2
@@ -1,74 +1,99 @@
1
1
  # Security Defaults
2
2
 
3
- > **Status: Stable · RFC 0173 (§A–§E), 0164 §22, 0170 §B.**
3
+ > **Status: Stable.**
4
4
  > **Normative home:** `sandbox`, `compensation`, `purposePropagation`.
5
5
 
6
6
  ## Why this exists
7
7
 
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.
8
+ In v2 a security behavior is not an opt-in flag. This document is the obligation table: which surface binds which behavior, the invariant, and the witness.
9
9
 
10
10
  ## The rule
11
11
 
12
- A security-load-bearing behavior is an obligation of the surface that needs it (RFC 0173 §A.1). Advertising the surface binds the behavior; no discovery field gates it. Every obligation in `core/` MUST name a surface, an invariant, and a witness class other than `unwitnessable`; a row that cannot is not in `core/` (§D.1).
12
+ A security-load-bearing behavior is an obligation of the surface that needs it. Advertising the surface binds the behavior; no discovery field gates it.
13
13
 
14
- A host MUST NOT advertise a surface whose obligation it has relaxed (§A.2).
14
+ - Every obligation in `core/` MUST name a surface, an invariant, and a witness class other than `unwitnessable`. A row that cannot is not in `core/`.
15
+ - A host MUST NOT advertise a surface whose obligation it has relaxed.
15
16
 
16
17
  ## The obligation table
17
18
 
18
- | Surface advertised | Obligation (v1 flag it replaces) | Witness | Invariant |
19
+ | Surface advertised | Obligation | Witness | Invariant |
19
20
  | --- | --- | --- | --- |
20
- | any lane in `auth.lanes[]` | the lane obligations of identity.md: the verify → bind → audience → resolve → fail-closed pipeline (RFC 0170 §B.1); a named trust root as `subject.issuer` (§B.2); revocation for the lane (§B.3); the advertised `minimumAssurance` floor, `mtls.required` becoming `key-bound` (§B.4); lane-scoped delegation proof (§B.5). Replaces the fourteen `auth.*` gates. | unaided or seam-gated per lane | `sender-constraint-no-bearer-downgrade`; per-lane rows (RFC 0170 §E) |
21
- | both `saml` and `scim` lanes | the leaver contract (RFC 0164; already mandatory) | seam-gated (RFC 0163 seams) | `subject-link-leaver-deny`, `subject-link-mandatory-when-both-advertised` |
22
- | `replay` (any mode) | side-effect suppression with `recorded-outcome` semantics as the only conforming behavior; `none` is not a value (replay.md) | witnessable-gated via the effect-seam manifest | `replay-fanout-no-refire`; effect-seam rows registered at Accepted |
23
- | `webhooks` | durable delivery: retries per the advertised policy with backoff, dead-letter on exhaustion, at-least-once; best-effort is not a conforming delivery mode (replaces `webhooks.durable`) | witnessable-gated (`webhook-signed-delivery` + dead-letter leg) | registered at Accepted (RFC 0173) |
24
- | `interrupt` with `approversList` or `refKinds` | enforcement: a resolver not in the list, group, or role MUST be refused (replaces the `approverRouting` gate; `refKinds[]` stays a facet) | witnessable-gated | registered at Accepted (RFC 0173) |
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
- | `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
- | `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` |
21
+ | any lane in `auth.lanes[]` | the lane obligations (§Auth lanes) | unaided or seam-gated per lane | `sender-constraint-no-bearer-downgrade`; per-lane rows |
22
+ | both `saml` and `scim` lanes | the leaver contract (mandatory) | seam-gated | `subject-link-leaver-deny`, `subject-link-mandatory-when-both-advertised` |
23
+ | `replay` (any mode) | side-effect suppression (§Replay suppression) | witnessable-gated via the effect-seam manifest | `replay-fanout-no-refire`; effect-seam rows registered at Accepted |
24
+ | `webhooks` | durable delivery (§Webhook durability) | witnessable-gated (`webhook-signed-delivery` + dead-letter leg) | registered at Accepted |
25
+ | `interrupt` with `approversList` or `refKinds` | approver enforcement (§Approver enforcement) | witnessable-gated | registered at Accepted |
26
+ | `packs` (pack execution) | isolation (§Sandbox isolation) | witnessable-gated (eight `sandbox-*` scenarios) | `node-pack-sandbox-*` |
27
+ | `compensation` | plan, attempt and inverse-action obligations (§Compensation) | witnessable-gated (reads) + seam-gated (operator actions) | `compensation-replay-no-refire`, `compensation-effect-id-retry-stable` |
28
+ | `idempotency` | Layer-2 effect identity (§Layer-2 effect identity) | witnessable-gated (fixture provider) | `logical-effect-id-retry-stable` |
29
+ | an `oauth2` or `oidc` lane | protected-resource metadata and challenges ([identity.md §2.5](identity.md)) | witnessable-gated | `auth-challenge-no-oracle` |
29
30
  | any outbound request | no inbound credential on an onward hop (§Onward hops) | seam-gated | `inbound-credential-no-passthrough` |
30
31
 
31
32
  ### Auth lanes
32
33
 
33
- The obligations are identity.md §2 and bind on advertisement.
34
+ The obligations are [identity.md §2](identity.md) and bind on advertisement:
35
+
36
+ - the verify → bind → audience → resolve → fail-closed pipeline;
37
+ - a named trust root as `subject.issuer`;
38
+ - revocation for the lane;
39
+ - the advertised `minimumAssurance` floor, with `mtls.required` becoming `key-bound`;
40
+ - lane-scoped delegation proof.
34
41
 
35
42
  ### Replay suppression
36
43
 
37
- Stated in replay.md §Suppression and §"The effect-seam manifest"; the `replay-side-effect-suppression` scenario witnesses it.
44
+ Side-effect suppression with `recorded-outcome` semantics is the only conforming behavior; `none` is not a value. Stated in replay.md §Suppression and §"The effect-seam manifest"; the `replay-side-effect-suppression` scenario witnesses it.
38
45
 
39
46
  ### Webhook durability
40
47
 
41
- Stated in webhooks.md §Durability; the `webhook-durable-delivery` scenario witnesses it.
48
+ Durable delivery means retries per the advertised policy with backoff, dead-letter on exhaustion, and at-least-once delivery; best-effort is not a conforming delivery mode. Stated in webhooks.md §Durability; the `webhook-durable-delivery` scenario witnesses it.
42
49
 
43
50
  ### Approver enforcement
44
51
 
45
- Stated in interrupt.md §"Approver enforcement"; the `approver-enforced` scenario witnesses it.
52
+ A resolver not in the list, group, or role MUST be refused; `refKinds[]` stays a facet. Stated in interrupt.md §"Approver enforcement"; the `approver-enforced` scenario witnesses it.
46
53
 
47
54
  ### Sandbox isolation
48
55
 
49
- A host that executes third-party packs MUST enforce the eight `node-pack-sandbox-*` invariants of `SECURITY/invariants.yaml` (`no-process`, `network-gated`, `fs-gated`, `no-env`, `timeout`, `memory-cap`, `isolated-context`, `no-eval`) and MUST advertise `sandbox.isolationModel ∈ wasm | process | container | vm` (`spec/v2/facets/sandbox.schema.json`). `node:vm` is not a value. A host that cannot isolate MUST NOT execute third-party packs; it MAY register and validate them. The `no-eval` row stays reference-impl in `ext/sandbox-runtime-notes` (§D.1). The `pack-isolation` scenario drives the eight legs.
56
+ A host that executes third-party packs:
57
+
58
+ - MUST enforce the eight `node-pack-sandbox-*` invariants of `SECURITY/invariants.yaml`: `no-process`, `network-gated`, `fs-gated`, `no-env`, `timeout`, `memory-cap`, `isolated-context`, `no-eval`;
59
+ - MUST advertise `sandbox.isolationModel ∈ wasm | process | container | vm` (`spec/v2/facets/sandbox.schema.json`). `node:vm` is not a value. `sandbox.isolationModel` names the mechanism and never relaxes the property.
60
+
61
+ A host that cannot isolate MUST NOT execute third-party packs; it MAY register and validate them. The `no-eval` row stays reference-impl in `ext/sandbox-runtime-notes`. The `pack-isolation` scenario drives the eight legs.
50
62
 
51
63
  The remaining `sandbox` facets name the bound each invariant already carries: `allowedHostCalls` is the host-call allowlist `network-gated` and `fs-gated` enforce, `memoryLimitBytes` is the ceiling of `memory-cap`, and `wallClockLimitMs` is the ceiling of `timeout`. An advertised bound MUST be enforced; none of the three gates the invariant, which binds whether or not the facet is advertised.
52
64
 
53
65
  ### Compensation
54
66
 
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.
67
+ 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. The read projection and the operator action family are the canonical wire. A host that does not advertise `compensation` has no obligation.
56
68
 
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.
69
+ The facets bind the policy shape (`schemas/v2/compensation-policy.schema.json`):
70
+
71
+ - `compensation.orderingModels` MUST list `reverse-completion` and MAY add `dependency-graph`; a policy naming a model outside it MUST be refused at registration.
72
+ - `compensation.profileVersion` participates in the inverse-action identity, so a policy naming a different one MUST be refused.
73
+ - `compensation.manualIntervention` is the `manual` status — a host advertising it records the unwind rather than abandoning it.
58
74
 
59
75
  ### Layer-2 effect identity
60
76
 
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).
77
+ Layer-2 effect identity is keyed on business identity; the activity recipe is the fallback. 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".
62
78
 
63
79
  ### Onward hops
64
80
 
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). One credential is not inbound in this sense: an A2A push-config credential (`authentication.credentials`, `token`) is one the client gave the host for its registered push URL. A host MAY attach it only to a push delivery to that URL's origin, MUST NOT attach it after a redirect or to any other request, MUST discard it when the config is deleted or the task's final push is attempted, and MUST hold it by reference outside the event log, run state, debug bundle and every response (interop.md §"A2A push delivery", RFC 0214).
81
+ A host MUST NOT attach a credential it received inbound to any outbound request: A2A, MCP, webhook, callback, `httpClient` or connector. Inbound credentials are an `Authorization`, `Cookie` or `Proxy-Authorization` value, a DPoP proof, an interrupt token, a peer's bearer, or credential material carried in a body.
82
+
83
+ 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](identity.md)).
66
84
 
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.
85
+ One credential is not inbound in this sense: an A2A push-config credential (`authentication.credentials`, `token`) is one the client gave the host for its registered push URL ([interop.md §"A2A push delivery"](interop.md)). A host:
86
+
87
+ - MAY attach it only to a push delivery to that URL's origin;
88
+ - MUST NOT attach it after a redirect or to any other request;
89
+ - MUST discard it when the config is deleted or the task's final push is attempted;
90
+ - MUST hold it by reference outside the event log, run state, debug bundle and every response.
91
+
92
+ 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.
68
93
 
69
94
  ## Relaxations
70
95
 
71
- A relaxation, where one is legitimate — a development deployment, a single-tenant appliance — is an operator setting, never a discovery field (RFC 0173 §A.2). Every relaxation a host runs under MUST be recorded in its certification bundle as `host.relaxations[]` (`schemas/v2/certification-bundle.schema.json`): `{ obligation, durability, reason }`, `durability ∈ session | deployment | persisted`.
96
+ A relaxation, where one is legitimate — a development deployment, a single-tenant appliance — is an operator setting, never a discovery field. Every relaxation a host runs under MUST be recorded in its certification bundle as `host.relaxations[]` (`schemas/v2/certification-bundle.schema.json`): `{ obligation, durability, reason }`, `durability ∈ session | deployment | persisted`.
72
97
 
73
98
  | Durability | Meaning |
74
99
  | --- | --- |
@@ -80,7 +105,7 @@ A bundle that records a relaxation MUST NOT certify the profile the relaxed obli
80
105
 
81
106
  ## Three dispositions
82
107
 
83
- Every security obligation in `core/` is exactly one of (RFC 0173 §D.1):
108
+ Every security obligation in `core/` is exactly one of:
84
109
 
85
110
  | Disposition | Where | Requirement |
86
111
  | --- | --- | --- |
@@ -88,23 +113,22 @@ Every security obligation in `core/` is exactly one of (RFC 0173 §D.1):
88
113
  | extension | `spec/v2/ext/` | MUST declare a witness class and both maturity axes. |
89
114
  | removed | — | No text survives. |
90
115
 
91
- Operation ids in the declaration file are canonical, and aliases are migration
92
- register rows. The provider semantic-option registry is
93
- `spec/v2/ext/provider-idempotency/registry.json`; provider qualification uses a
94
- fixture that rejects a changed idempotency key (§D.2).
116
+ Operation ids in the declaration file are canonical, and aliases are migration register rows. The provider semantic-option registry is `spec/v2/ext/provider-idempotency/registry.json`; provider qualification uses a fixture that rejects a changed idempotency key.
95
117
 
96
118
  ## Threat models
97
119
 
98
- The following threat-model artifacts are required:
99
-
100
120
  | Artifact | Requirement |
101
121
  | --- | --- |
102
122
  | `SECURITY/threat-model-replay.md` §6 Residual risks | MUST record branch re-fires, seams outside the manifest, and the manifest as a self-declaration. |
103
- | `SECURITY/threat-model-replay.md` §7 Verification, §8 References | MUST name the manifest scenario and `fork-a-v1-run`; a threat model missing a sibling section fails the template gate. |
123
+ | `SECURITY/threat-model-replay.md` §7 Verification, §8 References | MUST name the manifest scenario and `fork-a-v1-run`. |
104
124
  | `SECURITY/threat-model-interop.md` | MUST cover downgrade, identity, and cross-tenant risks in protocol composition. |
105
125
 
126
+ A threat model missing a sibling section fails the template gate.
127
+
106
128
  ## Migration
107
129
 
108
130
  Rows `C6.1`–`C6.9` are `spec/v1/migrations.json` entries.
109
131
 
110
132
  See also: identity.md, replay.md, webhooks.md, capabilities.md, conformance.md.
133
+
134
+ *Sources: RFC 0150, RFC 0163, RFC 0164, RFC 0170, RFC 0173, RFC 0214.*
@@ -1,22 +1,45 @@
1
1
  # Tool catalog
2
2
 
3
- > **Status: Stable · RFC 0078, RFC 0112.**
3
+ > **Status: Stable.**
4
4
  > **Normative home:** `toolCatalog`.
5
5
 
6
6
  ## Why this exists
7
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`.
8
+ A host's tool catalog lists the tools a caller may invoke, with a projection onto MCP `ToolAnnotations`. The shapes are `schemas/v2/tool-descriptor.schema.json` and `schemas/v2/compact-tool-descriptor.schema.json`.
9
9
 
10
10
  ## The catalog
11
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.
12
+ A host advertising `toolCatalog` MUST serve `GET /tools` (a `ToolDescriptor[]`) and `GET /tools/{toolId}`, both read-only.
13
+
14
+ - The list MUST hold only tools the caller may invoke in its tenant.
15
+ - An unknown or unauthorized `toolId` MUST return `404`.
16
+ - `toolCatalog.sources` names the sources projected; a consumer MUST tolerate any subset.
17
+ - A host SHOULD return tools sorted by `toolId`, so an unchanged catalog reads identically.
13
18
 
14
19
  ## The descriptor
15
20
 
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"`.
21
+ - `toolId` MUST be unique in the catalog and stable for a host version.
22
+ - `safetyTier: "exec"` MUST carry `source: "host-extension"`.
23
+ - A descriptor MUST NOT carry credential material.
24
+ - The host MUST assign `safetyTier`, `replayPolicy` and `egress` itself, and MUST NOT copy them from an MCP server's `annotations`, which are untrusted.
25
+ - A `source: "mcp"` tool the host has not classified MUST be `safetyTier: "write"`.
26
+
27
+ `annotations`, when present, MUST carry all four MCP hints, derived from those fields and not from MCP defaults (upstream, `destructiveHint` and `openWorldHint` default to `true`):
17
28
 
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`.
29
+ | Hint | True iff |
30
+ | --- | --- |
31
+ | `readOnlyHint` | `safetyTier` is `pure` or `read` |
32
+ | `destructiveHint` | `safetyTier` is `write` or `exec` |
33
+ | `idempotentHint` | `replayPolicy` is `deterministic` or `idempotent` |
34
+ | `openWorldHint` | `egress` is not `none` |
19
35
 
20
36
  ## Views and sessions
21
37
 
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.
38
+ 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.
39
+
40
+ - A compact `inputSchema` MUST NOT use `$ref`, `oneOf`, `allOf`, `anyOf`, `not`, `patternProperties` or `dependentSchemas` at any depth.
41
+ - Any other `view`, or a host not advertising it, yields the standard view.
42
+
43
+ A host advertising `toolCatalog.sessionLifecycle` MAY bracket calls with content-free `tool.session.opened` and `tool.session.closed`; a consumer MUST tolerate their absence.
44
+
45
+ *Sources: RFC 0078, RFC 0112, RFC 0204.*
@@ -1,77 +1,102 @@
1
1
  # Versioning and Release
2
2
 
3
- > **Status: Stable · RFC 0172, 0179, 0176.**
3
+ > **Status: Stable.**
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
- ## 1. Major negotiation (RFC 0172 §A)
9
+ ## 1. Major negotiation
10
10
 
11
11
  ### 1.1 Advertisement
12
12
 
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>"]`.
13
+ A v2 host MUST advertise two root fields, both REQUIRED in `schemas/v2/capabilities.schema.json` ([capabilities.md](capabilities.md)):
14
14
 
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).
15
+ - `protocolVersions[]` — every `<major>.<minor>` it serves, each matching `^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$`. Through the overlap that is `["1.<n>", "2.<m>"]`; after v1 end-of-support, `["2.<m>"]`.
16
+ - `preferredVersion` — MUST be a member of `protocolVersions[]`. Through the overlap it MUST name a 1.x member, because a header-less request is a v1 client's ([capabilities.md](capabilities.md) §1; §1.3). On a host serving a single major, it MUST equal `protocolVersion`.
17
+
18
+ A host that drops v1 advertises a `2.x` `preferredVersion`; its header-less representation becomes the closed v2 root.
19
+
20
+ A v2 consumer reads `preferredVersion` as the header-less default. When it is absent on a v1 document, the default is `max(protocolVersions[])`, else `protocolVersion`. The suite's `--target-major` defaults from it.
16
21
 
17
22
  ### 1.2 Paths
18
23
 
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.
24
+ - v1 operations keep their `/v1/…` path keys unchanged through the overlap.
25
+ - 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.
26
+ - An unversioned path is the v2 surface; v1's rule that it answers `400` does not apply.
20
27
 
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.
28
+ Advertising a major is a claim about the whole **path space**, not about `/.well-known/openwop` alone (§1.3 selects that resource's representation):
22
29
 
23
- Seam and proprietary paths are not manifest operations and need no per-major twin.
30
+ - 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.
31
+ - 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.
32
+ - Seam and proprietary paths are not manifest operations and need no per-major twin.
24
33
 
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`).
34
+ `spec/v2/path-manifest.json` (generated) lists operations (`method`, `path`, `operationId`) and channels (`name`, `address`) on a bare origin. Every path in it is unversioned; the pairing above compares each row with its `/v1` twin, derived by prefixing.
35
+
36
+ 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 are in [conformance.md](conformance.md).
26
37
 
27
38
  ### 1.3 The request header
28
39
 
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).
40
+ 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. What pins a minor is `minClientVersion` plus the additive rules (`COMPATIBILITY.md` §2.4).
30
41
 
31
42
  | Condition | Host behavior |
32
43
  | --- | --- |
33
44
  | Header names a major in `protocolVersions[]` | MUST serve that major |
34
- | Header names a major not in `protocolVersions[]` | MUST answer `406` `protocol_version_unsupported` with `details.protocolVersions[]` echoing the list |
45
+ | Header names a major not in `protocolVersions[]` | MUST answer `406` `protocol_version_unsupported`, with `details.protocolVersions[]` echoing the list |
35
46
  | Header absent on an unversioned path | MUST serve `preferredVersion`'s major |
36
47
  | `/v1/…` path with `OpenWOP-Version` other than `1` | MUST answer `400` `protocol_version_mismatch` |
37
48
 
38
- A request on a `/v1/…` path key MUST NOT carry `OpenWOP-Version` with a value other than `1`. All three codes are rows in `spec/v2/errors.json` (see `errors.md`).
49
+ A request on a `/v1/…` path key MUST NOT carry `OpenWOP-Version` with a value other than `1`. `protocol_version_unsupported`, `protocol_version_mismatch` and `client_version_unsupported` (§1.5) are rows in `spec/v2/errors.json` ([errors.md](errors.md)).
39
50
 
40
51
  ### 1.4 The response header
41
52
 
42
- Every protocol response MUST carry `OpenWOP-Version: <major>.<minor>` naming the contract that produced it. Reporting a version other than the one used is a silent downgrade and non-conformant; the `dual-stack-negotiation` scenario falsifies it. Emitting the header on `/v1/` responses is additive in v1.x and REQUIRED in v2.
53
+ Every protocol response MUST carry `OpenWOP-Version: <major>.<minor>` naming the contract that produced it, `/v1/` responses included (REQUIRED in v2). Reporting a version other than the one used is a silent downgrade and non-conformant (scenario `dual-stack-negotiation`).
54
+
55
+ A *protocol response* is one produced by an operation named in `spec/v2/path-manifest.json` (or its `/v1/` twin through the overlap). A shell, hosting fallback, conformance seam or proprietary route has no protocol version to name.
43
56
 
44
- A *protocol response* is one produced by an operation named in
45
- `spec/v2/path-manifest.json` (or its `/v1/` twin through the overlap). A shell,
46
- hosting fallback, conformance seam, or proprietary route has no protocol
47
- version to name.
57
+ On a manifest-named path:
48
58
 
49
- **On a manifest-named path, a non-protocol response MUST NOT carry `OpenWOP-Version` and MUST NOT be `application/json`**; a reader, a cache or the suite MUST NOT count a response without the header, or with a `text/html` body, as reaching the operation (`reachedUnderMajor2`). A vendor path (§5) is not a shared name and is unconstrained.
59
+ - A non-protocol response MUST NOT carry `OpenWOP-Version` and MUST NOT be `application/json`.
60
+ - A reader, a cache or the suite MUST NOT count a response without the header, or with a `text/html` body, as reaching the operation (`reachedUnderMajor2`).
50
61
 
51
- **Content negotiation on a shared name is permitted, with conditions.** A host MAY serve a protocol operation and a page under one unversioned name, selecting on `Accept`, iff:
62
+ A vendor path (§5) is not a shared name and is unconstrained.
52
63
 
53
- 1. A request identifying as a protocol client — `OpenWOP-Version` present, **or** an `Accept` admitting `application/json` without preferring `text/html` (absent and `*/*` included) — MUST get the protocol response for the applicable major (§1.3) with `OpenWOP-Version`; only an explicit `text/html` preference selects the page.
54
- 2. The page obeys the paragraph above.
64
+ #### Content negotiation on a shared name
65
+
66
+ A host MAY serve a protocol operation and a page under one unversioned name, selecting on `Accept`, iff:
67
+
68
+ 1. A request identifying as a protocol client — `OpenWOP-Version` present, **or** an `Accept` admitting `application/json` without preferring `text/html` (absent and `*/*` included) — MUST get the protocol response for the applicable major (§1.3) with `OpenWOP-Version`. Only an explicit `text/html` preference selects the page.
69
+ 2. The page obeys the rules above.
55
70
  3. The response carries `Vary: Accept, OpenWOP-Version`.
56
71
 
57
72
  Otherwise the page MUST move off the shared name.
58
73
 
59
74
  ### 1.5 Client precedence and `minClientVersion`
60
75
 
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`.
76
+ 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.
77
+
78
+ `minClientVersion` (axis 15) is optional. When a host advertises it:
62
79
 
63
- ## 2. The 18 version axes (RFC 0172 §B; RFC 0167 §E.1)
80
+ - It MUST use the axis-1 grammar.
81
+ - A host MAY refuse a client below it. A refusal MUST be `426` `client_version_unsupported`.
64
82
 
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.
83
+ ## 2. The 18 version axes
84
+
85
+ Dispositions:
86
+
87
+ - `unify` — one type and grammar, with a codemod.
88
+ - `first-class` — own schema-enforced grammar and negotiation rule.
89
+ - `retire` — absorbed into the capability record's `{status, since, until?}`.
90
+ - `delete` — removed, with a register row.
66
91
 
67
92
  | # | Axis | Disposition | v2 grammar | Owner |
68
93
  | --- | --- | --- | --- | --- |
69
- | 1 | `protocolVersion` | first-class; kept as `preferredVersion`'s twin for v1 readers through the overlap, removed after | `^(0\|[1-9][0-9]*)\.(0\|[1-9][0-9]*)$` | this document |
94
+ | 1 | `protocolVersion` | first-class; `preferredVersion`'s twin for v1 readers through the overlap, removed after | `^(0\|[1-9][0-9]*)\.(0\|[1-9][0-9]*)$` | this document |
70
95
  | 2 | `protocolVersions[]` + `preferredVersion` | first-class, negotiation input | as #1 | this document |
71
96
  | 3 | `engineVersion` | unify: integer everywhere; codemod `openwop.codemod.engine-version-unify` | `integer, minimum 0` | this document |
72
97
  | 4 | `eventLogSchemaVersion` | first-class, the era key | integer; v2 writes `3` | `persistence.md` |
73
98
  | 5 | per-event `schemaVersion` | first-class; §0 growth rule | integer | `events.md` |
74
- | 6 | `schemaVersions` map | first-class; the map moves into the record's `kinds` seat (RFC 0193) | `propertyNames` = the envelope-kind grammar, values `integer, minimum 0`; NOT a closed enum — a vendor kind is host-published and never corpus-declared | `events.md` |
99
+ | 6 | `schemaVersions` map | first-class; the map moves into the record's `kinds` seat | `propertyNames` = the envelope-kind grammar, values `integer, minimum 0`; not a closed enum — a vendor kind is host-published, never corpus-declared | `events.md` |
75
100
  | 7 | `version.pinned` | first-class; the v1-pinned-run disposition | integer min/max | `persistence.md` |
76
101
  | 8 | `contractProvenance` | delete | — | `capabilities.md` |
77
102
  | 9 | `minimumSuiteVersion` | retire into `spec/v2/declaration.json` | semver | `capabilities.md` |
@@ -80,51 +105,72 @@ When both majors are advertised, a v2 client MUST select the highest major it im
80
105
  | 12 | MCP `revisions[]` / `preferredVersion` | first-class facet of `mcp` | date | `interop.md` |
81
106
  | 13 | `multiAgent.executionModel.version` | first-class | integer with a schema `maximum` the suite reads | `events.md` |
82
107
  | 14 | OpenAPI / AsyncAPI `info.version` | generated from the corpus tag | semver | this document |
83
- | 15 | `minClientVersion` | first-class MUST (§1.5) | as #1 | this document |
108
+ | 15 | `minClientVersion` | first-class (§1.5) | as #1 | this document |
84
109
  | 16 | channel `schemaVersion` / `compatibleWith` | first-class | integer / range | `events.md` |
85
110
  | 17 | webhook signature scheme | retire into `deprecations.json` | — | `webhooks.md` |
86
111
  | 18 | pack `engines.openwop` + `registryVersion` | first-class with the absent-ceiling rule | semver range / semver | `packs.md` |
87
112
 
88
- One grammar covers protocol, envelope-kind, and pack axes wherever a version is `<major>.<minor>` (#1, #2, #11, #15). `typeId@<semver>` is a pack axis (`packs.md`); the `2` in `typeId@2.0.0` never means `OpenWOP-Version: 2`. `docs/PROTOCOL-STATUS.md` carries one row per axis (RFC 0172 §D.2).
113
+ - One grammar covers protocol, envelope-kind and pack axes wherever a version is `<major>.<minor>` (#1, #2, #11, #15).
114
+ - `typeId@<semver>` is a pack axis (`packs.md`); the `2` in `typeId@2.0.0` never means `OpenWOP-Version: 2`.
115
+ - `docs/PROTOCOL-STATUS.md` carries one row per axis.
89
116
 
90
117
  ### 2.1 `engineVersion` (axis 3)
91
118
 
92
- `engineVersion` MUST be an integer (`minimum 0`) at the discovery root and on every per-event carrier. A persisted v1 run document that carries the string form is legacy-stamped: the reader MUST normalise it to an integer and MUST NOT rewrite the stored document. The codemod `openwop.codemod.engine-version-unify` MUST refuse any value not matching `^(0|[1-9][0-9]*)$`.
119
+ - `engineVersion` MUST be an integer (`minimum 0`) at the discovery root and on every per-event carrier.
120
+ - A persisted v1 run document that carries the string form is legacy-stamped: the reader MUST normalise it to an integer and MUST NOT rewrite the stored document.
121
+ - The codemod `openwop.codemod.engine-version-unify` MUST refuse any value not matching `^(0|[1-9][0-9]*)$`.
93
122
 
94
- ### 2.2 `eventLogSchemaVersion` (axis 4; RFC 0176 §A.2)
123
+ ### 2.2 `eventLogSchemaVersion` (axis 4)
95
124
 
96
125
  `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`.
97
126
 
98
- ## 3. Where v2 lives (RFC 0172 §C)
127
+ ## 3. Where v2 lives
128
+
129
+ - `spec/v2/core/` and `spec/v2/ext/<key>/` hold the prose.
130
+ - `schemas/v2/` holds every v2 schema, with `$id` under `https://openwop.dev/spec/v2/`; the site publishes them at `/spec/v2/`.
131
+ - The flat `schemas/` tree (v1 `$id`s) is read-only. v1 `$id` values are immutable identifiers: a domain move is answered by a redirect, never a rewrite.
132
+ - AsyncAPI `servers.production.pathname` is empty; every channel address carries its own path, as OpenAPI path keys do.
133
+
134
+ ## 4. One release identity
135
+
136
+ The corpus tag `v2.<minor>.<patch>` (release candidates `v2.0.0-rc.<n>`) is the only release event; suite, SDKs, registry and site derive from it. `spec/v2/release.json` carries the next tag as `version`, and only the release PR that cuts the tag bumps it.
137
+
138
+ - Every human-surface version (README banner, `docs/PROTOCOL-STATUS.md`, OpenAPI and AsyncAPI `info.version`, `conformance/package.json`) MUST be generated from it and checked with `--check` in the merge gate.
139
+ - The published tarball digest MUST equal the tree's as a release precondition.
140
+ - The identity and advertised-versions checks keep their three-outcome discipline ([conformance.md](conformance.md)).
141
+ - A consumer that vendors any file from `schemas/`, `api/` or `spec/` MUST pin to a published tag, record it, and refuse a sync from any other ref.
142
+ - A v1.x consumer MUST NOT vendor `schemas/v2/`.
143
+
144
+ ## 5. The overlap
99
145
 
100
- `spec/v2/core/` and `spec/v2/ext/<key>/` hold the prose; `schemas/v2/` holds every v2 schema with `$id` under `https://openwop.dev/spec/v2/`; the site publishes them at `/spec/v2/`. The flat `schemas/` tree (v1 `$id`s) is read-only from the cut; v1 `$id` values are immutable identifiers, and a domain move is answered by a redirect, never a rewrite. AsyncAPI `servers.production.pathname` is empty and every channel address carries its own path, exactly as OpenAPI path keys do.
146
+ Through the overlap a host:
101
147
 
102
- ## 4. One release identity (RFC 0172 §D)
148
+ - MUST advertise both majors (§1.1);
149
+ - MUST emit `OpenWOP-Version` on every response (§1.4);
150
+ - MUST serve `/.well-known/openwop` as one resource whose representation the request header selects ([capabilities.md](capabilities.md)).
103
151
 
104
- The corpus tag `v2.<minor>.<patch>` (release candidates `v2.0.0-rc.<n>`) is the only release event; suite, SDKs, registry, and site derive from it. `spec/v2/release.json` carries the next tag as `version` and is bumped only by the release PR that cuts the tag. Every human-surface version (README banner, `docs/PROTOCOL-STATUS.md`, OpenAPI and AsyncAPI `info.version`, `conformance/package.json`) MUST be generated from it and checked with `--check` in the merge gate; the published tarball digest MUST equal the tree's as a release precondition. The identity and advertised-versions checks keep their three-outcome discipline (`conformance.md`).
152
+ The dual-stack scenario creates one run through `/v1/runs` with no header and reads it through `/runs` with `OpenWOP-Version: 2`; the response headers name the contract used.
105
153
 
106
- A consumer that vendors any file from `schemas/`, `api/`, or `spec/` MUST pin to a published tag, record it, and refuse a sync from any other ref; a v1.x consumer MUST NOT vendor `schemas/v2/` (RFC 0176 §E.1).
154
+ A run minted under major 1 and read under major 2 MUST use the tenant-bound projection `<tenantId>/<v1-id>` ([identity.md](identity.md) §5). A host MUST NOT return a bare v1 id in a major-2 response.
107
155
 
108
- ## 5. The overlap (RFC 0167 §B.5; RFC 0176)
156
+ ### Retirement
109
157
 
110
- Through the overlap a host MUST advertise both majors (§1.1), MUST emit `OpenWOP-Version` on every response (§1.4), and MUST serve `/.well-known/openwop` as one resource whose representation the request header selects (`capabilities.md`). The dual-stack scenario creates one run through `/v1/runs` with no header and reads it through `/runs` with `OpenWOP-Version: 2`; the response headers name the contract used.
158
+ The overlap ends at v1 end-of-support ([overview.md](overview.md)): `protocolVersions[]` drops the `1.<n>` member, and every alias carrying the `v1-end-of-support` trigger is removed.
111
159
 
112
- **A run minted under major 1 and read under major 2 MUST use the tenant-bound
113
- projection** `<tenantId>/<v1-id>` (`identity.md` §5). A host MUST NOT return a
114
- bare v1 id in a major-2 response.
160
+ - **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.
161
+ - **Retirement changes every header-less request's default contract**, from major 1 to major 2. Before retirement, a host MUST check for collisions between manifest top-level path segments and non-protocol unversioned routes, and MUST move each colliding route or apply §1.4 content negotiation.
115
162
 
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.
163
+ ### Host-proprietary paths: `/host/<org>/…`
117
164
 
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.
165
+ Every vendor namespace — capability records ([capabilities.md](capabilities.md) §3.2), error codes, event types, pack properties — is keyed to an org registered in `spec/v2/declaration.json`; paths join that pattern.
119
166
 
120
- **Retirement changes every header-less request's default contract.** Before
121
- end-of-support, a header-less unversioned request uses major 1; afterward it uses
122
- major 2. Before retirement, a host MUST check for collisions between manifest
123
- top-level path segments and non-protocol unversioned routes. It MUST move each
124
- colliding route or apply §1.4 content negotiation.
167
+ - A host MAY serve operations the manifest does not name under `/host/<org>/…` for its registered org. Such a path has no major, is served regardless of `OpenWOP-Version`, is never a protocol operation, is never measured, and is outside §1.4.
168
+ - An org MUST NOT be named after a manifest segment under `/host/` (`reservedOrgs`).
169
+ - A host SHOULD advertise the mount under `extensions.<org>.<name>`.
170
+ - A `/v1/host/<org>/…` twin MAY ride the overlap; it retires atomically with `/v1`.
125
171
 
126
- **Host-proprietary paths live at `/host/<org>/…` (RFC 0181).** Every vendor namespace — capability records (`capabilities.md` §3.2), error codes, event types, pack properties — is keyed to an org registered in `spec/v2/declaration.json`; paths join that pattern. A host MAY serve operations the manifest does not name under `/host/<org>/…` for its registered org: no major in the path, served regardless of `OpenWOP-Version`, never a protocol operation, never measured, outside §1.4. An org MUST NOT be named after a manifest segment under `/host/` (`reservedOrgs`); a host SHOULD advertise the mount under `extensions.<org>.<name>`. A `/v1/host/<org>/…` twin MAY ride the overlap and retires atomically with `/v1`.
172
+ ## 6. Migration rows
127
173
 
128
- ## 6. Migration rows (RFC 0172)
174
+ 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).
129
175
 
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).
176
+ *Sources: RFC 0167, RFC 0168, RFC 0172, RFC 0176, RFC 0179, RFC 0181, RFC 0193.*