@openwop/spec-artifacts 2.6.1 → 2.7.0

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 CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "_comment": "Provenance of @openwop/spec-artifacts (RFC 0168 §D.2). files: SHA-256 per file; the conformance suite compares the installed peer against dist/spec-artifacts.lock.json at start.",
3
3
  "package": "@openwop/spec-artifacts",
4
- "version": "2.6.1",
5
- "corpusTag": "v2.6.1",
4
+ "version": "2.7.0",
5
+ "corpusTag": "v2.7.0",
6
6
  "files": {
7
7
  "api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
8
8
  "api/asyncapi.yaml": "d5ecb9ee6114582be3b1f662c84bfac9ae96dae7bacb853e461168f70a8e1c7d",
9
9
  "api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
10
10
  "api/openapi.yaml": "39081c59fb696159806b0f2f9a42e7e9ff830d622fcf2ad4159b21357580a955",
11
11
  "api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
12
- "api/seams-v2.yaml": "daa6cb47c2fb29b8c1ff596c7c00a494a9a48c795ddd0485f9d89e3a1656baf6",
13
- "api/v2/asyncapi.yaml": "29f449a6b3386b4d6db141bc3cf0342f45850a9b3cc74dcf999bbdc5d8d1a57d",
14
- "api/v2/openapi.yaml": "a09adf882b9ac3a344caf16d1ea916cc1795a38544eb2e5df923f84129e86c6f",
12
+ "api/seams-v2.yaml": "0a44c26467543367068e89db69a0e01f3e95c7f5e41708bc18c625d252c6091e",
13
+ "api/v2/asyncapi.yaml": "5a431c280d7a7f3eeaabc5a6ee404762336d9cb4e615154fdc898f2b6a6ab557",
14
+ "api/v2/openapi.yaml": "ad75daf10c3f9bfb909f496c75a9480c967f699fbdd6ca1c722aef577c5c5319",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
17
17
  "schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
@@ -115,7 +115,7 @@
115
115
  "schemas/v2/artifact-type-pack-manifest.schema.json": "85630d1b760d0b41cf5a6fad2acfada39abaf7f0befd95cc4334e1e883e9615d",
116
116
  "schemas/v2/audit-verify-result.schema.json": "a748dfadb5155adfde8a91045e76b0db6695005fe559035d71670fdd55edb3ba",
117
117
  "schemas/v2/budget-policy.schema.json": "c7449daeb6e1d95e7a047b8c2814d3d54748697c27046972834874867d9b5f4c",
118
- "schemas/v2/capabilities.schema.json": "fa9b80a9107fc322ecadbac808e7fbe5e16ccf0af1a6bf673181faa8379dde33",
118
+ "schemas/v2/capabilities.schema.json": "5c6c6a70c73cb9cd0d61594e205a9bc2fd7905c41c7d0f43ae7e50523fdd85a9",
119
119
  "schemas/v2/certification-bundle.schema.json": "0bcf8f297266505ca39d30eea8100e3c0fb048f2651717fd746da8129fcb7920",
120
120
  "schemas/v2/channel-presence-payload.schema.json": "1c20ad810cb311d47aa0b95d928490826b2468fd161f884cd29e867053e6782f",
121
121
  "schemas/v2/channel-written-payload.schema.json": "ccecff3c71a3275ad8db035ac0e04db25e6f8d23cf091ddbcd5a60d1be1cbb6b",
@@ -187,6 +187,7 @@
187
187
  "schemas/v2/trigger-subscription-registration.schema.json": "04bc314a07c7e8b565577cb8df5821d968ce2af915900dfdccd4a24e928d20db",
188
188
  "schemas/v2/trigger-subscription.schema.json": "c887d4b9a12be0133f8c9dfd3a8bafcb518e27ecc2e800447ebc4d1fef111503",
189
189
  "schemas/v2/ui-plugin-message.schema.json": "879d65867c01656b3962d64283e66364dcb8f626ad26c5fcf2d2d55a79ae0ce9",
190
+ "schemas/v2/webhook-dead-letter-page.schema.json": "543f5ccc26d8f777684a037172ab7b9fdf70735e5394eeb42e5fa6569503f528",
190
191
  "schemas/v2/webhook-delivery.schema.json": "4e8ab3b722ad1731adf0548c1217f0de62da40de14e8abf77533aee4ace4c079",
191
192
  "schemas/v2/workflow-chain-pack-manifest.schema.json": "b61cc945b4df1c7093a1058fa71ee59ef10bacb3433ae4d7ae7536136e616cc2",
192
193
  "schemas/v2/workflow-definition.schema.json": "9aafddec32b84eb6aec3185be024850f1b9444c6193568771b0b636595fef136",
@@ -200,7 +201,7 @@
200
201
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
201
202
  "spec/v1/alias-detectors.json": "e90916db12d2297e2e560b2d54d2c4702d6cb3bef7179a575844687a7ec17262",
202
203
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
203
- "spec/v1/core-standard-manifest.json": "530dedda95648cf9eedd160bf8c0e582ec2a1b8daccbfe81b884d90e4eb81eec",
204
+ "spec/v1/core-standard-manifest.json": "bbb35b8db5c1670f08ac1948f75112344f1200ae935ae7d19db33f8d9ed94f65",
204
205
  "spec/v1/deprecations.json": "c81c8f71460936c8d489d8270477c7661cf4a5d7b7bad86c98899750b5656027",
205
206
  "spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
206
207
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -219,7 +220,7 @@
219
220
  "spec/v2/core/errors.md": "c3ac131dff970ab7574629d72735ace52cc56cd4a7ab5d1206ce91f382bc9a68",
220
221
  "spec/v2/core/events.md": "6ab8c727df3ebc5a60de3837c82a0075b4357d6f7e28435c6f80585687d41a76",
221
222
  "spec/v2/core/form-content-packs.md": "d4c5295dfd28972be205c87c34d0d34ced64f4a2561ebff7f9d24b436d83df25",
222
- "spec/v2/core/headers.md": "6c5eb48d998c141b5f0cb61fea926833a072748fdc4034e1a90a4dfe5448659c",
223
+ "spec/v2/core/headers.md": "14cdf4ae9ee7d80eebfd426d7c3552e577baea0300915cd4bb3a68e8588195a8",
223
224
  "spec/v2/core/idempotency.md": "803cd85947b1b2151cd2fb42cf0e0c52c9bcd19cdc6c23dcf34b1eddc600921a",
224
225
  "spec/v2/core/identity.md": "ae24870df315b527dfe9ecf7a4c26582bcc1113da7954f44acf69bf463ac390d",
225
226
  "spec/v2/core/interop.md": "8d8f4b040cb3625044c6aa586c8dcf5e9d15797de3d3b1cea631f44b8924701c",
@@ -231,9 +232,9 @@
231
232
  "spec/v2/core/runs.md": "b4c0bb2869077fcbf26e15bc6bbac06819f68b8241944b903a275a37db1c71fa",
232
233
  "spec/v2/core/security-defaults.md": "9ab1d1a88ccd0929f354422b151ec6d3164e8cd3784f8e58bb6f11cb7ee1e7d5",
233
234
  "spec/v2/core/versioning.md": "27b88cde88f9060567ef7e46f4897b6be8892ade9f4a46c2ab16e314c515eabd",
234
- "spec/v2/core/webhooks.md": "ecec4d22a35aeafd34276bb0579ae28610e79ab8850ebf42188cb51bc946a093",
235
+ "spec/v2/core/webhooks.md": "e08a736fd0bfdc79f5c2309c66f53caf96fac8d9954e0a184c2229de4ce286e9",
235
236
  "spec/v2/core/workflow-chain-packs.md": "26bb65721f826285b7d90c3cb62fa7e9fb2414c1bc6e0fd25b33209168c3102e",
236
- "spec/v2/declaration.json": "a09bac61c1b825e4a77b5abc0f86f1f8c20c381e0650eb08c2f6d0ef0aaec1dc",
237
+ "spec/v2/declaration.json": "0a5119e69983ea74adea739a4ca2aa206be7d1d4e32373c739b53fd0ae6d98d8",
237
238
  "spec/v2/declaration.schema.json": "c86e3083fb9789c1958ecb4576cc6f71aa90e6f339521139238543ed08211dd4",
238
239
  "spec/v2/errors.json": "4ff032033f02d7e3fb4204581456408ba5e7642b438c1f349bbd1c264e63e419",
239
240
  "spec/v2/event-codemap.json": "37869a03cdfd8758b57e6f350641a6ebbd383231cebda51f5473ad85f94ab74c",
@@ -266,13 +267,13 @@
266
267
  "spec/v2/facets/replay.schema.json": "0a5aefb0108c708c6794fadd533cf256709704c4f16dbf44cd63fa8980c78018",
267
268
  "spec/v2/facets/runList.schema.json": "6223e1baaebbb9f4faa71bfe968f8d22b4aa88046d0e43e8d5f56409e7f86e90",
268
269
  "spec/v2/facets/sandbox.schema.json": "e75f54486d387b2d089791aa93b5093cd1450f1920753a0f97fc23acdfe978ed",
269
- "spec/v2/facets/webhooks.schema.json": "0b766033ef4b4c6c2ac6f9979a19843ba024d3a1d1576972dcb55aaba52f1b9a",
270
+ "spec/v2/facets/webhooks.schema.json": "4bf3f8eb3161a43910efac4c44ccaf9567060c9da52d4cf09bcf3888d1b92192",
270
271
  "spec/v2/id-field-bindings.json": "e73c06f3055ad30173507ac817a458b96362c8f26209ba105c53653292cf63d3",
271
- "spec/v2/path-manifest.json": "a6f4e652e866889e8bde815874062f62929aee95dc8e58e7152c56adee262163",
272
+ "spec/v2/path-manifest.json": "c123c9fd77dc1b3f9c2e9346ace80cdae007e6511138894956abda01e61ec1c6",
272
273
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
273
274
  "spec/v2/profiles.json": "0636f19fceae625390003a347e70ef4797d84766b5c24ce8a02cea52aadebca4",
274
- "spec/v2/release.json": "5f3133ef7b959b76bb72c6b8e0fc7249bd93744c0b2431bdacb5fab43e4ae4a7",
275
+ "spec/v2/release.json": "fe784abdffc2089df66c6eda874d61a50b45912f8817b90051a91dc9c624380f",
275
276
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
276
277
  },
