@openwop/spec-artifacts 2.42.6 → 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.
- package/CORPUS-STAMP.json +64 -63
- package/api/seams-v2.yaml +187 -322
- package/api/v2/asyncapi.yaml +83 -113
- package/api/v2/openapi.yaml +339 -724
- package/package.json +1 -1
- package/schemas/audit-verify-result.schema.json +2 -2
- package/schemas/v2/audit-verify-result.schema.json +2 -2
- package/schemas/v2/capabilities.schema.json +2 -5
- package/spec/v1/core-standard-manifest.json +2 -2
- package/spec/v1/gaps.json +171 -1
- package/spec/v2/README.md +34 -36
- package/spec/v2/core/capabilities.md +186 -119
- package/spec/v2/core/conformance.md +78 -27
- package/spec/v2/core/connection-packs.md +8 -3
- package/spec/v2/core/conversation.md +10 -4
- package/spec/v2/core/errors.md +30 -9
- package/spec/v2/core/events.md +116 -80
- package/spec/v2/core/form-content-packs.md +11 -13
- package/spec/v2/core/headers.md +22 -14
- package/spec/v2/core/host-services.md +22 -5
- package/spec/v2/core/idempotency.md +48 -36
- package/spec/v2/core/identity.md +110 -42
- package/spec/v2/core/interop.md +82 -21
- package/spec/v2/core/interrupt.md +79 -40
- package/spec/v2/core/node-pack-runtimes.md +18 -4
- package/spec/v2/core/oauth.md +40 -6
- package/spec/v2/core/overview.md +61 -33
- package/spec/v2/core/packs.md +53 -28
- package/spec/v2/core/persistence.md +61 -80
- package/spec/v2/core/replay.md +56 -42
- package/spec/v2/core/runs.md +198 -60
- package/spec/v2/core/security-defaults.md +57 -33
- package/spec/v2/core/tool-catalog.md +29 -6
- package/spec/v2/core/versioning.md +95 -49
- package/spec/v2/core/webhooks.md +59 -20
- package/spec/v2/core/workflow-chain-packs.md +16 -14
- package/spec/v2/corrections.json +17 -1
- package/spec/v2/corrections.schema.json +1 -1
- package/spec/v2/declaration.json +24 -7
- package/spec/v2/declaration.schema.json +10 -0
- package/spec/v2/errors.json +109 -2
- package/spec/v2/errors.schema.json +38 -0
- package/spec/v2/ext/README.md +36 -23
- package/spec/v2/ext/a2uiSurface/README.md +75 -89
- package/spec/v2/ext/brand/README.md +15 -15
- package/spec/v2/ext/canvas/README.md +15 -15
- package/spec/v2/ext/chat/README.md +15 -15
- package/spec/v2/ext/coordination/README.md +15 -15
- package/spec/v2/ext/dataIntegration/README.md +17 -20
- package/spec/v2/ext/entities/README.md +15 -15
- package/spec/v2/ext/grpc-transport/README.md +6 -8
- package/spec/v2/ext/kanban/README.md +15 -15
- package/spec/v2/ext/knowledge/README.md +15 -15
- package/spec/v2/ext/launchStudio/README.md +16 -16
- package/spec/v2/ext/messaging/README.md +15 -15
- package/spec/v2/ext/portability/README.md +3 -17
- package/spec/v2/ext/provider-idempotency/README.md +7 -10
- package/spec/v2/ext/restTransport/README.md +30 -19
- package/spec/v2/ext/sandbox-runtime-notes/README.md +7 -9
- package/spec/v2/ext/webResearch/README.md +16 -16
- package/spec/v2/profiles.json +6 -2
- package/spec/v2/release.json +2 -2
- package/spec/v2/surface-baseline.json +542 -2
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
# Conformance
|
|
2
2
|
|
|
3
|
-
> **Status: Stable
|
|
3
|
+
> **Status: Stable.**
|
|
4
4
|
|
|
5
5
|
## Why this exists
|
|
6
6
|
|
|
7
|
-
The v2 evidence contract: how a requirement is asserted, how every requirement declares what can witness it, how the seams are mounted, what the suite ships, and what a bundle proves. Profiles are in overview.md; the capability vocabulary the suite gates on is capabilities.md.
|
|
7
|
+
The v2 evidence contract: how a requirement is asserted, how every requirement declares what can witness it, how the seams are mounted, what the suite ships, and what a bundle proves. Profiles are in [overview.md](overview.md); the capability vocabulary the suite gates on is in [capabilities.md](capabilities.md).
|
|
8
8
|
|
|
9
9
|
## Requirement ids
|
|
10
10
|
|
|
11
|
-
`expect(x, req('openwop.<area>.<slug>', '<doc> §<section>', '<requirement>'))` is the only assertion form.
|
|
11
|
+
`expect(x, req('openwop.<area>.<slug>', '<doc> §<section>', '<requirement>'))` is the only assertion form. Ids are minted in `conformance/requirements.json`, and every test declares its id explicitly.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- A scenario assertion without a requirement id MUST fail the suite's lint.
|
|
14
|
+
- A title reword without a corresponding `requirement-aliases.json` row MUST fail CI.
|
|
15
|
+
|
|
16
|
+
The ledger records per `it`; a bundle's `results.requirements[]` is the per-assertion list. A post-assertion soft-skip MUST record `skipped` for every id not reached and MUST NOT record `pass`.
|
|
14
17
|
|
|
15
18
|
### Whose fact is the reason?
|
|
16
19
|
|
|
17
|
-
A soft-skip carries a disposition and a reason. The reason MUST identify a fact
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
failure MUST be `blocked`, never `inapplicable
|
|
21
|
-
NOT issue a certification
|
|
20
|
+
A soft-skip carries a disposition and a reason. The reason MUST identify a fact about the host under test.
|
|
21
|
+
|
|
22
|
+
- Use `inapplicable` only when the requirement does not bind that host.
|
|
23
|
+
- A missing fixture, unreadable corpus file, or other suite-side failure MUST be `blocked`, never `inapplicable`.
|
|
24
|
+
- A suite with a blocked row MUST NOT issue a certification.
|
|
22
25
|
|
|
23
|
-
When more than one gate can skip a test, evaluate host predicates before suite
|
|
24
|
-
predicates.
|
|
26
|
+
When more than one gate can skip a test, evaluate host predicates before suite predicates.
|
|
25
27
|
|
|
26
28
|
## Witness class
|
|
27
29
|
|
|
@@ -36,19 +38,27 @@ Every family in `spec/v2/declaration.json`, every requirement in `conformance/re
|
|
|
36
38
|
| `negative-existence` | the suite asserts a thing is absent |
|
|
37
39
|
| `unwitnessable` | no observation path exists; `rationale` REQUIRED |
|
|
38
40
|
|
|
39
|
-
A protocol-tier invariant marked `unwitnessable` MUST fail the corpus gate.
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
- A protocol-tier invariant marked `unwitnessable` MUST fail the corpus gate.
|
|
42
|
+
- `tests: []` is expressible only as `unwitnessable`.
|
|
43
|
+
- `blocked` is a bundle disposition, not a witness class.
|
|
44
|
+
- A MUST whose only witness is `seam-gated` MUST either mint a normative observation path before the cut or be demoted to SHOULD.
|
|
45
|
+
- The seam count in `docs/witness-baseline.json` is a ratchet and MUST NOT rise.
|
|
42
46
|
|
|
43
47
|
## The seams profile
|
|
44
48
|
|
|
45
|
-
Test seams are the profile `openwop-conformance-seams-v2` (`spec/v2/profiles.json`), described by `api/seams-v2.yaml` with schemas under `schemas/v2/seams/`, in the path space `/conformance/seams/…`. The seam schemas `$ref` the canonical error and event schemas with no tolerance path.
|
|
49
|
+
Test seams are the profile `openwop-conformance-seams-v2` (`spec/v2/profiles.json`), described by `api/seams-v2.yaml` with schemas under `schemas/v2/seams/`, in the path space `/conformance/seams/…`. The seam schemas `$ref` the canonical error and event schemas with no tolerance path. The profile is versioned with the suite (`seams-v2` for 2.x).
|
|
50
|
+
|
|
51
|
+
- A host that mounts the seams MUST advertise the profile as `conformance.seamsProfile: "openwop-conformance-seams-v2"` at the discovery root (the closed root has no `profiles[]`; [capabilities.md](capabilities.md) §3).
|
|
52
|
+
- A host MUST NOT advertise a `testSeams` capability flag.
|
|
53
|
+
- `api/v2/openapi.yaml` and `spec/v2/path-manifest.json` MUST contain no seam or sample-host operation; an SDK generated from the canonical document has no seam method.
|
|
46
54
|
|
|
47
55
|
## Two products, two ledgers
|
|
48
56
|
|
|
49
57
|
Corpus-coherence checks run in the spec repo's CI (`scripts/check-spec-coherence.mjs`) and MUST NOT appear in a host bundle; the bundle schema forbids their ids. `--offline` is a declared property of a scenario, not a runtime discovery.
|
|
50
58
|
|
|
51
|
-
`@openwop/openwop-conformance@2.0.0` ships `dist`, `fixtures
|
|
59
|
+
- `@openwop/openwop-conformance@2.0.0` ships `dist`, `fixtures` and `vectors` only.
|
|
60
|
+
- The corpus — `api/`, `schemas/`, the `spec/v2/*.json` registries, `CORPUS-STAMP.json` — is `@openwop/spec-artifacts@2.0.0`, an exact-pinned peer dependency. The suite MUST digest-check it at start and MUST refuse to run against it on a mismatch.
|
|
61
|
+
- The suite is one package: `--target-major 1|2` selects the target (default: the host's `preferredVersion`), and scenario ids share one namespace across majors. The 1.x target is removed at v1 end-of-support.
|
|
52
62
|
|
|
53
63
|
## Bundle v3
|
|
54
64
|
|
|
@@ -57,7 +67,7 @@ A certification bundle validates against `schemas/v2/certification-bundle.schema
|
|
|
57
67
|
| Field | Rule |
|
|
58
68
|
| --- | --- |
|
|
59
69
|
| `suite` | `name`, `version`, `targetMajor`, `specArtifactsVersion` REQUIRED |
|
|
60
|
-
| `host` | `name`, `version`, `build.{kind, id}` REQUIRED; `kind` is `image-digest`, `commit
|
|
70
|
+
| `host` | `name`, `version`, `build.{kind, id}` REQUIRED; `kind` is `image-digest`, `commit` or `artifact-sha256` |
|
|
61
71
|
| `host.deployment` | OPTIONAL; `colocated-companion` only (below). Absent: the bundle measures the served host |
|
|
62
72
|
| `discovery` | `url`, `sha256`, `protocolVersions`, `preferredVersion` REQUIRED |
|
|
63
73
|
| `claimedProfiles[]` | `id`, `evidenceTier` (`self` \| `steward` \| `independent`), `witnessCount`, `certified` REQUIRED |
|
|
@@ -69,29 +79,70 @@ A certification bundle validates against `schemas/v2/certification-bundle.schema
|
|
|
69
79
|
| `durability.rung` | OPTIONAL; a claim the verifier re-derives (below) |
|
|
70
80
|
| `signature` | REQUIRED |
|
|
71
81
|
|
|
72
|
-
|
|
82
|
+
### Signature and attribution
|
|
83
|
+
|
|
84
|
+
`signature` is an Ed25519 attestation over the JCS bytes (§"Canonical JSON") of `{ witnessSha256, host.build, suite.version, discovery.sha256 }`; `over` MUST list exactly those four members.
|
|
85
|
+
|
|
86
|
+
- A host that signs bundles MUST publish the corresponding public keys as `signingKeys[]` in its discovery document, and `signature.keyId` MUST name one of them.
|
|
87
|
+
- A verifier MUST resolve `keyId` there — in the discovery document of the host the bundle is *about* — and MUST verify the attestation under the published key.
|
|
88
|
+
- A retired key MUST stay listed.
|
|
89
|
+
|
|
90
|
+
A signature that cannot be resolved to a published key attests **integrity only**, and the bundle MUST NOT be read as attributable evidence. A gate MUST distinguish three outcomes that a presence check collapses into one: *no discovery document was read*, *read and the key is not published*, and *the attestation does not verify*.
|
|
91
|
+
|
|
92
|
+
`evidenceTier: independent` MUST carry a `verifierKeyId` distinct from the host's signing key. The verifier MUST refuse, not warn, on a missing or self-signed independent claim.
|
|
93
|
+
|
|
94
|
+
### Certification
|
|
73
95
|
|
|
74
|
-
|
|
96
|
+
- A bundle with `totals.blocked > 0` does not certify.
|
|
97
|
+
- At major 2 a requirement a test did not observe records `blocked`, even when the test asserted setup facts first.
|
|
98
|
+
- An `executed-pass` carrying a `partial-witness:` detail is reserved for a leg that observed its requirement and skipped an optional extra.
|
|
99
|
+
- A verifier MUST derive the operator's opt-outs from the signed `skipped` rows and MUST reject a bundle whose captured discovery document advertises one of them (`opted-out-but-advertised`).
|
|
100
|
+
- v1 and v2 bundles are never upgraded to v3; a bundle is evidence at its own version.
|
|
75
101
|
|
|
76
|
-
|
|
102
|
+
### Colocated companion
|
|
103
|
+
|
|
104
|
+
A *colocated companion* is the served host's image run beside the suite, so it can trust a suite-held trust anchor.
|
|
105
|
+
|
|
106
|
+
- A bundle cut from one MUST carry `host.deployment: "colocated-companion"`, which the preimage covers (§"Canonical JSON").
|
|
107
|
+
- A host serving production traffic MUST NOT list a suite-held trust anchor among the trust roots it advertises.
|
|
108
|
+
- A companion is evidence only for the requirements in `spec/v2/harness-trust-anchors.json`, and only when it pairs with a certified served-host bundle of the same `image-digest` build, signed under a key that bundle's discovery publishes, whose discovery document is equal once each document's origin and the `oidc` lane's `issuers` are set aside.
|
|
77
109
|
|
|
78
110
|
### Canonical JSON
|
|
79
111
|
|
|
80
|
-
Every signature and digest in this corpus is over the RFC 8785 (JCS) serialization, UTF-8 encoded
|
|
112
|
+
Every signature and digest in this corpus is over the RFC 8785 (JCS) serialization, UTF-8 encoded. `conformance/vectors/jcs-v1.json` is normative.
|
|
113
|
+
|
|
114
|
+
The value MUST be I-JSON (RFC 7493):
|
|
115
|
+
|
|
116
|
+
- A signer or hasher MUST refuse, not coerce, a value with duplicate member names, a lone surrogate, a non-finite number, an integer literal whose magnitude exceeds 2^53 − 1, or a non-JSON value.
|
|
117
|
+
- A verifier that meets one in a document it must re-canonicalize MUST fail verification.
|
|
118
|
+
|
|
119
|
+
`witnessSha256` is SHA-256 over the JCS bytes of the rows:
|
|
81
120
|
|
|
82
|
-
|
|
121
|
+
- One object per `results.requirements[]` entry, with exactly `id`, `scenario`, `result` and, each only when present, `assertions`, `detail`, `evidence`.
|
|
122
|
+
- Rows sorted by `id` in UTF-16 code-unit order. A locale-sensitive comparator MUST NOT be used.
|
|
123
|
+
- Only when `host.relaxations[]` is non-empty or `host.deployment` is present, the preimage is instead `{ "rows": …, "relaxations": …, "deployment": … }`, carrying each of the last two only when so, with relaxations in the order carried.
|
|
124
|
+
|
|
125
|
+
`discovery.sha256` is SHA-256 over the JCS bytes of the captured document.
|
|
83
126
|
|
|
84
127
|
### Recovery evidence
|
|
85
128
|
|
|
86
|
-
Recovery evidence
|
|
129
|
+
Recovery evidence rides on rows: a row's `evidence` enters `witnessSha256` only when present.
|
|
87
130
|
|
|
88
131
|
| Row | `evidence` member |
|
|
89
132
|
| --- | --- |
|
|
90
|
-
| `0158.bound-is-derived` | `recoveryBounds[]` of `{ class, bound, terms[] }`, each term `{ name, ms }
|
|
91
|
-
| `0158.kill-after-accept`, `0158.kill-during-execution` | `recovery: { class, boundMs, observedMs }`
|
|
133
|
+
| `0158.bound-is-derived` | `recoveryBounds[]` of `{ class, bound, terms[] }`, each term `{ name, ms }` |
|
|
134
|
+
| `0158.kill-after-accept`, `0158.kill-during-execution` | `recovery: { class, boundMs, observedMs }` |
|
|
135
|
+
|
|
136
|
+
- In `recoveryBounds[]`, `bound` MUST equal the sum of its terms. There is one entry per recovery class and no aggregate bound.
|
|
137
|
+
- In `recovery`, `class` is the class exercised, `boundMs` the bound applied, `observedMs` the kill-to-resumption interval.
|
|
138
|
+
- `class` and `name` are opaque host-chosen identifiers, never a closed vocabulary.
|
|
92
139
|
|
|
93
|
-
`
|
|
140
|
+
`durability.rung` is outside the attestation, so a verifier MUST re-derive it and MUST reject (`rung-not-derivable`) a claim it cannot derive. Derivation requires every row of the rung to be `executed-pass`, and each kill row's `class` to name a declared entry whose `bound` equals its `boundMs` and is not exceeded by its `observedMs`. Only `durable-single-instance` is derivable in this revision; a higher claim is refused.
|
|
141
|
+
|
|
142
|
+
This proves the arithmetic and that recovery ran once inside the bound. It does not prove the kill landed in the class it names; killing only once the execution claim is held is the host's obligation.
|
|
94
143
|
|
|
95
144
|
## Corpus-gate evidence
|
|
96
145
|
|
|
97
|
-
An RFC whose acceptance criteria are corpus gates rather than host scenarios records the evidence label **corpus gate — no host tier** in its `Updated` line
|
|
146
|
+
An RFC whose acceptance criteria are corpus gates rather than host scenarios records the evidence label **corpus gate — no host tier** in its `Updated` line. For such an RFC the accepted-predicate check reads `(corpus)` rows from `evidence/corpus-ledger.json` and MUST NOT require a host bundle.
|
|
147
|
+
|
|
148
|
+
*Sources: RFC 0158, RFC 0168, RFC 0212, RFC 0216.*
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Connection Packs
|
|
2
2
|
|
|
3
|
-
> **Status: Stable
|
|
3
|
+
> **Status: Stable.**
|
|
4
4
|
> **Normative home:** `connections`.
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
A connection pack is a signed provider definition — the endpoints, scope catalog, and reach a connector's `auth.provider` string resolves against. The manifest is `schemas/v2/connection-pack-manifest.schema.json`; installation and signing follow packs.md.
|
|
8
|
+
A connection pack is a signed provider definition — the endpoints, scope catalog, and reach a connector's `auth.provider` string resolves against. The manifest is `schemas/v2/connection-pack-manifest.schema.json`; installation and signing follow [packs.md](packs.md).
|
|
9
9
|
|
|
10
10
|
## Provider identity
|
|
11
11
|
|
|
@@ -26,8 +26,13 @@ A connector MAY name a provider by its qualified form `<packName>#<id>`. A quali
|
|
|
26
26
|
|
|
27
27
|
## Resolution
|
|
28
28
|
|
|
29
|
-
A host advertising `connections.packsSupported` MUST resolve a connector's `auth: { type: "oauth2", provider: P }` (and any `host.oauth` invocation for `P`) against the definition selected above to obtain its endpoints and scope catalog.
|
|
29
|
+
A host advertising `connections.packsSupported` MUST resolve a connector's `auth: { type: "oauth2", provider: P }` (and any `host.oauth` invocation for `P`) against the definition selected above, to obtain its endpoints and scope catalog.
|
|
30
|
+
|
|
31
|
+
- An unresolvable provider MUST be refused when the dependent connector or pack is registered.
|
|
32
|
+
- On a publish-path host, resolution MUST run after the idempotency short-circuit: a byte-identical re-publish of an installed pack MUST succeed even when resolution inputs have since changed.
|
|
30
33
|
|
|
31
34
|
## Errors
|
|
32
35
|
|
|
33
36
|
Both codes are in `spec/v2/errors.json`: `connection_provider_conflict` (two claimants for one bare id) and `connection_provider_unresolved` (no definition for the referenced id).
|
|
37
|
+
|
|
38
|
+
*Sources: RFC 0095, RFC 0177.*
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# Conversation surfaces
|
|
2
2
|
|
|
3
|
-
> **Status: Stable
|
|
3
|
+
> **Status: Stable.**
|
|
4
4
|
> **Normative home:** `multiPartyConversation`, `channelPresence`, `conversationTurnModelProvenance`.
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
No client route opens a conversation. This document states the obligations a host takes on by advertising a multi-party conversation family.
|
|
9
9
|
|
|
10
10
|
## `multiPartyConversation`
|
|
11
11
|
|
|
12
|
-
A host advertising `multiPartyConversation
|
|
12
|
+
A host advertising `multiPartyConversation`:
|
|
13
|
+
|
|
14
|
+
- MUST accept an optional `participants` array of agent references on conversation creation;
|
|
15
|
+
- MUST refuse a turn from a principal absent from that roster, rather than silently accepting it;
|
|
16
|
+
- MUST refuse, at creation, a roster that exceeds `multiPartyConversation.maxParticipants`, rather than truncating it.
|
|
13
17
|
|
|
14
18
|
## `channelPresence`
|
|
15
19
|
|
|
@@ -17,4 +21,6 @@ A host advertising `channelPresence` MUST report present members as a subset of
|
|
|
17
21
|
|
|
18
22
|
## `conversationTurnModelProvenance`
|
|
19
23
|
|
|
20
|
-
A host that stamps model provenance on an agent turn MUST advertise `conversationTurnModelProvenance`. The stamp is non-secret and non-PII
|
|
24
|
+
A host that stamps model provenance on an agent turn MUST advertise `conversationTurnModelProvenance`. The stamp is non-secret and non-PII (provider and model identifiers only), and a host MUST NOT place prompt or completion content in it.
|
|
25
|
+
|
|
26
|
+
*Sources: RFC 0101, RFC 0109, RFC 0110.*
|
package/spec/v2/core/errors.md
CHANGED
|
@@ -1,30 +1,49 @@
|
|
|
1
1
|
# Errors
|
|
2
2
|
|
|
3
|
-
> **Status: Stable
|
|
3
|
+
> **Status: Stable.**
|
|
4
4
|
|
|
5
5
|
## Why this exists
|
|
6
6
|
|
|
7
|
-
Every error a v2 host returns is a row in one registry. A client routes on `error`, never on `message
|
|
7
|
+
Every error a v2 host returns is a row in one registry. A client routes on `error`, never on `message`. A code that is not registered is not a protocol error. The registry is the single source for the envelope schema, the HTTP status and retriability.
|
|
8
8
|
|
|
9
9
|
## The registry
|
|
10
10
|
|
|
11
|
-
`spec/v2/errors.json` holds one row per code: `{ code, httpStatus, retriable, details, since, deprecated? }` plus the provenance fields `statusSource` and `source`. It registers **107** codes. `schemas/v2/error-envelope.schema.json` is GENERATED from it and MUST NOT be edited by hand.
|
|
11
|
+
`spec/v2/errors.json` holds one row per code: `{ code, httpStatus, retriable, details, since, deprecated? }` plus the provenance fields `statusSource` and `source`, and an optional one-line `meaning`. `spec/v2/errors.schema.json` defines the row. It registers **107** codes. `schemas/v2/error-envelope.schema.json` is GENERATED from it and MUST NOT be edited by hand.
|
|
12
12
|
|
|
13
|
-
A host MUST return a registered code, or a vendor code, in every error response.
|
|
13
|
+
- A host MUST return a registered code, or a vendor code, in every error response.
|
|
14
|
+
- A vendor code MUST match `^(?!openwop\.)[a-z][a-z0-9]*(-[a-z0-9]+)*\.[a-z][a-z0-9_]*$`, with its first segment an org registered in `spec/v2/declaration.json`. `openwop.` is reserved.
|
|
15
|
+
- The registry grows by [overview.md](overview.md) §0.
|
|
14
16
|
|
|
15
17
|
## The envelope
|
|
16
18
|
|
|
17
|
-
Every error response body MUST be `{ error, message, details? }` and nothing else (`additionalProperties: false`).
|
|
19
|
+
Every error response body MUST be `{ error, message, details? }` and nothing else (`additionalProperties: false`).
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
- `error` is the registered code or a vendor code. `message` is a non-empty string.
|
|
22
|
+
- `details` is an object shaped by the row's `details` schema. A row whose `details` is `null` accepts any object. When a row registers a schema, the generated envelope becomes a `oneOf` discriminated on `error`.
|
|
23
|
+
- Contextual data (conflict refs, trace ids, validation paths) MUST live under `details`, never at a new top level.
|
|
24
|
+
- When present, `details.correlationId` MUST be a non-empty string.
|
|
25
|
+
|
|
26
|
+
The same envelope is the per-id `error` of `bulkCancelRuns` ([runs.md](runs.md)). `x-openwop-http-status` and `x-openwop-retriable` in the generated schema mirror the registry; a host MUST answer with the registered status.
|
|
20
27
|
|
|
21
28
|
## Retry timing
|
|
22
29
|
|
|
23
|
-
Retry timing lives in the `Retry-After` header only.
|
|
30
|
+
Retry timing lives in the `Retry-After` header only.
|
|
31
|
+
|
|
32
|
+
- A host MUST NOT emit `details.retryAfter`, `details.retryAfterMs` or `details.retryAfterSeconds`.
|
|
33
|
+
- A `429 rate_limited` response MUST set `Retry-After`.
|
|
34
|
+
|
|
35
|
+
The retriable rows are `residency_unavailable`, `rate_limited`, `internal_error`, `pack_registry_unreachable`, `runner_unavailable`.
|
|
24
36
|
|
|
25
37
|
## One code per state
|
|
26
38
|
|
|
27
|
-
An interrupt has one code per state
|
|
39
|
+
An interrupt has one code per state ([interrupt.md](interrupt.md), [identity.md](identity.md)):
|
|
40
|
+
|
|
41
|
+
- A token or run-scoped resolve against an interrupt that is already resolved, or whose run is cancelled or completed, MUST return `409 interrupt_already_resolved`.
|
|
42
|
+
- A signed token past its `expiresAt` MUST return `410 interrupt_expired`.
|
|
43
|
+
- A token whose `alg` or `kid` the host does not accept MUST return `401 interrupt_token_invalid`.
|
|
44
|
+
- `interrupt_cancelled` is registered but names no state of the core resolve surfaces. A host MUST NOT emit it from `resolveInterruptByRun`, `inspectInterruptByToken` or `resolveInterruptByToken`.
|
|
45
|
+
|
|
46
|
+
The idempotency mismatch code is `idempotency_key_mismatch` only ([idempotency.md](idempotency.md)).
|
|
28
47
|
|
|
29
48
|
## Codes by HTTP status
|
|
30
49
|
|
|
@@ -138,4 +157,6 @@ Code | Status
|
|
|
138
157
|
`payload_unprojectable` | 500
|
|
139
158
|
`credential_unavailable` | 501
|
|
140
159
|
`pack_registry_unreachable` | 503
|
|
141
|
-
`runner_unavailable` | 503
|
|
160
|
+
`runner_unavailable` | 503
|
|
161
|
+
|
|
162
|
+
*Sources: RFC 0171, RFC 0213.*
|
package/spec/v2/core/events.md
CHANGED
|
@@ -1,155 +1,191 @@
|
|
|
1
1
|
# Events
|
|
2
2
|
|
|
3
|
-
> **Status: Stable
|
|
3
|
+
> **Status: Stable.**
|
|
4
4
|
> **Normative home:** `heartbeat`, `envelopeContracts`, `envelopes`, `feedback`, `providerUsage`, `supportedEnvelopes`, `schemaVersions`, `envelopeStrictness`.
|
|
5
5
|
|
|
6
6
|
## Why this exists
|
|
7
7
|
|
|
8
|
-
A run is its append-only event log
|
|
8
|
+
A run is its append-only event log. Every snapshot, stream, poll, fork and diff is a projection of it. There is one closed envelope, type registry, payload registry, ordering field, events channel and poll cursor.
|
|
9
9
|
|
|
10
10
|
## The envelope
|
|
11
11
|
|
|
12
|
-
`schemas/v2/run-event.schema.json` (`RunEventDoc`) is closed. `eventId`, `runId`, `type`, `payload`, `timestamp`, `sequence` and `schemaVersion` are REQUIRED; `nodeId`, `engineVersion` and `causationId` are OPTIONAL. Every id field `$ref`s its grammar in `schemas/v2/ids.schema.json` (identity.md).
|
|
12
|
+
`schemas/v2/run-event.schema.json` (`RunEventDoc`) is closed. `eventId`, `runId`, `type`, `payload`, `timestamp`, `sequence` and `schemaVersion` are REQUIRED; `nodeId`, `engineVersion` and `causationId` are OPTIONAL. Every id field `$ref`s its grammar in `schemas/v2/ids.schema.json` ([identity.md](identity.md)).
|
|
13
13
|
|
|
14
|
-
| Field |
|
|
14
|
+
| Field | Meaning |
|
|
15
15
|
| --- | --- |
|
|
16
|
-
| `sequence` | The one ordering field: integer ≥ 0, first event `0`, strictly increasing per run
|
|
17
|
-
| `schemaVersion` | Per-event schema version, integer ≥ 1, first-class
|
|
18
|
-
| `engineVersion` | Integer ≥ 0 everywhere
|
|
19
|
-
| `eventId` | Host-minted, opaque
|
|
20
|
-
| `causationId` | The `eventId`, or AI-envelope `correlationId`, that caused this event
|
|
21
|
-
| `timestamp` | ISO 8601
|
|
16
|
+
| `sequence` | The one ordering field: integer ≥ 0, first event `0`, strictly increasing per run |
|
|
17
|
+
| `schemaVersion` | Per-event schema version, integer ≥ 1, first-class |
|
|
18
|
+
| `engineVersion` | Integer ≥ 0 everywhere |
|
|
19
|
+
| `eventId` | Host-minted, opaque |
|
|
20
|
+
| `causationId` | The `eventId`, or AI-envelope `correlationId`, that caused this event |
|
|
21
|
+
| `timestamp` | ISO 8601 |
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
- Persisted logs are never renumbered.
|
|
24
|
+
- A consumer MUST treat `eventId` as a string.
|
|
25
|
+
- A consumer MUST NOT throw on an event whose `type` it does not know; it folds what it understands and ignores the rest.
|
|
24
26
|
|
|
25
27
|
## Types
|
|
26
28
|
|
|
27
|
-
`type` is `oneOf` a closed enum of registered protocol types and a vendor pattern. The enum is
|
|
29
|
+
`type` is `oneOf` a closed enum of registered protocol types and a vendor pattern. The enum is generated from `spec/v2/event-codemap.json` and MUST NOT be edited by hand. The vendor branch is exactly:
|
|
28
30
|
|
|
29
31
|
```text
|
|
30
32
|
^(?!openwop\.)[a-z][a-z0-9]*(-[a-z0-9]+)*\.[a-z][a-z0-9]*(-[a-z0-9]+)*(\.[a-z][a-z0-9]*(-[a-z0-9]+)*)?$
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| Vendor events | A vendor type's first segment MUST be an org registered in the `extensions` object of `spec/v2/declaration.json` — the ORG REGISTRY, not the `extensions` metadata key a host publishes in its own discovery payload; an unregistered org fails validation. An org named in `reservedOrgs` is forbidden, never registered, and `extensionsKeyPattern` is the shape a vendor type must have, not a permission to use it. The registry is normally small: `example` is held by the protocol for documentation and conformance and is never assignable to a vendor. |
|
|
38
|
-
| Growth | The registry grows by the closed-enum rule in overview.md §0: a producer MUST NOT emit an unregistered protocol type; a consumer MUST accept an unknown registered member and MUST NOT act on it. |
|
|
35
|
+
- **Naming.** A protocol type is `domain.verb-ed`: kebab-case, exactly two segments, past tense for a transition (`run.started`, `node.suspend-failed`, `run.resume-started`). `domain.noun` is permitted only for an emitted artifact (`output.chunk`, `provider.usage`, `channel.presence`, `agent.handoff`, `envelope.refusal`, `agent.reasoning-delta`, `voice.synthesis-chunk`, `voice.endpoint-candidate`); each exception is recorded in the codemap.
|
|
36
|
+
- **Reserved prefix.** `openwop.` is the only reserved prefix. `core.`, `community.`, `vendor.`, `private.` and `local.` are pack namespaces, not event namespaces; a type under them is invalid.
|
|
37
|
+
- **Vendor events.** A vendor type's first segment MUST be an org registered in the `extensions` object of `spec/v2/declaration.json` (the org registry, not the `extensions` metadata key a host publishes in discovery). An unregistered org fails validation. An org in `reservedOrgs` is forbidden and never registered. `extensionsKeyPattern` is the shape a vendor type must have, not a permission to use it. `example` is held by the protocol for documentation and conformance and is never assignable to a vendor.
|
|
38
|
+
- **Growth.** The registry grows by the closed-enum rule in [overview.md](overview.md) §0. A producer MUST NOT emit an unregistered protocol type. A consumer MUST accept an unknown registered member and MUST NOT act on it.
|
|
39
39
|
|
|
40
40
|
## Payloads
|
|
41
41
|
|
|
42
|
-
`schemas/v2/run-event-payloads.schema.json` holds one `$defs` entry per payload,
|
|
42
|
+
`schemas/v2/run-event-payloads.schema.json` holds one `$defs` entry per payload, each `additionalProperties: false`, plus `_typeIndex`: the normative map from v2 type to `$defs` key, generated from `spec/v2/event-codemap.json`.
|
|
43
|
+
|
|
44
|
+
- A host MUST emit a payload that validates against the entry `_typeIndex` names for its `type`.
|
|
45
|
+
- Sub-typing is `$ref` composition, never duplication. `approval.*` and `clarification.*` resolve to `interruptRequested` / `interruptResolved` ([interrupt.md](interrupt.md)); `lease.acquired`, `lease.renewed` and `lease.lost` share `leaseLifecycle`.
|
|
46
|
+
- The CloudEvents mapping and the webhook delivery envelope are generated from the same definition. An event's `type`, `eventId`, `sequence` and `payload` are byte-identical across the run stream, a CloudEvents rendering and a webhook delivery.
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
Specific payloads:
|
|
45
49
|
|
|
46
|
-
`run.started` carries the `owner` block (identity.md §1.1).
|
|
47
|
-
`run.cancelled` carries `reason`, `cancelledBy`, `durationMs`, and `parentRunId`.
|
|
48
|
-
`run.completed` MUST carry `outputs` as an object
|
|
49
|
-
an absent key is not. This distinguishes “no outputs” from “outputs not
|
|
50
|
-
rendered” and is witnessed by `v2-run-completed-outputs`.
|
|
50
|
+
- `run.started` carries the `owner` block ([identity.md](identity.md) §1.1).
|
|
51
|
+
- `run.cancelled` carries `reason`, `cancelledBy`, `durationMs`, and `parentRunId`.
|
|
52
|
+
- `run.completed` MUST carry `outputs` as an object. An empty object is valid; an absent key is not. This separates "no outputs" from "outputs not rendered".
|
|
51
53
|
|
|
52
54
|
## AI envelopes: E1–E5
|
|
53
55
|
|
|
54
|
-
`schemas/v2/ai-envelope.schema.json` is the shape an LLM emits; the engine records its acceptance as one or more `RunEventDoc`s.
|
|
56
|
+
`schemas/v2/ai-envelope.schema.json` is the shape an LLM emits; the engine records its acceptance as one or more `RunEventDoc`s.
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
- `correlationId` and `meta.source` are REQUIRED on every envelope. An engine MUST reject an envelope that omits either; nothing is synthesized.
|
|
59
|
+
- An envelope kind MUST be namespaced under the same `<org>.` rule as events, universal kinds and the core content-primitive families `ui.*` and `media.*` excepted.
|
|
60
|
+
|
|
61
|
+
The five contracts:
|
|
62
|
+
|
|
63
|
+
- **E1 partial reassembly.** Every chunk of one partial emission carries the same `correlationId`, and the events that record them are ordered by `sequence`. The emission is complete at the first recorded chunk with `partial: false`. A consumer MAY render progressively but MUST NOT enable any action before that event.
|
|
64
|
+
- **E2 multi-turn correlation.** Each turn is an envelope with its own `correlationId`; every event it produces carries `causationId = correlationId`. A re-emission with a `correlationId` already recorded in the run MUST return the cached outcome and MUST NOT emit new events.
|
|
65
|
+
- **E3 vendor kinds.** The registry of vendor kinds is `spec/v2/declaration.json`. A kind whose org is not registered is invalid.
|
|
66
|
+
- **E4 sub-typing.** `$ref` composition, as in the payload registry above.
|
|
67
|
+
- **E5 refusal × retry.** `configurable.ai.maxRefusals` ([runs.md](runs.md)) is the ceiling on `envelope.refusal` events a run records. A host MUST NOT retry the emission that produced a refusal.
|
|
63
68
|
|
|
64
69
|
## The events channel
|
|
65
70
|
|
|
66
|
-
`api/v2/asyncapi.yaml` declares one channel, `runEvents`, at `/runs/{runId}/events`, and `api/v2/openapi.yaml` declares the same path (`streamRunEvents`)
|
|
71
|
+
`api/v2/asyncapi.yaml` declares one channel, `runEvents`, at `/runs/{runId}/events`, and `api/v2/openapi.yaml` declares the same path (`streamRunEvents`). The two MUST resolve to the same absolute path.
|
|
72
|
+
|
|
73
|
+
### Stream modes
|
|
74
|
+
|
|
75
|
+
The `streamMode` query parameter is one pattern:
|
|
67
76
|
|
|
68
77
|
```text
|
|
69
78
|
^(values|(updates|messages|debug)(,(updates|messages|debug))*)$
|
|
70
79
|
```
|
|
71
80
|
|
|
72
|
-
The default is `updates`. A host MUST implement `updates` and SHOULD implement all four. A value outside the pattern, or a mode the host does not implement, MUST return `400 unsupported_stream_mode` with `details.supported` listing each individual mode the host serves; combinations are not listed. Validation MUST run before any content negotiation.
|
|
73
|
-
|
|
74
81
|
| Mode | Emits | Combines |
|
|
75
82
|
| --- | --- | --- |
|
|
76
|
-
| `updates` |
|
|
83
|
+
| `updates` (default) | Deltas for run transitions, terminal node transitions, suspensions, `node.dispatched`, interrupt events, `artifact.created`, `eval.*`, `deployment.*`, `workspace.updated` | yes |
|
|
77
84
|
| `values` | One synthesized `state.snapshot` (`schemas/v2/run-snapshot.schema.json`) after each `updates`-tier transition | never |
|
|
78
|
-
| `messages` | `ai.message.chunk` (`outputChunk` payload) from streaming AI nodes only
|
|
85
|
+
| `messages` | `ai.message.chunk` (`outputChunk` payload) from streaming AI nodes only | yes |
|
|
79
86
|
| `debug` | Every event in the log, including `log.appended`, `variable.changed`, `version.pinned`, `lease.*`, `node.retried` and every vendor event | yes |
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
- A host MUST implement `updates` and SHOULD implement all four.
|
|
89
|
+
- A value outside the pattern, or a mode the host does not implement, MUST return `400 unsupported_stream_mode` with `details.supported` listing each individual mode the host serves; combinations are not listed.
|
|
90
|
+
- Validation MUST run before any content negotiation.
|
|
91
|
+
- In `messages`, a host MUST populate a Tier 1 `meta` slot whenever it has the data.
|
|
92
|
+
- Vendor events appear in `debug` only.
|
|
93
|
+
- In a mixed mode the host emits the union of the filters in log order and MUST NOT reorder. Each frame SHOULD carry `event:` naming the mode that admitted it. A consumer MUST tolerate an event admitted by more than one mode.
|
|
82
94
|
|
|
83
95
|
### SSE frames
|
|
84
96
|
|
|
85
|
-
Each frame carries `id
|
|
97
|
+
Each frame carries `id:` (the `sequence`), `event:` (the v2 `type`, in a single mode) and `data:` (the `RunEventDoc`). Three frame names are not types and are absent from the `type` enum:
|
|
98
|
+
|
|
99
|
+
- `state.snapshot` — `values` mode; `data:` is a `RunSnapshot`.
|
|
100
|
+
- `batch` — `bufferMs`; `data:` is an array of `RunEventDoc`.
|
|
101
|
+
- `ai.message.chunk` — `messages` mode; `data:` is the `outputChunk` payload, persisted as type `output.chunk`.
|
|
102
|
+
|
|
103
|
+
A host MUST set `Content-Type: text/event-stream`, MUST emit a keep-alive comment at least every 30 seconds, and MUST close the connection after the run's terminal event (`run.completed`, `run.failed`, `run.cancelled`).
|
|
104
|
+
|
|
105
|
+
#### Resuming with `Last-Event-ID`
|
|
106
|
+
|
|
107
|
+
`Last-Event-ID: N` resumes every mode as an exclusive cursor, with the semantics of poll's `afterSequence`.
|
|
108
|
+
|
|
109
|
+
- The host MUST stream the events with `sequence > N` in log order and MUST NOT re-emit `N`.
|
|
110
|
+
- When `N` is at or beyond the last persisted sequence there is no backlog. On a live run the host MUST hold the stream open for later events; on a terminal run it MUST close the stream without a frame.
|
|
111
|
+
- A host MUST NOT refuse a well-formed non-negative integer `Last-Event-ID` because no event carries that sequence. Any other value SHOULD be refused with `400 validation_error`.
|
|
112
|
+
- The header is evaluated only after the caller is authorized to read the run. For a run the caller cannot read, the response MUST be the one the host gives without the header.
|
|
113
|
+
- In `values` mode, resumption MUST emit a `state.snapshot` first.
|
|
86
114
|
|
|
87
|
-
|
|
115
|
+
#### Batching and subscribers
|
|
116
|
+
|
|
117
|
+
With `bufferMs` (0..5000) the host accumulates events into one `event: batch` frame whose `data:` is an array of `RunEventDoc`.
|
|
118
|
+
|
|
119
|
+
- It MUST flush on a terminal event, on `node.suspended`, and on close.
|
|
120
|
+
- The batch's `id:` SHOULD be its highest `sequence`, and `Last-Event-ID` MUST honor that id.
|
|
121
|
+
- A consumer MUST tolerate both a one-element batch and an unbatched frame.
|
|
122
|
+
- A host MUST NOT limit subscribers per run except for resource protection, and then MUST answer `429 rate_limited` with `Retry-After` rather than drop silently.
|
|
88
123
|
|
|
89
124
|
### Host events
|
|
90
125
|
|
|
91
|
-
`hostEvents` carries the heartbeat messages (`schemas/v2/heartbeat-evaluated.schema.json`, `schemas/v2/heartbeat-state-changed.schema.json`) at `/host/events` (`streamHostEvents`), the documented default
|
|
126
|
+
`hostEvents` carries the heartbeat messages (`schemas/v2/heartbeat-evaluated.schema.json`, `schemas/v2/heartbeat-state-changed.schema.json`) at `/host/events` (`streamHostEvents`), the documented default. A host MAY declare another address under `heartbeat.deliveryChannel` ([capabilities.md](capabilities.md)). The channel is content-free of run data. There is no channel without an address.
|
|
92
127
|
|
|
93
128
|
## Poll
|
|
94
129
|
|
|
95
130
|
`GET /runs/{runId}/events/poll` (`pollRunEvents`) is the long-poll fallback.
|
|
96
131
|
|
|
97
|
-
| Parameter |
|
|
132
|
+
| Parameter | Meaning |
|
|
98
133
|
| --- | --- |
|
|
99
|
-
| `afterSequence` | Integer ≥ 0;
|
|
100
|
-
| `timeout` | Seconds to wait for new events, 1..60, default 30
|
|
134
|
+
| `afterSequence` | Integer ≥ 0; return events with `sequence > afterSequence`. Omitted means from sequence 0 |
|
|
135
|
+
| `timeout` | Seconds to wait for new events, 1..60, default 30 |
|
|
136
|
+
|
|
137
|
+
`lastSequence` and `since` are not parameters.
|
|
138
|
+
|
|
139
|
+
The response is `{ runId, events, lastSequence, status, isTerminal }` (closed):
|
|
101
140
|
|
|
102
|
-
|
|
141
|
+
- `lastSequence` is the highest sequence in the log at the time of the response, `-1` when the log is empty.
|
|
142
|
+
- `status` is the snapshot status; `isTerminal` is whether the run is terminal.
|
|
143
|
+
- A cursor past the end of the log MUST return `200` with an empty `events` array.
|
|
103
144
|
|
|
104
145
|
## The terminal event
|
|
105
146
|
|
|
106
|
-
A run's log MUST contain exactly one terminal run event
|
|
147
|
+
A run's log MUST contain exactly one terminal run event: `run.completed`, `run.failed` or `run.cancelled`.
|
|
148
|
+
|
|
149
|
+
- After it, the log MUST NOT contain another terminal run event, `run.started`, `run.resumed`, `run.resume-started`, `run.paused`, `run.restored-from-snapshot`, any `node.*` event or any `interrupt.*` event.
|
|
150
|
+
- `compensation.*` events and `run.dead-lettered` MAY follow it (a compensating host unwinds after a cancelled parent). Vendor-prefixed types are unconstrained.
|
|
151
|
+
- A host that receives work for a run whose terminal event is recorded (a duplicate delivery, a late worker) MUST NOT append forward-execution events for it, SHOULD record the refusal in its operational log, and MUST NOT surface the refusal as a run event.
|
|
107
152
|
|
|
108
153
|
## Era-2 logs
|
|
109
154
|
|
|
110
|
-
An `eventLogSchemaVersion` of `2` means v1-written
|
|
155
|
+
An `eventLogSchemaVersion` of `2` means v1-written. Every reader, diff included, translates it per [persistence.md](persistence.md) §"The reader rule".
|
|
156
|
+
|
|
157
|
+
- A projection MUST NOT silently drop a property: it carries it or fails with `500 payload_unprojectable` (hatch `^(openwop-|x-|vendor\.)`).
|
|
158
|
+
- Fork and replay over an era-2 parent are in [replay.md](replay.md).
|
|
111
159
|
|
|
112
160
|
## The envelope-kind catalog
|
|
113
161
|
|
|
114
|
-
`supportedEnvelopes`, `schemaVersions` and `envelopeStrictness` are one flow, read in
|
|
115
|
-
that order on every inbound envelope.
|
|
162
|
+
`supportedEnvelopes`, `schemaVersions` and `envelopeStrictness` are one flow, read in that order on every inbound envelope.
|
|
116
163
|
|
|
117
|
-
`supportedEnvelopes
|
|
118
|
-
emitted `type` that is neither universal nor a member, with `unknown_envelope_kind`.
|
|
119
|
-
**An absent `kinds` is not an empty catalog and is not an unrestricted one**: a host
|
|
120
|
-
advertising `supportedEnvelopes` without it has made no catalog claim, and an engine
|
|
121
|
-
MUST refuse every non-universal kind rather than admit it unchecked.
|
|
164
|
+
### `supportedEnvelopes`
|
|
122
165
|
|
|
123
|
-
`
|
|
124
|
-
has a floor of `0`. An emitted `schemaVersion` ABOVE the floor MUST be refused with
|
|
125
|
-
`unknown_schema_version` whatever the strictness.
|
|
126
|
-
`ui.a2ui-surface` at schema version 2 is specified by `ext/a2uiSurface/README.md`.
|
|
166
|
+
`supportedEnvelopes.kinds` is the catalog. A host advertising it MUST refuse an emitted `type` that is neither universal nor a member, with `unknown_envelope_kind`.
|
|
127
167
|
|
|
128
|
-
`
|
|
129
|
-
when the seat is absent — an engine MUST validate against the advertised version and
|
|
130
|
-
log `envelope_schema_version_drift`. Under `strict` the same condition MUST refuse with
|
|
131
|
-
`unknown_schema_version`. A host MUST NOT read an absent `mode` as "no checking".
|
|
168
|
+
An absent `kinds` is not an empty catalog and is not an unrestricted one: a host advertising `supportedEnvelopes` without it has made no catalog claim, and an engine MUST refuse every non-universal kind rather than admit it unchecked.
|
|
132
169
|
|
|
133
|
-
|
|
170
|
+
### `schemaVersions`
|
|
134
171
|
|
|
135
|
-
`
|
|
136
|
-
sets. A host advertising `envelopeContracts.advertised` MUST refuse a node whose
|
|
137
|
-
emitted envelope `type` is neither universal nor listed in that node's accepted
|
|
138
|
-
set, and MUST refuse it distinctly from the capability-gated `typeId` refusal —
|
|
139
|
-
the two stack rather than substitute.
|
|
172
|
+
`schemaVersions.kinds` maps a kind to its advertised floor; a kind absent from the map has a floor of `0`. An emitted `schemaVersion` above the floor MUST be refused with `unknown_schema_version`, whatever the strictness. `ui.a2ui-surface` at schema version 2 is specified by `ext/a2uiSurface/README.md`.
|
|
140
173
|
|
|
141
|
-
|
|
174
|
+
### `envelopeStrictness`
|
|
175
|
+
|
|
176
|
+
`envelopeStrictness.mode` governs drift below the floor only. A host MUST NOT read an absent `mode` as "no checking".
|
|
177
|
+
|
|
178
|
+
- Under `warn` (the value when the seat is absent), an engine MUST validate against the advertised version and log `envelope_schema_version_drift`.
|
|
179
|
+
- Under `strict`, the same condition MUST refuse with `unknown_schema_version`.
|
|
142
180
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
than refusing on provider-specific grounds.
|
|
181
|
+
## Envelope contracts
|
|
182
|
+
|
|
183
|
+
`envelopeContracts` advertises that a host enforces per-node envelope permission sets. A host advertising `envelopeContracts.advertised` MUST refuse a node whose emitted envelope `type` is neither universal nor listed in that node's accepted set. It MUST refuse it distinctly from the capability-gated `typeId` refusal: the two stack rather than substitute.
|
|
147
184
|
|
|
148
|
-
|
|
149
|
-
refuse an annotation whose target is outside the advertised set, and MUST NOT write it
|
|
150
|
-
to the replayable run event log.
|
|
185
|
+
## Envelope, feedback and usage facets
|
|
151
186
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
a consumer MUST NOT treat it as a billed amount.
|
|
187
|
+
- **`envelopes.tierOneSubsetCompliance`** advertises that the host accepts the Tier 1 structured-output subset shared across major providers. A host advertising it MUST accept an envelope restricted to that subset from any provider it advertises, rather than refusing on provider-specific grounds.
|
|
188
|
+
- **`feedback.targets`** names the resources an annotation may be attached to. A host MUST refuse an annotation whose target is outside the advertised set, and MUST NOT write it to the replayable run event log.
|
|
189
|
+
- **`providerUsage.costEstimates`** advertises that the host stamps a derived cost on the `provider.usage` event. That figure is an estimate from the host's own rate table; a consumer MUST NOT treat it as a billed amount.
|
|
155
190
|
|
|
191
|
+
*Sources: RFC 0171, RFC 0172, RFC 0176, RFC 0185, RFC 0194, RFC 0213.*
|