@openwop/openwop-conformance 2.0.0-rc.9 → 2.0.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 +46 -0
- package/README.md +8 -3
- package/dist/cli.js +24 -34
- package/dist/lib/requirement-registry.js +69 -0
- package/dist/lib/scenario-disposition.js +84 -11
- package/dist/lib/seams.js +72 -0
- package/dist/lib/soft-skip.js +39 -8
- package/dist/spec-artifacts.lock.json +2 -2
- package/package.json +2 -2
- package/requirement-aliases.json +4 -1
- package/requirements.json +1028 -55
- package/scenario-majors.json +57 -3
- package/schemas/CORPUS-STAMP.json +40 -37
- package/src/cli.ts +23 -30
- package/src/global-setup.ts +11 -0
- package/src/lib/corpus-stamp.ts +24 -2
- package/src/lib/era2-seed.ts +12 -1
- package/src/lib/fixtures.ts +31 -0
- package/src/lib/requirement-registry.ts +68 -0
- package/src/lib/scenario-disposition.ts +88 -9
- package/src/lib/seams.ts +31 -1
- package/src/lib/soft-skip.ts +42 -7
- package/src/lib/sse.ts +8 -0
- package/src/scenarios/era-key-stamped-v1.test.ts +156 -0
- package/src/scenarios/pause-resume.test.ts +159 -75
- package/src/scenarios/v2-advertised-fixtures-exist.test.ts +25 -43
- package/src/scenarios/v2-advertised-path-space-served.test.ts +165 -0
- package/src/scenarios/v2-assurance-downgrade-audited.test.ts +1 -1
- package/src/scenarios/v2-chain-pin-exact.test.ts +1 -1
- package/src/scenarios/v2-coherence-not-in-bundle.test.ts +11 -2
- package/src/scenarios/v2-created-run-readable.test.ts +98 -0
- package/src/scenarios/v2-dual-stack-negotiation.test.ts +29 -1
- package/src/scenarios/v2-effect-identity-business-key.test.ts +1 -1
- package/src/scenarios/v2-effect-seam-manifest.test.ts +21 -55
- package/src/scenarios/v2-effect-seam-no-refire.test.ts +104 -0
- package/src/scenarios/v2-era-2-append-vocabulary.test.ts +16 -2
- package/src/scenarios/v2-interrupt-token-scheme.test.ts +1 -1
- package/src/scenarios/v2-malformed-body-envelope.test.ts +79 -0
- package/src/scenarios/v2-manifest-ceiling-refused.test.ts +1 -1
- package/src/scenarios/v2-manifest-hatch-carried.test.ts +1 -1
- package/src/scenarios/v2-minimum-version-refused.test.ts +1 -1
- package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +1 -1
- package/src/scenarios/v2-negotiation-authenticated.test.ts +1 -1
- package/src/scenarios/v2-negotiation-decided-emitted.test.ts +1 -1
- package/src/scenarios/v2-pack-isolation.test.ts +1 -1
- package/src/scenarios/v2-peer-dependency-declared.test.ts +1 -1
- package/src/scenarios/v2-poll-cursor-v2.test.ts +18 -0
- package/src/scenarios/v2-revocation-honored.test.ts +1 -1
- package/src/scenarios/v2-run-annotation-not-event.test.ts +71 -0
- package/src/scenarios/v2-run-bulk-cancel.test.ts +91 -0
- package/src/scenarios/v2-run-cancel.test.ts +97 -0
- package/src/scenarios/v2-run-completed-outputs.test.ts +93 -0
- package/src/scenarios/v2-run-diff-identical.test.ts +75 -0
- package/src/scenarios/v2-run-fork-prefix.test.ts +160 -0
- package/src/scenarios/v2-run-fork-refusals.test.ts +70 -0
- package/src/scenarios/v2-run-options-limits.test.ts +69 -0
- package/src/scenarios/v2-run-pause-resume.test.ts +117 -0
- package/src/scenarios/v2-run-snapshot-etag.test.ts +57 -0
- package/src/scenarios/v2-sse-last-event-id.test.ts +93 -0
- package/src/scenarios/v2-stream-mode-refusal.test.ts +118 -0
- package/src/scenarios/v2-stream-sse-projection.test.ts +79 -0
- package/src/scenarios/v2-subject-link-record.test.ts +1 -1
- package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +1 -1
- package/src/scenarios/version-negotiation.test.ts +25 -3
- package/src/setup.ts +104 -50
package/scenario-majors.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "GENERATED by conformance/scripts/generate-scenario-majors.mjs (RFC 0168 §D.3). Do not edit; add a file to BOTH_MAJORS in the generator to target both majors.",
|
|
3
3
|
"counts": {
|
|
4
|
-
"files":
|
|
5
|
-
"v1":
|
|
6
|
-
"v2":
|
|
4
|
+
"files": 516,
|
|
5
|
+
"v1": 445,
|
|
6
|
+
"v2": 72
|
|
7
7
|
},
|
|
8
8
|
"majors": {
|
|
9
9
|
"a2a-1-0-agent-card.test.ts": [
|
|
@@ -564,6 +564,9 @@
|
|
|
564
564
|
"envelope-variant-discriminator-static.test.ts": [
|
|
565
565
|
1
|
|
566
566
|
],
|
|
567
|
+
"era-key-stamped-v1.test.ts": [
|
|
568
|
+
1
|
|
569
|
+
],
|
|
567
570
|
"errors.test.ts": [
|
|
568
571
|
1
|
|
569
572
|
],
|
|
@@ -1231,6 +1234,9 @@
|
|
|
1231
1234
|
"v2-advertised-fixtures-exist.test.ts": [
|
|
1232
1235
|
2
|
|
1233
1236
|
],
|
|
1237
|
+
"v2-advertised-path-space-served.test.ts": [
|
|
1238
|
+
2
|
|
1239
|
+
],
|
|
1234
1240
|
"v2-approver-enforced.test.ts": [
|
|
1235
1241
|
2
|
|
1236
1242
|
],
|
|
@@ -1258,6 +1264,9 @@
|
|
|
1258
1264
|
"v2-configurable-closed.test.ts": [
|
|
1259
1265
|
2
|
|
1260
1266
|
],
|
|
1267
|
+
"v2-created-run-readable.test.ts": [
|
|
1268
|
+
2
|
|
1269
|
+
],
|
|
1261
1270
|
"v2-dual-stack-negotiation.test.ts": [
|
|
1262
1271
|
2
|
|
1263
1272
|
],
|
|
@@ -1267,6 +1276,9 @@
|
|
|
1267
1276
|
"v2-effect-seam-manifest.test.ts": [
|
|
1268
1277
|
2
|
|
1269
1278
|
],
|
|
1279
|
+
"v2-effect-seam-no-refire.test.ts": [
|
|
1280
|
+
2
|
|
1281
|
+
],
|
|
1270
1282
|
"v2-enum-growth-rule.test.ts": [
|
|
1271
1283
|
2
|
|
1272
1284
|
],
|
|
@@ -1309,6 +1321,9 @@
|
|
|
1309
1321
|
"v2-legacy-profiles-absent.test.ts": [
|
|
1310
1322
|
2
|
|
1311
1323
|
],
|
|
1324
|
+
"v2-malformed-body-envelope.test.ts": [
|
|
1325
|
+
2
|
|
1326
|
+
],
|
|
1312
1327
|
"v2-manifest-ceiling-refused.test.ts": [
|
|
1313
1328
|
2
|
|
1314
1329
|
],
|
|
@@ -1369,6 +1384,45 @@
|
|
|
1369
1384
|
"v2-revocation-honored.test.ts": [
|
|
1370
1385
|
2
|
|
1371
1386
|
],
|
|
1387
|
+
"v2-run-annotation-not-event.test.ts": [
|
|
1388
|
+
2
|
|
1389
|
+
],
|
|
1390
|
+
"v2-run-bulk-cancel.test.ts": [
|
|
1391
|
+
2
|
|
1392
|
+
],
|
|
1393
|
+
"v2-run-cancel.test.ts": [
|
|
1394
|
+
2
|
|
1395
|
+
],
|
|
1396
|
+
"v2-run-completed-outputs.test.ts": [
|
|
1397
|
+
2
|
|
1398
|
+
],
|
|
1399
|
+
"v2-run-diff-identical.test.ts": [
|
|
1400
|
+
2
|
|
1401
|
+
],
|
|
1402
|
+
"v2-run-fork-prefix.test.ts": [
|
|
1403
|
+
2
|
|
1404
|
+
],
|
|
1405
|
+
"v2-run-fork-refusals.test.ts": [
|
|
1406
|
+
2
|
|
1407
|
+
],
|
|
1408
|
+
"v2-run-options-limits.test.ts": [
|
|
1409
|
+
2
|
|
1410
|
+
],
|
|
1411
|
+
"v2-run-pause-resume.test.ts": [
|
|
1412
|
+
2
|
|
1413
|
+
],
|
|
1414
|
+
"v2-run-snapshot-etag.test.ts": [
|
|
1415
|
+
2
|
|
1416
|
+
],
|
|
1417
|
+
"v2-sse-last-event-id.test.ts": [
|
|
1418
|
+
2
|
|
1419
|
+
],
|
|
1420
|
+
"v2-stream-mode-refusal.test.ts": [
|
|
1421
|
+
2
|
|
1422
|
+
],
|
|
1423
|
+
"v2-stream-sse-projection.test.ts": [
|
|
1424
|
+
2
|
|
1425
|
+
],
|
|
1372
1426
|
"v2-subject-link-record.test.ts": [
|
|
1373
1427
|
2
|
|
1374
1428
|
],
|
|
@@ -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.0.0
|
|
5
|
-
"corpusTag":
|
|
4
|
+
"version": "2.0.0",
|
|
5
|
+
"corpusTag": "v2.0.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": "0568c438db8a84b9e51c221f118b660bad9f96722ec5607bce25b2fe1395afa0",
|
|
13
|
+
"api/v2/asyncapi.yaml": "fe31d75cdee4505900fe206fb5d1bdedbaa7ab6f54fd7ff1c63f14c5a1cd9595",
|
|
14
|
+
"api/v2/openapi.yaml": "1e33a399c7b29b93e317cab6ba60b891a3b9153e79c0ff907bf253f2c48aa6a6",
|
|
15
15
|
"api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
|
|
16
16
|
"schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
|
|
17
17
|
"schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"schemas/artifact-type-pack-manifest.schema.json": "13932ea58e819e01b3a0cc7a65590b70683dd5fe9208fc06c64c339943d3c4ce",
|
|
32
32
|
"schemas/audit-verify-result.schema.json": "e8fd013fb610ba5db27ab0113ec2eb18e7da5f9310dd3de2dd3dc87a259c21fe",
|
|
33
33
|
"schemas/budget-policy.schema.json": "3d4fe30ae129fe136ab9ece395f2a2a42a76360786b1b9a1d5f1cbc753eb5b39",
|
|
34
|
-
"schemas/capabilities.schema.json": "
|
|
34
|
+
"schemas/capabilities.schema.json": "b413e0235cad412081df09234237e0f322a85903b7411b91aaff54032e946671",
|
|
35
35
|
"schemas/certification-bundle-v2.schema.json": "2f85530dd04824a15810c94e96869362dee1e78396eca21fdd18e5501416bb7d",
|
|
36
36
|
"schemas/channel-presence-payload.schema.json": "f9d0ef4219814c2b765baf3e68cbe5eea2cb42379f516a93a0459dcd5f7db47e",
|
|
37
37
|
"schemas/channel-written-payload.schema.json": "54723a56bc5a35232f64544ca686ac1ac959a5fb05b32b2401facca6b3ef51a3",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"schemas/run-event.schema.json": "c70c06932b9831295042836213e617c8e946f20ddd49cf4e889b74d89d2175a8",
|
|
87
87
|
"schemas/run-options.schema.json": "f8241ece6ddc6527de9160d811d42c231b4f77b935f2e107b3c05608545c59ab",
|
|
88
88
|
"schemas/run-orchestrator-decided-event.schema.json": "17a43a3c44680a24d411141357a867b3caed6107d56de88fe2e062eaf93fa2c1",
|
|
89
|
-
"schemas/run-snapshot.schema.json": "
|
|
89
|
+
"schemas/run-snapshot.schema.json": "3343550f6973a0975c61624df569d341e843ac8592a2aa2b3b7cf540d72563ad",
|
|
90
90
|
"schemas/security-advisory.schema.json": "9c550f0bf10a3193dcca4a127081fb66fe5dc1b6f729c4c17bfaea3ba3ce05fc",
|
|
91
91
|
"schemas/self-hosted-runner-dispatch-frame.schema.json": "3f1d7edd572c6747657299525d8e85329b93b6fadf670e3a19c74d53e725adec",
|
|
92
92
|
"schemas/self-hosted-runner-registration.schema.json": "6c781adf1bb915a9e47796494f4a527353cbbf72b480e5a05be4aac65a6d0c6e",
|
|
@@ -100,9 +100,9 @@
|
|
|
100
100
|
"schemas/ui-plugin-message.schema.json": "346638babf1f8ea7b161cde75c0038b518cd2cc5bf0631772e20a9b74c96b5dd",
|
|
101
101
|
"schemas/v2/a2a-task-state.schema.json": "aa9bd0c15f653b7ecdb17427d61b1bccaf8156972c4b1a437dd3a8afb717b318",
|
|
102
102
|
"schemas/v2/a2ui-surface-delta-frame.schema.json": "43c10ebfd13c987520f0448df92fe74b52b846833763dfbbd5d35636bf75e8d9",
|
|
103
|
-
"schemas/v2/agent-deployment-transition.schema.json": "
|
|
104
|
-
"schemas/v2/agent-deployment.schema.json": "
|
|
105
|
-
"schemas/v2/agent-eval-suite.schema.json": "
|
|
103
|
+
"schemas/v2/agent-deployment-transition.schema.json": "d9fe6f2fa4dda8598bab4e5c051f68473ac0729dc0ebf31605954dda7abf5a80",
|
|
104
|
+
"schemas/v2/agent-deployment.schema.json": "dd1293ef8f20678bc36fc95fc4e5fcd135acbb10c61c1ddec8bc023e3f22622c",
|
|
105
|
+
"schemas/v2/agent-eval-suite.schema.json": "b2875edfc28b39c104fbf6f854ecfb81fe2d90b18f828ffd8d3232ef883cd208",
|
|
106
106
|
"schemas/v2/agent-inventory-response.schema.json": "bbf19724986a867a59ef51c115a43ece1cc4a003836b2f7f45dfefb3078db8f9",
|
|
107
107
|
"schemas/v2/agent-manifest.schema.json": "006ca6163ca8f9dc9fb91ca1ce01bd4c523f118680f6cbad971a4ac09e975381",
|
|
108
108
|
"schemas/v2/agent-org-chart.schema.json": "e64f1bcc6c0e9d3fc39c363e8e5e73b2b1fc49275b92f89b0cb941a7a80d67f2",
|
|
@@ -112,14 +112,14 @@
|
|
|
112
112
|
"schemas/v2/ai-envelope.schema.json": "0dc7dfbf032a37239ffd81fc2d67f999a40782ff5074866a56e414164cdee809",
|
|
113
113
|
"schemas/v2/annotation-create.schema.json": "c2fc19d055be29bc499e53c4975a562eb76981e12c521a82f63f5827ac6ff6c7",
|
|
114
114
|
"schemas/v2/annotation.schema.json": "75c6785775d00e62bc1282626c2c27eafde0f93a01c7e80e4e5e985055907475",
|
|
115
|
-
"schemas/v2/artifact-type-pack-manifest.schema.json": "
|
|
115
|
+
"schemas/v2/artifact-type-pack-manifest.schema.json": "85630d1b760d0b41cf5a6fad2acfada39abaf7f0befd95cc4334e1e883e9615d",
|
|
116
116
|
"schemas/v2/audit-verify-result.schema.json": "cb54c4d89ba5dfb73f49aa8959a980be65c2dc2a87a12f71ba36d3e836fe85da",
|
|
117
117
|
"schemas/v2/budget-policy.schema.json": "c7449daeb6e1d95e7a047b8c2814d3d54748697c27046972834874867d9b5f4c",
|
|
118
118
|
"schemas/v2/capabilities.schema.json": "792669b2cc7b1fd44ce9a4fd3e79696ad1277734e29299a4504b39eda15913ed",
|
|
119
|
-
"schemas/v2/certification-bundle.schema.json": "
|
|
119
|
+
"schemas/v2/certification-bundle.schema.json": "b893ffa4de998b8b2b69a1038ebba0d7d50c8a32cde91ccae2b7c653fe459aa6",
|
|
120
120
|
"schemas/v2/channel-presence-payload.schema.json": "9475d46f358d21c19126e78204987a5633979917a2293653354ef5c5e044d54e",
|
|
121
121
|
"schemas/v2/channel-written-payload.schema.json": "ccecff3c71a3275ad8db035ac0e04db25e6f8d23cf091ddbcd5a60d1be1cbb6b",
|
|
122
|
-
"schemas/v2/chat-card-pack-manifest.schema.json": "
|
|
122
|
+
"schemas/v2/chat-card-pack-manifest.schema.json": "8df0d9d273ae22efc6876d5586833f1d4c2e551edc3ac6cf6e8f0719329f03dd",
|
|
123
123
|
"schemas/v2/compact-tool-descriptor.schema.json": "fc03f20c254c0ddc2cba7e7d5a6c46080ebd2cf9fae36f3c2510cbf88aadebdc",
|
|
124
124
|
"schemas/v2/compensation-policy.schema.json": "b3c1142637f5bf980f2b0bb67adb47e8cb7abb99a0405a4b6816ccf5d9c089d6",
|
|
125
125
|
"schemas/v2/compensation-projection.schema.json": "f46977c7076347b5473faa8c4bbe73d8321c33b33c98fff2f26ee7cbada4ed98",
|
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
"schemas/v2/conversation-turn.schema.json": "4c24aa85dd83f6ad00945b4a13ee8ff0a071893e884011e9289a07e97d22989d",
|
|
130
130
|
"schemas/v2/credential-provenance.schema.json": "f86b09e94b1c524dec7d1c6353965665ae8891e9517faef6e742d639c5578c99",
|
|
131
131
|
"schemas/v2/credential-reference.schema.json": "ea699ce30f58fb2c32d4279158b3f730f70be7b2dc8c3037693a76e66eb3e001",
|
|
132
|
-
"schemas/v2/debug-bundle.schema.json": "
|
|
132
|
+
"schemas/v2/debug-bundle.schema.json": "0bfa4b1d91fefbc12c95670dba9d5eacb72b879bb9a5c074e821ca9ed0fee6fd",
|
|
133
133
|
"schemas/v2/dispatch-config.schema.json": "4a7db312e6b4a14cf5b1ad2b71367878c77b6321cc456f5b3644dd6434e94cbd",
|
|
134
|
-
"schemas/v2/effect-ledger-projection.schema.json": "
|
|
135
|
-
"schemas/v2/effect-seam-manifest.schema.json": "
|
|
134
|
+
"schemas/v2/effect-ledger-projection.schema.json": "928340b243c60aaf04c1b40adb09be8a90340d44f57be1dfff837be10f104822",
|
|
135
|
+
"schemas/v2/effect-seam-manifest.schema.json": "197ef9944ab027a50d1b9352f317cbbc12c8ad955fdb14650fb90477052ffef0",
|
|
136
136
|
"schemas/v2/envelopes/clarification.request.schema.json": "9e39d7b09f0b3ce7902d6aa19ca0eb52867b634efc78a881469c4d44fb3333e7",
|
|
137
137
|
"schemas/v2/envelopes/error.schema.json": "6a11fa3b9d61736fcb5675e6ac9825919aa609dceba13ef5615993d54647802b",
|
|
138
138
|
"schemas/v2/envelopes/media.audio.schema.json": "a422352240a592c12840172e70835729f72b6b21915d14e926b6ffcd5d52a704",
|
|
@@ -141,22 +141,22 @@
|
|
|
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": "
|
|
145
|
-
"schemas/v2/eval-summary.schema.json": "
|
|
144
|
+
"schemas/v2/error-envelope.schema.json": "72d3332fad8fa36d07439c830acf352eefc6da2379374faa2ebbe49e98b8cb08",
|
|
145
|
+
"schemas/v2/eval-summary.schema.json": "bcb165148531d33b7dc01de83da3a049d19ebbef6d12300b17a234c7b03d77d9",
|
|
146
146
|
"schemas/v2/export-bundle.schema.json": "bd28905a7729437ab7f2ad8bb33e13a371b2bf5605a7eb2962a0d246de312d69",
|
|
147
147
|
"schemas/v2/form-content-pack-manifest.schema.json": "307884e57946703b6f86ec283034bf56beb68bea4a000743ebbc9eebeed31b07",
|
|
148
148
|
"schemas/v2/frontend-plugin-manifest.schema.json": "fed6b8ddb3056c53b1bfc91525410a4445a3c37a8bf9eb9f6f9964ffea26d993",
|
|
149
|
-
"schemas/v2/goal.schema.json": "
|
|
149
|
+
"schemas/v2/goal.schema.json": "146c4182e36d3538778f947e668a92cdb69ec42ee0820104b00063b035e342d7",
|
|
150
150
|
"schemas/v2/heartbeat-evaluated.schema.json": "4086b1ba1d0547c08b038dfb263ac89416a3e406430db1250156fb2f9b74f8d6",
|
|
151
151
|
"schemas/v2/heartbeat-state-changed.schema.json": "eb68d0082aa996650e3a6b8ccf32457f959cebc7e6728cc7c331b9d171a4bef6",
|
|
152
|
-
"schemas/v2/ids.schema.json": "
|
|
152
|
+
"schemas/v2/ids.schema.json": "05c98e3f8a72fa79be123765bd9c2ea7c6620188d69df8524160399225316cd6",
|
|
153
153
|
"schemas/v2/localized-content-language-settings.schema.json": "92240f19a2b4b2f05ab41a797f703485a28813848035478e72f395edd04c1d35",
|
|
154
154
|
"schemas/v2/localized-content-page-response.schema.json": "476b5f2775b42e35e679814a4ce846a7be1d5311d3a748c10df4275a78b0fb27",
|
|
155
155
|
"schemas/v2/localized-content-page.schema.json": "717bb51fbc64d0b34eb0a4b35c8b463d08d505267bf251b4cbc67e0a016a567a",
|
|
156
156
|
"schemas/v2/localized-content-section.schema.json": "29c7bad0ad9ebc6c45211282e8afb3fdb35a4ca075ce0404b6e2c29f35fa5313",
|
|
157
157
|
"schemas/v2/memory-entry.schema.json": "290576ae84f4fef4cdf975932b87963283b11c50ea3d2654b32cd96aa6537c3d",
|
|
158
158
|
"schemas/v2/memory-list-options.schema.json": "f66703bccb68efb28391c273abb66aa117ee5b5ce475c477846ed700c336afcd",
|
|
159
|
-
"schemas/v2/node-pack-manifest.schema.json": "
|
|
159
|
+
"schemas/v2/node-pack-manifest.schema.json": "0da826ca63a29026f7a9551748048104910e0d9962db6bad2b50b97a24a9ea30",
|
|
160
160
|
"schemas/v2/orchestrator-decision.schema.json": "2da17538e84cfbe70151eb118f1ccf670cff58b8697148e394074d32ac4af6b4",
|
|
161
161
|
"schemas/v2/org-chart-responsibility-view.schema.json": "ebac7d2889bfd659bcf30311efb0d6eb0c7e940b972b6b62da69c7351b5bb586",
|
|
162
162
|
"schemas/v2/pack-lockfile.schema.json": "2685417702c105146b780cd99154296a46578fbb10d81c8c713348ee26fea898",
|
|
@@ -164,16 +164,16 @@
|
|
|
164
164
|
"schemas/v2/prompt-pack-manifest.schema.json": "a51667da3d601043d2c33fddaafa572e9dd7e47b8840393742b80eaf6238a1a5",
|
|
165
165
|
"schemas/v2/prompt-ref.schema.json": "11538fa36a7a652c93100cac4f1857eb4130137b546e3d94890618636d44b729",
|
|
166
166
|
"schemas/v2/prompt-template.schema.json": "494fc83028cb3af5dbb8a943d0e83b2348f7775e9fa02369162bcb58a6f81559",
|
|
167
|
-
"schemas/v2/proposal.schema.json": "
|
|
167
|
+
"schemas/v2/proposal.schema.json": "cb5ea4fcb54be94fd2a92cf2799357dc73335181a89f5766f432d69e21cc3a80",
|
|
168
168
|
"schemas/v2/registry-version-manifest.schema.json": "270704ebc6bae63be949efbf9503578938b103733db9da3cb8fcbee1cd7684dd",
|
|
169
169
|
"schemas/v2/residency.schema.json": "af2658a7104cbcacd0e20a91226271c4a77f91ef46ae97612768fe743e6091d8",
|
|
170
170
|
"schemas/v2/run-ancestry-response.schema.json": "907e36341ba83a2147a5d76963950b6dcd47506b663ecbccae9dfa553f3724d3",
|
|
171
171
|
"schemas/v2/run-diff-response.schema.json": "6ab6cd265dc7e0a2086c6659c46aa0e7b43e6302949f0adac5d7deb1c7c0ecd3",
|
|
172
|
-
"schemas/v2/run-event-payloads.schema.json": "
|
|
173
|
-
"schemas/v2/run-event.schema.json": "
|
|
174
|
-
"schemas/v2/run-options.schema.json": "
|
|
172
|
+
"schemas/v2/run-event-payloads.schema.json": "3a7161af78b0dd2730309371f5ea8b889d92a37c708db05e4354209f12ffbe30",
|
|
173
|
+
"schemas/v2/run-event.schema.json": "1a9946374af9323b71635d00fed22abe02c300fa2cf3ae3e9c30f3e553e408ec",
|
|
174
|
+
"schemas/v2/run-options.schema.json": "ff240805478158cbd2f661979c5eb4f5eda11f9c053b7ba587cb0211a9252d74",
|
|
175
175
|
"schemas/v2/run-orchestrator-decided-event.schema.json": "bb76e15ff72e669f12938684033b55dc567470e1a378e19ffc3fa0e4034ab5a7",
|
|
176
|
-
"schemas/v2/run-snapshot.schema.json": "
|
|
176
|
+
"schemas/v2/run-snapshot.schema.json": "0ee8a50c6be210db415a7c4345298e70a6ae3dd0dd764ccc514bc1c501437586",
|
|
177
177
|
"schemas/v2/security-advisory.schema.json": "6a382f737730a738d634266315e9d335e5760020a0cdd9f30727c2f987a01770",
|
|
178
178
|
"schemas/v2/self-hosted-runner-dispatch-frame.schema.json": "d8129f11d4e731d17ea951e66faaea2086081d13958b62ceaaa359fd6637dd7d",
|
|
179
179
|
"schemas/v2/self-hosted-runner-registration.schema.json": "93d60003a668cacb0eeac37699ca2884c6b79332d9494cb9e0a1752ac8f8a16c",
|
|
@@ -186,8 +186,9 @@
|
|
|
186
186
|
"schemas/v2/trigger-subscription-registration.schema.json": "202f7ab9c29e78249e0ad04341ac53377b506d24a0cbfbb7bb54494e80165832",
|
|
187
187
|
"schemas/v2/trigger-subscription.schema.json": "074bec7f016aa9f4d60359c3a093296cc847045510f01e0a9dceaf4fa5084d12",
|
|
188
188
|
"schemas/v2/ui-plugin-message.schema.json": "879d65867c01656b3962d64283e66364dcb8f626ad26c5fcf2d2d55a79ae0ce9",
|
|
189
|
-
"schemas/v2/
|
|
190
|
-
"schemas/v2/workflow-
|
|
189
|
+
"schemas/v2/webhook-delivery.schema.json": "66025cd7b7899b6897b61c61e99ec2c554e232a6c9742124441adcd81912cef0",
|
|
190
|
+
"schemas/v2/workflow-chain-pack-manifest.schema.json": "22801f14845a3df30660e6f31a41e1a3fbff2425bf56c8a475eab96f1c95882a",
|
|
191
|
+
"schemas/v2/workflow-definition.schema.json": "da7e565cee6ecf3bcc9d46833bad224f579f8db8a378ae22ff3fbf58b1348f38",
|
|
191
192
|
"schemas/v2/workload-identity.schema.json": "1f589debfac6d70e0908da511550ec69a27b4bcc8314551cd843b6d923605efc",
|
|
192
193
|
"schemas/v2/workspace-file-create.schema.json": "b6b5260857318c3b67de0231ed15e3a746f525880a763e7b36a7854178dd10d0",
|
|
193
194
|
"schemas/v2/workspace-file.schema.json": "d2ed39e8c229dde33b56905c8df6f8b2ff056c97e1c5f615e3124baa54a6254f",
|
|
@@ -198,21 +199,21 @@
|
|
|
198
199
|
"schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
|
|
199
200
|
"spec/v1/alias-detectors.json": "fee4594ef49953953ffcd0b3813300067d16b3e65ebff2aac722034ac9b3f545",
|
|
200
201
|
"spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
|
|
201
|
-
"spec/v1/core-standard-manifest.json": "
|
|
202
|
-
"spec/v1/deprecations.json": "
|
|
203
|
-
"spec/v1/deprecations.schema.json": "
|
|
202
|
+
"spec/v1/core-standard-manifest.json": "08eb68a1f07020390cf3a76ce6ac9bec697cd35ba02a0d8618939e39cac87a0a",
|
|
203
|
+
"spec/v1/deprecations.json": "1d5acb69a9b8ccb57275a95605f74aef1d920685f8407c9d382a46b59dc803bb",
|
|
204
|
+
"spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
|
|
204
205
|
"spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
|
|
205
206
|
"spec/v1/event-codemap.schema.json": "d52caf29071e3784d4c20259cdbd5a7b533986548a440bb632a80b82cadd7ea5",
|
|
206
|
-
"spec/v1/extensions.json": "
|
|
207
|
+
"spec/v1/extensions.json": "79a60754aa16cbdbdb604f8e5c00038af535a1690a4d07bd5ff7c38f0256a7bc",
|
|
207
208
|
"spec/v1/gaps.json": "96ca051cb20f1a669b355d67a89421c56fef28aa5e6710c9519f592f26af33a3",
|
|
208
209
|
"spec/v1/gaps.schema.json": "8fd83259f556553c9df0f53e7a82ca8c2a4771d471197f69b4e2ae0ceeacfd66",
|
|
209
210
|
"spec/v1/migrations.json": "8839497d6a4830b53fa7867014a8336f0d725ef2346352e54fb580b7947897af",
|
|
210
211
|
"spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
|
|
211
212
|
"spec/v1/operation-path-manifest.json": "5f5f4e3842669371730ebbd1aace3fb794192615f0018dc144f484ba5db82ac3",
|
|
212
213
|
"spec/v1/spec-gaps.json": "6cc9962c6b969f632e07a78b52a4f61447ff579e2990cbae989866f584a86042",
|
|
213
|
-
"spec/v2/declaration.json": "
|
|
214
|
+
"spec/v2/declaration.json": "a624cfa6a46d0b10e0dac40fa49abbe05190aff87a8e852ce125d19379067b00",
|
|
214
215
|
"spec/v2/declaration.schema.json": "b0881a76228dfbd1b85a2ec7b7259a60197f768344535cdb475db6ff719b0e54",
|
|
215
|
-
"spec/v2/errors.json": "
|
|
216
|
+
"spec/v2/errors.json": "f179414a92f30b5dadf26e9e57699649a67324bd7186d5287647d17605d137d3",
|
|
216
217
|
"spec/v2/event-codemap.json": "37869a03cdfd8758b57e6f350641a6ebbd383231cebda51f5473ad85f94ab74c",
|
|
217
218
|
"spec/v2/event-codemap.schema.json": "ce2d0ca085d7668d7ef745d2560b385ec6881d24a6d4b47c49931986b2ba642d",
|
|
218
219
|
"spec/v2/ext/provider-idempotency/registry.json": "5b5fecad604fb4ab38da39f5abe697a4e57b05406c398f8afeb377331b2bd965",
|
|
@@ -225,10 +226,12 @@
|
|
|
225
226
|
"spec/v2/facets/replay.schema.json": "0a5aefb0108c708c6794fadd533cf256709704c4f16dbf44cd63fa8980c78018",
|
|
226
227
|
"spec/v2/facets/sandbox.schema.json": "e75f54486d387b2d089791aa93b5093cd1450f1920753a0f97fc23acdfe978ed",
|
|
227
228
|
"spec/v2/facets/webhooks.schema.json": "0b766033ef4b4c6c2ac6f9979a19843ba024d3a1d1576972dcb55aaba52f1b9a",
|
|
229
|
+
"spec/v2/id-field-bindings.json": "d9d1f8e266660b581f11020b9511a65c677e026b1a71ada870682ad77e18555d",
|
|
228
230
|
"spec/v2/path-manifest.json": "034152e09b1458c66810d4050e20a273b2b9b8fe2d92b66e8b819477de58a1be",
|
|
229
231
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
230
|
-
"spec/v2/profiles.json": "
|
|
231
|
-
"spec/v2/release.json": "
|
|
232
|
+
"spec/v2/profiles.json": "0636f19fceae625390003a347e70ef4797d84766b5c24ce8a02cea52aadebca4",
|
|
233
|
+
"spec/v2/release.json": "517c6d3ccefcc5e76cc8206a580222af2ae51dcca99869db83191e046c461a49",
|
|
234
|
+
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
|
|
232
235
|
},
|
|
233
|
-
"corpusCommit": "
|
|
236
|
+
"corpusCommit": "2e5c91a9376498ce8825f97fcb76f2edac0efb4f"
|
|
234
237
|
}
|
package/src/cli.ts
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
type DiscoveryPayload,
|
|
55
55
|
PROFILE_FLOOR_SCENARIOS,
|
|
56
56
|
} from './lib/profiles.js';
|
|
57
|
-
import { setV2ProfileFloors } from './lib/requirement-registry.js';
|
|
57
|
+
import { setV2ProfileFloors, v2ProfileFloorFiles } from './lib/requirement-registry.js';
|
|
58
58
|
|
|
59
59
|
interface ParsedArgs {
|
|
60
60
|
readonly baseUrl: string | undefined;
|
|
@@ -377,35 +377,10 @@ function claimedProfilesForV2(doc: DiscoveryPayload, conformanceRoot: string): s
|
|
|
377
377
|
* fail a host for the corpus's own backlog.
|
|
378
378
|
*/
|
|
379
379
|
function v2ProfileFloors(conformanceRoot: string): Record<string, readonly string[]> {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
let known: Set<string>;
|
|
383
|
-
try {
|
|
384
|
-
known = new Set(Object.keys((JSON.parse(readFileSync(resolvePath(conformanceRoot, 'scenario-majors.json'), 'utf8')) as { majors: Record<string, number[]> }).majors));
|
|
385
|
-
} catch {
|
|
386
|
-
known = new Set();
|
|
387
|
-
}
|
|
388
|
-
let registry: { profiles?: Array<{ id?: unknown; floorScenarios?: unknown }> };
|
|
389
|
-
try {
|
|
390
|
-
registry = JSON.parse(readFileSync(registryPath, 'utf8'));
|
|
391
|
-
} catch {
|
|
392
|
-
return {};
|
|
393
|
-
}
|
|
394
|
-
const out: Record<string, readonly string[]> = {};
|
|
395
|
-
for (const p of registry.profiles ?? []) {
|
|
396
|
-
if (typeof p.id !== 'string') continue;
|
|
397
|
-
const raw = Array.isArray(p.floorScenarios) ? (p.floorScenarios as unknown[]).map(String) : [];
|
|
398
|
-
const files: string[] = [];
|
|
399
|
-
for (const entry of raw) {
|
|
400
|
-
const name = entry.startsWith('planned:') ? `v2-${entry.slice('planned:'.length)}.test.ts` : entry.endsWith('.test.ts') ? entry : `${entry}.test.ts`;
|
|
401
|
-
if (known.size === 0 || known.has(name)) files.push(name);
|
|
402
|
-
}
|
|
403
|
-
out[p.id] = files;
|
|
404
|
-
}
|
|
405
|
-
return out;
|
|
380
|
+
// One derivation, shared with the ledger's floor-file set (requirement-registry.ts).
|
|
381
|
+
return v2ProfileFloorFiles(conformanceRoot);
|
|
406
382
|
}
|
|
407
383
|
|
|
408
|
-
/** A single scenario test file's terminal state, derived from the vitest JSON report. */
|
|
409
384
|
type ScenarioState = 'passed' | 'failed' | 'skipped';
|
|
410
385
|
|
|
411
386
|
/** The subset of vitest's JSON reporter output we read. */
|
|
@@ -476,6 +451,16 @@ async function resolveTargetMajor(args: ParsedArgs, baseUrl: string | undefined,
|
|
|
476
451
|
// §1.1), so auto-detection on a dual-stack host resolves to major 1 by design.
|
|
477
452
|
// Say so, or an operator reads a v1 run as the host's only option.
|
|
478
453
|
if (major === 1 && dualStack) source += ' (the host also serves 2.x — pass --target-major 2 to measure it)';
|
|
454
|
+
// The RUNNER's own process must see the target major, not only the vitest
|
|
455
|
+
// child (rc.55). `requirementIdForFile()` decides "is this file a floor?"
|
|
456
|
+
// through `targetMajor()` = process.env; until rc.55 `--target-major 2` set
|
|
457
|
+
// the env on the child alone, so the worker recorded every v2 floor file
|
|
458
|
+
// under `openwop.floor.<stem>` while the runner looked it up as
|
|
459
|
+
// `openwop.scenario.<stem>`, found nothing, emitted a report-derived pass
|
|
460
|
+
// with no assertion count, and its own verifier rejected the bundle as a
|
|
461
|
+
// `vacuous-pass` emitter defect (exit 2, nothing written). The child env is
|
|
462
|
+
// spread from process.env after this, so one assignment covers both.
|
|
463
|
+
process.env['OPENWOP_TARGET_MAJOR'] = String(major);
|
|
479
464
|
const manifest = JSON.parse(readFileSync(resolvePath(conformanceRoot, 'scenario-majors.json'), 'utf8')) as { majors: Record<string, number[]> };
|
|
480
465
|
const files = Object.entries(manifest.majors).filter(([, m]) => m.includes(major as number)).map(([f]) => `src/scenarios/${f}`);
|
|
481
466
|
return { major, files, source };
|
|
@@ -666,14 +651,22 @@ async function runCertify(args: ParsedArgs, baseUrl: string, apiKey: string): Pr
|
|
|
666
651
|
const doc3 = document as Record<string, unknown>;
|
|
667
652
|
const protocolVersions = Array.isArray(doc3['protocolVersions']) ? (doc3['protocolVersions'] as string[]) : [String(doc3['protocolVersion'] ?? '')];
|
|
668
653
|
const preferredVersion = typeof doc3['preferredVersion'] === 'string' ? (doc3['preferredVersion'] as string) : (protocolVersions[0] ?? '');
|
|
669
|
-
// witnessCount: executed-pass rows on the profile's floor
|
|
654
|
+
// witnessCount: witnessed executed-pass rows on the profile's floor. At major
|
|
655
|
+
// 2 the verdict already counted them against the declaration's floor
|
|
656
|
+
// (`witnessedPasses`); the v1 hand table below knows no v2 file and printed
|
|
657
|
+
// 0 for every v2 profile until rc.45 — the third unjoined floor site.
|
|
658
|
+
const verdictFor = (profile: string) => derived.verdicts.find((v) => v.profile === profile);
|
|
670
659
|
const witnessCountFor = (profile: string): number => {
|
|
660
|
+
if (target.major === 2) return verdictFor(profile)?.witnessedPasses ?? 0;
|
|
671
661
|
const floor = PROFILE_FLOOR_SCENARIOS[profile];
|
|
672
662
|
if (!floor) return 0;
|
|
673
663
|
const onFloor = (scenario: string): boolean => floor.required.includes(scenario) || (floor.requiredAnyPrefix ?? []).some((pre) => scenario.startsWith(pre));
|
|
674
664
|
return derived.requirements.filter((r) => r.disposition === 'executed-pass' && onFloor(r.scenarioId)).length;
|
|
675
665
|
};
|
|
676
|
-
|
|
666
|
+
// `certified` IS the verdict (RFC 0148 §A; RFC 0168 §E.1 adds the bundle-wide
|
|
667
|
+
// blocked rule). Until rc.45 it was `!notHeld && !rejected && blocked === 0`
|
|
668
|
+
// and never read `certifiable` — an empty v2 floor certified on no evidence.
|
|
669
|
+
const claimed3 = claimedProfiles.filter((p) => !(p in DEPRECATED_PROFILE_ALIASES)).map((p) => ({ id: p, evidenceTier: args.evidenceTier, witnessCount: witnessCountFor(p), certified: (verdictFor(p)?.certifiable ?? false) && !notHeld.has(p) && !rejectedProfiles.some((v) => v.profile === p) && totals3.blocked === 0 }));
|
|
677
670
|
let relaxations: BundleV3['host']['relaxations'];
|
|
678
671
|
if (process.env['OPENWOP_HOST_RELAXATIONS']) { try { relaxations = JSON.parse(process.env['OPENWOP_HOST_RELAXATIONS']) as BundleV3['host']['relaxations']; } catch { process.stderr.write('openwop-conformance --certify: OPENWOP_HOST_RELAXATIONS is not JSON\n'); process.exit(2); } }
|
|
679
672
|
const lockPath = resolvePath(conformanceRoot, 'dist', 'spec-artifacts.lock.json');
|
package/src/global-setup.ts
CHANGED
|
@@ -75,6 +75,17 @@ export function setup(): void {
|
|
|
75
75
|
// Suite 2.0.0: in the published layout the contract is the spec-artifacts peer (RFC 0168 §D.2).
|
|
76
76
|
const stamp = LAYOUT === 'published' ? verifyPeerContract(PKG_ROOT_PATH) : verifyCorpusStamp(PKG_ROOT_PATH, LAYOUT);
|
|
77
77
|
process.stderr.write(`${describeVerdict(stamp)}\n`);
|
|
78
|
+
// A version skew and a digest mismatch both have to refuse, but they are
|
|
79
|
+
// different faults with different fixes, and reporting them in the same words
|
|
80
|
+
// sends the reader to debug a corrupt install when nothing is corrupt.
|
|
81
|
+
if (stamp.kind === 'peer-version') {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`openwop-conformance: refusing to run — this suite was packed against @openwop/spec-artifacts@${stamp.lockVersion}, ` +
|
|
84
|
+
`but @openwop/spec-artifacts@${stamp.peerVersion} is installed. They are declared EXACT peers. ` +
|
|
85
|
+
`Install both at the same explicit version; do NOT install at a dist-tag such as \`next\`, which moves per package ` +
|
|
86
|
+
`and can name a pair that was never published together.`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
78
89
|
if (stamp.kind === 'mismatch') {
|
|
79
90
|
throw new Error('openwop-conformance: refusing to run — schemas/CORPUS-STAMP.json digests do not match the vendored api/ + schemas/ files. Reinstall the package; do not hand-patch vendored contract files.');
|
|
80
91
|
}
|
package/src/lib/corpus-stamp.ts
CHANGED
|
@@ -39,7 +39,17 @@ export interface CorpusStamp {
|
|
|
39
39
|
export type StampVerdict =
|
|
40
40
|
| { readonly kind: 'verified'; readonly files: number }
|
|
41
41
|
| { readonly kind: 'not-applicable'; readonly reason: string }
|
|
42
|
-
| { readonly kind: 'mismatch'; readonly missing: readonly string[]; readonly altered: readonly string[]; readonly extra: readonly string[] }
|
|
42
|
+
| { readonly kind: 'mismatch'; readonly missing: readonly string[]; readonly altered: readonly string[]; readonly extra: readonly string[] }
|
|
43
|
+
/**
|
|
44
|
+
* The peer is INSTALLED and INTACT but is a different version than the suite
|
|
45
|
+
* was packed against. Its own kind because the remedy is completely different
|
|
46
|
+
* from a digest mismatch — nothing is corrupt, two versions are simply out of
|
|
47
|
+
* step — and because the generic message sends readers to debug a broken
|
|
48
|
+
* install. Reported by a tier-2 host that hit it through the `next` dist-tag:
|
|
49
|
+
* the tag moves per package, so `@next` can name an exact-peer PAIR that was
|
|
50
|
+
* never published together.
|
|
51
|
+
*/
|
|
52
|
+
| { readonly kind: 'peer-version'; readonly peerVersion: string; readonly lockVersion: string };
|
|
43
53
|
|
|
44
54
|
export const STAMP_RELATIVE_PATH = join('schemas', 'CORPUS-STAMP.json');
|
|
45
55
|
|
|
@@ -94,7 +104,11 @@ export function verifyPeerContract(pkgRoot: string): StampVerdict {
|
|
|
94
104
|
if (!existsSync(stampPath)) return { kind: 'mismatch', missing: ['@openwop/spec-artifacts/CORPUS-STAMP.json'], altered: [], extra: [] };
|
|
95
105
|
const stamp = JSON.parse(readFileSync(stampPath, 'utf8')) as { package: string; version: string; files: Record<string, string> };
|
|
96
106
|
const digest = createHash('sha256').update(JSON.stringify({ package: stamp.package, version: stamp.version, files: stamp.files })).digest('hex');
|
|
97
|
-
|
|
107
|
+
// A plain version difference is NOT corruption; report it as itself so the
|
|
108
|
+
// message names the two versions and the fix, instead of sending the reader
|
|
109
|
+
// to hunt a damaged install.
|
|
110
|
+
if (stamp.version !== lock.version) return { kind: 'peer-version', peerVersion: stamp.version, lockVersion: lock.version };
|
|
111
|
+
if (digest !== lock.stampSha256) return { kind: 'mismatch', missing: [], altered: [`@openwop/spec-artifacts ${stamp.version} stamp digest ${digest.slice(0, 12)} ≠ the suite's lock ${lock.stampSha256.slice(0, 12)} — same version, different contents`], extra: [] };
|
|
98
112
|
const missing: string[] = []; const altered: string[] = [];
|
|
99
113
|
for (const [rel, d] of Object.entries(stamp.files)) { const p = join(peerRoot, ...rel.split('/')); if (!existsSync(p)) missing.push(rel); else if (sha256File(p) !== d) altered.push(rel); }
|
|
100
114
|
if (missing.length || altered.length) return { kind: 'mismatch', missing, altered, extra: [] };
|
|
@@ -143,6 +157,14 @@ export function describeVerdict(v: StampVerdict): string {
|
|
|
143
157
|
return `[openwop-conformance] corpus stamp VERIFIED — ${v.files} vendored api/ + schemas/ files match their SHA-256 digests`;
|
|
144
158
|
case 'not-applicable':
|
|
145
159
|
return `[openwop-conformance] corpus stamp not checked — ${v.reason}`;
|
|
160
|
+
case 'peer-version':
|
|
161
|
+
return (
|
|
162
|
+
`[openwop-conformance] peer version MISMATCH — this suite was packed against ` +
|
|
163
|
+
`@openwop/spec-artifacts@${v.lockVersion} but @openwop/spec-artifacts@${v.peerVersion} is installed. ` +
|
|
164
|
+
`Nothing is corrupt: the two are declared EXACT peers and are simply out of step. ` +
|
|
165
|
+
`Install both at the same explicit version — never at a dist-tag such as \`next\`, which moves per package ` +
|
|
166
|
+
`and can therefore name a pair that was never published together.`
|
|
167
|
+
);
|
|
146
168
|
case 'mismatch':
|
|
147
169
|
return (
|
|
148
170
|
`[openwop-conformance] corpus stamp MISMATCH — the vendored contract is not the one this suite shipped ` +
|
package/src/lib/era2-seed.ts
CHANGED
|
@@ -69,7 +69,18 @@ async function http(fn: () => Promise<OpenWOPResponse>): Promise<OpenWOPResponse
|
|
|
69
69
|
export function era2Gate(doc: Record<string, unknown> | null): Seeded | null {
|
|
70
70
|
if (!doc) return { ok: false, kind: 'blocked', reason: 'discovery unreachable' };
|
|
71
71
|
if (!seamsProfileAdvertised(doc)) {
|
|
72
|
-
|
|
72
|
+
// rc.63: `inapplicable`, not `blocked` — the host never claimed the
|
|
73
|
+
// instrument, so the obligation is out of scope for it (`lib/seams.ts`).
|
|
74
|
+
// rc.62 fixed the fifteen scenarios that call `seamsProfileAdvertised`
|
|
75
|
+
// directly and MISSED this one, which mints the same disposition one call
|
|
76
|
+
// deeper for six scenarios that import only `era2Gate`: era-2-append-
|
|
77
|
+
// vocabulary, fork-a-v1-run, pinned-run-disposition, stream-sse-projection,
|
|
78
|
+
// unmapped-type-refused, v1-events-translated. On MyndHyve's bundle that
|
|
79
|
+
// left 16 rows blocked on advert-absence after rc.62 — the same defect
|
|
80
|
+
// wearing a different import. `blocked` above (discovery unreachable) and
|
|
81
|
+
// below (the seam does not answer) is untouched: those are real failed
|
|
82
|
+
// measurements.
|
|
83
|
+
return { ok: false, kind: 'inapplicable', reason: `seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — an era-2 log can only be seeded through ${SEED_PATH}` };
|
|
73
84
|
}
|
|
74
85
|
return null;
|
|
75
86
|
}
|
package/src/lib/fixtures.ts
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
* @see RFCS/0003-fixture-gating.md
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
|
+
import { softSkip } from './soft-skip.js';
|
|
44
45
|
import type { DiscoveryPayload } from './profiles.js';
|
|
45
46
|
|
|
46
47
|
let _advertisedFixtures: ReadonlySet<string> | null = null;
|
|
@@ -76,7 +77,29 @@ function loadOptedOutPredicate(): (id: string) => boolean {
|
|
|
76
77
|
* filtered out of the cache before storage so downstream lookups can
|
|
77
78
|
* stay a single sync set-membership test.
|
|
78
79
|
*/
|
|
80
|
+
let _discoveryUnreadable: string | null = null;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Suite init could not READ the discovery document. This is not "the host
|
|
84
|
+
* advertises no fixtures" and MUST NOT be recorded as such: with 311
|
|
85
|
+
* fixture-gated sites, an empty cache turns an entire lane into `inapplicable`
|
|
86
|
+
* rows that read exactly like a host that advertises nothing. Measured
|
|
87
|
+
* 2026-09-05: all four workers hit the 5 s init abort against a host that
|
|
88
|
+
* answers `/.well-known/openwop` in 120–200 ms (a Cloud Run cold start), and
|
|
89
|
+
* every fixture-gated scenario skipped as "not advertised". The cache stays
|
|
90
|
+
* null; every gate that consults it records `blocked` with this reason.
|
|
91
|
+
*/
|
|
92
|
+
export function setDiscoveryUnreadable(reason: string): void {
|
|
93
|
+
_advertisedFixtures = null;
|
|
94
|
+
_discoveryUnreadable = reason;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function discoveryUnreadableReason(): string | null {
|
|
98
|
+
return _discoveryUnreadable;
|
|
99
|
+
}
|
|
100
|
+
|
|
79
101
|
export function setAdvertisedFixtures(c: DiscoveryPayload | null | undefined): void {
|
|
102
|
+
_discoveryUnreadable = null;
|
|
80
103
|
if (c == null || !Array.isArray(c.fixtures)) {
|
|
81
104
|
_advertisedFixtures = new Set();
|
|
82
105
|
return;
|
|
@@ -103,6 +126,13 @@ export function setAdvertisedFixtures(c: DiscoveryPayload | null | undefined): v
|
|
|
103
126
|
* );
|
|
104
127
|
*/
|
|
105
128
|
export function isFixtureAdvertised(id: string): boolean {
|
|
129
|
+
if (_advertisedFixtures === null && _discoveryUnreadable !== null) {
|
|
130
|
+
// Evidence went unread, on the suite's side. `blocked` outranks the
|
|
131
|
+
// `inapplicable` the caller is about to record (soft-skip.ts RANK), so the
|
|
132
|
+
// file resolves to the honest word instead of the vacuous one.
|
|
133
|
+
softSkip('blocked', `suite init could not read /.well-known/openwop (${_discoveryUnreadable}) — fixture ${id} is UNKNOWN, not unadvertised`);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
106
136
|
return _advertisedFixtures?.has(id) ?? false;
|
|
107
137
|
}
|
|
108
138
|
|
|
@@ -127,4 +157,5 @@ export function isFixtureCacheReady(): boolean {
|
|
|
127
157
|
/** Test-only: reset the module-level cache. */
|
|
128
158
|
export function __resetForTests(): void {
|
|
129
159
|
_advertisedFixtures = null;
|
|
160
|
+
_discoveryUnreadable = null;
|
|
130
161
|
}
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { PROFILE_FLOOR_SCENARIOS } from './profiles.js';
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
26
|
+
import { dirname, resolve as resolvePath } from 'node:path';
|
|
27
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
25
28
|
|
|
26
29
|
/** `runs-lifecycle.test.ts` → `openwop.floor.runs-lifecycle`. */
|
|
27
30
|
export function requirementIdForScenario(scenarioFile: string): string {
|
|
@@ -94,6 +97,17 @@ export function setV2ProfileFloors(floors: Readonly<Record<string, readonly stri
|
|
|
94
97
|
v2Floors = floors;
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
/**
|
|
101
|
+
* True while a major-2 floor map is installed. The v1 hand table
|
|
102
|
+
* (`PROFILE_FLOOR_SCENARIOS`) MUST NOT be consulted for any per-profile fact
|
|
103
|
+
* (`discoveryOnly`, `runtimeDerived`, the floor itself, the witness count) while
|
|
104
|
+
* this is true — every one of those reads is a floor site, and rc.41 found two
|
|
105
|
+
* of four unjoined; rc.45 found the other two.
|
|
106
|
+
*/
|
|
107
|
+
export function v2FloorsActive(): boolean {
|
|
108
|
+
return v2Floors !== null;
|
|
109
|
+
}
|
|
110
|
+
|
|
97
111
|
export function requirementsFor(profile: string, document?: Readonly<Record<string, unknown>>): readonly string[] | null {
|
|
98
112
|
if (v2Floors !== null) {
|
|
99
113
|
const files = v2Floors[profile];
|
|
@@ -124,3 +138,57 @@ export function allRequirements(): readonly string[] {
|
|
|
124
138
|
}
|
|
125
139
|
return [...ids].sort();
|
|
126
140
|
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The MAJOR-2 floors, derived from `spec/v2/profiles.json` (itself generated
|
|
144
|
+
* from `spec/v2/declaration.json`), keyed by profile id and resolved to
|
|
145
|
+
* scenario file names. A `planned:<stem>` entry names `v2-<stem>.test.ts`; an
|
|
146
|
+
* entry is kept only if `scenario-majors.json` knows the file.
|
|
147
|
+
*
|
|
148
|
+
* This function exists in ONE place on purpose. Until 2026-09-05 the CLI
|
|
149
|
+
* derived these floors privately for `--certify` while the ledger decided
|
|
150
|
+
* "is this file a floor?" from PROFILE_FLOOR_SCENARIOS — the v1 hand table,
|
|
151
|
+
* which knows no v2 file. So a v2 floor file was MINTED as
|
|
152
|
+
* `openwop.scenario.v2-…` and LOOKED UP at certify time as
|
|
153
|
+
* `openwop.floor.v2-…`: 101 executed-pass rows, `witnessCount: 0` on both
|
|
154
|
+
* claimed profiles, and `REJECTING — openwop-discovery-core: unclassified` on
|
|
155
|
+
* a tier-1 host's first production bundle. Two sources of the same fact, one
|
|
156
|
+
* of them stale, and the join between them silent.
|
|
157
|
+
*/
|
|
158
|
+
export function v2ProfileFloorFiles(conformanceRoot: string): Record<string, readonly string[]> {
|
|
159
|
+
const candidates: string[] = [];
|
|
160
|
+
try {
|
|
161
|
+
const req = createRequire(resolvePath(conformanceRoot, 'package.json'));
|
|
162
|
+
candidates.push(resolvePath(dirname(req.resolve('@openwop/spec-artifacts/package.json')), 'spec', 'v2', 'profiles.json'));
|
|
163
|
+
} catch { /* not installed as a package; the repo-layout candidates below */ }
|
|
164
|
+
candidates.push(
|
|
165
|
+
resolvePath(conformanceRoot, 'spec', 'v2', 'profiles.json'),
|
|
166
|
+
resolvePath(conformanceRoot, '..', 'spec', 'v2', 'profiles.json'),
|
|
167
|
+
);
|
|
168
|
+
const registryPath = candidates.find((c) => existsSync(c));
|
|
169
|
+
if (registryPath === undefined) return {};
|
|
170
|
+
let known: Set<string>;
|
|
171
|
+
try {
|
|
172
|
+
known = new Set(Object.keys((JSON.parse(readFileSync(resolvePath(conformanceRoot, 'scenario-majors.json'), 'utf8')) as { majors: Record<string, number[]> }).majors));
|
|
173
|
+
} catch {
|
|
174
|
+
known = new Set();
|
|
175
|
+
}
|
|
176
|
+
let registry: { profiles?: Array<{ id?: unknown; floorScenarios?: unknown }> };
|
|
177
|
+
try {
|
|
178
|
+
registry = JSON.parse(readFileSync(registryPath, 'utf8'));
|
|
179
|
+
} catch {
|
|
180
|
+
return {};
|
|
181
|
+
}
|
|
182
|
+
const out: Record<string, readonly string[]> = {};
|
|
183
|
+
for (const p of registry.profiles ?? []) {
|
|
184
|
+
if (typeof p.id !== 'string') continue;
|
|
185
|
+
const raw = Array.isArray(p.floorScenarios) ? (p.floorScenarios as unknown[]).map(String) : [];
|
|
186
|
+
const files: string[] = [];
|
|
187
|
+
for (const entry of raw) {
|
|
188
|
+
const name = entry.startsWith('planned:') ? `v2-${entry.slice('planned:'.length)}.test.ts` : entry.endsWith('.test.ts') ? entry : `${entry}.test.ts`;
|
|
189
|
+
if (known.size === 0 || known.has(name)) files.push(name);
|
|
190
|
+
}
|
|
191
|
+
out[p.id] = files;
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|