277
- "corpusCommit": "11c348ccb11f58a9bdb413030ab9d0366f71642d"
278
+ "corpusCommit": "35659ff7e741cc827a52f41140cac72aa0a4abeb"
278
279
  }
package/api/seams-v2.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: OpenWOP conformance seams profile (openwop-conformance-seams-v2)
4
- version: 2.6.1
4
+ version: 2.7.0
5
5
  description: 'GENERATED by scripts/derive-v2-api.py. RFC 0168 §C: the seams are a versioned conformance profile with their
6
6
  own document and path space (/conformance/seams/…), validated against the canonical v2 schemas with no tolerance path,
7
7
  forbidden from the capability namespace (a host advertises the profile, never a testSeams flag). This document carries
@@ -1,7 +1,7 @@
1
1
  asyncapi: 3.1.0
2
2
  info:
3
3
  title: OpenWOP v2 event streams
4
- version: 2.6.1
4
+ version: 2.7.0
5
5
  description: GENERATED by scripts/derive-v2-api.py (RFC 0171 §E.1, RFC 0172 §C.2). One run-events channel whose address
6
6
  is the OpenAPI path key; the server pathname is empty (bare origin). streamMode is a pattern over the closed set and its
7
7
  comma-separated combinations (`values` never combines). hostEvents has a real address (RFC 0171 §E.1) — the documented
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: OpenWOP v2 API
4
- version: 2.6.1
4
+ version: 2.7.0
5
5
  summary: REST surface for declaring, executing, suspending, resuming, and observing multi-step workflows.
