@openwop/openwop-conformance 2.0.0-rc.6 → 2.0.0-rc.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +8 -3
  2. package/dist/cli.js +24 -34
  3. package/dist/lib/requirement-registry.js +69 -0
  4. package/dist/lib/scenario-disposition.js +84 -11
  5. package/dist/lib/seams.js +42 -0
  6. package/dist/lib/soft-skip.js +39 -8
  7. package/dist/spec-artifacts.lock.json +2 -2
  8. package/package.json +2 -2
  9. package/requirement-aliases.json +4 -1
  10. package/requirements.json +1124 -51
  11. package/scenario-majors.json +60 -3
  12. package/schemas/CORPUS-STAMP.json +39 -36
  13. package/src/cli.ts +23 -30
  14. package/src/global-setup.ts +11 -0
  15. package/src/lib/corpus-stamp.ts +24 -2
  16. package/src/lib/fixtures.ts +31 -0
  17. package/src/lib/requirement-registry.ts +68 -0
  18. package/src/lib/scenario-disposition.ts +88 -9
  19. package/src/lib/soft-skip.ts +42 -7
  20. package/src/lib/sse.ts +8 -0
  21. package/src/scenarios/era-key-stamped-v1.test.ts +156 -0
  22. package/src/scenarios/pause-resume.test.ts +159 -75
  23. package/src/scenarios/v2-advertised-fixtures-exist.test.ts +25 -43
  24. package/src/scenarios/v2-advertised-path-space-served.test.ts +165 -0
  25. package/src/scenarios/v2-coherence-not-in-bundle.test.ts +11 -2
  26. package/src/scenarios/v2-created-run-readable.test.ts +98 -0
  27. package/src/scenarios/v2-dual-stack-negotiation.test.ts +29 -1
  28. package/src/scenarios/v2-effect-seam-manifest.test.ts +9 -53
  29. package/src/scenarios/v2-effect-seam-no-refire.test.ts +88 -0
  30. package/src/scenarios/v2-era-2-append-vocabulary.test.ts +16 -2
  31. package/src/scenarios/v2-era-stamp-universal.test.ts +1 -1
  32. package/src/scenarios/v2-interrupt-token-scheme.test.ts +1 -1
  33. package/src/scenarios/v2-malformed-body-envelope.test.ts +79 -0
  34. package/src/scenarios/v2-run-annotation-not-event.test.ts +71 -0
  35. package/src/scenarios/v2-run-bulk-cancel.test.ts +91 -0
  36. package/src/scenarios/v2-run-cancel.test.ts +97 -0
  37. package/src/scenarios/v2-run-completed-outputs.test.ts +93 -0
  38. package/src/scenarios/v2-run-diff-identical.test.ts +75 -0
  39. package/src/scenarios/v2-run-fork-prefix.test.ts +140 -0
  40. package/src/scenarios/v2-run-fork-refusals.test.ts +70 -0
  41. package/src/scenarios/v2-run-options-limits.test.ts +69 -0
  42. package/src/scenarios/v2-run-pause-resume.test.ts +117 -0
  43. package/src/scenarios/v2-run-snapshot-etag.test.ts +57 -0
  44. package/src/scenarios/v2-sse-last-event-id.test.ts +93 -0
  45. package/src/scenarios/v2-stream-mode-refusal.test.ts +118 -0
  46. package/src/scenarios/v2-stream-sse-projection.test.ts +79 -0
  47. package/src/scenarios/v2-version-header-honored.test.ts +124 -0
  48. package/src/scenarios/version-negotiation.test.ts +25 -3
  49. package/src/setup.ts +104 -50
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": 542,
6
- "tests": 2113,
7
- "withStableId": 2113,
8
- "interpolatedTitles": 0,
9
- "explicitIds": 2057
5
+ "files": 565,
6
+ "tests": 2150,
7
+ "withStableId": 2149,
8
+ "interpolatedTitles": 1,
9
+ "explicitIds": 2058
10
10
  },
11
11
  "records": [
12
12
  {
@@ -12262,6 +12262,58 @@
12262
12262
  }
12263
12263
  ]
12264
12264
  },
