@openwop/openwop-conformance 2.42.9 → 2.43.1

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 (33) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +3 -3
  3. package/coverage.md +1 -1
  4. package/dist/cli.js +15 -12
  5. package/dist/lib/certification-bundle-v3.js +19 -0
  6. package/dist/spec-artifacts.lock.json +2 -2
  7. package/fixtures/conformance-approval-reject-loopback.json +33 -0
  8. package/fixtures/conformance-approval-reject-routed.json +32 -0
  9. package/fixtures/conformance-approval-timeout-approve.json +46 -0
  10. package/fixtures/conformance-approval-timeout.json +28 -0
  11. package/fixtures.md +59 -2
  12. package/package.json +2 -2
  13. package/requirements.json +535 -38
  14. package/scenario-majors.json +20 -5
  15. package/schemas/CORPUS-STAMP.json +55 -54
  16. package/src/cli.ts +15 -12
  17. package/src/lib/auditIntegrity.ts +45 -0
  18. package/src/lib/certification-bundle-v3.ts +25 -0
  19. package/src/lib/standard-webhooks.ts +53 -0
  20. package/src/scenarios/agent-org-chart-scoping.test.ts +63 -0
  21. package/src/scenarios/audit-anomaly-shape.test.ts +100 -0
  22. package/src/scenarios/audit-checkpoint-signature.test.ts +14 -15
  23. package/src/scenarios/audit-log-integrity.test.ts +102 -46
  24. package/src/scenarios/byok-roundtrip.test.ts +21 -7
  25. package/src/scenarios/v2-agent-org-chart-served-shape.test.ts +63 -0
  26. package/src/scenarios/v2-approval-reject-disposition.test.ts +262 -0
  27. package/src/scenarios/v2-error-registry.test.ts +59 -0
  28. package/src/scenarios/v2-manifest-ceiling-refused.test.ts +21 -9
  29. package/src/scenarios/v2-manifest-hatch-carried.test.ts +23 -7
  30. package/src/scenarios/v2-pack-isolation.test.ts +10 -6
  31. package/src/scenarios/v2-peer-dependency-declared.test.ts +18 -6
  32. package/src/scenarios/v2-registry-lifecycle.test.ts +232 -0
  33. package/src/scenarios/v2-webhook-secret-rotation.test.ts +28 -11
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": 642,
6
- "tests": 2466,
7
- "withStableId": 2466,
5
+ "files": 646,
6
+ "tests": 2488,
7
+ "withStableId": 2488,
8
8
  "interpolatedTitles": 0,
9
- "explicitIds": 2356
9
+ "explicitIds": 2370
10
10
  },
11
11
  "records": [
12
12
  {
@@ -1912,7 +1912,7 @@
1912
1912
  {
1913
1913
  "id": "openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco",
1914
1914
  "file": "agent-org-chart-scoping.test.ts",
1915
- "line": 39,
1915
+ "line": 60,
1916
1916
  "title": "serves the normative org-chart + responsibility roll-up, tree-shaped and tenant-scoped",
1917
1917
  "explicitId": "openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco",
1918
1918
  "citations": [
@@ -1974,6 +1974,31 @@
1974
1974
  }
1975
1975
  ]
1976
1976
  },
1977
+ {
1978
+ "id": "openwop.it.agent-org-chart-scoping.serves-the-org-chart-read-pair-in-the-exact-schema-shape",
1979
+ "file": "agent-org-chart-scoping.test.ts",
1980
+ "line": 193,
1981
+ "title": "serves the org-chart read pair in the exact schema shape",
1982
+ "explicitId": "openwop.it.agent-org-chart-scoping.serves-the-org-chart-read-pair-in-the-exact-schema-shape",
1983
+ "citations": [
1984
+ {
1985
+ "section": "agent-org-chart.md §A / §E",
1986
+ "requirement": "a host advertising agents.orgChart.supported MUST serve GET /v1/agents/org-chart with 200"
1987
+ },
1988
+ {
1989
+ "section": "agent-org-chart.schema.json (RFC 0087 §A)",
1990
+ "requirement": "the served GET /v1/agents/org-chart body MUST validate against agent-org-chart.schema.json (owner required; no extra keys)"
1991
+ },
1992
+ {
1993
+ "section": "agent-org-chart.md §D / §E",
1994
+ "requirement": "a host advertising agents.orgChart.responsibilityView MUST serve GET /v1/agents/org-chart/{departmentId} with 200 for a department in the caller's chart"
1995
+ },
1996
+ {
1997
+ "section": "org-chart-responsibility-view.schema.json (RFC 0087 §D)",
1998
+ "requirement": "the served GET /v1/agents/org-chart/{departmentId} body MUST validate against org-chart-responsibility-view.schema.json"
1999
+ }
2000
+ ]
2001
+ },
1977
2002
  {
1978
2003
  "id": "openwop.it.agent-org-chart-shape.the-capabilities-schema-declares-agents-orgchart-with-its-sub-flags",
1979
2004
  "file": "agent-org-chart-shape.test.ts",
@@ -5425,15 +5450,72 @@
5425
5450
  }
5426
5451
  ]
5427
5452
  },