6
6
  description: GENERATED by scripts/derive-v2-api.py from api/openapi.yaml and the RFC 0167 children (v2 charter Phase 3,
7
7
  P3-C). Bare origin, unversioned path keys, negotiation by `OpenWOP-Version` + `protocolVersions[]` (RFC 0172 §A). No seam
@@ -3067,6 +3067,60 @@ paths:
3067
3067
  $ref: '#/components/responses/NotFound'
3068
3068
  parameters:
3069
3069
  - $ref: '#/components/parameters/OpenWOPVersion'
3070
+ /webhooks/{webhookId}/dead-letters:
3071
+ get:
3072
+ tags:
3073
+ - Webhooks
3074
+ operationId: listWebhookDeadLetters
3075
+ summary: A subscription's dead-lettered deliveries (RFC 0188 §A.1)
3076
+ description: 'The read that makes `webhooks.md` §Durability observable. A delivery whose retries are exhausted, or a
3077
+ `payload_unprojectable` delivery dead-lettered on its first attempt, appears here until `retentionDays` elapse. Gated
3078
+ on the `webhooks.deadLetter` facet: a host that does not advertise it answers `404 not_found`. **Content-free (RFC
3079
+ 0188 §B.1):** the record NAMES a delivery and never carries the delivered bytes, the request headers, or the subscription
3080
+ secret — a dead-letter read is a diagnostic surface, not a payload-replay surface.'
3081
+ parameters:
3082
+ - name: webhookId
3083
+ in: path
3084
+ required: true
3085
+ schema:
3086
+ $ref: ../../schemas/v2/ids.schema.json#/$defs/subscriptionId
3087
+ description: The subscription, tenant-bound (`identity.md` §5, RFC 0187 §A.1) and carried as ONE path segment — `~`-projected
3088
+ per RFC 0184, or percent-encoded.
3089
+ - name: limit
3090
+ in: query
3091
+ required: false
3092
+ schema:
3093
+ type: integer
3094
+ minimum: 1
3095
+ description: Page size; clamped to `webhooks.deadLetter.maxPageSize`.
3096
+ - name: cursor
3097
+ in: query
3098
+ required: false
3099
+ schema:
3100
+ type: string
3101
+ minLength: 1
3102
+ maxLength: 2048
3103
+ description: Opaque cursor from a previous page's `nextCursor`. A cursor minted for another subscription MUST be refused
3104
+ `400 validation_error`.
3105
+ - $ref: '#/components/parameters/OpenWOPVersion'
3106
+ responses:
3107
+ '200':
3108
+ description: One page of dead-lettered deliveries, newest first.
3109
+ content:
3110
+ application/json:
3111
+ schema:
3112
+ $ref: ../../schemas/v2/webhook-dead-letter-page.schema.json
3113
+ headers:
3114
+ OpenWOP-Version:
3115
+ $ref: '#/components/headers/OpenWOPVersion'
3116
+ '400':
3117
+ $ref: '#/components/responses/ValidationError'
3118
+ '401':
3119
+ $ref: '#/components/responses/Unauthenticated'
3120
+ '403':
3121
+ $ref: '#/components/responses/Forbidden'
3122
+ '404':
3123
+ $ref: '#/components/responses/NotFound'
3070
3124
  /host/events:
