@openwop/openwop-conformance 1.162.0 → 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (553) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +54 -1
  3. package/dist/lib/paths.js +25 -3
  4. package/dist/lib/requirement-ids.js +34 -4
  5. package/dist/lib/scenario-disposition.js +1 -0
  6. package/dist/lib/spec-coherence.js +13 -32
  7. package/dist/spec-artifacts.lock.json +5 -0
  8. package/package.json +11 -33
  9. package/requirements.json +20303 -11809
  10. package/scenario-majors.json +1343 -0
  11. package/schemas/CORPUS-STAMP.json +138 -6
  12. package/src/cli.ts +47 -1
  13. package/src/global-setup.ts +3 -2
  14. package/src/lib/corpus-stamp.ts +29 -1
  15. package/src/lib/paths.ts +25 -3
  16. package/src/lib/requirement-ids.ts +33 -4
  17. package/src/lib/scenario-disposition.ts +1 -0
  18. package/src/lib/spec-coherence.ts +15 -32
  19. package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
  20. package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
  21. package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
  22. package/src/scenarios/a2a-peer-authority.test.ts +7 -6
  23. package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
  24. package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
  25. package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
  26. package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
  27. package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
  28. package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
  29. package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
  30. package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
  31. package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
  32. package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
  33. package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
  34. package/src/scenarios/agent-deployment-shape.test.ts +22 -24
  35. package/src/scenarios/agent-eval-run.test.ts +19 -18
  36. package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
  37. package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
  38. package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
  39. package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
  40. package/src/scenarios/agent-live-structured-output.test.ts +7 -6
  41. package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
  42. package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
  43. package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
  44. package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
  45. package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
  46. package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
  47. package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
  48. package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
  49. package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
  50. package/src/scenarios/agent-platform-profile.test.ts +18 -19
  51. package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
  52. package/src/scenarios/agent-roster-attribution.test.ts +18 -17
  53. package/src/scenarios/agent-roster-shape.test.ts +17 -19
  54. package/src/scenarios/agent-verifier-shape.test.ts +11 -11
  55. package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
  56. package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
  57. package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
  58. package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
  59. package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
  60. package/src/scenarios/agentMessageReducer.test.ts +2 -1
  61. package/src/scenarios/agentMetadata.test.ts +2 -1
  62. package/src/scenarios/agentPackCatalog.test.ts +23 -21
  63. package/src/scenarios/agentPackExport.test.ts +4 -2
  64. package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
  65. package/src/scenarios/agentPackInstall.test.ts +4 -2
  66. package/src/scenarios/agentPackProvenance.test.ts +2 -1
  67. package/src/scenarios/agentReasoningEvents.test.ts +3 -2
  68. package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
  69. package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
  70. package/src/scenarios/ai-envelope-shape.test.ts +31 -29
  71. package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
  72. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
  73. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
  74. package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
  75. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
  76. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
  77. package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
  78. package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
  79. package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
  80. package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
  81. package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
  82. package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
  83. package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
  84. package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
  85. package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
  86. package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
  87. package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
  88. package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
  89. package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
  90. package/src/scenarios/append-ordering.test.ts +7 -5
  91. package/src/scenarios/approval-gate-events.test.ts +4 -3
  92. package/src/scenarios/approval-gate-flow.test.ts +4 -3
  93. package/src/scenarios/approval-payload.test.ts +5 -4
  94. package/src/scenarios/artifact-auth.test.ts +7 -6
  95. package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
  96. package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
  97. package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
  98. package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
  99. package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
  100. package/src/scenarios/audit-log-integrity.test.ts +8 -6
  101. package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
  102. package/src/scenarios/auth-mtls.test.ts +22 -20
  103. package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
  104. package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
  105. package/src/scenarios/auth-saml-profile.test.ts +14 -12
  106. package/src/scenarios/auth-scim-profile.test.ts +3 -2
  107. package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
  108. package/src/scenarios/auth-subject-link.test.ts +11 -10
  109. package/src/scenarios/auth.test.ts +5 -4
  110. package/src/scenarios/authorization-fail-closed.test.ts +3 -2
  111. package/src/scenarios/authorization-roles-shape.test.ts +9 -7
  112. package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
  113. package/src/scenarios/blob-presign-expiry.test.ts +12 -10
  114. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  115. package/src/scenarios/budget-enforcement.test.ts +15 -14
  116. package/src/scenarios/budget-policy-shape.test.ts +18 -19
  117. package/src/scenarios/bulk-cancel.test.ts +9 -8
  118. package/src/scenarios/byok-auth-modes.test.ts +13 -14
  119. package/src/scenarios/byok-roundtrip.test.ts +12 -10
  120. package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
  121. package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
  122. package/src/scenarios/callai-multimodal.test.ts +5 -3
  123. package/src/scenarios/cancellation.test.ts +6 -5
  124. package/src/scenarios/cap-breach.test.ts +15 -14
  125. package/src/scenarios/capability-arm-witness.test.ts +5 -3
  126. package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
  127. package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
  128. package/src/scenarios/certification-bundle-v2.test.ts +11 -10
  129. package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
  130. package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
  131. package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
  132. package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
  133. package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
  134. package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
  135. package/src/scenarios/channel-presence-shape.test.ts +11 -12
  136. package/src/scenarios/channel-ttl.test.ts +6 -5
  137. package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
  138. package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
  139. package/src/scenarios/commitment-fired.test.ts +6 -5
  140. package/src/scenarios/compensation-behavior.test.ts +24 -23
  141. package/src/scenarios/compensation-recovery.test.ts +28 -27
  142. package/src/scenarios/configurable-schema.test.ts +8 -6
  143. package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
  144. package/src/scenarios/conformance-execution-witness.test.ts +9 -8
  145. package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
  146. package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
  147. package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
  148. package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
  149. package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
  150. package/src/scenarios/connection-provider-resolution.test.ts +18 -16
  151. package/src/scenarios/connector-manifest-validity.test.ts +8 -7
  152. package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
  153. package/src/scenarios/context-summarization-replay.test.ts +14 -12
  154. package/src/scenarios/contract-provenance.test.ts +18 -18
  155. package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
  156. package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
  157. package/src/scenarios/conversationLifecycle.test.ts +2 -1
  158. package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
  159. package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
  160. package/src/scenarios/core-standard-profile.test.ts +8 -9
  161. package/src/scenarios/cost-attribution.test.ts +23 -21
  162. package/src/scenarios/credential-payload-redaction.test.ts +4 -3
  163. package/src/scenarios/credentials-capability-shape.test.ts +5 -4
  164. package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
  165. package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
  166. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
  167. package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
  168. package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
  169. package/src/scenarios/data-residency-admission.test.ts +15 -14
  170. package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
  171. package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
  172. package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
  173. package/src/scenarios/debugBundle.test.ts +25 -23
  174. package/src/scenarios/discovery-families-view.test.ts +5 -4
  175. package/src/scenarios/discovery.test.ts +30 -29
  176. package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
  177. package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
  178. package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
  179. package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
  180. package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
  181. package/src/scenarios/dispatchLoop.test.ts +3 -2
  182. package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
  183. package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
  184. package/src/scenarios/distillation-shape.test.ts +4 -4
  185. package/src/scenarios/distillation-stable-archive.test.ts +6 -6
  186. package/src/scenarios/distillation-token-budget.test.ts +5 -5
  187. package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
  188. package/src/scenarios/egress-audience-binding.test.ts +11 -10
  189. package/src/scenarios/egress-decision-content-free.test.ts +6 -5
  190. package/src/scenarios/egress-provenance-shape.test.ts +17 -18
  191. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
  192. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
  193. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
  194. package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
  195. package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
  196. package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
  197. package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
  198. package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
  199. package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
  200. package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
  201. package/src/scenarios/envelope-truncated.test.ts +19 -17
  202. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
  203. package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
  204. package/src/scenarios/errors.test.ts +20 -19
  205. package/src/scenarios/eventOrdering.test.ts +16 -14
  206. package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
  207. package/src/scenarios/experimental-tier-shape.test.ts +17 -15
  208. package/src/scenarios/export-bundle-portability.test.ts +17 -17
  209. package/src/scenarios/failure-path.test.ts +7 -6
  210. package/src/scenarios/feedback-capability-shape.test.ts +4 -3
  211. package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
  212. package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
  213. package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
  214. package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
  215. package/src/scenarios/feedback-record-and-list.test.ts +2 -1
  216. package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
  217. package/src/scenarios/fixtures-gating.test.ts +29 -28
  218. package/src/scenarios/fixtures-valid.test.ts +16 -15
  219. package/src/scenarios/form-content-instantiation.test.ts +15 -14
  220. package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
  221. package/src/scenarios/fs-path-traversal.test.ts +14 -12
  222. package/src/scenarios/goal-standing-continuation.test.ts +21 -21
  223. package/src/scenarios/grpc-transport.test.ts +9 -7
  224. package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
  225. package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
  226. package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
  227. package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
  228. package/src/scenarios/highConcurrency.test.ts +14 -13
  229. package/src/scenarios/host-callback-declaration.test.ts +8 -7
  230. package/src/scenarios/http-client-ssrf.test.ts +7 -5
  231. package/src/scenarios/i18n-negotiation.test.ts +14 -12
  232. package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
  233. package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
  234. package/src/scenarios/idempotency.test.ts +8 -7
  235. package/src/scenarios/idempotencyRetry.test.ts +13 -11
  236. package/src/scenarios/identity-owner-shape.test.ts +6 -5
  237. package/src/scenarios/identity-passthrough.test.ts +4 -3
  238. package/src/scenarios/interrupt-approval.test.ts +6 -5
  239. package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
  240. package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
  241. package/src/scenarios/interrupt-clarification.test.ts +4 -3
  242. package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
  243. package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
  244. package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
  245. package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
  246. package/src/scenarios/interruptRace.test.ts +12 -10
  247. package/src/scenarios/kv-atomic-increment.test.ts +11 -9
  248. package/src/scenarios/kv-cas.test.ts +14 -12
  249. package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
  250. package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
  251. package/src/scenarios/localized-content-delivery.test.ts +24 -26
  252. package/src/scenarios/maliciousManifest.test.ts +10 -8
  253. package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
  254. package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
  255. package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
  256. package/src/scenarios/mcp-discoverability.test.ts +9 -7
  257. package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
  258. package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
  259. package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
  260. package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
  261. package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
  262. package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
  263. package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
  264. package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
  265. package/src/scenarios/mcp-stateless-request.test.ts +11 -10
  266. package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
  267. package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
  268. package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
  269. package/src/scenarios/media-url-inline-cap.test.ts +21 -19
  270. package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
  271. package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
  272. package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
  273. package/src/scenarios/memory-attribution-shape.test.ts +4 -3
  274. package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
  275. package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
  276. package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
  277. package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
  278. package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
  279. package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
  280. package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
  281. package/src/scenarios/memory-degraded-projection.test.ts +10 -9
  282. package/src/scenarios/memory-injection-budget.test.ts +15 -14
  283. package/src/scenarios/metric-emission.test.ts +4 -3
  284. package/src/scenarios/model-capability-insufficient.test.ts +19 -17
  285. package/src/scenarios/model-capability-substituted.test.ts +20 -18
  286. package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
  287. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
  288. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
  289. package/src/scenarios/multi-node-ordering.test.ts +4 -3
  290. package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
  291. package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
  292. package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
  293. package/src/scenarios/multi-region-idempotency.test.ts +6 -5
  294. package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
  295. package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
  296. package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
  297. package/src/scenarios/oauth-capability-shape.test.ts +5 -4
  298. package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
  299. package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
  300. package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
  301. package/src/scenarios/orchestratorDispatch.test.ts +2 -1
  302. package/src/scenarios/orchestratorTermination.test.ts +2 -1
  303. package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
  304. package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
  305. package/src/scenarios/otel-emission-grpc.test.ts +3 -2
  306. package/src/scenarios/otel-emission.test.ts +6 -5
  307. package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
  308. package/src/scenarios/otel-trace-propagation.test.ts +2 -1
  309. package/src/scenarios/owner-subject-echo.test.ts +13 -12
  310. package/src/scenarios/owner-subject-shape.test.ts +11 -10
  311. package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
  312. package/src/scenarios/pack-registry-isolation.test.ts +4 -3
  313. package/src/scenarios/pack-registry-publish.test.ts +65 -63
  314. package/src/scenarios/pack-registry.test.ts +38 -36
  315. package/src/scenarios/pause-resume.test.ts +18 -16
  316. package/src/scenarios/policies.test.ts +20 -18
  317. package/src/scenarios/production-backpressure.test.ts +18 -16
  318. package/src/scenarios/production-retention-expiry.test.ts +8 -6
  319. package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
  320. package/src/scenarios/profileDerivation.test.ts +34 -33
  321. package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
  322. package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
  323. package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
  324. package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
  325. package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
  326. package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
  327. package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
  328. package/src/scenarios/prompt-pack-install.test.ts +14 -12
  329. package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
  330. package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
  331. package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
  332. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
  333. package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
  334. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
  335. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
  336. package/src/scenarios/prompt-template-shape.test.ts +30 -28
  337. package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
  338. package/src/scenarios/protocol-versions-array.test.ts +10 -9
  339. package/src/scenarios/provider-usage.test.ts +17 -15
  340. package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
  341. package/src/scenarios/purpose-propagation.test.ts +23 -21
  342. package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
  343. package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
  344. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
  345. package/src/scenarios/rate-limit-envelope.test.ts +6 -5
  346. package/src/scenarios/redaction.test.ts +13 -11
  347. package/src/scenarios/redactionAdversarial.test.ts +11 -9
  348. package/src/scenarios/registry-public.test.ts +12 -11
  349. package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
  350. package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
  351. package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
  352. package/src/scenarios/replay-fork.test.ts +20 -19
  353. package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
  354. package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
  355. package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
  356. package/src/scenarios/replay-retention-expiry.test.ts +11 -9
  357. package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
  358. package/src/scenarios/replayDeterminism.test.ts +13 -12
  359. package/src/scenarios/requirement-ledger.test.ts +15 -14
  360. package/src/scenarios/restart-during-run.test.ts +3 -2
  361. package/src/scenarios/route-coverage.test.ts +20 -19
  362. package/src/scenarios/run-diff.test.ts +22 -20
  363. package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
  364. package/src/scenarios/run-transport-economy.test.ts +13 -11
  365. package/src/scenarios/runner-ledger.test.ts +17 -16
  366. package/src/scenarios/runs-lifecycle.test.ts +7 -6
  367. package/src/scenarios/runtime-capabilities.test.ts +12 -10
  368. package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
  369. package/src/scenarios/runtime-requires-shape.test.ts +7 -6
  370. package/src/scenarios/safefetch-behavior.test.ts +22 -21
  371. package/src/scenarios/safefetch-live-audit.test.ts +14 -13
  372. package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
  373. package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
  374. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
  375. package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
  376. package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
  377. package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
  378. package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
  379. package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
  380. package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
  381. package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
  382. package/src/scenarios/self-hosted-runner.test.ts +26 -24
  383. package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
  384. package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
  385. package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
  386. package/src/scenarios/sql-injection-rejection.test.ts +8 -6
  387. package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
  388. package/src/scenarios/staleClaim.test.ts +5 -4
  389. package/src/scenarios/stream-modes-buffer.test.ts +8 -7
  390. package/src/scenarios/stream-modes-mixed.test.ts +10 -9
  391. package/src/scenarios/stream-modes.test.ts +12 -11
  392. package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
  393. package/src/scenarios/stream-text-fixture.test.ts +14 -13
  394. package/src/scenarios/streamReconnect.test.ts +13 -11
  395. package/src/scenarios/strict-behavior-gate.test.ts +9 -8
  396. package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
  397. package/src/scenarios/subrun-approval-gate.test.ts +3 -3
  398. package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
  399. package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
  400. package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
  401. package/src/scenarios/subworkflow.test.ts +10 -9
  402. package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
  403. package/src/scenarios/table-cursor-pagination.test.ts +8 -6
  404. package/src/scenarios/table-schema-enforcement.test.ts +7 -5
  405. package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
  406. package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
  407. package/src/scenarios/tool-catalog-projection.test.ts +11 -9
  408. package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
  409. package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
  410. package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
  411. package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
  412. package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
  413. package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
  414. package/src/scenarios/tool-hooks-shape.test.ts +3 -3
  415. package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
  416. package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
  417. package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
  418. package/src/scenarios/trigger-ingestion.test.ts +19 -17
  419. package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
  420. package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
  421. package/src/scenarios/verifier-gating.test.ts +8 -6
  422. package/src/scenarios/version-fold.test.ts +9 -8
  423. package/src/scenarios/version-negotiation.test.ts +12 -11
  424. package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
  425. package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
  426. package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
  427. package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
  428. package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
  429. package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
  430. package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
  431. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
  432. package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
  433. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
  434. package/src/scenarios/wasm-pack-load.test.ts +4 -3
  435. package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
  436. package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
  437. package/src/scenarios/webhook-negative.test.ts +11 -9
  438. package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
  439. package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
  440. package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
  441. package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
  442. package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
  443. package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
  444. package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
  445. package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
  446. package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
  447. package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
  448. package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
  449. package/src/scenarios/workflow-variable-format.test.ts +24 -24
  450. package/src/scenarios/workload-identity-behavior.test.ts +15 -13
  451. package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
  452. package/src/scenarios/workspace-behavior.test.ts +19 -18
  453. package/src/scenarios/workspace-capability-shape.test.ts +3 -2
  454. package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
  455. package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
  456. package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
  457. package/src/setup.ts +4 -2
  458. package/vitest.config.ts +5 -1
  459. package/api/.redocly.lint-ignore.yaml +0 -22
  460. package/api/asyncapi.yaml +0 -834
  461. package/api/grpc/openwop.proto +0 -251
  462. package/api/openapi.yaml +0 -2693
  463. package/api/redocly.yaml +0 -23
  464. package/schemas/README.md +0 -144
  465. package/schemas/a2a-task-state.schema.json +0 -78
  466. package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
  467. package/schemas/agent-deployment-transition.schema.json +0 -49
  468. package/schemas/agent-deployment.schema.json +0 -54
  469. package/schemas/agent-eval-suite.schema.json +0 -140
  470. package/schemas/agent-inventory-response.schema.json +0 -115
  471. package/schemas/agent-manifest.schema.json +0 -156
  472. package/schemas/agent-org-chart.schema.json +0 -82
  473. package/schemas/agent-ref.schema.json +0 -63
  474. package/schemas/agent-roster-entry.schema.json +0 -81
  475. package/schemas/agent-roster-response.schema.json +0 -21
  476. package/schemas/ai-envelope.schema.json +0 -134
  477. package/schemas/annotation-create.schema.json +0 -37
  478. package/schemas/annotation.schema.json +0 -56
  479. package/schemas/artifact-type-pack-manifest.schema.json +0 -244
  480. package/schemas/audit-verify-result.schema.json +0 -90
  481. package/schemas/budget-policy.schema.json +0 -18
  482. package/schemas/capabilities.schema.json +0 -4124
  483. package/schemas/certification-bundle-v2.schema.json +0 -118
  484. package/schemas/channel-presence-payload.schema.json +0 -41
  485. package/schemas/channel-written-payload.schema.json +0 -55
  486. package/schemas/chat-card-pack-manifest.schema.json +0 -253
  487. package/schemas/compact-tool-descriptor.schema.json +0 -51
  488. package/schemas/compensation-policy.schema.json +0 -64
  489. package/schemas/conformance-certification-bundle.schema.json +0 -86
  490. package/schemas/connection-pack-manifest.schema.json +0 -353
  491. package/schemas/conversation-event.schema.json +0 -168
  492. package/schemas/conversation-turn.schema.json +0 -117
  493. package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
  494. package/schemas/credential-provenance.schema.json +0 -18
  495. package/schemas/credential-reference.schema.json +0 -21
  496. package/schemas/debug-bundle.schema.json +0 -196
  497. package/schemas/dispatch-config.schema.json +0 -112
  498. package/schemas/envelopes/clarification.request.schema.json +0 -52
  499. package/schemas/envelopes/error.schema.json +0 -30
  500. package/schemas/envelopes/media.audio.schema.json +0 -38
  501. package/schemas/envelopes/media.file.schema.json +0 -37
  502. package/schemas/envelopes/media.image.schema.json +0 -33
  503. package/schemas/envelopes/schema.request.schema.json +0 -26
  504. package/schemas/envelopes/schema.response.schema.json +0 -22
  505. package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
  506. package/schemas/error-envelope.schema.json +0 -25
  507. package/schemas/eval-summary.schema.json +0 -92
  508. package/schemas/export-bundle.schema.json +0 -66
  509. package/schemas/form-content-pack-manifest.schema.json +0 -243
  510. package/schemas/frontend-plugin-manifest.schema.json +0 -109
  511. package/schemas/goal.schema.json +0 -104
  512. package/schemas/heartbeat-evaluated.schema.json +0 -14
  513. package/schemas/heartbeat-state-changed.schema.json +0 -14
  514. package/schemas/localized-content-language-settings.schema.json +0 -26
  515. package/schemas/localized-content-page-response.schema.json +0 -60
  516. package/schemas/localized-content-page.schema.json +0 -62
  517. package/schemas/localized-content-section.schema.json +0 -51
  518. package/schemas/memory-entry.schema.json +0 -36
  519. package/schemas/memory-list-options.schema.json +0 -37
  520. package/schemas/node-pack-manifest.schema.json +0 -654
  521. package/schemas/orchestrator-decision.schema.json +0 -90
  522. package/schemas/org-chart-responsibility-view.schema.json +0 -26
  523. package/schemas/pack-lockfile.schema.json +0 -108
  524. package/schemas/prompt-kind.schema.json +0 -8
  525. package/schemas/prompt-pack-manifest.schema.json +0 -117
  526. package/schemas/prompt-ref.schema.json +0 -40
  527. package/schemas/prompt-template.schema.json +0 -149
  528. package/schemas/proposal.schema.json +0 -84
  529. package/schemas/registry-version-manifest.schema.json +0 -208
  530. package/schemas/residency.schema.json +0 -16
  531. package/schemas/run-ancestry-response.schema.json +0 -54
  532. package/schemas/run-diff-response.schema.json +0 -64
  533. package/schemas/run-event-payloads.schema.json +0 -4452
  534. package/schemas/run-event.schema.json +0 -211
  535. package/schemas/run-options.schema.json +0 -80
  536. package/schemas/run-orchestrator-decided-event.schema.json +0 -20
  537. package/schemas/run-snapshot.schema.json +0 -148
  538. package/schemas/security-advisory.schema.json +0 -109
  539. package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
  540. package/schemas/self-hosted-runner-registration.schema.json +0 -53
  541. package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
  542. package/schemas/subject.schema.json +0 -56
  543. package/schemas/suspend-request.schema.json +0 -207
  544. package/schemas/tool-descriptor.schema.json +0 -63
  545. package/schemas/trigger-event.schema.json +0 -222
  546. package/schemas/trigger-subscription-registration.schema.json +0 -67
  547. package/schemas/trigger-subscription.schema.json +0 -26
  548. package/schemas/ui-plugin-message.schema.json +0 -90
  549. package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
  550. package/schemas/workflow-definition.schema.json +0 -850
  551. package/schemas/workload-identity.schema.json +0 -79
  552. package/schemas/workspace-file-create.schema.json +0 -20
  553. package/schemas/workspace-file.schema.json +0 -39
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
23
23
  import { driver } from '../lib/driver.js';