5453
+ {
5454
+ "id": "openwop.it.audit-anomaly-shape.every-anomaly-kind-validates-in-its-own-shape",
5455
+ "file": "audit-anomaly-shape.test.ts",
5456
+ "line": 74,
5457
+ "title": "every anomaly kind validates in its own shape",
5458
+ "explicitId": "openwop.requirement.0218.anomaly-shape",
5459
+ "citations": [
5460
+ {
5461
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5462
+ "requirement": null,
5463
+ "interpolated": true
5464
+ },
5465
+ {
5466
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5467
+ "requirement": null,
5468
+ "interpolated": true
5469
+ }
5470
+ ]
5471
+ },
5472
+ {
5473
+ "id": "openwop.it.audit-anomaly-shape.an-anomaly-outside-its-kind-s-shape-is-refused",
5474
+ "file": "audit-anomaly-shape.test.ts",
5475
+ "line": 84,
5476
+ "title": "an anomaly outside its kind's shape is refused",
5477
+ "explicitId": "openwop.requirement.0218.anomaly-shape",
5478
+ "citations": [
5479
+ {
5480
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5481
+ "requirement": null,
5482
+ "interpolated": true
5483
+ }
5484
+ ]
5485
+ },
5486
+ {
5487
+ "id": "openwop.it.audit-anomaly-shape.chainvalid-is-false-exactly-when-anomalies-is-non-empty",
5488
+ "file": "audit-anomaly-shape.test.ts",
5489
+ "line": 92,
5490
+ "title": "chainValid is false exactly when anomalies is non-empty",
5491
+ "explicitId": "openwop.requirement.0218.anomaly-shape",
5492
+ "citations": [
5493
+ {
5494
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5495
+ "requirement": null,
5496
+ "interpolated": true
5497
+ },
5498
+ {
5499
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5500
+ "requirement": null,
5501
+ "interpolated": true
5502
+ },
5503
+ {
5504
+ "section": "RFC 0218 §C · spec/v1/auth-profiles.md §\"Audit-log integrity\" 4",
5505
+ "requirement": null,
5506
+ "interpolated": true
5507
+ }
5508
+ ]
5509
+ },
5428
5510
  {
5429
5511
  "id": "openwop.it.audit-checkpoint-signature.every-checkpoint-get-v1-audit-verify-returns-verifies-under-the-advertised-key",
5430
5512
  "file": "audit-checkpoint-signature.test.ts",
5431
- "line": 30,
5513
+ "line": 29,
5432
5514
  "title": "every checkpoint GET /v1/audit/verify returns verifies under the advertised key",
5433
5515
  "explicitId": "openwop.requirement.0218.checkpoint-signature-over-root",
5434
5516
  "citations": [
5435
5517
  {
5436
- "section": "RFC 0218 · spec/v1/auth-profiles.md §\"Audit-log integrity\" 3",
5518
+ "section": "RFC 0218 · spec/v1/auth-profiles.md §\"Audit-log integrity\" 3; spec/v2/core/security-defaults.md §\"Audit-log integrity\" (RFC 0224)",
5437
5519
  "requirement": null,
5438
5520
  "interpolated": true
5439
5521
  }
@@ -5534,10 +5616,19 @@
5534
5616
  {
5535
5617
  "id": "openwop.it.audit-log-integrity.host-that-claims-the-profile-advertises-required-capability-fields",
5536
5618
  "file": "audit-log-integrity.test.ts",
5537
- "line": 60,
5619
+ "line": 80,
5538
5620
  "title": "host that claims the profile advertises required capability fields",
5539
5621
  "explicitId": "openwop.it.audit-log-integrity.host-that-claims-the-profile-advertises-required-capability-fields",
5540
5622
  "citations": [
5623
+ {
5624
+ "section": "security-defaults.md §\"Audit-log integrity\"",
5625
+ "requirement": null,
5626
+ "interpolated": true
5627
+ },
5628
+ {
5629
+ "section": "security-defaults.md §\"Audit-log integrity\"",
5630
+ "requirement": "auditLogIntegrity.checkpointPublicKey MUST be an Ed25519 SubjectPublicKeyInfo, base64"
5631
+ },
5541
5632
  {
5542
5633
  "section": "auth-profiles.md §\"Audit-log integrity\"",
5543
5634
  "requirement": "openwop-audit-log-integrity profile MUST advertise auditLogIntegrity.hashChain: true"
@@ -5551,13 +5642,14 @@
5551
5642
  {
5552
5643
  "id": "openwop.it.audit-log-integrity.get-v1-audit-verify-on-a-recent-range-reports-chainvalid-true",
5553
5644
  "file": "audit-log-integrity.test.ts",
5554
- "line": 83,
5645
+ "line": 111,
5555
5646
  "title": "GET /v1/audit/verify on a recent range reports chainValid: true",
5556
5647
  "explicitId": "openwop.it.audit-log-integrity.get-v1-audit-verify-on-a-recent-range-reports-chainvalid-true",
5557
5648
  "citations": [
5558
5649
  {
5559
5650
  "section": "auth-profiles.md §\"Audit-log integrity\" §\"Verification endpoint\"",
5560
- "requirement": "claiming openwop-audit-log-integrity profile REQUIRES exposing GET /v1/audit/verify"
5651
+ "requirement": null,
5652
+ "interpolated": true
5561
5653
  },
5562
5654
  {
5563
5655
  "section": "audit-verify-result.schema.json",
@@ -5574,6 +5666,29 @@
5574
5666
  }
5575
5667
  ]
5576
5668
  },
5669
+ {
5670
+ "id": "openwop.it.audit-log-integrity.verify-lists-every-checkpoint-ascending-no-more-than-checkpointintervalentries-a",
5671
+ "file": "audit-log-integrity.test.ts",
5672
+ "line": 163,
5673
+ "title": "verify lists every checkpoint ascending, no more than checkpointIntervalEntries apart",
5674
+ "explicitId": "openwop.requirement.0224.checkpoint-cadence",
5675
+ "citations": [
5676
+ {
5677
+ "section": "security-defaults.md §\"Audit-log integrity\"",
5678
+ "requirement": "every checkpoint MUST carry an integer atSequence"
5679
+ },
5680
+ {
5681
+ "section": "security-defaults.md §\"Audit-log integrity\"",
5682
+ "requirement": null,
5683
+ "interpolated": true
5684
+ },
5685
+ {
5686
+ "section": "security-defaults.md §\"Audit-log integrity\"",
5687
+ "requirement": null,
5688
+ "interpolated": true
5689
+ }
5690
+ ]
5691
+ },
5577
5692
  {
5578
5693
  "id": "openwop.it.auth-api-key-rotation.host-claiming-rotation-profile-advertises-required-fields",
5579
5694
  "file": "auth-api-key-rotation.test.ts",
@@ -6731,7 +6846,7 @@
6731
6846
  {
6732
6847
  "id": "openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h",
6733
6848
  "file": "byok-roundtrip.test.ts",
6734
- "line": 39,
6849
+ "line": 51,
6735
6850
  "title": "the canary fixture run MUST resolve a host-provisioned secret and emit SHA-256 hex",
6736
6851
  "explicitId": "openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h",
6737
6852
  "citations": [
@@ -6756,7 +6871,7 @@
6756
6871
  {
6757
6872
  "id": "openwop.it.byok-roundtrip.byok-fixture-run-must-emit-a-node-completed-event-for-the-resolve-step",
6758
6873
  "file": "byok-roundtrip.test.ts",
6759
- "line": 104,
6874
+ "line": 116,
6760
6875
  "title": "BYOK fixture run MUST emit a node.completed event for the resolve step",
6761
6876
  "explicitId": "openwop.it.byok-roundtrip.byok-fixture-run-must-emit-a-node-completed-event-for-the-resolve-step",
6762
6877
  "citations": [
@@ -6769,7 +6884,7 @@
6769
6884
  {
6770
6885
  "id": "openwop.it.byok-roundtrip.byok-fixture-run-event-log-must-not-echo-the-resolved-secret-value-redaction",
6771
6886
  "file": "byok-roundtrip.test.ts",
6772
- "line": 130,
6887
+ "line": 143,
6773
6888
  "title": "BYOK fixture run event log MUST NOT echo the resolved secret value (redaction)",
6774
6889
  "explicitId": "openwop.it.byok-roundtrip.byok-fixture-run-event-log-must-not-echo-the-resolved-secret-value-redaction",
6775
6890
  "citations": [
@@ -27713,6 +27828,215 @@
27713
27828
  }
27714
27829
  ]
27715
27830
  },
27831
+ {
27832
+ "id": "openwop.it.v2-agent-org-chart-served-shape.serves-the-org-chart-read-pair-in-the-exact-v2-schema-shape",
27833
+ "file": "v2-agent-org-chart-served-shape.test.ts",
27834
+ "line": 30,
27835
+ "title": "serves the org-chart read pair in the exact v2 schema shape",
27836
+ "explicitId": "openwop.it.v2-agent-org-chart-served-shape.serves-the-org-chart-read-pair-in-the-exact-v2-schema-shape",
27837
+ "citations": [
27838
+ {
27839
+ "section": "api/v2/openapi.yaml /agents/org-chart (RFC 0087 §D)",
27840
+ "requirement": "a host advertising agents.orgChart MUST serve GET /agents/org-chart with 200"
27841
+ },
27842
+ {
27843
+ "section": "schemas/v2/agent-org-chart.schema.json (RFC 0087 §A)",
27844
+ "requirement": "the served GET /agents/org-chart body MUST validate against agent-org-chart.schema.json (owner required; no extra keys)"
27845
+ },
27846
+ {
27847
+ "section": "api/v2/openapi.yaml /agents/org-chart/{departmentId} (RFC 0087 §D)",
27848
+ "requirement": "a host advertising agents.orgChart.responsibilityView MUST serve GET /agents/org-chart/{departmentId} with 200 for a department in the caller's chart"
27849
+ },
27850
+ {
27851
+ "section": "schemas/v2/org-chart-responsibility-view.schema.json (RFC 0087 §D)",
27852
+ "requirement": "the served GET /agents/org-chart/{departmentId} body MUST validate against org-chart-responsibility-view.schema.json"
27853
+ }
27854
+ ]
27855
+ },
27856
+ {
27857
+ "id": "openwop.it.v2-approval-reject-disposition.a-rejected-gate-with-no-routing-edge-fails-the-run-with-approval-rejected",
27858
+ "file": "v2-approval-reject-disposition.test.ts",
27859
+ "line": 126,
27860
+ "title": "a rejected gate with no routing edge fails the run with approval_rejected",
27861
+ "explicitId": null,
27862
+ "citations": [
27863
+ {
27864
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27865
+ "requirement": null,
27866
+ "interpolated": true
27867
+ },
27868
+ {
27869
+ "section": null,
27870
+ "requirement": "the terminal snapshot error.code MUST be approval_rejected",
27871
+ "interpolated": true
27872
+ },
27873
+ {
27874
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27875
+ "requirement": "run.failed.error.code MUST be approval_rejected"
27876
+ }
27877
+ ]
27878
+ },
27879
+ {
27880
+ "id": "openwop.it.v2-approval-reject-disposition.interrupt-resolved-records-action-reject-and-decision-rejected",
27881
+ "file": "v2-approval-reject-disposition.test.ts",
27882
+ "line": 137,
27883
+ "title": "interrupt.resolved records action reject and decision rejected",
27884
+ "explicitId": null,
27885
+ "citations": [
27886
+ {
27887
+ "section": null,
27888
+ "requirement": "the reject MUST be recorded as interrupt.resolved",
27889
+ "interpolated": true
27890
+ },
27891
+ {
27892
+ "section": null,
27893
+ "requirement": "interrupt.resolved MUST carry action \"reject\" and decision \"rejected\"",
27894
+ "interpolated": true
27895
+ }
27896
+ ]
27897
+ },
27898
+ {
27899
+ "id": "openwop.it.v2-approval-reject-disposition.the-gate-node-fails-with-approval-rejected-not-retryable-and-run-failed-names-it",
27900
+ "file": "v2-approval-reject-disposition.test.ts",
27901
+ "line": 150,
27902
+ "title": "the gate node fails with approval_rejected, not retryable, and run.failed names it",
27903
+ "explicitId": null,
27904
+ "citations": [
27905
+ {
27906
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27907
+ "requirement": "the gate that does not turn the rejection into an output MUST emit node.failed"
27908
+ },
27909
+ {
27910
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27911
+ "requirement": "node.failed.error MUST carry code approval_rejected and retryable false"
27912
+ },
27913
+ {
27914
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27915
+ "requirement": "run.failed.failedNodeId MUST name the gate"
27916
+ }
27917
+ ]
27918
+ },
27919
+ {
27920
+ "id": "openwop.it.v2-approval-reject-disposition.a-majority-reject-decides-the-quorum-gate-on-the-deciding-vote-and-fails-the-run",
27921
+ "file": "v2-approval-reject-disposition.test.ts",
27922
+ "line": 163,
27923
+ "title": "a majority reject decides the quorum gate on the deciding vote and fails the run with approval_rejected",
27924
+ "explicitId": null,
27925
+ "citations": [
27926
+ {
27927
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27928
+ "requirement": "one reject of three under majority does not decide the gate: the run MUST stay waiting-approval"
27929
+ },
27930
+ {
27931
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27932
+ "requirement": "a vote that does not decide the gate MUST NOT emit interrupt.resolved"
27933
+ },
27934
+ {
27935
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27936
+ "requirement": null,
27937
+ "interpolated": true
27938
+ },
27939
+ {
27940
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27941
+ "requirement": "the terminal snapshot error.code MUST be approval_rejected"
27942
+ }
27943
+ ]
27944
+ },
27945
+ {
27946
+ "id": "openwop.it.v2-approval-reject-disposition.a-rejected-gate-routed-over-an-any-failed-edge-fails-as-a-node-its-all-success-s",
27947
+ "file": "v2-approval-reject-disposition.test.ts",
27948
+ "line": 186,
27949
+ "title": "a rejected gate routed over an any_failed edge fails as a node, its all_success sibling never runs, and the run completes",
27950
+ "explicitId": null,
27951
+ "citations": [
27952
+ {
27953
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27954
+ "requirement": "the routed gate still fails as a node: node.failed.error MUST carry approval_rejected and retryable false"
27955
+ },
27956
+ {
27957
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27958
+ "requirement": "the any_failed edge admits the failed gate: on-reject MUST run to node.completed"
27959
+ },
27960
+ {
27961
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27962
+ "requirement": "a rejected gate MUST NOT satisfy an all_success edge: on-accept MUST NOT run"
27963
+ },
27964
+ {
27965
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27966
+ "requirement": null,
27967
+ "interpolated": true
27968
+ }
27969
+ ]
27970
+ },
27971
+ {
27972
+ "id": "openwop.it.v2-approval-reject-disposition.an-unresolved-gate-past-its-timeoutms-with-no-ontimeout-is-resolved-rejected-by",
27973
+ "file": "v2-approval-reject-disposition.test.ts",
27974
+ "line": 205,
27975
+ "title": "an unresolved gate past its timeoutMs with no onTimeout is resolved rejected by the host and fails the run naming the gate",
27976
+ "explicitId": null,
27977
+ "citations": [
27978
+ {
27979
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27980
+ "requirement": "the host MUST resolve the timed-out gate itself, recording action \"timeout\", decision \"rejected\" and reason \"timeout\""
27981
+ },
27982
+ {
27983
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27984
+ "requirement": "the timed-out gate MUST fail with approval_rejected"
27985
+ },
27986
+ {
27987
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
27988
+ "requirement": "with no routing edge the run MUST terminate failed, run.failed carrying approval_rejected and failedNodeId naming the gate"
27989
+ }
27990
+ ]
27991
+ },
27992
+ {
27993
+ "id": "openwop.it.v2-approval-reject-disposition.a-gate-whose-ontimeout-is-approve-still-resolves-rejected-on-timeout-and-fails-t",
27994
+ "file": "v2-approval-reject-disposition.test.ts",
27995
+ "line": 224,
27996
+ "title": "a gate whose onTimeout is approve still resolves rejected on timeout and fails the run: a timeout never grants",
27997
+ "explicitId": null,
27998
+ "citations": [
27999
+ {
28000
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
28001
+ "requirement": "whatever onTimeout holds, the host MUST resolve the timed-out gate rejected (action \"timeout\", decision \"rejected\") — onTimeout \"approve\" is treated as reject"
28002
+ },
28003
+ {
28004
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
28005
+ "requirement": "the timed-out gate MUST fail with approval_rejected"
28006
+ },
28007
+ {
28008
+ "section": "spec/v2/core/interrupt.md §Rejection (RFC 0223)",
28009
+ "requirement": null,
28010
+ "interpolated": true
28011
+ }
28012
+ ]
28013
+ },
28014
+ {
28015
+ "id": "openwop.it.v2-approval-reject-disposition.a-rejected-gate-looped-back-to-itself-is-asked-again-under-a-new-key-and-the-fir",
28016
+ "file": "v2-approval-reject-disposition.test.ts",
28017
+ "line": 242,
28018
+ "title": "a rejected gate looped back to itself is asked again under a new key, and the first rejection is not replayed",
28019
+ "explicitId": null,
28020
+ "citations": [
28021
+ {
28022
+ "section": "spec/v2/core/interrupt.md §Re-entry and resume values",
28023
+ "requirement": "the second visit of the gate MUST raise a new interrupt.requested"
28024
+ },
28025
+ {
28026
+ "section": "spec/v2/core/interrupt.md §Re-entry and resume values",
28027
+ "requirement": null,
28028
+ "interpolated": true
28029
+ },
28030
+ {
28031
+ "section": "spec/v2/core/interrupt.md §Re-entry and resume values",
28032
+ "requirement": "the second visit MUST wait for a new decision: the run is waiting-approval again"
28033
+ },
28034
+ {
28035
+ "section": "spec/v2/core/interrupt.md §Re-entry and resume values",
28036
+ "requirement": "an earlier visit's resumeValue MUST NOT be returned: only the one caller resolve is recorded"
28037
+ }
28038
+ ]
28039
+ },
27716
28040
  {
27717
28041
  "id": "openwop.it.v2-approver-enforced.a-resolver-outside-approverslist-is-refused-at-resolve-time",
27718
28042
  "file": "v2-approver-enforced.test.ts",
@@ -29415,7 +29739,7 @@
29415
29739
  {
29416
29740
  "id": "openwop.it.v2-error-registry.an-error-response-is-the-closed-envelope-with-a-registered-code-at-its-registere",
29417
29741
  "file": "v2-error-registry.test.ts",
29418
- "line": 52,
29742
+ "line": 72,
29419
29743
  "title": "an error response is the closed envelope with a registered code at its registered status",
29420
29744
  "explicitId": "openwop.requirement.0171.error-registry.envelope",
29421
29745
  "citations": [
@@ -29434,7 +29758,7 @@
29434
29758
  {
29435
29759
  "id": "openwop.it.v2-error-registry.retry-timing-is-never-spelled-inside-details",
29436
29760
  "file": "v2-error-registry.test.ts",
29437
- "line": 64,
29761
+ "line": 84,
29438
29762
  "title": "retry timing is never spelled inside details",
29439
29763
  "explicitId": "openwop.requirement.0171.error-registry.no-retry-details",
29440
29764
  "citations": [
@@ -29447,7 +29771,7 @@
29447
29771
  {
29448
29772
  "id": "openwop.it.v2-error-registry.a-429-rate-limited-response-carries-retry-after",
29449
29773
  "file": "v2-error-registry.test.ts",
29450
- "line": 72,
29774
+ "line": 92,
29451
29775
  "title": "a 429 rate_limited response carries Retry-After",
29452
29776
  "explicitId": "openwop.requirement.0171.error-registry.retry-after",
29453
29777
  "citations": [
@@ -29461,6 +29785,24 @@
29461
29785
  }
29462
29786
  ]
29463
29787
  },
29788
+ {
29789
+ "id": "openwop.it.v2-error-registry.an-error-code-on-run-failed-node-failed-and-the-snapshot-is-registered-or-a-vend",
29790
+ "file": "v2-error-registry.test.ts",
29791
+ "line": 110,
29792
+ "title": "an error code on run.failed, node.failed and the snapshot is registered or a vendor code (advisory in 2.43.1)",
29793
+ "explicitId": "openwop.requirement.errors.event-code-registered",
29794
+ "citations": [
29795
+ {
29796
+ "section": "spec/v2/core/errors.md §The registry",
29797
+ "requirement": null,
29798
+ "interpolated": true
29799
+ },
29800
+ {
29801
+ "section": "spec/v2/core/errors.md §The registry",
29802
+ "requirement": "every error code on run.failed, node.failed and the snapshot MUST be registered or a vendor code"
29803
+ }
29804
+ ]
29805
+ },
29464
29806
  {
29465
29807
  "id": "openwop.it.v2-event-type-closed.every-emitted-type-is-a-registered-protocol-type-or-a-vendor-type-under-an-adver",
29466
29808
  "file": "v2-event-type-closed.test.ts",
@@ -30415,7 +30757,7 @@
30415
30757
  {
30416
30758
  "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",
30417
30759
  "file": "v2-manifest-ceiling-refused.test.ts",
30418
- "line": 105,
30760
+ "line": 117,
30419
30761
  "title": "an engines.openwop range with no upper bound (>=1.0.0) reads <2.0.0 and is refused at install with pack_engine_unsupported",
30420
30762
  "explicitId": "openwop.requirement.0177.manifest-ceiling-refused.unbounded",
30421
30763
  "citations": [
@@ -30432,7 +30774,7 @@
30432
30774
  {
30433
30775
  "id": "openwop.it.v2-manifest-ceiling-refused.a-v1-ceiling-1-0-0-2-0-0-is-refused-at-install-with-pack-engine-unsupported",
30434
30776
  "file": "v2-manifest-ceiling-refused.test.ts",
30435
- "line": 114,
30777
+ "line": 126,
30436
30778
  "title": "a v1 ceiling (>=1.0.0 <2.0.0) is refused at install with pack_engine_unsupported",
30437
30779
  "explicitId": "openwop.requirement.0177.manifest-ceiling-refused.v1-ceiling",
30438
30780
  "citations": [
@@ -30449,7 +30791,7 @@
30449
30791
  {
30450
30792
  "id": "openwop.it.v2-manifest-ceiling-refused.a-range-admitting-the-host-major-2-0-0-3-0-0-installs",
30451
30793
  "file": "v2-manifest-ceiling-refused.test.ts",
30452
- "line": 123,
30794
+ "line": 135,
30453
30795
  "title": "a range admitting the host major (>=2.0.0 <3.0.0) installs",
30454
30796
  "explicitId": "openwop.requirement.0177.manifest-ceiling-refused.v2-installs",
30455
30797
  "citations": [
@@ -30463,7 +30805,7 @@
30463
30805
  {
30464
30806
  "id": "openwop.it.v2-manifest-hatch-carried.an-x-field-inside-agents-0-of-a-node-pack-is-ignored-not-rejected-the-pack-insta",
30465
30807
  "file": "v2-manifest-hatch-carried.test.ts",
30466
- "line": 85,
30808
+ "line": 97,
30467
30809
  "title": "an x- field inside agents[0] of a node pack is ignored, not rejected — the pack installs",
30468
30810
  "explicitId": "openwop.requirement.0177.manifest-hatch-carried.agents-x-field",
30469
30811
  "citations": [
@@ -30477,7 +30819,7 @@
30477
30819
  {
30478
30820
  "id": "openwop.it.v2-manifest-hatch-carried.an-x-field-inside-a-prompt-template-of-a-prompt-pack-is-ignored-not-rejected-the",
30479
30821
  "file": "v2-manifest-hatch-carried.test.ts",
30480
- "line": 103,
30822
+ "line": 119,
30481
30823
  "title": "an x- field inside a prompt template of a prompt pack is ignored, not rejected — the pack installs",
30482
30824
  "explicitId": "openwop.requirement.0177.manifest-hatch-carried.prompt-template-x-field",
30483
30825
  "citations": [
@@ -31899,7 +32241,7 @@
31899
32241
  {
31900
32242
  "id": "openwop.it.v2-pack-isolation.sandbox-isolationmodel-names-a-real-mechanism-never-node-vm",
31901
32243
  "file": "v2-pack-isolation.test.ts",
31902
- "line": 78,
32244
+ "line": 82,
31903
32245
  "title": "sandbox.isolationModel names a real mechanism, never node:vm",
31904
32246
  "explicitId": "openwop.requirement.0173.pack-isolation",
31905
32247
  "citations": [
@@ -31917,7 +32259,7 @@
31917
32259
  {
31918
32260
  "id": "openwop.it.v2-pack-isolation.the-sandbox-invoke-seam-answers-the-seam-contract",
31919
32261
  "file": "v2-pack-isolation.test.ts",
31920
- "line": 92,
32262
+ "line": 96,
31921
32263
  "title": "the sandbox-invoke seam answers the seam contract",
31922
32264
  "explicitId": "openwop.requirement.0173.pack-isolation.seam",
31923
32265
  "citations": [
@@ -31931,7 +32273,7 @@
31931
32273
  {
31932
32274
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-fs-gated-a-host-filesystem-read-is-refused",
31933
32275
  "file": "v2-pack-isolation.test.ts",
31934
- "line": 104,
32276
+ "line": 108,
31935
32277
  "title": "node-pack-sandbox-fs-gated: a host filesystem read is refused",
31936
32278
  "explicitId": null,
31937
32279
  "citations": []
@@ -31939,7 +32281,7 @@
31939
32281
  {
31940
32282
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-fs-gated-a-host-filesystem-write-is-refused",
31941
32283
  "file": "v2-pack-isolation.test.ts",
31942
- "line": 111,
32284
+ "line": 115,
31943
32285
  "title": "node-pack-sandbox-fs-gated: a host filesystem write is refused",
31944
32286
  "explicitId": null,
31945
32287
  "citations": []
@@ -31947,7 +32289,7 @@
31947
32289
  {
31948
32290
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-no-env-the-host-environment-does-not-leak",
31949
32291
  "file": "v2-pack-isolation.test.ts",
31950
- "line": 118,
32292
+ "line": 122,
31951
32293
  "title": "node-pack-sandbox-no-env: the host environment does not leak",
31952
32294
  "explicitId": null,
31953
32295
  "citations": []
@@ -31955,7 +32297,7 @@
31955
32297
  {
31956
32298
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-network-gated-ungated-network-egress-is-refused",
31957
32299
  "file": "v2-pack-isolation.test.ts",
31958
- "line": 125,
32300
+ "line": 129,
31959
32301
  "title": "node-pack-sandbox-network-gated: ungated network egress is refused",
31960
32302
  "explicitId": null,
31961
32303
  "citations": []
@@ -31963,7 +32305,7 @@
31963
32305
  {
31964
32306
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-no-process-host-process-access-is-refused",
31965
32307
  "file": "v2-pack-isolation.test.ts",
31966
- "line": 132,
32308
+ "line": 136,
31967
32309
  "title": "node-pack-sandbox-no-process: host process access is refused",
31968
32310
  "explicitId": null,
31969
32311
  "citations": []
@@ -31971,7 +32313,7 @@
31971
32313
  {
31972
32314
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-timeout-exceeding-wallclocklimitms-fails-with-sandbox-timeout",
31973
32315
  "file": "v2-pack-isolation.test.ts",
31974
- "line": 139,
32316
+ "line": 143,
31975
32317
  "title": "node-pack-sandbox-timeout: exceeding wallClockLimitMs fails with sandbox_timeout",
31976
32318
  "explicitId": "openwop.requirement.0173.pack-isolation.timeout",
31977
32319
  "citations": [
@@ -31984,7 +32326,7 @@
31984
32326
  {
31985
32327
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-memory-cap-exceeding-memorylimitbytes-fails-with-sandbox-memor",
31986
32328
  "file": "v2-pack-isolation.test.ts",
31987
- "line": 146,
32329
+ "line": 150,
31988
32330
  "title": "node-pack-sandbox-memory-cap: exceeding memoryLimitBytes fails with sandbox_memory_exceeded",
31989
32331
  "explicitId": "openwop.requirement.0173.pack-isolation.memory-cap",
31990
32332
  "citations": [
@@ -31997,7 +32339,7 @@
31997
32339
  {
31998
32340
  "id": "openwop.it.v2-pack-isolation.node-pack-sandbox-isolated-context-a-pack-cannot-mutate-state-another-invocation",
31999
32341
  "file": "v2-pack-isolation.test.ts",
32000
- "line": 153,
32342
+ "line": 157,
32001
32343
  "title": "node-pack-sandbox-isolated-context: a pack cannot mutate state another invocation sees",
32002
32344
  "explicitId": "openwop.requirement.0173.pack-isolation.isolated-context",
32003
32345
  "citations": [
@@ -32142,7 +32484,7 @@
32142
32484
  {
32143
32485
  "id": "openwop.it.v2-peer-dependency-declared.a-peerdependencies-key-the-declaration-file-does-not-name-is-refused-with-pack-p",
32144
32486
  "file": "v2-peer-dependency-declared.test.ts",
32145
- "line": 104,
32487
+ "line": 116,
32146
32488
  "title": "a peerDependencies key the declaration file does not name is refused with pack_peer_dependency_undefined",
32147
32489
  "explicitId": "openwop.requirement.0177.peer-dependency-declared.undefined-key",
32148
32490
  "citations": [
@@ -32159,7 +32501,7 @@
32159
32501
  {
32160
32502
  "id": "openwop.it.v2-peer-dependency-declared.an-alias-table-row-host-fs-fs-resolves-through-the-overlap-and-the-pack-installs",
32161
32503
  "file": "v2-peer-dependency-declared.test.ts",
32162
- "line": 113,
32504
+ "line": 125,
32163
32505
  "title": "an alias-table row (host.fs → fs) resolves through the overlap and the pack installs",
32164
32506
  "explicitId": "openwop.requirement.0177.peer-dependency-declared.alias-overlap",
32165
32507
  "citations": [
@@ -32594,6 +32936,56 @@
32594
32936
  }
32595
32937
  ]
32596
32938
  },
32939
+ {
32940
+ "id": "openwop.it.v2-registry-lifecycle.a-yanked-version-is-never-latest-while-an-unyanked-one-exists-the-flags-agree-ac",
32941
+ "file": "v2-registry-lifecycle.test.ts",
32942
+ "line": 130,
32943
+ "title": "a yanked version is never latest while an unyanked one exists, the flags agree across index and manifest, and a yanked version stays served",
32944
+ "explicitId": "openwop.requirement.0222.yanked-version-lifecycle",
32945
+ "citations": [
32946
+ {
32947
+ "section": "RFC 0222 · packs.md §\"Version manifests\"",
32948
+ "requirement": null,
32949
+ "interpolated": true
32950
+ },
32951
+ {
32952
+ "section": "RFC 0222 · packs.md §\"Version manifests\"",
32953
+ "requirement": "the per-pack index MUST NOT name a yanked version latest while an unyanked one exists, and the index MUST agree with each version manifest"
32954
+ },
32955
+ {
32956
+ "section": "RFC 0222 · packs.md §\"Version manifests\"",
32957
+ "requirement": null,
32958
+ "interpolated": true
32959
+ }
32960
+ ]
32961
+ },
32962
+ {
32963
+ "id": "openwop.it.v2-registry-lifecycle.every-served-version-names-a-listed-key-whose-permittednamespaces-admit-it-and-i",
32964
+ "file": "v2-registry-lifecycle.test.ts",
32965
+ "line": 177,
32966
+ "title": "every served version names a listed key whose permittedNamespaces admit it, and its signature verifies — whatever the key status",
32967
+ "explicitId": "openwop.requirement.0222.signing-keys-cover-served-versions",
32968
+ "citations": [
32969
+ {
32970
+ "section": "RFC 0222 · packs.md §Signing",
32971
+ "requirement": null,
32972
+ "interpolated": true
32973
+ },
32974
+ {
32975
+ "section": "RFC 0222 · packs.md §Signing",
32976
+ "requirement": "every signingKeys[] entry MUST carry keyId, publicKeyUrl, status and permittedNamespaces"
32977
+ },
32978
+ {
32979
+ "section": "RFC 0222 · packs.md §Signing",
32980
+ "requirement": "the v2 tree MUST serve at least one version manifest to witness"
32981
+ },
32982
+ {
32983
+ "section": "RFC 0222 · packs.md §Signing",
32984
+ "requirement": null,
32985
+ "interpolated": true
32986
+ }
32987
+ ]
32988
+ },
32597
32989
  {
32598
32990
  "id": "openwop.it.v2-relaxation-recorded.a-bundle-recording-a-relaxation-cannot-certify-the-relaxed-profile",
32599
32991
  "file": "v2-relaxation-recorded.test.ts",
@@ -34206,7 +34598,7 @@
34206
34598
  {
34207
34599
  "id": "openwop.it.v2-webhook-secret-rotation.a-rotation-dual-signs-for-overlapseconds-keeps-openwop-signature-on-the-previous",
34208
34600
  "file": "v2-webhook-secret-rotation.test.ts",
34209
- "line": 67,
34601
+ "line": 76,
34210
34602
  "title": "a rotation dual-signs for overlapSeconds, keeps OpenWOP-Signature on the previous secret, and is tenant-checked",
34211
34603
  "explicitId": "openwop.requirement.0201.secret-rotation",
34212
34604
  "citations": [
@@ -42161,7 +42553,7 @@
42161
42553
  {
42162
42554
  "id": "openwop.it.v2-error-registry-prose-parity.errors-md-states-the-registry-count-it-was-generated-from-and-renders-every-code",
42163
42555
  "file": "v2-error-registry-prose-parity.test.ts",
42164
- "line": 26,
42556
+ "line": 35,
42165
42557
  "title": "errors.md states the registry count it was generated from and renders every code",
42166
42558
  "explicitId": "openwop.requirement.0171.error-registry-prose-parity",
42167
42559
  "citations": [
@@ -42181,6 +42573,34 @@
42181
42573
  }
42182
42574
  ]
42183
42575
  },
42576
+ {
42577
+ "id": "openwop.it.v2-error-registry-prose-parity.approval-rejected-is-a-registered-422-not-retriable-and-interrupt-md-rejection-n",
42578
+ "file": "v2-error-registry-prose-parity.test.ts",
42579
+ "line": 67,
42580
+ "title": "approval_rejected is a registered 422, not retriable, and interrupt.md §Rejection names it",
42581
+ "explicitId": "openwop.requirement.0223.code-registered",
42582
+ "citations": [
42583
+ {
42584
+ "section": "spec/v2/errors.json",
42585
+ "requirement": null,
42586
+ "interpolated": true
42587
+ },
42588
+ {
42589
+ "section": "spec/v2/errors.json",
42590
+ "requirement": null,
42591
+ "interpolated": true
42592
+ },
42593
+ {
42594
+ "section": "spec/v2/core/interrupt.md §Rejection",
42595
+ "requirement": null,
42596
+ "interpolated": true
42597
+ },
42598
+ {
42599
+ "section": "schemas/v2/suspend-request.schema.json ApprovalData.onTimeout",
42600
+ "requirement": "onTimeout MUST exist and declare no default — absent means reject by prose (RFC 0223)"
42601
+ }
42602
+ ]
42603
+ },
42184
42604
  {
42185
42605
  "id": "openwop.it.v2-event-naming-rule.every-closed-enum-v2-event-type-is-two-kebab-segments-and-every-recorded-artifac",
42186
42606
  "file": "v2-event-naming-rule.test.ts",
@@ -43029,9 +43449,86 @@
43029
43449
  ]
43030
43450
  },
43031
43451
  {
43032
- "id": "openwop.it.v2-surface-monotone-gate.an-open-object-closed-to-additionalproperties-false-is-refused-b-6",
43452
+ "id": "openwop.it.v2-surface-monotone-gate.positive-control-a-required-under-a-then-selecting-only-enum-members-this-diff-a",
43033
43453
  "file": "v2-surface-monotone-gate.test.ts",
43034
43454
  "line": 156,
43455
+ "title": "POSITIVE CONTROL — a `required` under a `then` selecting only enum members this diff adds is additive",
43456
+ "explicitId": "openwop.requirement.0197.no-reshape",
43457
+ "citations": [
43458
+ {
43459
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43460
+ "requirement": null,
43461
+ "interpolated": true
43462
+ },
43463
+ {
43464
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43465
+ "requirement": "the gate must say it admitted the conditional, not pass it silently"
43466
+ }
43467
+ ]
43468
+ },
43469
+ {
43470
+ "id": "openwop.it.v2-surface-monotone-gate.a-required-under-a-then-an-existing-enum-value-selects-is-refused-b-6",
43471
+ "file": "v2-surface-monotone-gate.test.ts",
43472
+ "line": 171,
43473
+ "title": "a `required` under a `then` an EXISTING enum value selects is REFUSED (§B.6)",
43474
+ "explicitId": "openwop.requirement.0197.no-reshape",
43475
+ "citations": [
43476
+ {
43477
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43478
+ "requirement": null,
43479
+ "interpolated": true
43480
+ },
43481
+ {
43482
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43483
+ "requirement": "the refusal must name the property and the object"
43484
+ }
43485
+ ]
43486
+ },
43487
+ {
43488
+ "id": "openwop.it.v2-surface-monotone-gate.a-then-pinning-only-a-pre-existing-value-or-pinning-nothing-required-licenses-no",
43489
+ "file": "v2-surface-monotone-gate.test.ts",
43490
+ "line": 186,
43491
+ "title": "a `then` pinning only a PRE-EXISTING value, or pinning nothing required, licenses nothing",
43492
+ "explicitId": "openwop.requirement.0197.no-reshape",
43493
+ "citations": [
43494
+ {
43495
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43496
+ "requirement": null,
43497
+ "interpolated": true
43498
+ },
43499
+ {
43500
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43501
+ "requirement": null,
43502
+ "interpolated": true
43503
+ },
43504
+ {
43505
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43506
+ "requirement": "the refusal must name the property and the object"
43507
+ }
43508
+ ]
43509
+ },
43510
+ {
43511
+ "id": "openwop.it.v2-surface-monotone-gate.a-new-value-conditional-does-not-launder-an-unconditional-required-beside-it",
43512
+ "file": "v2-surface-monotone-gate.test.ts",
43513
+ "line": 204,
43514
+ "title": "a new-value conditional does not launder an UNCONDITIONAL `required` beside it",
43515
+ "explicitId": "openwop.requirement.0197.no-reshape",
43516
+ "citations": [
43517
+ {
43518
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43519
+ "requirement": null,
43520
+ "interpolated": true
43521
+ },
43522
+ {
43523
+ "section": "spec/v2/core/overview.md §0a (RFC 0197 §A.1)",
43524
+ "requirement": "the refusal must name the unconditional property"
43525
+ }
43526
+ ]
43527
+ },
43528
+ {
43529
+ "id": "openwop.it.v2-surface-monotone-gate.an-open-object-closed-to-additionalproperties-false-is-refused-b-6",
43530
+ "file": "v2-surface-monotone-gate.test.ts",
43531
+ "line": 218,
43035
43532
  "title": "an OPEN object closed to `additionalProperties: false` is REFUSED (§B.6)",
43036
43533
  "explicitId": "openwop.requirement.0197.no-reshape",
43037
43534
  "citations": [
@@ -43049,7 +43546,7 @@
43049
43546
  {
43050
43547
  "id": "openwop.it.v2-surface-monotone-gate.a-narrowed-type-is-refused-a-1-add-the-new-shape-beside-the-old-one",
43051
43548
  "file": "v2-surface-monotone-gate.test.ts",
43052
- "line": 163,
43549
+ "line": 225,
43053
43550
  "title": "a narrowed `type` is REFUSED (§A.1 — add the new shape beside the old one)",
43054
43551
  "explicitId": "openwop.requirement.0197.no-reshape",
43055
43552
  "citations": [
@@ -43067,7 +43564,7 @@
43067
43564
  {
43068
43565
  "id": "openwop.it.v2-surface-monotone-gate.a-removed-operation-is-refused-a-path-manifest-row-is-a-surface-too",
43069
43566
  "file": "v2-surface-monotone-gate.test.ts",
43070
- "line": 170,
43567
+ "line": 232,
43071
43568
  "title": "a removed OPERATION is REFUSED (a path-manifest row is a surface too)",
43072
43569
  "explicitId": "openwop.requirement.0197.no-reshape",
43073
43570
  "citations": [