3071
3125
  get:
3072
3126
  tags:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/spec-artifacts",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "The OpenWOP machine-readable contract: api/ (OpenAPI, AsyncAPI, the seams profile), schemas/ (v1 and v2 JSON Schemas), the spec/v1 and spec/v2 registries (errors, event codemap, declaration, deprecations, migrations, gaps) and CORPUS-STAMP.json — published from the openwop/openwop corpus tag; the peer dependency @openwop/openwop-conformance digest-checks at start (RFC 0168 §D.2).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -5146,6 +5146,28 @@
5146
5146
  }
5147
5147
  },
5148
5148
  "description": "spec/v2/core/webhooks.md §Delivery — the policy a host retries a failed attempt under. The webhooks family carries it at v2; `triggerBridge.retryPolicy` is the v1 carrier and stays through the overlap."
5149
+ },
5150
+ "deadLetter": {
5151
+ "type": "object",
5152
+ "additionalProperties": false,
5153
+ "required": [
5154
+ "retentionDays",
5155
+ "maxPageSize"
5156
+ ],
5157
+ "description": "RFC 0188 §A.5 — the DELIVERY dead-letter sink, advertised only by a host that serves `GET /webhooks/{webhookId}/dead-letters`. **Distinct from the top-level `deadLetter` FAMILY (RFC 0053), which is the RUN sink** and whose own `retentionDays` governs a dead-lettered run's fork-eligibility window. Three documents previously routed delivery dead-letters to RFC 0053, which is run-scoped and says so twice; this facet is where the delivery sink actually lives.",
5158
+ "properties": {
5159
+ "retentionDays": {
5160
+ "type": "integer",
5161
+ "minimum": 1,
5162
+ "description": "How long a dead-lettered delivery stays readable. Observable: a record's `expiresAt − deadLetteredAt` matches it."
5163
+ },
5164
+ "maxPageSize": {
5165
+ "type": "integer",
5166
+ "minimum": 1,
5167
+ "maximum": 1000,
5168
+ "description": "Ceiling the host clamps `limit` to (RFC 0182 §A.3 page-ceiling idiom)."
5169
+ }
5170
+ }
5149
5171
  }