24
24
  import { pollUntilStatus, pollUntilTerminal } from '../lib/polling.js';
25
25
  import { isFixtureAdvertised } from '../lib/fixtures.js';
26
+ import { req } from '../lib/requirement-ids.js';
27
+ import { softSkip } from '../lib/soft-skip.js';
26
28
 
27
29
  const WORKFLOW_ID = 'conformance-interrupt-auth-required';
28
30
  const NODE_ID = 'gate';
@@ -40,7 +42,7 @@ describe.skipIf(SKIP)('interrupt: auth-required — bearer resume succeeds', ()
40
42
  `/v1/runs/${encodeURIComponent(runId)}/interrupts/${encodeURIComponent(NODE_ID)}`,
41
43
  { resumeValue: { action: 'accept' } },
42
44
  );
43
- expect(resolve.status, driver.describe(
45
+ expect(resolve.status, req('openwop.it.interrupt-auth-required-resume.valid-bearer-with-approvals-respond-drives-terminal-completed',
44
46
  'interrupt-profiles.md §openwop-interrupt-auth-required',
45
47
  'bearer-token resume with approvals:respond scope MUST succeed',
46
48
  )).toBeGreaterThanOrEqual(200);
@@ -63,7 +65,7 @@ describe.skipIf(SKIP)('interrupt: auth-required — insufficient scope returns 4
63
65
  '[interrupt-auth-required-resume] skipping insufficient-scope subtest: ' +
64
66
  'OPENWOP_TEST_LOW_SCOPE_KEY not set',
65
67
  );
66
- return;
68
+ return softSkip('blocked', 'precondition not met — `!lowScopeKey` returned early (seam, prior step, or fixture unavailable)');
67
69
  }
68
70
 
69
71
  const create = await driver.post('/v1/runs', { workflowId: WORKFLOW_ID });
@@ -76,7 +78,7 @@ describe.skipIf(SKIP)('interrupt: auth-required — insufficient scope returns 4
76
78
  { resumeValue: { action: 'accept' } },
77
79
  { headers: { Authorization: `Bearer ${lowScopeKey}` } },
78
80
  );
79
- expect(resolve.status, driver.describe(
81
+ expect(resolve.status, req('openwop.it.interrupt-auth-required-resume.bearer-without-approvals-respond-scope-is-rejected',
80
82
  'auth.md §scopes + interrupt-profiles.md §openwop-interrupt-auth-required',
81
83
  'bearer without approvals:respond scope MUST return 403',
82
84
  )).toBe(403);
@@ -10,6 +10,7 @@ import { describe, it, expect } from 'vitest';
10
10
  import { driver } from '../lib/driver.js';
11
11
  import { pollUntilStatus, pollUntilTerminal } from '../lib/polling.js';
12
12
  import { isFixtureAdvertised } from '../lib/fixtures.js';
13
+ import { req } from '../lib/requirement-ids.js';
13
14
 
14
15
  const WORKFLOW_ID = 'conformance-clarification';
15
16
  const NODE_ID = 'ask';
@@ -22,7 +23,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('interrupt: clarification answers resume to `co
22
23
  const runId = (create.json as { runId: string }).runId;
23
24
 
24
25
  const suspended = await pollUntilStatus(runId, 'waiting-input', { timeoutMs: 10_000 });
25
- expect(suspended.currentNodeId, driver.describe(
26
+ expect(suspended.currentNodeId, req('openwop.it.interrupt-clarification.run-suspends-at-ask-answers-payload-drives-terminal-completed',
26
27
  'fixtures.md conformance-clarification',
27
28
  'suspended run MUST report currentNodeId === "ask"',
28
29
  )).toBe(NODE_ID);
@@ -31,13 +32,13 @@ describe.skipIf(SKIP_NO_FIXTURE)('interrupt: clarification answers resume to `co
31
32
  `/v1/runs/${encodeURIComponent(runId)}/interrupts/${encodeURIComponent(NODE_ID)}`,
32
33
  { resumeValue: { answers: { q1: 'blue' } } },
33
34
  );
34
- expect(resolve.status, driver.describe(
35
+ expect(resolve.status, req('openwop.it.interrupt-clarification.run-suspends-at-ask-answers-payload-drives-terminal-completed',
35
36
  'rest-endpoints.md POST /v1/runs/{runId}/interrupts/{nodeId}',
36
37
  'valid clarification resolve MUST return 200',
37
38
  )).toBe(200);
38
39
 
39
40
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 10_000 });
40
- expect(terminal.status, driver.describe(
41
+ expect(terminal.status, req('openwop.it.interrupt-clarification.run-suspends-at-ask-answers-payload-drives-terminal-completed',
41
42
  'fixtures.md conformance-clarification §Terminal status',
42
43
  'fixture after resolve MUST reach terminal `completed`',
43
44
  )).toBe('completed');
@@ -22,6 +22,7 @@ import { describe, it, expect } from 'vitest';
22
22
  import { driver } from '../lib/driver.js';
23
23
  import { pollUntilStatus, pollUntilTerminal } from '../lib/polling.js';
24
24
  import { isFixtureAdvertised } from '../lib/fixtures.js';
25
+ import { req } from '../lib/requirement-ids.js';
25
26
 
26
27
  const WORKFLOW_ID = 'conformance-interrupt-external-event';
27
28
  const SKIP = !isFixtureAdvertised(WORKFLOW_ID);
@@ -51,7 +52,7 @@ describe.skipIf(SKIP)('interrupt: external-event — matching correlation resume
51
52
  await pollUntilStatus(runId, 'waiting-external', { timeoutMs: 10_000 });
52
53
 
53
54
  const token = await fetchInterruptToken(runId);
54
- expect(token, driver.describe(
55
+ expect(token, req('openwop.it.interrupt-external-event-correlation.signed-token-post-with-matching-correlation-drives-terminal-completed',
55
56
  'interrupt.md §Signed-token callback',
56
57
  'suspended external-event interrupt MUST expose a signed token to the caller',
57
58
  )).not.toBeNull();
@@ -63,14 +64,14 @@ describe.skipIf(SKIP)('interrupt: external-event — matching correlation resume
63
64
  externalReference: 'conformance-test-123',
64
65
  },
65
66
  });
66
- expect(resolve.status, driver.describe(
67
+ expect(resolve.status, req('openwop.it.interrupt-external-event-correlation.signed-token-post-with-matching-correlation-drives-terminal-completed',
67
68
  'rest-endpoints.md POST /v1/interrupts/{token}',
68
69
  'token resolve with matching correlation MUST return 2xx',
69
70
  )).toBeGreaterThanOrEqual(200);
70
71
  expect(resolve.status).toBeLessThan(300);
71
72
 
72
73
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 10_000 });
73
- expect(terminal.status, driver.describe(
74
+ expect(terminal.status, req('openwop.it.interrupt-external-event-correlation.signed-token-post-with-matching-correlation-drives-terminal-completed',
74
75
  'fixtures.md conformance-interrupt-external-event',
75
76
  'matching external event MUST drive terminal completed',
76
77
  )).toBe('completed');
@@ -96,7 +97,7 @@ describe.skipIf(SKIP)('interrupt: external-event — mismatched correlation reje
96
97
  });
97
98
  expect(
98
99
  [422, 400].includes(resolve.status),
99
- driver.describe(
100
+ req('openwop.it.interrupt-external-event-correlation.correlation-mismatch-returns-422-and-leaves-run-suspended',
100
101
  'interrupt-profiles.md §openwop-interrupt-external-event',
101
102
  'correlation mismatch MUST return 422 (or 400) without resuming',
102
103
  ),
@@ -104,7 +105,7 @@ describe.skipIf(SKIP)('interrupt: external-event — mismatched correlation reje
104
105
 
105
106
  const still = await driver.get(`/v1/runs/${encodeURIComponent(runId)}`);
106
107
  const status = (still.json as { status: string }).status;
107
- expect(status, 'run MUST remain suspended after correlation rejection').toMatch(/^waiting-/);
108
+ expect(status, req('openwop.it.interrupt-external-event-correlation.correlation-mismatch-returns-422-and-leaves-run-suspended', 'interrupt-profiles.md §openwop-interrupt-external-event', 'run MUST remain suspended after correlation rejection')).toMatch(/^waiting-/);
108
109
 
109
110
  await driver.post(`/v1/runs/${encodeURIComponent(runId)}/cancel`, {
110
111
  reason: 'conformance-cleanup',
@@ -21,6 +21,7 @@ import { describe, it, expect } from 'vitest';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { pollUntilStatus, pollUntilTerminal } from '../lib/polling.js';
23
23
  import { isFixtureAdvertised } from '../lib/fixtures.js';
24
+ import { req } from '../lib/requirement-ids.js';
24
25
 
25
26
  const PARENT_WORKFLOW = 'conformance-interrupt-parent-child-cancel';
26
27
  const CHILD_WORKFLOW = 'conformance-interrupt-parent-child-cancel-child';
@@ -50,7 +51,7 @@ describe.skipIf(SKIP)('interrupt: parent/child — parent cancel cascades to chi
50
51
  await pollUntilStatus(parentRunId, 'waiting-approval', { timeoutMs: 15_000 });
51
52
 
52
53
  const childRunId = await findChildRunId(parentRunId);
53
- expect(childRunId, driver.describe(
54
+ expect(childRunId, req('openwop.it.interrupt-parent-child-cascade.child-transitions-to-cancelled-when-parent-is-cancelled-mid-suspend',
54
55
  'fixtures.md conformance-interrupt-parent-child-cancel',
55
56
  'parent snapshot MUST surface the spawned child runId',
56
57
  )).not.toBeNull();
@@ -65,7 +66,7 @@ describe.skipIf(SKIP)('interrupt: parent/child — parent cancel cascades to chi
65
66
  expect(parentTerminal.status).toBe('cancelled');
66
67
 
67
68
  const childTerminal = await pollUntilTerminal(childRunId!, { timeoutMs: 10_000 });
68
- expect(childTerminal.status, driver.describe(
69
+ expect(childTerminal.status, req('openwop.it.interrupt-parent-child-cascade.child-transitions-to-cancelled-when-parent-is-cancelled-mid-suspend',
69
70
  'interrupt-profiles.md §openwop-interrupt-parent-child',
70
71
  'parent cancellation MUST cascade — child run MUST reach terminal cancelled',
71
72
  )).toBe('cancelled');
@@ -93,7 +94,7 @@ describe.skipIf(SKIP)('interrupt: parent/child — post-cascade resolve of child
93
94
  );
94
95
  expect(
95
96
  [410, 409, 404].includes(lateResolve.status),
96
- driver.describe(
97
+ req('openwop.it.interrupt-parent-child-cascade.attempting-to-resolve-the-cascaded-child-interrupt-is-rejected',
97
98
  'interrupt-profiles.md §openwop-interrupt-parent-child',
98
99
  'resolving a cascaded child interrupt MUST be rejected (410 Gone preferred, 409/404 acceptable)',
99
100
  ),
@@ -21,6 +21,7 @@ import { describe, it, expect } from 'vitest';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { pollUntilStatus, pollUntilTerminal } from '../lib/polling.js';
23
23
  import { isFixtureAdvertised } from '../lib/fixtures.js';
24
+ import { req } from '../lib/requirement-ids.js';
24
25
 
25
26
  // Profile gating: a host claims `openwop-interrupt-quorum` support by
26
27
  // advertising the fixture. Hosts that don't support quorum semantics
@@ -42,7 +43,7 @@ describe.skipIf(SKIP)('interrupt: quorum — three accepts resume to completed',
42
43
  `/v1/runs/${encodeURIComponent(runId)}/interrupts/${encodeURIComponent(NODE_ID)}`,
43
44
  { resumeValue: { action: 'accept', voter: `approver-${i}` } },
44
45
  );
45
- expect(partial.status, driver.describe(
46
+ expect(partial.status, req('openwop.it.interrupt-quorum-resolution.first-two-accepts-persist-without-resuming-third-accept-drives-terminal-complete',
46
47
  'interrupt-profiles.md §openwop-interrupt-quorum',
47
48
  `partial vote ${i}/3 MUST be accepted (2xx) without terminating the run`,
48
49
  )).toBeGreaterThanOrEqual(200);
@@ -50,7 +51,7 @@ describe.skipIf(SKIP)('interrupt: quorum — three accepts resume to completed',
50
51
 
51
52
  const stillWaiting = await driver.get(`/v1/runs/${encodeURIComponent(runId)}`);
52
53
  const status = (stillWaiting.json as { status: string }).status;
53
- expect(status, driver.describe(
54
+ expect(status, req('openwop.it.interrupt-quorum-resolution.first-two-accepts-persist-without-resuming-third-accept-drives-terminal-complete',
54
55
  'interrupt-profiles.md §openwop-interrupt-quorum',
55
56
  `run MUST still be in waiting-approval after ${i}/3 votes (quorum not met)`,
56
57
  )).toBe('waiting-approval');
@@ -64,7 +65,7 @@ describe.skipIf(SKIP)('interrupt: quorum — three accepts resume to completed',
64
65
  expect(final.status).toBeLessThan(300);
65
66
 
66
67
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 10_000 });
67
- expect(terminal.status, driver.describe(
68
+ expect(terminal.status, req('openwop.it.interrupt-quorum-resolution.first-two-accepts-persist-without-resuming-third-accept-drives-terminal-complete',
68
69
  'fixtures.md conformance-interrupt-quorum §Terminal status',
69
70
  'three accepts (quorum met) MUST drive terminal completed',
70
71
  )).toBe('completed');
@@ -89,7 +90,7 @@ describe.skipIf(SKIP)('interrupt: quorum — majority reject fails the gate', ()
89
90
  );
90
91
 
91
92
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 10_000 });
92
- expect(['failed', 'rejected'], driver.describe(
93
+ expect(['failed', 'rejected'], req('openwop.it.interrupt-quorum-resolution.two-rejects-out-of-three-votes-trigger-the-majority-reject-termination',
93
94
  'interrupt-profiles.md §openwop-interrupt-quorum (rejectionPolicy: majority)',
94
95
  'majority rejection MUST drive a non-completed terminal state',
95
96
  )).toContain(terminal.status);
@@ -30,6 +30,8 @@ import { describe, it, expect } from 'vitest';
30
30
  import { driver } from '../lib/driver.js';
31
31
  import { pollUntilStatus } from '../lib/polling.js';
32
32
  import { isFixtureAdvertised } from '../lib/fixtures.js';
33
+ import { req } from '../lib/requirement-ids.js';
34
+ import { softSkip } from '../lib/soft-skip.js';
33
35
 
34
36
  const FIXTURE = 'conformance-interrupt-external-event';
35
37
  const SKIP = !isFixtureAdvertised(FIXTURE);
@@ -45,7 +47,7 @@ describe.skipIf(SKIP)('interrupt-token-matrix: GET /v1/interrupts/{token} negati
45
47
  const malformed = '!!!not-a-valid-token!!!';
46
48
  const res = await driver.get(`/v1/interrupts/${encodeURIComponent(malformed)}`);
47
49
  expect([400, 404]).toContain(res.status);
48
- expect(res.status, driver.describe(
50
+ expect(res.status, req('openwop.it.interrupt-token-matrix.malformed-token-returns-400-or-404-never-200',
49
51
  'rest-endpoints.md GET /v1/interrupts/{token}',
50
52
  'malformed interrupt token MUST NOT return 200',
51
53
  )).not.toBe(200);
@@ -55,7 +57,7 @@ describe.skipIf(SKIP)('interrupt-token-matrix: GET /v1/interrupts/{token} negati
55
57
  // Plausibly-shaped opaque token that the host has no record of.
56
58
  const unknown = `tok_${randomBytesB64(32)}`;
57
59
  const res = await driver.get(`/v1/interrupts/${encodeURIComponent(unknown)}`);
58
- expect(res.status, driver.describe(
60
+ expect(res.status, req('openwop.it.interrupt-token-matrix.well-formed-but-unknown-token-returns-404',
59
61
  'rest-endpoints.md GET /v1/interrupts/{token}',
60
62
  'unknown interrupt token MUST return 404',
61
63
  )).toBe(404);
@@ -83,7 +85,7 @@ describe.skipIf(SKIP)('interrupt-token-matrix: POST /v1/interrupts/{token} negat
83
85
  await driver.post(`/v1/runs/${encodeURIComponent(runId)}/cancel`, {
84
86
  reason: 'conformance-cleanup',
85
87
  });
86
- return;
88
+ return softSkip('blocked', 'precondition not met — `typeof token !== \'string\'` returned early ([interrupt-token-matrix] host did not surface an interrupt token; skipping replay subtest) (seam, prior step, or fixture unavailable)');
87
89
  }
88
90
 
89
91
  const resolve1 = await driver.post(`/v1/interrupts/${encodeURIComponent(token)}`, {
@@ -97,13 +99,13 @@ describe.skipIf(SKIP)('interrupt-token-matrix: POST /v1/interrupts/{token} negat
97
99
  await driver.post(`/v1/runs/${encodeURIComponent(runId)}/cancel`, {
98
100
  reason: 'conformance-cleanup',
99
101
  });
100
- return;
102
+ return softSkip('blocked', 'precondition not met — `resolve1.status !== 200 && resolve1.status !== 202` returned early ([interrupt-token-matrix] first resolve returned …; can\'t exercise replay path. Skipping.) (seam, prior step, or fixture unava…');
101
103
  }
102
104
 
103
105
  const resolve2 = await driver.post(`/v1/interrupts/${encodeURIComponent(token)}`, {
104
106
  correlation: { orderId: 'order-token-matrix', status: 'accepted' },
105
107
  });
106
- expect([404, 409, 410], driver.describe(
108
+ expect([404, 409, 410], req('openwop.it.interrupt-token-matrix.replay-after-successful-resolve-returns-409-or-404',
107
109
  'rest-endpoints.md POST /v1/interrupts/{token}',
108
110
  'replay of an already-resolved interrupt token MUST NOT return 2xx (host MAY 404/409/410)',
109
111
  )).toContain(resolve2.status);
@@ -118,7 +120,7 @@ describe.skipIf(SKIP)('interrupt-token-matrix: POST /v1/interrupts/{token} negat
118
120
  const res = await driver.post(`/v1/interrupts/${encodeURIComponent(unknown)}`, {
119
121
  correlation: { orderId: 'noop', status: 'whatever' },
120
122
  });
121
- expect(res.status, driver.describe(
123
+ expect(res.status, req('openwop.it.interrupt-token-matrix.unknown-token-returns-404-on-post',
122
124
  'rest-endpoints.md POST /v1/interrupts/{token}',
123
125
  'POST on an unknown interrupt token MUST return 404',
124
126
  )).toBe(404);
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
23
23
  import { driver } from '../lib/driver.js';
24
24
  import { pollUntil } from '../lib/polling.js';
25
25
  import { isFixtureAdvertised } from '../lib/fixtures.js';
26
+ import { req } from '../lib/requirement-ids.js';
27
+ import { softSkip } from '../lib/soft-skip.js';
26
28
 
27
29
  const APPROVAL_WORKFLOW_ID = 'conformance-approval';
28
30
  const NOOP_WORKFLOW_ID = 'conformance-noop';
@@ -45,13 +47,13 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
45
47
  it(
46
48
  'concurrent cancel + interrupt-resolve resolves to one of: cancelled or completed',
47
49
  async () => {
48
- if (!(await hostClaimsInterrupts())) return; // skip-equivalent
50
+ if (!(await hostClaimsInterrupts())) return softSkip('blocked', 'precondition not met — `!(await hostClaimsInterrupts())` returned early (skip-equivalent) (seam, prior step, or fixture unavailable)'); // skip-equivalent
49
51
 
50
52
  // Phase 1: start a workflow that suspends at an approval gate.
51
53
  const create = await driver.post('/v1/runs', { workflowId: APPROVAL_WORKFLOW_ID });
52
54
  if (create.status !== 201) {
53
55
  // Host may not seed conformance-approval fixture; skip.
54
- return;
56
+ return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (Host may not seed conformance-approval fixture; skip.) (seam, prior step, or fixture unavailable)');
55
57
  }
56
58
  const runId = (create.json as { runId: string }).runId;
57
59
 
@@ -72,7 +74,7 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
72
74
  if (typeof nodeId !== 'string') {
73
75
  // Host doesn't expose currentNodeId on suspended snapshots —
74
76
  // can't drive the race deterministically; skip-equivalent.
75
- return;
77
+ return softSkip('blocked', 'precondition not met — `typeof nodeId !== \'string\'` returned early (Host doesn\'t expose currentNodeId on suspended snapshots — can\'t drive the race deterministically; skip-equivalent.) (seam, prior step, or fixture un…');
76
78
  }
77
79
 
78
80
  // Phase 3: fire cancel + resolve concurrently. Promise.all so
@@ -92,14 +94,14 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
92
94
  // (operation lost the race). Anything else is non-deterministic.
93
95
  expect(
94
96
  [200, 202, 409].includes(cancelRes.status),
95
- driver.describe(
97
+ req('openwop.it.interruptRace.concurrent-cancel-interrupt-resolve-resolves-to-one-of-cancelled-or-completed',
96
98
  'spec/v1/interrupt.md',
97
99
  `cancel response under race MUST be 200/202/409; got ${cancelRes.status}`,
98
100
  ),
99
101
  ).toBe(true);
100
102
  expect(
101
103
  [200, 202, 400, 404, 409].includes(resolveRes.status),
102
- driver.describe(
104
+ req('openwop.it.interruptRace.concurrent-cancel-interrupt-resolve-resolves-to-one-of-cancelled-or-completed',
103
105
  'spec/v1/interrupt.md',
104
106
  `resolve response under race MUST be 200/202/400/404/409; got ${resolveRes.status}`,
105
107
  ),
@@ -110,7 +112,7 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
110
112
  const resolveSucceeded = resolveRes.status === 200 || resolveRes.status === 202;
111
113
  expect(
112
114
  cancelSucceeded || resolveSucceeded,
113
- driver.describe(
115
+ req('openwop.it.interruptRace.concurrent-cancel-interrupt-resolve-resolves-to-one-of-cancelled-or-completed',
114
116
  'spec/v1/interrupt.md',
115
117
  'under cancel/resolve race, at least one operation MUST succeed',
116
118
  ),
@@ -131,7 +133,7 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
131
133
 
132
134
  expect(
133
135
  ['completed', 'cancelled', 'failed'].includes(terminal.status),
134
- driver.describe(
136
+ req('openwop.it.interruptRace.concurrent-cancel-interrupt-resolve-resolves-to-one-of-cancelled-or-completed',
135
137
  'spec/v1/interrupt.md',
136
138
  'race outcome MUST converge on a terminal status, not stay in waiting-approval forever',
137
139
  ),
@@ -143,7 +145,7 @@ describe.skipIf(SKIP_NO_APPROVAL)('interrupt-race: concurrent cancel + resolve d
143
145
  // (assuming the workflow has nothing else to fail on after the
144
146
  // approval gate).
145
147
  if (cancelSucceeded && !resolveSucceeded) {
146
- expect(terminal.status, driver.describe(
148
+ expect(terminal.status, req('openwop.it.interruptRace.concurrent-cancel-interrupt-resolve-resolves-to-one-of-cancelled-or-completed',
147
149
  'spec/v1/interrupt.md',
148
150
  'when cancel wins the race, run MUST terminate as cancelled',
149
151
  )).toBe('cancelled');
@@ -158,7 +160,7 @@ describe.skipIf(SKIP_NO_NOOP)('interrupt-race: cancel against a non-suspended ru
158
160
  // Self-test that doesn't require a race. Runs against any host
159
161
  // that supports cancel (every conforming host does).
160
162
  const create = await driver.post('/v1/runs', { workflowId: 'conformance-noop' });
161
- if (create.status !== 201) return;
163
+ if (create.status !== 201) return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
162
164
  const runId = (create.json as { runId: string }).runId;
163
165
 
164
166
  await pollUntil(
@@ -168,7 +170,7 @@ describe.skipIf(SKIP_NO_NOOP)('interrupt-race: cancel against a non-suspended ru
168
170
  );
169
171
 
170
172
  const cancel = await driver.post(`/v1/runs/${encodeURIComponent(runId)}/cancel`, {});
171
- expect(cancel.status, driver.describe(
173
+ expect(cancel.status, req('openwop.it.interruptRace.cancel-of-a-completed-run-returns-200-with-the-existing-terminal-status-idempote',
172
174
  'spec/v1/rest-endpoints.md POST /v1/runs/{runId}/cancel',
173
175
  'cancel of an already-terminal run MUST return 200 (idempotent)',
174
176
  )).toBe(200);
@@ -11,6 +11,8 @@
11
11
  import { describe, it, expect } from 'vitest';
12
12
  import { driver } from '../lib/driver.js';
13
13
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
14
+ import { req } from '../lib/requirement-ids.js';
15
+ import { softSkip } from '../lib/soft-skip.js';
14
16
 
15
17
  interface DiscoveryDoc {
16
18
  capabilities?: Record<string, unknown>;
@@ -31,10 +33,10 @@ async function call(op: string, args: Record<string, unknown>) {
31
33
  describe('kv-atomic-increment: advertisement shape (RFC 0015)', () => {
32
34
  it('capabilities.kvStorage is either absent or a well-formed object', async () => {
33
35
  const cap = await readCap();
34
- if (cap === null) return;
36
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
35
37
  expect(
36
38
  typeof cap.supported,
37
- driver.describe(
39
+ req('openwop.it.kv-atomic-increment.capabilities-kvstorage-is-either-absent-or-a-well-formed-object',
38
40
  'capabilities.schema.json §kvStorage',
39
41
  'capabilities.kvStorage.supported MUST be a boolean when present',
40
42
  ),
@@ -43,33 +45,33 @@ describe('kv-atomic-increment: advertisement shape (RFC 0015)', () => {
43
45
 
44
46
  it('atomicIncrement is a boolean when set', async () => {
45
47
  const cap = await readCap();
46
- if (!cap || cap.supported !== true) return;
48
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
47
49
  const sub = cap.atomicIncrement;
48
- if (sub === undefined) return;
49
- expect(typeof sub, driver.describe('RFC 0015 §A', 'atomicIncrement MUST be boolean when present')).toBe('boolean');
50
+ if (sub === undefined) return softSkip('blocked', 'precondition not met — `sub === undefined` returned early (seam, prior step, or fixture unavailable)');
51
+ expect(typeof sub, req('openwop.it.kv-atomic-increment.atomicincrement-is-a-boolean-when-set', 'RFC 0015 §A', 'atomicIncrement MUST be boolean when present')).toBe('boolean');
50
52
  });
51
53
  });
52
54
 
53
55
  describe('kv-atomic-increment: behavioral (RFC 0015 §B point 4)', () => {
54
56
  it('N concurrent +1 increments converge to exactly N', async () => {
55
57
  const cap = await readCap();
56
- if (!cap || cap.supported !== true || cap.atomicIncrement !== true) return;
58
+ if (!cap || cap.supported !== true || cap.atomicIncrement !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true || cap.atomicIncrement !== true` returned early');
57
59
  const key = `atomic-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
58
60
  const probe = await call('atomicIncrement', { key, delta: 0 });
59
- if (probe.status === 404) return; // seam not exposed
61
+ if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam not exposed) (seam, prior step, or fixture unavailable)'); // seam not exposed
60
62
 
61
63
  const N = 50;
62
64
  const results = await Promise.all(
63
65
  Array.from({ length: N }, () => call('atomicIncrement', { key, delta: 1 })),
64
66
  );
65
67
  for (const r of results) {
66
- expect(r.status, 'each increment MUST succeed').toBe(200);
68
+ expect(r.status, req('openwop.it.kv-atomic-increment.n-concurrent-1-increments-converge-to-exactly-n', 'RFC 0015 §B point 4', 'each increment MUST succeed')).toBe(200);
67
69
  }
68
70
  const finalRes = await call('get', { key });
69
71
  const finalBody = finalRes.json as { value?: unknown };
70
72
  expect(
71
73
  finalBody.value,
72
- driver.describe('RFC 0015 §B point 4', `${N} concurrent increments MUST converge to exactly ${N}`),
74
+ req('openwop.it.kv-atomic-increment.n-concurrent-1-increments-converge-to-exactly-n', 'RFC 0015 §B point 4', `${N} concurrent increments MUST converge to exactly ${N}`),
73
75
  ).toBe(N);
74
76
  });
75
77
  });
@@ -11,6 +11,8 @@
11
11
  import { describe, it, expect } from 'vitest';
12
12
  import { driver } from '../lib/driver.js';
13
13
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
14
+ import { req } from '../lib/requirement-ids.js';
15
+ import { softSkip } from '../lib/soft-skip.js';
14
16
 
15
17
  interface DiscoveryDoc {
16
18
  capabilities?: Record<string, unknown>;
@@ -31,10 +33,10 @@ async function call(op: string, args: Record<string, unknown>) {
31
33
  describe('kv-cas: advertisement shape (RFC 0015)', () => {
32
34
  it('capabilities.kvStorage is either absent or a well-formed object', async () => {
33
35
  const cap = await readCap();
34
- if (cap === null) return;
36
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
35
37
  expect(
36
38
  typeof cap.supported,
37
- driver.describe(
39
+ req('openwop.it.kv-cas.capabilities-kvstorage-is-either-absent-or-a-well-formed-object',
38
40
  'capabilities.schema.json §kvStorage',
39
41
  'capabilities.kvStorage.supported MUST be a boolean when present',
40
42
  ),
@@ -43,34 +45,34 @@ describe('kv-cas: advertisement shape (RFC 0015)', () => {
43
45
 
44
46
  it('compareAndSwap is a boolean when set', async () => {
45
47
  const cap = await readCap();
46
- if (!cap || cap.supported !== true) return;
48
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
47
49
  const sub = cap.compareAndSwap;
48
- if (sub === undefined) return;
49
- expect(typeof sub, driver.describe('RFC 0015 §A', 'compareAndSwap MUST be boolean when present')).toBe('boolean');
50
+ if (sub === undefined) return softSkip('blocked', 'precondition not met — `sub === undefined` returned early (seam, prior step, or fixture unavailable)');
51
+ expect(typeof sub, req('openwop.it.kv-cas.compareandswap-is-a-boolean-when-set', 'RFC 0015 §A', 'compareAndSwap MUST be boolean when present')).toBe('boolean');
50
52
  });
51
53
  });
52
54
 
53
55
  describe('kv-cas: behavioral (RFC 0015 §B point 5)', () => {
54
56
  it('CAS with matching expect succeeds; stale expect fails with swapped:false', async () => {
55
57
  const cap = await readCap();
56
- if (!cap || cap.supported !== true || cap.compareAndSwap !== true) return;
58
+ if (!cap || cap.supported !== true || cap.compareAndSwap !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true || cap.compareAndSwap !== true` returned early');
57
59
  const key = `cas-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
58
60
 
59
61
  const setRes = await call('set', { key, value: 'v1' });
60
- if (setRes.status === 404) return;
62
+ if (setRes.status === 404) return softSkip('blocked', 'precondition not met — `setRes.status === 404` returned early (seam, prior step, or fixture unavailable)');
61
63
  expect(setRes.status).toBe(200);
62
64
 
63
65
  // Matching expect → swaps.
64
66
  const okRes = await call('cas', { key, expect: 'v1', set: 'v2' });
65
- expect(okRes.status, 'matching CAS MUST 200').toBe(200);
67
+ expect(okRes.status, req('openwop.it.kv-cas.cas-with-matching-expect-succeeds-stale-expect-fails-with-swapped-false', 'RFC 0015 §B', 'matching CAS MUST 200')).toBe(200);
66
68
  const okBody = okRes.json as { swapped?: boolean };
67
- expect(okBody.swapped, 'matching expect MUST swap').toBe(true);
69
+ expect(okBody.swapped, req('openwop.it.kv-cas.cas-with-matching-expect-succeeds-stale-expect-fails-with-swapped-false', 'RFC 0015 §B', 'matching expect MUST swap')).toBe(true);
68
70
 
69
71
  // Stale expect → no swap.
70
72
  const staleRes = await call('cas', { key, expect: 'v1', set: 'v3' });
71
- expect(staleRes.status, 'stale CAS MUST 200 (CAS is non-throwing)').toBe(200);
73
+ expect(staleRes.status, req('openwop.it.kv-cas.cas-with-matching-expect-succeeds-stale-expect-fails-with-swapped-false', 'RFC 0015 §B', 'stale CAS MUST 200 (CAS is non-throwing)')).toBe(200);
72
74
  const staleBody = staleRes.json as { swapped?: boolean; actual?: unknown };
73
- expect(staleBody.swapped, 'stale expect MUST NOT swap').toBe(false);
74
- expect(staleBody.actual, 'stale CAS MUST surface current value').toBe('v2');
75
+ expect(staleBody.swapped, req('openwop.it.kv-cas.cas-with-matching-expect-succeeds-stale-expect-fails-with-swapped-false', 'RFC 0015 §B', 'stale expect MUST NOT swap')).toBe(false);
76
+ expect(staleBody.actual, req('openwop.it.kv-cas.cas-with-matching-expect-succeeds-stale-expect-fails-with-swapped-false', 'RFC 0015 §B', 'stale CAS MUST surface current value')).toBe('v2');
75
77
  });
76
78
  });
@@ -19,6 +19,8 @@
19
19
  import { describe, it, expect } from 'vitest';
20
20
  import { driver } from '../lib/driver.js';
21
21
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
22
+ import { req } from '../lib/requirement-ids.js';
23
+ import { softSkip } from '../lib/soft-skip.js';
22
24
 
23
25
  interface DiscoveryDoc {
24
26
  capabilities?: Record<string, unknown>;
@@ -39,10 +41,10 @@ async function call(tenantId: string, op: string, args: Record<string, unknown>)
39
41
  describe('kv-cross-tenant-isolation: advertisement shape (RFC 0015)', () => {
40
42
  it('capabilities.kvStorage is either absent or a well-formed object', async () => {
41
43
  const cap = await readCap();
42
- if (cap === null) return;
44
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
43
45
  expect(
44
46
  typeof cap.supported,
45
- driver.describe(
47
+ req('openwop.it.kv-cross-tenant-isolation.capabilities-kvstorage-is-either-absent-or-a-well-formed-object',
46
48
  'capabilities.schema.json §kvStorage',
47
49
  'capabilities.kvStorage.supported MUST be a boolean when present',
48
50
  ),
@@ -53,18 +55,18 @@ describe('kv-cross-tenant-isolation: advertisement shape (RFC 0015)', () => {
53
55
  describe('kv-cross-tenant-isolation: behavioral (RFC 0015 §B)', () => {
54
56
  it('set under tenant A → get under tenant B with same key returns found:false', async () => {
55
57
  const cap = await readCap();
56
- if (!cap || cap.supported !== true) return;
58
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
57
59
  const key = `xtenant-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
58
60
  const setRes = await call('tenant-a', 'set', { key, value: 'from-A' });
59
- if (setRes.status === 404) return; // host doesn't expose test seam
60
- expect(setRes.status, driver.describe('RFC 0015 §B', 'set MUST succeed')).toBe(200);
61
+ if (setRes.status === 404) return softSkip('blocked', 'precondition not met — `setRes.status === 404` returned early (host doesn\'t expose test seam) (seam, prior step, or fixture unavailable)'); // host doesn't expose test seam
62
+ expect(setRes.status, req('openwop.it.kv-cross-tenant-isolation.set-under-tenant-a-get-under-tenant-b-with-same-key-returns-found-false', 'RFC 0015 §B', 'set MUST succeed')).toBe(200);
61
63
 
62
64
  const getRes = await call('tenant-b', 'get', { key });
63
65
  expect(getRes.status).toBe(200);
64
66
  const body = getRes.json as { value?: unknown; found?: boolean };
65
67
  expect(
66
68
  body.found,
67
- driver.describe(
69
+ req('openwop.it.kv-cross-tenant-isolation.set-under-tenant-a-get-under-tenant-b-with-same-key-returns-found-false',
68
70
  'SECURITY/invariants.yaml kv-cross-tenant-isolation',
69
71
  'tenant B MUST NOT see tenant A value at the same key',
70
72
  ),
@@ -73,14 +75,14 @@ describe('kv-cross-tenant-isolation: behavioral (RFC 0015 §B)', () => {
73
75
 
74
76
  it('same-tenant set→get round-trips the value', async () => {
75
77
  const cap = await readCap();
76
- if (!cap || cap.supported !== true) return;
78
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
77
79
  const key = `roundtrip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
78
80
  const setRes = await call('tenant-a', 'set', { key, value: 'rt-A' });
79
- if (setRes.status === 404) return;
81
+ if (setRes.status === 404) return softSkip('blocked', 'precondition not met — `setRes.status === 404` returned early (seam, prior step, or fixture unavailable)');
80
82
  expect(setRes.status).toBe(200);
81
83
  const getRes = await call('tenant-a', 'get', { key });
82
84
  const body = getRes.json as { value?: unknown; found?: boolean };
83
- expect(body.found, 'same-tenant get MUST succeed').toBe(true);
84
- expect(body.value, 'same-tenant get MUST return the stored value').toBe('rt-A');
85
+ expect(body.found, req('openwop.it.kv-cross-tenant-isolation.same-tenant-set-get-round-trips-the-value', 'RFC 0015 §B', 'same-tenant get MUST succeed')).toBe(true);
86
+ expect(body.value, req('openwop.it.kv-cross-tenant-isolation.same-tenant-set-get-round-trips-the-value', 'RFC 0015 §B', 'same-tenant get MUST return the stored value')).toBe('rt-A');
85
87
  });
86
88
  });
@@ -16,6 +16,8 @@
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
18
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
19
+ import { req } from '../lib/requirement-ids.js';
20
+ import { softSkip } from '../lib/soft-skip.js';
19
21
 
20
22
  interface DiscoveryDoc {
21
23
  capabilities?: Record<string, unknown>;
@@ -32,10 +34,10 @@ async function readCap(): Promise<Record<string, unknown> | null> {
32
34
  describe('kv-ttl-expiry: advertisement shape (RFC 0015)', () => {
33
35
  it('capabilities.kvStorage is either absent or a well-formed object', async () => {
34
36
  const cap = await readCap();
35
- if (cap === null) return; // host doesn't advertise — skip
37
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early (host doesn\'t advertise — skip)'); // host doesn't advertise — skip
36
38
  expect(
37
39
  typeof cap.supported,
38
- driver.describe(
40
+ req('openwop.it.kv-ttl-expiry.capabilities-kvstorage-is-either-absent-or-a-well-formed-object',
39
41
  'capabilities.schema.json §kvStorage',
40
42
  'capabilities.kvStorage.supported MUST be a boolean when present',
41
43
  ),
@@ -50,7 +52,7 @@ async function call(op: string, args: Record<string, unknown>) {
50
52
  describe('kv-ttl-expiry: behavioral (RFC 0015 §B point 3 — 1s TTL drift)', () => {
51
53
  it('set with ttlSeconds=2 → get before expiry returns value; get after expiry returns found:false', async () => {
52
54
  const probe = await call('get', { key: '__ttl-probe__' });
53
- if (probe.status === 404) return; // host doesn't expose the seam
55
+ if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (host doesn\'t expose the seam) (seam, prior step, or fixture unavailable)'); // host doesn't expose the seam
54
56
  const key = `ttl-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
55
57
  const setRes = await call('set', { key, value: 'expires-soon', ttlSeconds: 2 });
56
58
  expect(setRes.status).toBe(200);
@@ -61,7 +63,7 @@ describe('kv-ttl-expiry: behavioral (RFC 0015 §B point 3 — 1s TTL drift)', ()
61
63
  const withinBody = within.json as { value?: unknown; found?: boolean };
62
64
  expect(
63
65
  withinBody.value,
64
- driver.describe('RFC 0015 §B point 3', 'get within TTL window MUST return the stored value'),
66
+ req('openwop.it.kv-ttl-expiry.set-with-ttlseconds-2-get-before-expiry-returns-value-get-after-expiry-returns-f', 'RFC 0015 §B point 3', 'get within TTL window MUST return the stored value'),
65
67
  ).toBe('expires-soon');
66
68
  expect(withinBody.found).toBe(true);
67
69
 
@@ -73,7 +75,7 @@ describe('kv-ttl-expiry: behavioral (RFC 0015 §B point 3 — 1s TTL drift)', ()
73
75
  const afterBody = after.json as { value?: unknown; found?: boolean };
74
76
  expect(
75
77
  afterBody.found,
76
- driver.describe('RFC 0015 §B point 3', 'get after TTL expiry MUST surface as found:false (≤1s drift)'),
78
+ req('openwop.it.kv-ttl-expiry.set-with-ttlseconds-2-get-before-expiry-returns-value-get-after-expiry-returns-f', 'RFC 0015 §B point 3', 'get after TTL expiry MUST surface as found:false (≤1s drift)'),
77
79
  ).toBe(false);
78
80
  });
79
81
  });