12265
+ {
12266
+ "id": "openwop.it.era-key-stamped-v1.a-run-the-host-just-created-carries-eventlogschemaversion",
12267
+ "file": "era-key-stamped-v1.test.ts",
12268
+ "line": 75,
12269
+ "title": "a run the host just created carries eventLogSchemaVersion",
12270
+ "explicitId": null,
12271
+ "citations": [
12272
+ {
12273
+ "section": null,
12274
+ "requirement": "every persisted run document MUST carry an eventLogSchemaVersion — the field is prose-only (run-snapshot.schema.json requires just runId, workflowId and status), so a snapshot without it validates cleanly and only this check can see its absence",
12275
+ "interpolated": true
12276
+ },
12277
+ {
12278
+ "section": null,
12279
+ "requirement": null,
12280
+ "interpolated": true
12281
+ }
12282
+ ]
12283
+ },
12284
+ {
12285
+ "id": "openwop.it.era-key-stamped-v1.a-freshly-created-run-is-not-classified-legacy-by-the-host-s-own-rule",
12286
+ "file": "era-key-stamped-v1.test.ts",
12287
+ "line": 98,
12288
+ "title": "a freshly created run is not classified legacy by the host's own rule",
12289
+ "explicitId": null,
12290
+ "citations": [
12291
+ {
12292
+ "section": "spec/v1/version-negotiation.md §Legacy detection",
12293
+ "requirement": null,
12294
+ "interpolated": true
12295
+ }
12296
+ ]
12297
+ },
12298
+ {
12299
+ "id": "openwop.it.era-key-stamped-v1.a-run-the-host-just-created-carries-engineversion-the-legacy-escape-cannot-reach",
12300
+ "file": "era-key-stamped-v1.test.ts",
12301
+ "line": 124,
12302
+ "title": "a run the host just created carries engineVersion — the legacy escape cannot reach it",
12303
+ "explicitId": null,
12304
+ "citations": [
12305
+ {
12306
+ "section": null,
12307
+ "requirement": "every persisted run document MUST carry engineVersion; the \"MAY omit\" escape applies only to legacy runs that predate the contract, and this run was created moments ago",
12308
+ "interpolated": true
12309
+ },
12310
+ {
12311
+ "section": null,
12312
+ "requirement": null,
12313
+ "interpolated": true
12314
+ }
12315
+ ]
12316
+ },
12265
12317
  {
12266
12318
  "id": "openwop.it.errors.get-v1-runs-nonexistentid-returns-canonical-envelope",
12267
12319
  "file": "errors.test.ts",
@@ -18675,80 +18727,131 @@
18675
18727
  {
18676
18728
  "id": "openwop.it.pause-resume.pause-transitions-to-paused-resume-returns-the-run-to-running",
18677
18729
  "file": "pause-resume.test.ts",
18678
- "line": 36,
18730
+ "line": 62,
18679
18731
  "title": "pause transitions to paused; resume returns the run to running",
18680
18732
  "explicitId": "openwop.it.pause-resume.pause-transitions-to-paused-resume-returns-the-run-to-running",
18681
18733
  "citations": [
18682
18734
  {
18683
- "section": "rest-endpoints.md POST /v1/runs/{runId}:pause",
18684
- "requirement": ":pause MUST return 202 on a pausable run"
18735
+ "section": null,
18736
+ "requirement": ":pause MUST return 202 on a pausable run",
18737
+ "interpolated": true
18685
18738
  },
18686
18739
  {
18687
- "section": "rest-endpoints.md POST /v1/runs/{runId}:resume",
18688
- "requirement": ":resume MUST return 202 on a paused run"
18740
+ "section": null,
18741
+ "requirement": ":resume MUST return 202 on a paused run",
18742
+ "interpolated": true
18689
18743
  }
18690
18744
  ]
18691
18745
  },
18692
18746
  {
18693
18747
  "id": "openwop.it.pause-resume.resuming-a-running-not-paused-run-returns-409-with-details-runstatus",
18694
18748
  "file": "pause-resume.test.ts",
18695
- "line": 82,
18749
+ "line": 110,
18696
18750
  "title": "resuming a running (not paused) run returns 409 with details.runStatus",
18697
18751
  "explicitId": "openwop.it.pause-resume.resuming-a-running-not-paused-run-returns-409-with-details-runstatus",
18698
18752
  "citations": [
18699
18753
  {
18700
- "section": "rest-endpoints.md POST /v1/runs/{runId}:resume",
18701
- "requirement": ":resume on a non-paused run MUST return 409"
18754
+ "section": null,
18755
+ "requirement": ":resume on a non-paused run MUST return 409",
18756
+ "interpolated": true
18757
+ },
18758
+ {
18759
+ "section": null,
18760
+ "requirement": "the 409 MUST carry details.runStatus with the actual state",
18761
+ "interpolated": true
18702
18762
  }
18703
18763
  ]
18704
18764
  },
18705
18765
  {
18706
- "id": "openwop.it.pause-resume.pause-on-an-already-paused-run-is-a-no-op-200-202-idempotent",
18766
+ "id": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless",
18707
18767
  "file": "pause-resume.test.ts",
18708
- "line": 115,
18709
- "title": ":pause on an already-paused run is a no-op (200/202) — idempotent",
18710
- "explicitId": "openwop.it.pause-resume.pause-on-an-already-paused-run-is-a-no-op-200-202-idempotent",
18768
+ "line": 144,
18769
+ "title": ":pause on an already-paused run returns 409 with details.runStatus paused, unless the request carries the original Idempotency-Key",
18770
+ "explicitId": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless",
18711
18771
  "citations": [
18712
18772
  {
18713
- "section": "rest-endpoints.md POST /v1/runs/{runId}:pause",
18714
- "requirement": ":pause on an already-paused run MUST be idempotent (200/202), not 409"
18773
+ "section": null,
18774
+ "requirement": ":pause MUST return 202 on a pausable run",
18775
+ "interpolated": true
18776
+ },
18777
+ {
18778
+ "section": null,
18779
+ "requirement": ":pause on an already-paused run without a matching Idempotency-Key MUST return 409",
18780
+ "interpolated": true
18781
+ },
18782
+ {
18783
+ "section": null,
18784
+ "requirement": "the 409 MUST carry details.runStatus: paused",
18785
+ "interpolated": true
18786
+ },
18787
+ {
18788
+ "section": null,
18789
+ "requirement": ":pause with an Idempotency-Key MUST return 202 on a pausable run",
18790
+ "interpolated": true
18791
+ },
18792
+ {
18793
+ "section": null,
18794
+ "requirement": "a :pause carrying the original Idempotency-Key MUST return 202 with the cached response, not 409",
18795
+ "interpolated": true
18715
18796
  }
18716
18797
  ]
18717
18798
  },
18718
18799
  {
18719
18800
  "id": "openwop.it.pause-resume.pause-on-a-completed-cancelled-failed-run-must-return-409",
18720
18801
  "file": "pause-resume.test.ts",
18721
- "line": 153,
18802
+ "line": 205,
18722
18803
  "title": ":pause on a completed/cancelled/failed run MUST return 409",
18723
18804
  "explicitId": "openwop.it.pause-resume.pause-on-a-completed-cancelled-failed-run-must-return-409",
18724
18805
  "citations": [
18725
18806
  {
18726
- "section": "rest-endpoints.md POST /v1/runs/{runId}:pause",
18727
- "requirement": ":pause on a terminal run MUST return 409"
18807
+ "section": null,
18808
+ "requirement": ":pause on a terminal run MUST return 409",
18809
+ "interpolated": true
18810
+ }
18811
+ ]
18812
+ },
18813
+ {
18814
+ "id": "openwop.it.pause-resume.under-drain-current-node-node-completed-precedes-run-paused-in-the-log",
18815
+ "file": "pause-resume.test.ts",
18816
+ "line": 229,
18817
+ "title": "under drain-current-node node.completed precedes run.paused in the log",
18818
+ "explicitId": "openwop.it.pause-resume.under-drain-current-node-node-completed-precedes-run-paused-in-the-log",
18819
+ "citations": [
18820
+ {
18821
+ "section": null,
18822
+ "requirement": ":pause with drainPolicy drain-current-node MUST return 202 (pause requested)",
18823
+ "interpolated": true
18824
+ },
18825
+ {
18826
+ "section": null,
18827
+ "requirement": null,
18828
+ "interpolated": true
18728
18829
  }
18729
18830
  ]
18730
18831
  },
18731
18832
  {
18732
18833
  "id": "openwop.it.pause-resume.pause-must-not-silently-override-an-active-interrupt-suspend",
18733
18834
  "file": "pause-resume.test.ts",
18734
- "line": 177,
18835
+ "line": 268,
18735
18836
  "title": ":pause MUST NOT silently override an active interrupt suspend",
18736
18837
  "explicitId": "openwop.it.pause-resume.pause-must-not-silently-override-an-active-interrupt-suspend",
18737
18838
  "citations": [
18738
18839
  {
18739
- "section": "rest-endpoints.md POST /v1/runs/{runId}:pause",
18740
- "requirement": ":pause-during-suspend MUST surface the active waiting-* status in the conflict envelope"
18840
+ "section": null,
18841
+ "requirement": ":pause-during-suspend MUST surface the active waiting-* status in the conflict envelope",
18842
+ "interpolated": true
18741
18843
  },
18742
18844
  {
18743
- "section": "rest-endpoints.md POST /v1/runs/{runId}:pause",
18744
- "requirement": ":pause-during-suspend MUST NOT silently discard the active interrupt"
18845
+ "section": null,
18846
+ "requirement": ":pause-during-suspend MUST NOT silently discard the active interrupt",
18847
+ "interpolated": true
18745
18848
  }
18746
18849
  ]
18747
18850
  },
18748
18851
  {
18749
18852
  "id": "openwop.it.pause-resume.every-drainpolicy-advertised-by-the-host-is-accepted-on-pause",
18750
18853
  "file": "pause-resume.test.ts",
18751
- "line": 238,
18854
+ "line": 324,
18752
18855
  "title": "every drainPolicy advertised by the host is accepted on :pause",
18753
18856
  "explicitId": "openwop.it.pause-resume.every-drainpolicy-advertised-by-the-host-is-accepted-on-pause",
18754
18857
  "citations": [
@@ -25742,10 +25845,10 @@
25742
25845
  ]
25743
25846
  },
25744
25847
  {
25745
- "id": "openwop.it.v2-advertised-fixtures-exist.every-advertised-fixture-id-is-one-the-corpus-defines",
25848
+ "id": "openwop.it.v2-advertised-fixtures-exist.a-sampled-advertised-fixture-is-actually-creatable-not-just-listed",
25746
25849
  "file": "v2-advertised-fixtures-exist.test.ts",
25747
- "line": 60,
25748
- "title": "every advertised fixture id is one the corpus defines",
25850
+ "line": 62,
25851
+ "title": "a sampled advertised fixture is actually creatable, not just listed",
25749
25852
  "explicitId": null,
25750
25853
  "citations": [
25751
25854
  {
@@ -25756,16 +25859,21 @@
25756
25859
  ]
25757
25860
  },
25758
25861
  {
25759
- "id": "openwop.it.v2-advertised-fixtures-exist.a-sampled-advertised-fixture-is-actually-creatable-not-just-listed",
25760
- "file": "v2-advertised-fixtures-exist.test.ts",
25761
- "line": 80,
25762
- "title": "a sampled advertised fixture is actually creatable, not just listed",
25862
+ "id": "openwop.it.v2-advertised-path-space-served.a-host-advertising-major-2-reaches-the-surfaces-it-already-serves-under-v1",
25863
+ "file": "v2-advertised-path-space-served.test.ts",
25864
+ "line": 107,
25865
+ "title": "a host advertising major 2 reaches the surfaces it already serves under /v1",
25763
25866
  "explicitId": null,
25764
25867
  "citations": [
25765
25868
  {
25766
25869
  "section": null,
25767
25870
  "requirement": null,
25768
25871
  "interpolated": true
25872
+ },
25873
+ {
25874
+ "section": null,
25875
+ "requirement": "at least one non-well-known surface MUST be reachable under major 2, or the advertisement rests entirely on the one resource the header selects",
25876
+ "interpolated": true
25769
25877
  }
25770
25878
  ]
25771
25879
  },
@@ -26120,7 +26228,7 @@
26120
26228
  {
26121
26229
  "id": "openwop.it.v2-coherence-not-in-bundle.the-bundle-schema-rejects-a-v3-bundle-carrying-a-corpus-coherence-id-and-accepts",
26122
26230
  "file": "v2-coherence-not-in-bundle.test.ts",
26123
- "line": 89,
26231
+ "line": 98,
26124
26232
  "title": "the bundle schema rejects a v3 bundle carrying a corpus-coherence id and accepts one under openwop.requirement.",
26125
26233
  "explicitId": "openwop.requirement.0168.coherence-not-in-bundle.schema-forbids-coherence-ids",
26126
26234
  "citations": [
@@ -26254,6 +26362,40 @@
26254
26362
  }
26255
26363
  ]
26256
26364
  },
26365
+ {
26366
+ "id": "openwop.it.v2-created-run-readable.a-run-created-at-this-base-is-readable-and-pollable-at-this-base-by-the-id-it-re",
26367
+ "file": "v2-created-run-readable.test.ts",
26368
+ "line": 63,
26369
+ "title": "a run created at this base is readable and pollable at this base by the id it returned, and its links stay on this base",
26370
+ "explicitId": null,
26371
+ "citations": [
26372
+ {
26373
+ "section": "spec/v2/core/identity.md §5",
26374
+ "requirement": null,
26375
+ "interpolated": true
26376
+ },
26377
+ {
26378
+ "section": null,
26379
+ "requirement": null,
26380
+ "interpolated": true
26381
+ },
26382
+ {
26383
+ "section": "spec/v2/core/events.md §Poll",
26384
+ "requirement": null,
26385
+ "interpolated": true
26386
+ },
26387
+ {
26388
+ "section": null,
26389
+ "requirement": null,
26390
+ "interpolated": true
26391
+ },
26392
+ {
26393
+ "section": null,
26394
+ "requirement": null,
26395
+ "interpolated": true
26396
+ }
26397
+ ]
26398
+ },
26257
26399
  {
26258
26400
  "id": "openwop.it.v2-dual-stack-negotiation.a-run-created-through-v1-runs-with-no-header-is-readable-through-runs-under-open",
26259
26401
  "file": "v2-dual-stack-negotiation.test.ts",
@@ -26271,7 +26413,8 @@
26271
26413
  },
26272
26414
  {
26273
26415
  "section": "spec/v2/core/versioning.md §5",
26274
- "requirement": "the v2 read MUST name the same run"
26416
+ "requirement": null,
26417
+ "interpolated": true
26275
26418
  },
26276
26419
  {
26277
26420
  "section": "spec/v2/core/versioning.md §1.4",
@@ -26282,7 +26425,7 @@
26282
26425
  {
26283
26426
  "id": "openwop.it.v2-dual-stack-negotiation.an-unlisted-major-is-406-protocol-version-unsupported-with-details-protocolversi",
26284
26427
  "file": "v2-dual-stack-negotiation.test.ts",
26285
- "line": 83,
26428
+ "line": 111,
26286
26429
  "title": "an unlisted major is 406 protocol_version_unsupported with details.protocolVersions[]",
26287
26430
  "explicitId": "openwop.requirement.0172.dual-stack-negotiation.unlisted-major",
26288
26431
  "citations": [
@@ -26306,7 +26449,7 @@
26306
26449
  {
26307
26450
  "id": "openwop.it.v2-dual-stack-negotiation.openwop-version-2-0-on-a-v1-path-is-400-protocol-version-mismatch",
26308
26451
  "file": "v2-dual-stack-negotiation.test.ts",
26309
- "line": 94,
26452
+ "line": 122,
26310
26453
  "title": "OpenWOP-Version: 2.0 on a /v1/ path is 400 protocol_version_mismatch",
26311
26454
  "explicitId": "openwop.requirement.0172.dual-stack-negotiation.v1-path-mismatch",
26312
26455
  "citations": [
@@ -26325,7 +26468,7 @@
26325
26468
  {
26326
26469
  "id": "openwop.it.v2-dual-stack-negotiation.every-response-reports-the-contract-that-produced-it",
26327
26470
  "file": "v2-dual-stack-negotiation.test.ts",
26328
- "line": 103,
26471
+ "line": 131,
26329
26472
  "title": "every response reports the contract that produced it",
26330
26473
  "explicitId": "openwop.requirement.0172.dual-stack-negotiation.response-header",
26331
26474
  "citations": [
@@ -26410,7 +26553,7 @@
26410
26553
  {
26411
26554
  "id": "openwop.it.v2-effect-seam-manifest.get-host-effect-seams-validates-and-every-row-is-guarded",
26412
26555
  "file": "v2-effect-seam-manifest.test.ts",
26413
- "line": 51,
26556
+ "line": 53,
26414
26557
  "title": "GET /host/effect-seams validates and every row is guarded",
26415
26558
  "explicitId": "openwop.requirement.0173.effect-seam-manifest",
26416
26559
  "citations": [
@@ -26457,7 +26600,7 @@
26457
26600
  {
26458
26601
  "id": "openwop.it.v2-effect-seam-manifest.the-replay-facet-names-the-manifest-address-as-the-constant-host-effect-seams",
26459
26602
  "file": "v2-effect-seam-manifest.test.ts",
26460
- "line": 106,
26603
+ "line": 108,
26461
26604
  "title": "the replay facet names the manifest address as the constant /host/effect-seams",
26462
26605
  "explicitId": "openwop.requirement.0173.effect-seam-manifest.facet",
26463
26606
  "citations": [
@@ -26468,11 +26611,11 @@
26468
26611
  ]
26469
26612
  },
26470
26613
  {
26471
- "id": "openwop.it.v2-effect-seam-manifest.driving-one-seam-of-each-kind-observes-no-re-fire-on-replay",
26472
- "file": "v2-effect-seam-manifest.test.ts",
26473
- "line": 117,
26614
+ "id": "openwop.it.v2-effect-seam-no-refire.driving-one-seam-of-each-kind-observes-no-re-fire-on-replay",
26615
+ "file": "v2-effect-seam-no-refire.test.ts",
26616
+ "line": 42,
26474
26617
  "title": "driving one seam of each kind observes no re-fire on replay",
26475
- "explicitId": "openwop.requirement.0173.effect-seam-manifest.no-re-fire",
26618
+ "explicitId": "openwop.requirement.0173.effect-seam-no-refire",
26476
26619
  "citations": [
26477
26620
  {
26478
26621
  "section": "spec/v2/core/replay.md §The effect-seam manifest",
@@ -26561,7 +26704,7 @@
26561
26704
  {
26562
26705
  "id": "openwop.it.v2-era-2-append-vocabulary.the-run-keeps-the-era-it-was-created-with-an-append-does-not-promote-it-to-era-3",
26563
26706
  "file": "v2-era-2-append-vocabulary.test.ts",
26564
- "line": 119,
26707
+ "line": 133,
26565
26708
  "title": "the run keeps the era it was created with; an append does not promote it to era 3",
26566
26709
  "explicitId": null,
26567
26710
  "citations": [
@@ -27070,6 +27213,39 @@
27070
27213
  }
27071
27214
  ]
27072
27215
  },
27216
+ {
27217
+ "id": null,
27218
+ "file": "v2-malformed-body-envelope.test.ts",
27219
+ "line": 53,
27220
+ "title": null,
27221
+ "explicitId": null,
27222
+ "citations": [
27223
+ {
27224
+ "section": null,
27225
+ "requirement": null,
27226
+ "interpolated": true
27227
+ },
27228
+ {
27229
+ "section": "spec/v2/core/errors.md",
27230
+ "requirement": null,
27231
+ "interpolated": true
27232
+ },
27233
+ {
27234
+ "section": "spec/v2/core/errors.md",
27235
+ "requirement": null,
27236
+ "interpolated": true
27237
+ },
27238
+ {
27239
+ "section": "spec/v2/core/errors.md",
27240
+ "requirement": null,
27241
+ "interpolated": true
27242
+ },
27243
+ {
27244
+ "section": "spec/v2/core/errors.md",
27245
+ "requirement": "the envelope's `error` MUST be the registered code for a malformed request body, validation_error"
27246
+ }
27247
+ ]
27248
+ },
27073
27249
  {
27074
27250
  "id": "openwop.it.v2-manifest-ceiling-refused.an-engines-openwop-range-with-no-upper-bound-1-0-0-reads-2-0-0-and-is-refused-at",
27075
27251
  "file": "v2-manifest-ceiling-refused.test.ts",
@@ -27956,6 +28132,661 @@
27956
28132
  }
27957
28133
  ]
27958
28134
  },
28135
+ {
28136
+ "id": "openwop.it.v2-run-annotation-not-event.an-annotation-is-created-and-listed-and-never-enters-the-run-s-event-log",
28137
+ "file": "v2-run-annotation-not-event.test.ts",
28138
+ "line": 40,
28139
+ "title": "an annotation is created and listed, and never enters the run's event log",
28140
+ "explicitId": null,
28141
+ "citations": [
28142
+ {
28143
+ "section": null,
28144
+ "requirement": null,
28145
+ "interpolated": true
28146
+ },
28147
+ {
28148
+ "section": "schemas/v2/annotation.schema.json",
28149
+ "requirement": null,
28150
+ "interpolated": true
28151
+ },
28152
+ {
28153
+ "section": null,
28154
+ "requirement": null,
28155
+ "interpolated": true
28156
+ },
28157
+ {
28158
+ "section": null,
28159
+ "requirement": "listAnnotations MUST return the annotation just created (the control: a host that discards annotations must not pass the log assertion for free)",
28160
+ "interpolated": true
28161
+ },
28162
+ {
28163
+ "section": null,
28164
+ "requirement": "run.annotated is a live notification and MUST NOT enter the event log",
28165
+ "interpolated": true
28166
+ },
28167
+ {
28168
+ "section": null,
28169
+ "requirement": null,
28170
+ "interpolated": true
28171
+ }
28172
+ ]
28173
+ },
28174
+ {
28175
+ "id": "openwop.it.v2-run-bulk-cancel.101-ids-are-refused-400-validation-error-with-details-maxrunids",
28176
+ "file": "v2-run-bulk-cancel.test.ts",
28177
+ "line": 48,
28178
+ "title": "101 ids are refused 400 validation_error with details.maxRunIds",
28179
+ "explicitId": null,
28180
+ "citations": [
28181
+ {
28182
+ "section": null,
28183
+ "requirement": null,
28184
+ "interpolated": true
28185
+ },
28186
+ {
28187
+ "section": null,
28188
+ "requirement": "the refusal MUST be validation_error",
28189
+ "interpolated": true
28190
+ },
28191
+ {
28192
+ "section": null,
28193
+ "requirement": null,
28194
+ "interpolated": true
28195
+ }
28196
+ ]
28197
+ },
28198
+ {
28199
+ "id": "openwop.it.v2-run-bulk-cancel.results-come-back-in-request-order-each-id-processed-independently-a-foreign-id",
28200
+ "file": "v2-run-bulk-cancel.test.ts",
28201
+ "line": 63,
28202
+ "title": "results[] come back in request order, each id processed independently, a foreign id refused in its entry and never as a top-level 403",
28203
+ "explicitId": null,
28204
+ "citations": [
28205
+ {
28206
+ "section": null,
28207
+ "requirement": null,
28208
+ "interpolated": true
28209
+ },
28210
+ {
28211
+ "section": null,
28212
+ "requirement": null,
28213
+ "interpolated": true
28214
+ },
28215
+ {
28216
+ "section": null,
28217
+ "requirement": "results[] MUST be in request order",
28218
+ "interpolated": true
28219
+ },
28220
+ {
28221
+ "section": null,
28222
+ "requirement": "the foreign-tenant entry MUST be ok: false",
28223
+ "interpolated": true
28224
+ },
28225
+ {
28226
+ "section": "api/v2/openapi.yaml bulkCancelRuns results[].error",
28227
+ "requirement": null,
28228
+ "interpolated": true
28229
+ },
28230
+ {
28231
+ "section": "spec/v2/core/identity.md §5",
28232
+ "requirement": null,
28233
+ "interpolated": true
28234
+ },
28235
+ {
28236
+ "section": null,
28237
+ "requirement": null,
28238
+ "interpolated": true
28239
+ }
28240
+ ]
28241
+ },
28242
+ {
28243
+ "id": "openwop.it.v2-run-cancel.cancelling-a-terminal-run-is-refused-409-run-terminal",
28244
+ "file": "v2-run-cancel.test.ts",
28245
+ "line": 65,
28246
+ "title": "cancelling a terminal run is refused 409 run_terminal",
28247
+ "explicitId": null,
28248
+ "citations": [
28249
+ {
28250
+ "section": null,
28251
+ "requirement": null,
28252
+ "interpolated": true
28253
+ },
28254
+ {
28255
+ "section": null,
28256
+ "requirement": "the refusal MUST be run_terminal",
28257
+ "interpolated": true
28258
+ }
28259
+ ]
28260
+ },
28261
+ {
28262
+ "id": "openwop.it.v2-run-cancel.cancelling-a-running-run-answers-200-with-cancelling-cancelled-emits-run-cancell",
28263
+ "file": "v2-run-cancel.test.ts",
28264
+ "line": 79,
28265
+ "title": "cancelling a running run answers 200 with cancelling|cancelled, emits run.cancelled within 5 s, and the snapshot reads cancelled",
28266
+ "explicitId": null,
28267
+ "citations": [
28268
+ {
28269
+ "section": null,
28270
+ "requirement": null,
28271
+ "interpolated": true
28272
+ },
28273
+ {
28274
+ "section": null,
28275
+ "requirement": "the 200 body MUST carry the run's runId",
28276
+ "interpolated": true
28277
+ },
28278
+ {
28279
+ "section": null,
28280
+ "requirement": null,
28281
+ "interpolated": true
28282
+ },
28283
+ {
28284
+ "section": null,
28285
+ "requirement": null,
28286
+ "interpolated": true
28287
+ },
28288
+ {
28289
+ "section": "spec/v2/core/events.md §run.cancelled",
28290
+ "requirement": null,
28291
+ "interpolated": true
28292
+ }
28293
+ ]
28294
+ },
28295
+ {
28296
+ "id": "openwop.it.v2-run-completed-outputs.the-run-completed-event-of-a-run-that-completed-carries-an-outputs-object",
28297
+ "file": "v2-run-completed-outputs.test.ts",
28298
+ "line": 72,
28299
+ "title": "the run.completed event of a run that completed carries an outputs object",
28300
+ "explicitId": null,
28301
+ "citations": [
28302
+ {
28303
+ "section": null,
28304
+ "requirement": "run.completed MUST carry a payload object",
28305
+ "interpolated": true
28306
+ },
28307
+ {
28308
+ "section": null,
28309
+ "requirement": null,
28310
+ "interpolated": true
28311
+ },
28312
+ {
28313
+ "section": null,
28314
+ "requirement": null,
28315
+ "interpolated": true
28316
+ }
28317
+ ]
28318
+ },
28319
+ {
28320
+ "id": "openwop.it.v2-run-diff-identical.two-identical-logs-diff-to-divergedatseq-null-and-empty-eventdiffs-in-a-response",
28321
+ "file": "v2-run-diff-identical.test.ts",
28322
+ "line": 54,
28323
+ "title": "two identical logs diff to divergedAtSeq null and empty eventDiffs, in a response that validates and echoes both ids",
28324
+ "explicitId": null,
28325
+ "citations": [
28326
+ {
28327
+ "section": null,
28328
+ "requirement": null,
28329
+ "interpolated": true
28330
+ },
28331
+ {
28332
+ "section": "schemas/v2/run-diff-response.schema.json",
28333
+ "requirement": null,
28334
+ "interpolated": true
28335
+ },
28336
+ {
28337
+ "section": null,
28338
+ "requirement": "the response MUST name the two runs it compared",
28339
+ "interpolated": true
28340
+ },
28341
+ {
28342
+ "section": null,
28343
+ "requirement": null,
28344
+ "interpolated": true
28345
+ },
28346
+ {
28347
+ "section": null,
28348
+ "requirement": "identical logs MUST yield empty eventDiffs",
28349
+ "interpolated": true
28350
+ },
28351
+ {
28352
+ "section": null,
28353
+ "requirement": null,
28354
+ "interpolated": true
28355
+ }
28356
+ ]
28357
+ },
28358
+ {
28359
+ "id": "openwop.it.v2-run-fork-prefix.a-replay-fork-inherits-exactly-0-fromseq-the-event-at-fromseq-is-re-executed-nev",
28360
+ "file": "v2-run-fork-prefix.test.ts",
28361
+ "line": 86,
28362
+ "title": "a replay fork inherits exactly [0, fromSeq): the event at fromSeq is re-executed, never carried over",
28363
+ "explicitId": null,
28364
+ "citations": [
28365
+ {
28366
+ "section": "spec/v2/core/runs.md §Fork",
28367
+ "requirement": null,
28368
+ "interpolated": true
28369
+ },
28370
+ {
28371
+ "section": null,
28372
+ "requirement": null,
28373
+ "interpolated": true
28374
+ },
28375
+ {
28376
+ "section": null,
28377
+ "requirement": null,
28378
+ "interpolated": true
28379
+ }
28380
+ ]
28381
+ },
28382
+ {
28383
+ "id": "openwop.it.v2-run-fork-refusals.replay-overlay-400-a-fromseq-outside-the-log-422-fork-point-invalid-a-valid-repl",
28384
+ "file": "v2-run-fork-refusals.test.ts",
28385
+ "line": 38,
28386
+ "title": "replay+overlay → 400; a fromSeq outside the log → 422 fork_point_invalid; a valid replay fork → 201 with the parent's owner verbatim",
28387
+ "explicitId": null,
28388
+ "citations": [
28389
+ {
28390
+ "section": null,
28391
+ "requirement": null,
28392
+ "interpolated": true
28393
+ },
28394
+ {
28395
+ "section": null,
28396
+ "requirement": null,
28397
+ "interpolated": true
28398
+ },
28399
+ {
28400
+ "section": null,
28401
+ "requirement": "the refusal MUST be fork_point_invalid",
28402
+ "interpolated": true
28403
+ },
28404
+ {
28405
+ "section": null,
28406
+ "requirement": null,
28407
+ "interpolated": true
28408
+ },
28409
+ {
28410
+ "section": null,
28411
+ "requirement": "the 201 MUST name the parent as sourceRunId",
28412
+ "interpolated": true
28413
+ },
28414
+ {
28415
+ "section": null,
28416
+ "requirement": "the 201 MUST echo the mode",
28417
+ "interpolated": true
28418
+ },
28419
+ {
28420
+ "section": null,
28421
+ "requirement": "the 201 MUST carry runId and eventsUrl",
28422
+ "interpolated": true
28423
+ },
28424
+ {
28425
+ "section": "RFCS/0170 §A.4",
28426
+ "requirement": "the child's owner MUST be copied verbatim from the parent"
28427
+ }
28428
+ ]
28429
+ },
28430
+ {
28431
+ "id": "openwop.it.v2-run-options-limits.more-than-100-tags-a-tag-over-256-characters-and-an-unknown-root-key-are-each-re",
28432
+ "file": "v2-run-options-limits.test.ts",
28433
+ "line": 46,
28434
+ "title": "more than 100 tags, a tag over 256 characters, and an unknown root key are each refused 400 validation_error",
28435
+ "explicitId": null,
28436
+ "citations": []
28437
+ },
28438
+ {
28439
+ "id": "openwop.it.v2-run-options-limits.odd-format-tags-and-free-form-metadata-are-accepted-and-surface-unchanged-on-the",
28440
+ "file": "v2-run-options-limits.test.ts",
28441
+ "line": 56,
28442
+ "title": "odd-format tags and free-form metadata are accepted and surface unchanged on the snapshot",
28443
+ "explicitId": null,
28444
+ "citations": [
28445
+ {
28446
+ "section": null,
28447
+ "requirement": null,
28448
+ "interpolated": true
28449
+ },
28450
+ {
28451
+ "section": null,
28452
+ "requirement": "tags MUST surface unchanged on RunSnapshot",
28453
+ "interpolated": true
28454
+ },
28455
+ {
28456
+ "section": null,
28457
+ "requirement": "metadata MUST be persisted and surface unchanged on RunSnapshot",
28458
+ "interpolated": true
28459
+ }
28460
+ ]
28461
+ },
28462
+ {
28463
+ "id": "openwop.it.v2-run-pause-resume.pause-and-resume-on-a-terminal-run-answer-409-with-an-error-envelope",
28464
+ "file": "v2-run-pause-resume.test.ts",
28465
+ "line": 59,
28466
+ "title": "pause and resume on a terminal run answer 409 with an error envelope",
28467
+ "explicitId": null,
28468
+ "citations": [
28469
+ {
28470
+ "section": null,
28471
+ "requirement": null,
28472
+ "interpolated": true
28473
+ },
28474
+ {
28475
+ "section": null,
28476
+ "requirement": null,
28477
+ "interpolated": true
28478
+ },
28479
+ {
28480
+ "section": null,
28481
+ "requirement": null,
28482
+ "interpolated": true
28483
+ },
28484
+ {
28485
+ "section": null,
28486
+ "requirement": null,
28487
+ "interpolated": true
28488
+ }
28489
+ ]
28490
+ },
28491
+ {
28492
+ "id": "openwop.it.v2-run-pause-resume.a-running-run-pauses-202-paused-refuses-a-second-pause-409-resumes-202-running-a",
28493
+ "file": "v2-run-pause-resume.test.ts",
28494
+ "line": 77,
28495
+ "title": "a running run pauses (202 paused), refuses a second pause (409), resumes (202 running), and the log carries run.paused then run.resumed",
28496
+ "explicitId": null,
28497
+ "citations": [
28498
+ {
28499
+ "section": null,
28500
+ "requirement": null,
28501
+ "interpolated": true
28502
+ },
28503
+ {
28504
+ "section": null,
28505
+ "requirement": "the 202 MUST carry the runId",
28506
+ "interpolated": true
28507
+ },
28508
+ {
28509
+ "section": null,
28510
+ "requirement": null,
28511
+ "interpolated": true
28512
+ },
28513
+ {
28514
+ "section": null,
28515
+ "requirement": null,
28516
+ "interpolated": true
28517
+ },
28518
+ {
28519
+ "section": null,
28520
+ "requirement": null,
28521
+ "interpolated": true
28522
+ },
28523
+ {
28524
+ "section": null,
28525
+ "requirement": null,
28526
+ "interpolated": true
28527
+ },
28528
+ {
28529
+ "section": null,
28530
+ "requirement": null,
28531
+ "interpolated": true
28532
+ },
28533
+ {
28534
+ "section": null,
28535
+ "requirement": null,
28536
+ "interpolated": true
28537
+ },
28538
+ {
28539
+ "section": "spec/v2/core/events.md §run.paused",
28540
+ "requirement": null,
28541
+ "interpolated": true
28542
+ },
28543
+ {
28544
+ "section": null,
28545
+ "requirement": null,
28546
+ "interpolated": true
28547
+ },
28548
+ {
28549
+ "section": null,
28550
+ "requirement": null,
28551
+ "interpolated": true
28552
+ }
28553
+ ]
28554
+ },
28555
+ {
28556
+ "id": "openwop.it.v2-run-snapshot-etag.a-matching-if-none-match-receives-304-with-no-body-and-the-version-header-a-non",
28557
+ "file": "v2-run-snapshot-etag.test.ts",
28558
+ "line": 34,
28559
+ "title": "a matching If-None-Match receives 304 with no body and the version header; a non-matching one receives 200",
28560
+ "explicitId": null,
28561
+ "citations": [
28562
+ {
28563
+ "section": null,
28564
+ "requirement": null,
28565
+ "interpolated": true
28566
+ },
28567
+ {
28568
+ "section": null,
28569
+ "requirement": null,
28570
+ "interpolated": true
28571
+ },
28572
+ {
28573
+ "section": "spec/v2/core/versioning.md §1.4",
28574
+ "requirement": "every response carries OpenWOP-Version, the 304 included"
28575
+ },
28576
+ {
28577
+ "section": null,
28578
+ "requirement": null,
28579
+ "interpolated": true
28580
+ },
28581
+ {
28582
+ "section": null,
28583
+ "requirement": "the 200 body is the snapshot",
28584
+ "interpolated": true
28585
+ }
28586
+ ]
28587
+ },
28588
+ {
28589
+ "id": "openwop.it.v2-sse-last-event-id.last-event-id-resumes-at-the-next-sequence-never-re-emits-the-resumption-point-l",
28590
+ "file": "v2-sse-last-event-id.test.ts",
28591
+ "line": 59,
28592
+ "title": "Last-Event-ID resumes at the next sequence, never re-emits the resumption point, loses nothing, and at the last id yields nothing",
28593
+ "explicitId": null,
28594
+ "citations": [
28595
+ {
28596
+ "section": null,
28597
+ "requirement": null,
28598
+ "interpolated": true
28599
+ },
28600
+ {
28601
+ "section": null,
28602
+ "requirement": "the completed log MUST stream as at least one frame",
28603
+ "interpolated": true
28604
+ },
28605
+ {
28606
+ "section": null,
28607
+ "requirement": null,
28608
+ "interpolated": true
28609
+ },
28610
+ {
28611
+ "section": null,
28612
+ "requirement": null,
28613
+ "interpolated": true
28614
+ },
28615
+ {
28616
+ "section": null,
28617
+ "requirement": "frames MUST arrive in log order",
28618
+ "interpolated": true
28619
+ },
28620
+ {
28621
+ "section": null,
28622
+ "requirement": null,
28623
+ "interpolated": true
28624
+ },
28625
+ {
28626
+ "section": null,
28627
+ "requirement": null,
28628
+ "interpolated": true
28629
+ },
28630
+ {
28631
+ "section": null,
28632
+ "requirement": null,
28633
+ "interpolated": true
28634
+ },
28635
+ {
28636
+ "section": null,
28637
+ "requirement": null,
28638
+ "interpolated": true
28639
+ },
28640
+ {
28641
+ "section": null,
28642
+ "requirement": null,
28643
+ "interpolated": true
28644
+ },
28645
+ {
28646
+ "section": null,
28647
+ "requirement": "the host MUST close the empty resume itself",
28648
+ "interpolated": true
28649
+ },
28650
+ {
28651
+ "section": null,
28652
+ "requirement": null,
28653
+ "interpolated": true
28654
+ },
28655
+ {
28656
+ "section": null,
28657
+ "requirement": null,
28658
+ "interpolated": true
28659
+ }
28660
+ ]
28661
+ },
28662
+ {
28663
+ "id": "openwop.it.v2-stream-mode-refusal.a-value-outside-the-pattern-a-forbidden-combination-and-an-unimplemented-mode-ar",
28664
+ "file": "v2-stream-mode-refusal.test.ts",
28665
+ "line": 64,
28666
+ "title": "a value outside the pattern, a forbidden combination, and an unimplemented mode are refused 400 unsupported_stream_mode with details.supported — before content negotiation",
28667
+ "explicitId": null,
28668
+ "citations": [
28669
+ {
28670
+ "section": null,
28671
+ "requirement": null,
28672
+ "interpolated": true
28673
+ },
28674
+ {
28675
+ "section": null,
28676
+ "requirement": "the refusal MUST be unsupported_stream_mode",
28677
+ "interpolated": true
28678
+ },
28679
+ {
28680
+ "section": null,
28681
+ "requirement": null,
28682
+ "interpolated": true
28683
+ },
28684
+ {
28685
+ "section": null,
28686
+ "requirement": "a host MUST implement updates, so supported MUST list it",
28687
+ "interpolated": true
28688
+ },
28689
+ {
28690
+ "section": null,
28691
+ "requirement": null,
28692
+ "interpolated": true
28693
+ },
28694
+ {
28695
+ "section": null,
28696
+ "requirement": null,
28697
+ "interpolated": true
28698
+ },
28699
+ {
28700
+ "section": null,
28701
+ "requirement": "the refusal MUST be unsupported_stream_mode",
28702
+ "interpolated": true
28703
+ },
28704
+ {
28705
+ "section": null,
28706
+ "requirement": null,
28707
+ "interpolated": true
28708
+ },
28709
+ {
28710
+ "section": null,
28711
+ "requirement": "the refusal MUST be unsupported_stream_mode",
28712
+ "interpolated": true
28713
+ }
28714
+ ]
28715
+ },
28716
+ {
28717
+ "id": "openwop.it.v2-stream-mode-refusal.updates-streams-200-text-event-stream-with-frames-bufferms-yields-at-least-one-b",
28718
+ "file": "v2-stream-mode-refusal.test.ts",
28719
+ "line": 95,
28720
+ "title": "updates streams 200 text/event-stream with frames; bufferMs yields at least one batch frame whose data is an array and loses nothing; without bufferMs no frame is batch",
28721
+ "explicitId": null,
28722
+ "citations": [
28723
+ {
28724
+ "section": null,
28725
+ "requirement": null,
28726
+ "interpolated": true
28727
+ },
28728
+ {
28729
+ "section": "spec/v2/core/events.md §SSE frames",
28730
+ "requirement": "the completed run's log MUST stream as at least one frame before the server closes"
28731
+ },
28732
+ {
28733
+ "section": "spec/v2/core/events.md §SSE frames",
28734
+ "requirement": null,
28735
+ "interpolated": true
28736
+ },
28737
+ {
28738
+ "section": "spec/v2/core/events.md §SSE frames",
28739
+ "requirement": "without bufferMs no frame is a batch (the control for the batch leg)"
28740
+ },
28741
+ {
28742
+ "section": "spec/v2/core/events.md §SSE frames",
28743
+ "requirement": null,
28744
+ "interpolated": true
28745
+ },
28746
+ {
28747
+ "section": "spec/v2/core/events.md §SSE frames",
28748
+ "requirement": null,
28749
+ "interpolated": true
28750
+ },
28751
+ {
28752
+ "section": "spec/v2/core/events.md §SSE frames",
28753
+ "requirement": "a batch frame's data MUST be an array of RunEventDoc"
28754
+ },
28755
+ {
28756
+ "section": "spec/v2/core/events.md §SSE frames",
28757
+ "requirement": "batching MUST NOT lose or reorder events: the flattened buffered stream equals the unbuffered log (a one-element batch and an unbatched frame are both tolerated)"
28758
+ }
28759
+ ]
28760
+ },
28761
+ {
28762
+ "id": "openwop.it.v2-stream-sse-projection.every-data-frame-on-the-major-2-stream-carries-the-tenant-bound-runid-of-the-run",
28763
+ "file": "v2-stream-sse-projection.test.ts",
28764
+ "line": 52,
28765
+ "title": "every data: frame on the major-2 stream carries the tenant-bound runId of the run it belongs to",
28766
+ "explicitId": null,
28767
+ "citations": [
28768
+ {
28769
+ "section": "spec/v2/core/identity.md §5",
28770
+ "requirement": null,
28771
+ "interpolated": true
28772
+ },
28773
+ {
28774
+ "section": null,
28775
+ "requirement": null,
28776
+ "interpolated": true
28777
+ },
28778
+ {
28779
+ "section": null,
28780
+ "requirement": null,
28781
+ "interpolated": true
28782
+ },
28783
+ {
28784
+ "section": null,
28785
+ "requirement": null,
28786
+ "interpolated": true
28787
+ }
28788
+ ]
28789
+ },
27959
28790
  {
27960
28791
  "id": "openwop.it.v2-subject-link-record.the-link-formed-across-scim-and-saml-is-a-closed-subjectlink-record",
27961
28792
  "file": "v2-subject-link-record.test.ts",
@@ -28124,6 +28955,49 @@
28124
28955
  }
28125
28956
  ]
28126
28957
  },
28958
+ {
28959
+ "id": "openwop.it.v2-version-header-honored.openwop-version-is-honored-or-refused-never-ignored",
28960
+ "file": "v2-version-header-honored.test.ts",
28961
+ "line": 61,
28962
+ "title": "OpenWOP-Version is honored or refused — never ignored",
28963
+ "explicitId": null,
28964
+ "citations": [
28965
+ {
28966
+ "section": null,
28967
+ "requirement": "a host that does not serve major 2 MUST refuse with 406 protocol_version_unsupported, which it did",
28968
+ "interpolated": true
28969
+ },
28970
+ {
28971
+ "section": null,
28972
+ "requirement": "answering 200 to OpenWOP-Version: 2.0 with a body byte-identical to the header-less fetch means the header was IGNORED, not honored — the host served v1 and called it v2. Refusing with 406 is the correct answer for a host that does not implement major 2; silently returning v1 is the one answer that no presence-gated scenario can detect, because an absent v2 shape records `inapplicable` whether the host refused or ignored",
28973
+ "interpolated": true
28974
+ }
28975
+ ]
28976
+ },
28977
+ {
28978
+ "id": "openwop.it.v2-version-header-honored.a-host-advertising-two-majors-serves-two-different-representations",
28979
+ "file": "v2-version-header-honored.test.ts",
28980
+ "line": 92,
28981
+ "title": "a host advertising two majors serves two different representations",
28982
+ "explicitId": null,
28983
+ "citations": [
28984
+ {
28985
+ "section": null,
28986
+ "requirement": null,
28987
+ "interpolated": true
28988
+ },
28989
+ {
28990
+ "section": null,
28991
+ "requirement": "the v1 document and the closed v2 root differ by construction (capabilities.md §1), so a host advertising both majors returning identical bytes for both has advertised a major it does not actually serve",
28992
+ "interpolated": true
28993
+ },
28994
+ {
28995
+ "section": null,
28996
+ "requirement": null,
28997
+ "interpolated": true
28998
+ }
28999
+ ]
29000
+ },
28127
29001
  {
28128
29002
  "id": "openwop.it.v2-webhook-durable-delivery.a-failed-attempt-is-retried-and-the-event-is-delivered-at-least-once",
28129
29003
  "file": "v2-webhook-durable-delivery.test.ts",
@@ -28377,7 +29251,7 @@
28377
29251
  {
28378
29252
  "id": "openwop.it.version-negotiation.get-well-known-openwop-returns-capabilities-with-protocolversion-string",
28379
29253
  "file": "version-negotiation.test.ts",
28380
- "line": 46,
29254
+ "line": 68,
28381
29255
  "title": "GET /.well-known/openwop returns Capabilities with protocolVersion (string)",
28382
29256
  "explicitId": "openwop.it.version-negotiation.get-well-known-openwop-returns-capabilities-with-protocolversion-string",
28383
29257
  "citations": [
@@ -28390,7 +29264,7 @@
28390
29264
  {
28391
29265
  "id": "openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json",
28392
29266
  "file": "version-negotiation.test.ts",
28393
- "line": 60,
29267
+ "line": 82,
28394
29268
  "title": "every event has the 6 required RunEventDoc fields per run-event.schema.json",
28395
29269
  "explicitId": "openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json",
28396
29270
  "citations": [
@@ -28431,7 +29305,7 @@
28431
29305
  {
28432
29306
  "id": "openwop.it.version-negotiation.event-sequences-within-a-run-are-strictly-monotonic",
28433
29307
  "file": "version-negotiation.test.ts",
28434
- "line": 104,
29308
+ "line": 126,
28435
29309
  "title": "event sequences within a run are strictly monotonic",
28436
29310
  "explicitId": "openwop.it.version-negotiation.event-sequences-within-a-run-are-strictly-monotonic",
28437
29311
  "citations": [
@@ -28445,7 +29319,7 @@
28445
29319
  {
28446
29320
  "id": "openwop.it.version-negotiation.events-poll-with-lastsequence-past-current-end-returns-empty-events-iscomplete",
28447
29321
  "file": "version-negotiation.test.ts",
28448
- "line": 132,
29322
+ "line": 154,
28449
29323
  "title": "events/poll with lastSequence past current end returns empty events + isComplete",
28450
29324
  "explicitId": "openwop.it.version-negotiation.events-poll-with-lastsequence-past-current-end-returns-empty-events-iscomplete",
28451
29325
  "citations": [
@@ -34492,6 +35366,82 @@
34492
35366
  }
34493
35367
  ]
34494
35368
  },
35369
+ {
35370
+ "id": "openwop.it.v2-bundle-signature-attributable.the-v2-discovery-root-publishes-signingkeys-the-surface-the-rfc-named",
35371
+ "file": "v2-bundle-signature-attributable.test.ts",
35372
+ "line": 103,
35373
+ "title": "the v2 discovery root publishes signingKeys[] — the surface the RFC named",
35374
+ "explicitId": null,
35375
+ "citations": [
35376
+ {
35377
+ "section": null,
35378
+ "requirement": "the v2 discovery root MUST carry signingKeys[] — RFC 0168 disposed of \"an Ed25519 attestation without a key registry is a signature nobody can check\" by naming this surface, so if it is absent the disposition names a place that does not exist and every bundle signature is unattributable",
35379
+ "interpolated": true
35380
+ },
35381
+ {
35382
+ "section": null,
35383
+ "requirement": null,
35384
+ "interpolated": true
35385
+ },
35386
+ {
35387
+ "section": null,
35388
+ "requirement": "a signingKeys[] entry MUST be closed; an open key record lets a host attach meaning the verifier does not read",
35389
+ "interpolated": true
35390
+ },
35391
+ {
35392
+ "section": null,
35393
+ "requirement": "a signingKeys[] entry MUST be able to record retirement, because a retired key has to stay listed — dropping it silently invalidates every bundle it already signed, which is the opposite of what an evidence trail is for",
35394
+ "interpolated": true
35395
+ }
35396
+ ]
35397
+ },
35398
+ {
35399
+ "id": "openwop.it.v2-bundle-signature-attributable.the-front-door-gate-verifies-the-attestation-instead-of-inspecting-the-string",
35400
+ "file": "v2-bundle-signature-attributable.test.ts",
35401
+ "line": 134,
35402
+ "title": "the Front-door gate verifies the attestation instead of inspecting the string",
35403
+ "explicitId": null,
35404
+ "citations": [
35405
+ {
35406
+ "section": null,
35407
+ "requirement": "the gate MUST NOT accept a bundle signature by presence: `typeof signature.sig === 'string'` is satisfied by any string, so it cannot distinguish a host key from a keypair minted seconds earlier by whoever wrote the bundle",
35408
+ "interpolated": true
35409
+ },
35410
+ {
35411
+ "section": null,
35412
+ "requirement": "the gate MUST resolve signature.keyId against the host's published signingKeys[] and verify the Ed25519 attestation under it — resolving without verifying, or verifying against a key the bundle supplied itself, both leave the signature unaccountable",
35413
+ "interpolated": true
35414
+ }
35415
+ ]
35416
+ },
35417
+ {
35418
+ "id": "openwop.it.v2-bundle-signature-attributable.the-four-signature-outcomes-stay-distinct-collapsing-any-two-restores-the-defect",
35419
+ "file": "v2-bundle-signature-attributable.test.ts",
35420
+ "line": 149,
35421
+ "title": "the four signature outcomes stay distinct — collapsing any two restores the defect",
35422
+ "explicitId": null,
35423
+ "citations": [
35424
+ {
35425
+ "section": null,
35426
+ "requirement": null,
35427
+ "interpolated": true
35428
+ }
35429
+ ]
35430
+ },
35431
+ {
35432
+ "id": "openwop.it.v2-bundle-signature-attributable.signingkeys-is-reachable-from-a-v1-root-too-a-bundle-is-v3-regardless-of-major",
35433
+ "file": "v2-bundle-signature-attributable.test.ts",
35434
+ "line": 170,
35435
+ "title": "signingKeys[] is reachable from a v1 root too — a bundle is v3 regardless of major",
35436
+ "explicitId": null,
35437
+ "citations": [
35438
+ {
35439
+ "section": null,
35440
+ "requirement": "the v1 discovery root MUST also carry signingKeys[]: a certification bundle is v3 regardless of major, and a v1-only host has only this document to resolve signature.keyId against — putting the key on the v2 root alone leaves every v1 host bundle unattributable",
35441
+ "interpolated": true
35442
+ }
35443
+ ]
35444
+ },
34495
35445
  {
34496
35446
  "id": "openwop.it.v2-corpus-tag-pinned.every-vendoring-consumer-in-the-cross-repo-inventory-records-a-published-corpus",
34497
35447
  "file": "v2-corpus-tag-pinned.test.ts",
@@ -34520,6 +35470,58 @@
34520
35470
  }
34521
35471
  ]
34522
35472
  },
35473
+ {
35474
+ "id": "openwop.it.v2-eos-clock.the-clock-file-is-current-with-the-matrix-and-the-public-history",
35475
+ "file": "v2-eos-clock.test.ts",
35476
+ "line": 43,
35477
+ "title": "the clock file is current with the matrix and the public history",
35478
+ "explicitId": null,
35479
+ "citations": [
35480
+ {
35481
+ "section": null,
35482
+ "requirement": null,
35483
+ "interpolated": true
35484
+ }
35485
+ ]
35486
+ },
35487
+ {
35488
+ "id": "openwop.it.v2-eos-clock.check-removal-dates-fails-the-v1-tree-sources-of-v1-end-of-support-rows-once-the",
35489
+ "file": "v2-eos-clock.test.ts",
35490
+ "line": 49,
35491
+ "title": "check-removal-dates FAILS the v1-tree sources of v1-end-of-support rows once the clock has passed",
35492
+ "explicitId": null,
35493
+ "citations": [
35494
+ {
35495
+ "section": null,
35496
+ "requirement": null,
35497
+ "interpolated": true
35498
+ },
35499
+ {
35500
+ "section": null,
35501
+ "requirement": "the failure MUST name the row and the source it found",
35502
+ "interpolated": true
35503
+ }
35504
+ ]
35505
+ },
35506
+ {
35507
+ "id": "openwop.it.v2-eos-clock.check-removal-dates-passes-under-the-same-clock-when-today-is-before-the-date-an",
35508
+ "file": "v2-eos-clock.test.ts",
35509
+ "line": 59,
35510
+ "title": "check-removal-dates PASSES under the same clock when today is before the date, and prints the clock state",
35511
+ "explicitId": null,
35512
+ "citations": [
35513
+ {
35514
+ "section": null,
35515
+ "requirement": null,
35516
+ "interpolated": true
35517
+ },
35518
+ {
35519
+ "section": null,
35520
+ "requirement": "the script MUST print the clock state on a green run — \"not anchored\" and \"far away\" must not print the same nothing",
35521
+ "interpolated": true
35522
+ }
35523
+ ]
35524
+ },
34523
35525
  {
34524
35526
  "id": "openwop.it.v2-error-registry-prose-parity.errors-md-states-the-registry-count-it-was-generated-from-and-renders-every-code",
34525
35527
  "file": "v2-error-registry-prose-parity.test.ts",
@@ -34623,6 +35625,20 @@
34623
35625
  }
34624
35626
  ]
34625
35627
  },
35628
+ {
35629
+ "id": "openwop.it.v2-id-kinds-bound.every-v2-id-field-refs-its-kind-and-every-id-property-is-triaged",
35630
+ "file": "v2-id-kinds-bound.test.ts",
35631
+ "line": 57,
35632
+ "title": "every v2 id field $refs its kind, and every *Id property is triaged",
35633
+ "explicitId": null,
35634
+ "citations": [
35635
+ {
35636
+ "section": "spec/v2/core/identity.md §5",
35637
+ "requirement": null,
35638
+ "interpolated": true
35639
+ }
35640
+ ]
35641
+ },
34626
35642
  {
34627
35643
  "id": "openwop.it.v2-one-signing-scheme.registry-version-manifest-signing-has-exactly-one-scheme-ed25519-canonical-json",
34628
35644
  "file": "v2-one-signing-scheme.test.ts",
@@ -34709,6 +35725,63 @@
34709
35725
  }
34710
35726
  ]
34711
35727
  },
35728
+ {
35729
+ "id": "openwop.it.v2-retention-floors.the-registry-validates-and-the-script-prints-the-floor-state-offline",
35730
+ "file": "v2-retention-floors.test.ts",
35731
+ "line": 53,
35732
+ "title": "the registry validates and the script prints the floor state offline",
35733
+ "explicitId": null,
35734
+ "citations": [
35735
+ {
35736
+ "section": null,
35737
+ "requirement": null,
35738
+ "interpolated": true
35739
+ },
35740
+ {
35741
+ "section": null,
35742
+ "requirement": "the floor state MUST be printed on every run — \"not started\" and \"every version present\" must not print the same nothing",
35743
+ "interpolated": true
35744
+ }
35745
+ ]
35746
+ },
35747
+ {
35748
+ "id": "openwop.it.v2-retention-floors.a-pinned-old-major-version-missing-from-its-registry-while-the-floor-is-open-fai",
35749
+ "file": "v2-retention-floors.test.ts",
35750
+ "line": 60,
35751
+ "title": "a pinned old-major version missing from its registry while the floor is open FAILS, naming the artifact",
35752
+ "explicitId": null,
35753
+ "citations": [
35754
+ {
35755
+ "section": null,
35756
+ "requirement": null,
35757
+ "interpolated": true
35758
+ },
35759
+ {
35760
+ "section": null,
35761
+ "requirement": "the failure MUST name the artifact and the version",
35762
+ "interpolated": true
35763
+ }
35764
+ ]
35765
+ },
35766
+ {
35767
+ "id": "openwop.it.v2-retention-floors.the-same-probe-with-every-pinned-version-present-passes-while-the-floor-is-open",
35768
+ "file": "v2-retention-floors.test.ts",
35769
+ "line": 67,
35770
+ "title": "the same probe with every pinned version present PASSES while the floor is open",
35771
+ "explicitId": null,
35772
+ "citations": [
35773
+ {
35774
+ "section": null,
35775
+ "requirement": null,
35776
+ "interpolated": true
35777
+ },
35778
+ {
35779
+ "section": null,
35780
+ "requirement": "the open floor MUST print its closing date",
35781
+ "interpolated": true
35782
+ }
35783
+ ]
35784
+ },
34712
35785
  {
34713
35786
  "id": "openwop.it.v2-seams-not-in-canonical.the-corpus-gate-script-exits-0",
34714
35787
  "file": "v2-seams-not-in-canonical.test.ts",