5150
5172
  },
5151
5173
  "allOf": [
@@ -5183,7 +5205,7 @@
5183
5205
  }
5184
5206
  }
5185
5207
  ],
5186
- "description": "core/capabilities.md#webhooks — witness: witnessable-gated; maturity experimental/none",
5208
+ "description": "core/capabilities.md#webhooks — witness: witnessable-gated; maturity experimental/none; RFC 0188",
5187
5209
  "x-openwop-facets-from": "spec/v2/facets/webhooks.schema.json"
5188
5210
  },
5189
5211
  "triggerBridge": {
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v2/webhook-dead-letter-page.schema.json",
4
+ "title": "WebhookDeadLetterPage",
5
+ "description": "RFC 0188 §A.1 — one page of dead-lettered deliveries for a subscription. This is the read that makes `webhooks.md` §Durability observable: before it, the corpus asserted that an exhausted delivery is routed to a sink `inspectable for retentionDays` and served no endpoint that could see it, so every host's bundle recorded `exhaustion was observed, routing to the sink was not`. The record NAMES a delivery; it never carries the delivered bytes.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["deliveries"],
9
+ "properties": {
10
+ "deliveries": {
11
+ "type": "array",
12
+ "description": "Dead-lettered deliveries, newest first. Empty when the subscription has none within `retentionDays`.",
13
+ "items": { "$ref": "#/$defs/deadLetteredDelivery" }
14
+ },
15
+ "nextCursor": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "maxLength": 2048,
19
+ "description": "Opaque continuation cursor; absent on the last page. A cursor minted by one subscription MUST NOT be accepted on another (RFC 0182 §A.3 cursor discipline)."
20
+ }
21
+ },
22
+ "$defs": {
23
+ "deadLetteredDelivery": {
24
+ "type": "object",
25
+ "additionalProperties": false,
26
+ "required": ["deliveryId", "webhookId", "runId", "eventId", "eventType", "attempts", "deadLetteredAt", "expiresAt", "reason"],
27
+ "description": "One delivery that will not be retried again. **Content-free by construction (RFC 0188 §B.1):** no request body, no delivery headers, no subscription secret. A dead-letter read is a diagnostic surface, not a payload-replay surface, and a record that carried the body would hand an attacker with read scope every event the subscriber ever failed to receive.",
28
+ "properties": {
29
+ "deliveryId": {
30
+ "$ref": "ids.schema.json#/$defs/deliveryId",
31
+ "description": "The delivery attempt's tenant-bound id. This is the seat that makes the `deliveryId` KIND witnessable: `identity.md` §5 bound it and, until this read existed, no v2 surface returned one, so `v2-bound-id-kinds` recorded a CORPUS gap rather than a host one."
32
+ },
33
+ "webhookId": { "$ref": "ids.schema.json#/$defs/subscriptionId", "description": "The subscription the delivery was for. Equals the path segment." },
34
+ "runId": { "$ref": "ids.schema.json#/$defs/runId", "description": "The run whose event was being delivered." },
35
+ "eventId": { "$ref": "ids.schema.json#/$defs/eventId", "description": "The event that was being delivered." },
36
+ "eventType": { "type": "string", "minLength": 1, "description": "The event type, in the spelling the subscription's contract major renders (RFC 0187 §B)." },
37
+ "attempts": { "type": "integer", "minimum": 1, "description": "How many delivery attempts were made before the host gave up. `1` for `payload_unprojectable`, which is dead-lettered on first attempt." },
38
+ "deadLetteredAt": { "type": "string", "format": "date-time", "description": "When the host routed the delivery to the sink." },
39
+ "expiresAt": {
40
+ "type": "string",
41
+ "format": "date-time",
42
+ "description": "When this record ages out. **This is what makes `retentionDays` observable rather than merely advertised:** a reader can check `expiresAt − deadLetteredAt` against the advertised facet, which no surface could do before."
43
+ },
44
+ "reason": {
45
+ "type": "string",
46
+ "enum": ["retries_exhausted", "payload_unprojectable"],
47
+ "description": "Why it will not be retried. `retries_exhausted`: the retry policy ran out. `payload_unprojectable`: the event could not be rendered into the subscription's contract major, which `webhooks.md` dead-letters on the FIRST attempt because retrying cannot change the outcome."
48
+ },
49
+ "lastStatus": { "type": "integer", "description": "The HTTP status of the final attempt, when there was a response. Absent when every attempt failed to connect." }
50
+ }
51
+ }
52
+ }
53
+ }
@@ -4,7 +4,7 @@
4
4
  "provenance": {
5
5
  "suite": {
6
6
  "package": "@openwop/openwop-conformance",
7
- "version": "2.6.1"
7
+ "version": "2.7.0"
8
8
  },
9
9
  "note": "Derived from the corpus at generation time. Regenerate with --write; verify with --check."
10
10
  },
