@openwop/openwop-conformance 2.23.0 → 2.25.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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/spec-artifacts.lock.json +2 -2
- package/package.json +2 -2
- package/requirements.json +90 -5
- package/schemas/CORPUS-STAMP.json +19 -16
- package/src/scenarios/v2-webhook-durable-delivery.test.ts +48 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [2.25.0] — 2026-09-19 — a leg that asserted nothing
|
|
4
|
+
|
|
5
|
+
- `v2-webhook-durable-delivery` — the `0188.dead-letter-content-free` leg read a **fresh** subscription's sink, looped over zero rows, and asserted nothing; RFC 0148 §A resolves that silent return to `blocked`, denying certification. It now exhausts a real delivery first and asserts over the records it gets, and records `blocked` with a reason when the sink is empty.
|
|
6
|
+
- Suite pinned to corpus `2.25.0`.
|
|
7
|
+
|
|
8
|
+
## [2.24.0] — 2026-09-19 — the envelope-kind catalog gets a seat
|
|
9
|
+
|
|
10
|
+
- `v2-envelope-catalog.test.ts` — six corpus witnesses for RFC 0193. The generator leg sabotages a scratch copy (removes a seat file, asserts the refusal names the family), because the committed tree is clean and a bare exit-0 wrapper would pass just as happily with the guard deleted. The optionality leg asserts no seat is `required` — MyndHyve publishes two of these records without one, and the v2 root is closed.
|
|
11
|
+
- Suite pinned to corpus `2.24.0`.
|
|
12
|
+
|
|
3
13
|
## [2.23.0] — 2026-09-19 — zero undeclared families
|
|
4
14
|
|
|
5
15
|
**Why a minor.** Three new `spec/v2/core/*.md` documents and `spec/v2/declaration.json`
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# --legacy-peer-deps is REQUIRED, not optional: the exact peer pin is what npm's
|
|
12
12
|
# default resolver refuses. npm 10.9 fails outright with
|
|
13
13
|
# "Cannot read properties of null (reading 'edgesOut')" — use npm >= 11.
|
|
14
|
-
npm install --legacy-peer-deps @openwop/openwop-conformance@2.
|
|
14
|
+
npm install --legacy-peer-deps @openwop/openwop-conformance@2.25.0 @openwop/spec-artifacts@2.25.0
|
|
15
15
|
# or run without install:
|
|
16
16
|
npx @openwop/openwop-conformance --base-url https://api.example.com --api-key hk_test_...
|
|
17
17
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@openwop/spec-artifacts": "file:../spec-artifacts"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@openwop/spec-artifacts": "2.
|
|
59
|
+
"@openwop/spec-artifacts": "2.25.0"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/requirements.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"$comment": "GENERATED by conformance/scripts/generate-requirement-registry.mjs — do not edit. One record per it()/test() in src/scenarios. Ids: openwop.it.<file-stem>.<title-slug>[~n] (src/lib/requirement-ids.ts). A record with id null has an interpolated title; its run-time row is keyed by the rendered title and maps here by file+line only. Renamed ids need a row in requirement-aliases.json.",
|
|
3
3
|
"generatedFrom": "src/scenarios/*.test.ts",
|
|
4
4
|
"counts": {
|
|
5
|
-
"files":
|
|
6
|
-
"tests":
|
|
7
|
-
"withStableId":
|
|
5
|
+
"files": 579,
|
|
6
|
+
"tests": 2198,
|
|
7
|
+
"withStableId": 2198,
|
|
8
8
|
"interpolatedTitles": 0,
|
|
9
|
-
"explicitIds":
|
|
9
|
+
"explicitIds": 2152
|
|
10
10
|
},
|
|
11
11
|
"records": [
|
|
12
12
|
{
|
|
@@ -29469,7 +29469,8 @@
|
|
|
29469
29469
|
"citations": [
|
|
29470
29470
|
{
|
|
29471
29471
|
"section": "RFC 0188 §B.1",
|
|
29472
|
-
"requirement":
|
|
29472
|
+
"requirement": null,
|
|
29473
|
+
"interpolated": true
|
|
29473
29474
|
}
|
|
29474
29475
|
]
|
|
29475
29476
|
},
|
|
@@ -35884,6 +35885,90 @@
|
|
|
35884
35885
|
}
|
|
35885
35886
|
]
|
|
35886
35887
|
},
|
|
35888
|
+
{
|
|
35889
|
+
"id": "openwop.it.v2-envelope-catalog.each-of-the-three-carries-its-seat",
|
|
35890
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35891
|
+
"line": 64,
|
|
35892
|
+
"title": "each of the three carries its seat",
|
|
35893
|
+
"explicitId": "openwop.requirement.0193.seats-present",
|
|
35894
|
+
"citations": [
|
|
35895
|
+
{
|
|
35896
|
+
"section": "RFC 0193 §B",
|
|
35897
|
+
"requirement": null,
|
|
35898
|
+
"interpolated": true
|
|
35899
|
+
}
|
|
35900
|
+
]
|
|
35901
|
+
},
|
|
35902
|
+
{
|
|
35903
|
+
"id": "openwop.it.v2-envelope-catalog.no-seat-is-required-a-published-record-without-one-stays-valid",
|
|
35904
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35905
|
+
"line": 73,
|
|
35906
|
+
"title": "no seat is required — a published record without one stays valid",
|
|
35907
|
+
"explicitId": "openwop.requirement.0193.seats-optional",
|
|
35908
|
+
"citations": [
|
|
35909
|
+
{
|
|
35910
|
+
"section": "RFC 0193 §B",
|
|
35911
|
+
"requirement": null,
|
|
35912
|
+
"interpolated": true
|
|
35913
|
+
}
|
|
35914
|
+
]
|
|
35915
|
+
},
|
|
35916
|
+
{
|
|
35917
|
+
"id": "openwop.it.v2-envelope-catalog.the-generator-refuses-a-family-whose-payload-it-cannot-carry",
|
|
35918
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35919
|
+
"line": 82,
|
|
35920
|
+
"title": "the generator refuses a family whose payload it cannot carry",
|
|
35921
|
+
"explicitId": "openwop.requirement.0193.generator-refuses",
|
|
35922
|
+
"citations": [
|
|
35923
|
+
{
|
|
35924
|
+
"section": "RFC 0193 §A/§B",
|
|
35925
|
+
"requirement": null,
|
|
35926
|
+
"interpolated": true
|
|
35927
|
+
}
|
|
35928
|
+
]
|
|
35929
|
+
},
|
|
35930
|
+
{
|
|
35931
|
+
"id": "openwop.it.v2-envelope-catalog.an-absent-catalog-is-stated-to-fail-closed",
|
|
35932
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35933
|
+
"line": 95,
|
|
35934
|
+
"title": "an absent catalog is stated to fail CLOSED",
|
|
35935
|
+
"explicitId": "openwop.requirement.0193.absence-is-closed",
|
|
35936
|
+
"citations": [
|
|
35937
|
+
{
|
|
35938
|
+
"section": "RFC 0193 §C",
|
|
35939
|
+
"requirement": null,
|
|
35940
|
+
"interpolated": true
|
|
35941
|
+
}
|
|
35942
|
+
]
|
|
35943
|
+
},
|
|
35944
|
+
{
|
|
35945
|
+
"id": "openwop.it.v2-envelope-catalog.both-refusal-codes-are-registered-at-major-2",
|
|
35946
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35947
|
+
"line": 106,
|
|
35948
|
+
"title": "both refusal codes are registered at major 2",
|
|
35949
|
+
"explicitId": "openwop.requirement.0193.codes-registered",
|
|
35950
|
+
"citations": [
|
|
35951
|
+
{
|
|
35952
|
+
"section": "RFC 0193 §F",
|
|
35953
|
+
"requirement": null,
|
|
35954
|
+
"interpolated": true
|
|
35955
|
+
}
|
|
35956
|
+
]
|
|
35957
|
+
},
|
|
35958
|
+
{
|
|
35959
|
+
"id": "openwop.it.v2-envelope-catalog.versioning-axis-6-no-longer-contradicts-the-record",
|
|
35960
|
+
"file": "v2-envelope-catalog.test.ts",
|
|
35961
|
+
"line": 116,
|
|
35962
|
+
"title": "versioning axis 6 no longer contradicts the record",
|
|
35963
|
+
"explicitId": "openwop.requirement.0193.axis-6-agrees",
|
|
35964
|
+
"citations": [
|
|
35965
|
+
{
|
|
35966
|
+
"section": "RFC 0193 §D",
|
|
35967
|
+
"requirement": null,
|
|
35968
|
+
"interpolated": true
|
|
35969
|
+
}
|
|
35970
|
+
]
|
|
35971
|
+
},
|
|
35887
35972
|
{
|
|
35888
35973
|
"id": "openwop.it.v2-eos-clock.the-clock-file-is-current-with-the-matrix-and-the-public-history",
|
|
35889
35974
|
"file": "v2-eos-clock.test.ts",
|
|
@@ -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.
|
|
5
|
-
"corpusTag": "v2.
|
|
4
|
+
"version": "2.25.0",
|
|
5
|
+
"corpusTag": "v2.25.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": "
|
|
13
|
-
"api/v2/asyncapi.yaml": "
|
|
14
|
-
"api/v2/openapi.yaml": "
|
|
12
|
+
"api/seams-v2.yaml": "f8a8a952166e13505d28e6859788f3269493fe4c440433442214b282334fef72",
|
|
13
|
+
"api/v2/asyncapi.yaml": "b165823a2a95a9bbefcb1d71d7768b2031342297077e0c89e414c69eec917ed6",
|
|
14
|
+
"api/v2/openapi.yaml": "b131c9fbde1e2d39dca11287f277ee9d51d1b83b684f5713f9c6e277f07636ce",
|
|
15
15
|
"api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
|
|
16
16
|
"schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
|
|
17
17
|
"schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
|
|
@@ -115,8 +115,8 @@
|
|
|
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": "
|
|
119
|
-
"schemas/v2/certification-bundle.schema.json": "
|
|
118
|
+
"schemas/v2/capabilities.schema.json": "50d3f90d6f92637e2f16956c99bc4826f69f28d935fb75fb06ab6fb910078706",
|
|
119
|
+
"schemas/v2/certification-bundle.schema.json": "be5de0cc4362207c27885c51165c92c9541a545c5bd2c59da1d5c28fc265c162",
|
|
120
120
|
"schemas/v2/channel-presence-payload.schema.json": "1c20ad810cb311d47aa0b95d928490826b2468fd161f884cd29e867053e6782f",
|
|
121
121
|
"schemas/v2/channel-written-payload.schema.json": "ccecff3c71a3275ad8db035ac0e04db25e6f8d23cf091ddbcd5a60d1be1cbb6b",
|
|
122
122
|
"schemas/v2/chat-card-pack-manifest.schema.json": "8df0d9d273ae22efc6876d5586833f1d4c2e551edc3ac6cf6e8f0719329f03dd",
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
"schemas/v2/envelopes/schema.request.schema.json": "be2c5f7aa881cdd252ccff47ac02193659e1393633a1541f4297383205d384a2",
|
|
142
142
|
"schemas/v2/envelopes/schema.response.schema.json": "d049a081267c06c28879c331b147f3ed821b14ccfd93005c67aff64db0a8c68e",
|
|
143
143
|
"schemas/v2/envelopes/ui.a2ui-surface.schema.json": "0a06fbbdc8ba797a6818c79336a98e211ac5ba5747945b4e4098072cd3974d79",
|
|
144
|
-
"schemas/v2/error-envelope.schema.json": "
|
|
144
|
+
"schemas/v2/error-envelope.schema.json": "bb3e6c487dafa951a56ff224a7c029c462f0f1b754a7f51f6729609b4f43a438",
|
|
145
145
|
"schemas/v2/eval-summary.schema.json": "9d31025752d0f67ad3b8a32e82a5314972c530ef9f780dd82e484ae8c5131198",
|
|
146
146
|
"schemas/v2/export-bundle.schema.json": "bd28905a7729437ab7f2ad8bb33e13a371b2bf5605a7eb2962a0d246de312d69",
|
|
147
147
|
"schemas/v2/form-content-pack-manifest.schema.json": "461529e4287ec3b15a9fbcde57226a1c6f17ea3ae71b33b418e6f595ff0619fe",
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
"schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
|
|
202
202
|
"spec/v1/alias-detectors.json": "40069d5976eeb6ba1384a648e57e5cfd673db3fce36175115fb8293bee9664d4",
|
|
203
203
|
"spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
|
|
204
|
-
"spec/v1/core-standard-manifest.json": "
|
|
204
|
+
"spec/v1/core-standard-manifest.json": "c17bb554c788d68fafc3413593dc6686aef0ad65864e925a9d19c4c3833bd0f5",
|
|
205
205
|
"spec/v1/deprecations.json": "307083ce29c23fd406015951f99a30d78d6187ff061d38dc9732f62191b40f3f",
|
|
206
206
|
"spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
|
|
207
207
|
"spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
|
|
@@ -218,8 +218,8 @@
|
|
|
218
218
|
"spec/v2/core/conformance.md": "a451c0a2ba79d93c55e540ccef480eba7de9602d59bbb03eead05daafde0beac",
|
|
219
219
|
"spec/v2/core/connection-packs.md": "466bdb9dde79d85615ad8281dacfb7bf923ca22d7fb3ed219749e59574c753ed",
|
|
220
220
|
"spec/v2/core/conversation.md": "e425887c4ba199b8cdc5c99e792689f7bd7d46de492f28670de2e402fa6d9506",
|
|
221
|
-
"spec/v2/core/errors.md": "
|
|
222
|
-
"spec/v2/core/events.md": "
|
|
221
|
+
"spec/v2/core/errors.md": "0dff4a0ae102a86f6a17a9a3b16a203292588a0f422ed19d1c0d9213995aa01d",
|
|
222
|
+
"spec/v2/core/events.md": "c98742f5a310eee8287ca8135493502152e88b479200a6544bb3340fed1e4efe",
|
|
223
223
|
"spec/v2/core/form-content-packs.md": "af3517dd7125106088249c0e32220b0b9fc3e9304c10378a6327cc8ad84b6bf1",
|
|
224
224
|
"spec/v2/core/headers.md": "14cdf4ae9ee7d80eebfd426d7c3552e577baea0300915cd4bb3a68e8588195a8",
|
|
225
225
|
"spec/v2/core/host-services.md": "3753f1e034d325bb4bd5751ae6d321fbb16700d4e28032ab4e273d25eb134fc4",
|
|
@@ -233,12 +233,12 @@
|
|
|
233
233
|
"spec/v2/core/replay.md": "b980a66e2543107240e3dc4f58131b9f4ff52478737e79ade6d5777b26ad1119",
|
|
234
234
|
"spec/v2/core/runs.md": "136319842bacbbb300178980e4b83444917d5b193cc5fdd92e39a4902ba8d3c0",
|
|
235
235
|
"spec/v2/core/security-defaults.md": "2a54ceaa4cef02c26ee0fbcf44f822ceeea79537c7d5a51ed300f21aa4fea576",
|
|
236
|
-
"spec/v2/core/versioning.md": "
|
|
236
|
+
"spec/v2/core/versioning.md": "56c1e273c790bcb0a2c3c760ffc7595afc9f5d4a745965e57f36aefcd456da76",
|
|
237
237
|
"spec/v2/core/webhooks.md": "46c1311c1897236f9bf9db5025c8af31dd84cd19208da3e5e9ff69eec9436965",
|
|
238
238
|
"spec/v2/core/workflow-chain-packs.md": "df78b76dd79f2267fb6b72c08e0911e5f9d5bb1925c6efdd6deda62fe8a51dc8",
|
|
239
|
-
"spec/v2/declaration.json": "
|
|
239
|
+
"spec/v2/declaration.json": "0f35205af96f29cacced435d1b606e9e8292c74a5509444bec78f17d315d63bf",
|
|
240
240
|
"spec/v2/declaration.schema.json": "c86e3083fb9789c1958ecb4576cc6f71aa90e6f339521139238543ed08211dd4",
|
|
241
|
-
"spec/v2/errors.json": "
|
|
241
|
+
"spec/v2/errors.json": "296117235d21ce4a393371c2f80caf03a4ae93d1f80a89f87cd3f56902cf5b01",
|
|
242
242
|
"spec/v2/event-codemap.json": "37869a03cdfd8758b57e6f350641a6ebbd383231cebda51f5473ad85f94ab74c",
|
|
243
243
|
"spec/v2/event-codemap.schema.json": "b173f2a9bcc0bf9b62a474ce3b91e1431d597e64fd1560fc58662cd8606eaf9c",
|
|
244
244
|
"spec/v2/ext/README.md": "ff91a503e0795e1b898e37d9e445add2d5975529723f7b32b2599b60a24c1ae3",
|
|
@@ -263,6 +263,7 @@
|
|
|
263
263
|
"spec/v2/facets/a2a.schema.json": "6b0bceddec6d18d5115aa7d04720a0cc1ad7a9a0a78f53c208b34becaba5d16e",
|
|
264
264
|
"spec/v2/facets/aiProviders.schema.json": "0c76e48e5d487b5be3b3ab1f6512a4e206c840ee5087d1336c7d7e2853b58d03",
|
|
265
265
|
"spec/v2/facets/auth.schema.json": "73440c944ad12c41aab0618aeb799a90a0b59e97fc685527f248afb7d015381a",
|
|
266
|
+
"spec/v2/facets/envelopeStrictness.schema.json": "28be0a27f880bd45ec1222a16155f5e9167bbca57bf0322970fe1eb2654562aa",
|
|
266
267
|
"spec/v2/facets/heartbeat.schema.json": "81d7fa1895a8b0241bd07cf00a7e7905bef0fd14eb3427325261c62eee5746a6",
|
|
267
268
|
"spec/v2/facets/interrupt.schema.json": "c76c58c0abd99de619f8c8afad246568f5bc9cce3b7a0d097d16d87eba84be3a",
|
|
268
269
|
"spec/v2/facets/mcp.schema.json": "f56609fe24ba6160ad29ae31aa16043354ff005e5cb6a0f3871c4d226087cc08",
|
|
@@ -270,14 +271,16 @@
|
|
|
270
271
|
"spec/v2/facets/replay.schema.json": "0a5aefb0108c708c6794fadd533cf256709704c4f16dbf44cd63fa8980c78018",
|
|
271
272
|
"spec/v2/facets/runList.schema.json": "6223e1baaebbb9f4faa71bfe968f8d22b4aa88046d0e43e8d5f56409e7f86e90",
|
|
272
273
|
"spec/v2/facets/sandbox.schema.json": "e75f54486d387b2d089791aa93b5093cd1450f1920753a0f97fc23acdfe978ed",
|
|
274
|
+
"spec/v2/facets/schemaVersions.schema.json": "890d3416c4b66511d51f329abc68e6f467f4338f16807e489fe682999b2b56b9",
|
|
275
|
+
"spec/v2/facets/supportedEnvelopes.schema.json": "644f22cc2236e30a611b5b7f1ba0458ff1925d68b94c514d9672583224e126bd",
|
|
273
276
|
"spec/v2/facets/webhooks.schema.json": "4bf3f8eb3161a43910efac4c44ccaf9567060c9da52d4cf09bcf3888d1b92192",
|
|
274
277
|
"spec/v2/facets/workflowChainPacks.schema.json": "cd30907ac92396866a524e4db8d8c1537e3818cfff455d780efd72bcd0ebdac1",
|
|
275
278
|
"spec/v2/id-field-bindings.json": "e73c06f3055ad30173507ac817a458b96362c8f26209ba105c53653292cf63d3",
|
|
276
279
|
"spec/v2/path-manifest.json": "c123c9fd77dc1b3f9c2e9346ace80cdae007e6511138894956abda01e61ec1c6",
|
|
277
280
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
278
281
|
"spec/v2/profiles.json": "0636f19fceae625390003a347e70ef4797d84766b5c24ce8a02cea52aadebca4",
|
|
279
|
-
"spec/v2/release.json": "
|
|
282
|
+
"spec/v2/release.json": "c315b1ff1a7b15dce5e0a0fda70abe67067f39ac5f171668ba8d637867133c51",
|
|
280
283
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
|
|
281
284
|
},
|
|
282
|
-
"corpusCommit": "
|
|
285
|
+
"corpusCommit": "f0ab0fc3a632d984a9cac159b349e908d54b6919"
|
|
283
286
|
}
|
|
@@ -400,22 +400,57 @@ describe('RFC 0173 §B — webhook-durable-delivery (gated on webhooks)', () =>
|
|
|
400
400
|
it('a dead-letter record carries no delivered payload', async () => {
|
|
401
401
|
// Its own `it`: RFC 0168 §A.1 allows one explicit requirement id per it(),
|
|
402
402
|
// and `check-req-only` enforces it.
|
|
403
|
-
|
|
403
|
+
//
|
|
404
|
+
// THIS LEG USED TO REGISTER A FRESH SUBSCRIPTION AND READ ITS SINK. A fresh
|
|
405
|
+
// subscription has no dead letters by construction, so the loop over
|
|
406
|
+
// `deliveries` ran zero times, the test asserted NOTHING, and RFC 0148 §A
|
|
407
|
+
// resolves a silent return to `blocked` — which denies certification
|
|
408
|
+
// (RFC 0168 §E.1). It went unnoticed because every host recorded
|
|
409
|
+
// `inapplicable` for want of the facet: the first host ever to advertise
|
|
410
|
+
// `webhooks.deadLetter` was refused certification by this leg on its first
|
|
411
|
+
// cut, with 232 other rows passing and zero failing.
|
|
412
|
+
//
|
|
413
|
+
// §B.1 is a claim about what a REAL record carries, so the leg has to make
|
|
414
|
+
// one: exhaust a delivery against a receiver that never succeeds — the same
|
|
415
|
+
// move the sibling 0173 dead-letter leg performs — and then read.
|
|
416
|
+
const doc = await discovery();
|
|
417
|
+
if (!doc) return softSkip('blocked', 'discovery unreachable');
|
|
404
418
|
const fam = await gateFamily('webhooks');
|
|
405
|
-
if (!fam
|
|
406
|
-
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
await
|
|
419
|
+
if (!fam) return softSkip('inapplicable', 'webhooks family not advertised');
|
|
420
|
+
if (!fam['deadLetter']) return softSkip('inapplicable', 'host does not advertise the webhooks.deadLetter facet — RFC 0188 §A.5 makes the read a 404 rather than an obligation');
|
|
421
|
+
if (!fixtureAdvertised(doc, FIXTURE)) return softSkip('inapplicable', `${FIXTURE} fixture not advertised — no delivery to exhaust`);
|
|
422
|
+
|
|
423
|
+
const receiver = await startReceiver(Number.POSITIVE_INFINITY); // never succeeds
|
|
424
|
+
active = receiver.server;
|
|
425
|
+
const sub = await register(receiver.url);
|
|
426
|
+
if (sub === null) return softSkip('blocked', 'registration refused (reason recorded above)');
|
|
427
|
+
const create = await driver.post('/runs', { workflowId: FIXTURE });
|
|
428
|
+
if (create.status !== 201) {
|
|
429
|
+
await driver.delete(`/webhooks/${encodeURIComponent(sub.webhookId)}`);
|
|
430
|
+
return softSkip('blocked', `POST /runs answered ${create.status} — no delivery to exhaust`);
|
|
431
|
+
}
|
|
432
|
+
const runId = (create.json as { runId: string }).runId;
|
|
433
|
+
await waitTerminal(runId, 10_000);
|
|
434
|
+
const policy = advertisedRetryPolicy(doc);
|
|
435
|
+
// Filter by SUBSCRIPTION as well as run, as the sibling leg does: a host
|
|
436
|
+
// that cannot reach loopback shares one tunnelled receiver URL across
|
|
437
|
+
// scenarios, so another scenario's attempts land in this budget otherwise.
|
|
438
|
+
const ours = () => receiver.attempts.filter((a) => a.runId === runId && a.webhookId === sub.webhookId);
|
|
439
|
+
await waitFor(() => ours().length >= (policy?.maxAttempts ?? 2), retryWaitMs(doc));
|
|
440
|
+
await new Promise((r) => setTimeout(r, 1_000));
|
|
441
|
+
|
|
442
|
+
const sink = await driver.get(`/webhooks/${projectBoundId(sub.webhookId)}/dead-letters`);
|
|
443
|
+
await driver.delete(`/webhooks/${encodeURIComponent(sub.webhookId)}`);
|
|
412
444
|
if (sink.status !== 200) return softSkip('blocked', `the dead-letter read answered ${sink.status}`);
|
|
413
445
|
const rows = ((sink.json as { deliveries?: Array<Record<string, unknown>> } | null)?.deliveries ?? []);
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
).toBe(true);
|
|
446
|
+
// An empty sink is NOT a pass. Recording one as a pass is exactly the
|
|
447
|
+
// vacuous witness this leg used to produce; say so instead.
|
|
448
|
+
if (rows.length === 0) {
|
|
449
|
+
return softSkip('blocked', 'the exhausted delivery did not reach the sink inside the retry window — §B.1 is a claim about a real record and there is none here to read');
|
|
419
450
|
}
|
|
451
|
+
expect(
|
|
452
|
+
rows.every((r) => r['body'] === undefined && r['headers'] === undefined && r['secret'] === undefined),
|
|
453
|
+
req('openwop.requirement.0188.dead-letter-content-free', 'RFC 0188 §B.1', `a dead-letter record MUST NOT carry the delivered body, headers or subscription secret — the queue is precisely the traffic the subscriber never received, so a record carrying any of it turns one read scope into a replay of that traffic for the whole retention window (read ${rows.length} record(s))`),
|
|
454
|
+
).toBe(true);
|
|
420
455
|
}, DEAD_LETTER_TEST_TIMEOUT_MS);
|
|
421
456
|
});
|