@@ -419,5 +419,5 @@
419
419
  "$id": "https://openwop.dev/spec/v1/workspace-file.schema.json"
420
420
  }
421
421
  ],
422
- "digest": "2752bd707ded939b2fc724e7f0523636d57836e3102dbd5a94fdb21d3ff242a8"
422
+ "digest": "ad097f5a97036bd42ca27c49119a4251e5b485a8f3075a4d96c9bda21a7e56b9"
423
423
  }
@@ -16,7 +16,7 @@ RFC 0171 §C.1: every non-standard header is `OpenWOP-<Name>` and every header i
16
16
  | `Last-Event-ID` | 1 | Resume from sequence after this ID. |
17
17
  | `OpenWOP-Dedup` | 1 | When set, server cross-host claim system rejects duplicate `(tenantId, scopeId)` pairs with `409 Conflict`. |
18
18
  | `OpenWOP-Force-Engine-Version` | 1 | **Test-keys-only.** When set, the server emits events for this run AS IF it |
19
- | `OpenWOP-Version` | 52 | RFC 0172 §A.3 — selects a listed major.minor; absent ⇒ the host's `preferredVersion`; unlisted ⇒ 406 protocol_version_unsupported. |
19
+ | `OpenWOP-Version` | 53 | RFC 0172 §A.3 — selects a listed major.minor; absent ⇒ the host's `preferredVersion`; unlisted ⇒ 406 protocol_version_unsupported. |
20
20
 
21
21
  ## Response headers
22
22
 
@@ -28,7 +28,7 @@ RFC 0171 §C.1: every non-standard header is `OpenWOP-<Name>` and every header i
28
28
  | `ETag` | 3 | Optional probe handle for mid-session capability change detection. Deprecated toward v2 (RFC 0165 §C.2). |
29
29
  | `Location` | 1 | Canonical URI of the new template. |
30
30
  | `OpenWOP-Idempotent-Replay` | 1 | Set when the response was served from the idempotency cache. |
31
- | `OpenWOP-Version` | 52 | RFC 0172 §A.4 — the contract that produced this response; MUST equal the one used. |
31
+ | `OpenWOP-Version` | 53 | RFC 0172 §A.4 — the contract that produced this response; MUST equal the one used. |
32
32
  | `Retry-After` | 1 | Seconds until the active claim is stale-eligible. |
33
33
 
34
34
  ## Webhook delivery headers
@@ -51,7 +51,7 @@ A host advertising both majors MUST send, on every delivery, the `X-openwop-*` f
51
51
  Durable delivery is an obligation of the `webhooks` surface (RFC 0173 §B; security-defaults.md). A host MUST:
52
52
 
53
53
  - retry a failed attempt per its advertised `retryPolicy` (`maxAttempts`, `backoff ∈ none | fixed | exponential`) with backoff between attempts;
54
- - route a delivery whose retries are exhausted to the dead-letter sink, inspectable for `retentionDays`, rather than drop it;
54
+ - route a delivery whose retries are exhausted to the dead-letter sink, rather than drop it. A host advertising `webhooks.deadLetter` MUST serve `GET /webhooks/{webhookId}/dead-letters` (RFC 0188), and that record MUST NOT carry the delivered body, the delivery headers, or the subscription secret — a dead-letter read names a delivery, it does not replay one. This sink is the DELIVERY sink; the `deadLetter` family (RFC 0053) is the RUN sink and is a different thing;
55
55
  - deliver each matching event at least once; a receiver MAY observe the same event more than once;
56
56
  - dead-letter a `payload_unprojectable` delivery (events.md §Era-2) on the first attempt, never retry it.
57
57
 
@@ -25,12 +25,12 @@
25
25
  "note": "Never assignable to a real vendor (RFC 2606 precedent). A conformance scenario needs one registered org whose events no host owns, so the positive half of the vendor rule is drivable; without it the registry could only ever say no."
26
26
  },
27
27
  "openwop-app": {
28
- "name": "openwop-app — the reference application host (app.openwop.dev), steward-affiliated; github.com/openwop/openwop-app",
28
+ "name": "openwop-app \u2014 the reference application host (app.openwop.dev), steward-affiliated; github.com/openwop/openwop-app",
29
29
  "registered": "2026-09-11",
30
30
  "note": "Ships vendor event types (e.g. openwop-app.conversation.recall_used), vendor error codes, and the /host/openwop-app/ path namespace (RFC 0181). Registered by the steward on the host's application over the steward bus, 2026-09-10."
31
31
  },
32
32
  "myndhyve": {
33
- "name": "MyndHyve — workflow-runtime host (api.myndhyve.ai), steward-affiliated sibling",
33
+ "name": "MyndHyve \u2014 workflow-runtime host (api.myndhyve.ai), steward-affiliated sibling",
34
34
  "registered": "2026-09-11",
35
35
  "note": "Ships vendor event types and error codes under myndhyve.* and the /host/myndhyve/ path namespace (RFC 0181). Registered by the steward on the host's application over the steward bus, 2026-09-10."
36
36
  }
@@ -1095,12 +1095,13 @@
1095
1095
  "adoption": "none"
1096
1096
  },
1097
1097
  "facets": [
1098
+ "deadLetter",
1098
1099
  "retryPolicy",
1099
1100
  "signatureAlgorithms"
1100
1101
  ],
1101
1102
  "floorScenarios": [],
1102
1103
  "requirementIds": [],
1103
- "owningRfc": null,
1104
+ "owningRfc": "0188",
1104
1105
  "facetsFrom": "spec/v2/facets/webhooks.schema.json"
1105
1106
  },
1106
1107
  {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$comment": "RFC 0173 §B — durable delivery binds with webhooks; no durable flag; retryPolicy is the v2 carrier of the delivery obligation (was triggerBridge.retryPolicy at v1)",
2
+ "$comment": "RFC 0173 \u00a7B \u2014 durable delivery binds with webhooks; no durable flag; retryPolicy is the v2 carrier of the delivery obligation (was triggerBridge.retryPolicy at v1)",
3
3
  "properties": {
4
4
  "signatureAlgorithms": {
5
5
  "type": "array",
@@ -32,7 +32,29 @@
32
32
  ]
33
33
  }
34
34
  },
35
- "description": "spec/v2/core/webhooks.md §Delivery — the policy a host retries a failed attempt under. The webhooks family carries it at v2; `triggerBridge.retryPolicy` is the v1 carrier and stays through the overlap."
35
+ "description": "spec/v2/core/webhooks.md \u00a7Delivery \u2014 the policy a host retries a failed attempt under. The webhooks family carries it at v2; `triggerBridge.retryPolicy` is the v1 carrier and stays through the overlap."
36
+ },
37
+ "deadLetter": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": [
41
+ "retentionDays",
42
+ "maxPageSize"
43
+ ],
44
+ "description": "RFC 0188 \u00a7A.5 \u2014 the DELIVERY dead-letter sink, advertised only by a host that serves `GET /webhooks/{webhookId}/dead-letters`. **Distinct from the top-level `deadLetter` FAMILY (RFC 0053), which is the RUN sink** and whose own `retentionDays` governs a dead-lettered run's fork-eligibility window. Three documents previously routed delivery dead-letters to RFC 0053, which is run-scoped and says so twice; this facet is where the delivery sink actually lives.",
45
+ "properties": {
46
+ "retentionDays": {
47
+ "type": "integer",
48
+ "minimum": 1,
49
+ "description": "How long a dead-lettered delivery stays readable. Observable: a record's `expiresAt \u2212 deadLetteredAt` matches it."
50
+ },
51
+ "maxPageSize": {
52
+ "type": "integer",
53
+ "minimum": 1,
54
+ "maximum": 1000,
55
+ "description": "Ceiling the host clamps `limit` to (RFC 0182 \u00a7A.3 page-ceiling idiom)."
56
+ }
57
+ }
36
58
  }
37
59
  },
38
60
  "required": [
@@ -261,6 +261,11 @@
261
261
  "path": "/webhooks/{webhookId}",
262
262
  "operationId": "unregisterWebhook"
263
263
  },
264
+ {
265
+ "method": "GET",
266
+ "path": "/webhooks/{webhookId}/dead-letters",
267
+ "operationId": "listWebhookDeadLetters"
268
+ },
264
269
  {
265
270
  "method": "GET",
266
271
  "path": "/workflows/{workflowId}",
@@ -278,7 +283,7 @@
278
283
  }
279
284
  ],
280
285
  "counts": {
281
- "operations": 52,
286
+ "operations": 53,
282
287
  "channels": 2
283
288
  }
284
289
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "RFC 0172 §D.1 — the one release identity the v2 artifacts derive from. `version` is the next corpus tag `v<version>` (the publish workflow's coordinated-release tag pattern `v*`; RFC 0172's `openwop/v2.<minor>.<patch>` spelling is amended to this at its flip). api/v2/*.yaml info.version, the suite's 2.x version and @openwop/spec-artifacts read it. Bumped by the release PR that cuts the tag, never by hand elsewhere.",
3
- "version": "2.6.1",
4
- "corpusTag": "v2.6.1",
3
+ "version": "2.7.0",
4
+ "corpusTag": "v2.7.0",
5
5
  "updated": "2026-09-18"
6
6
  }