@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
@@ -20,6 +20,8 @@ import { describe, it, expect } from 'vitest';
20
20
  import { driver } from '../lib/driver.js';
21
21
  import { behaviorGate } from '../lib/behavior-gate.js';
22
22
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
23
+ import { req } from '../lib/requirement-ids.js';
24
+ import { softSkip } from '../lib/soft-skip.js';
23
25
 
24
26
  const SEAM = '/v1/host/sample/ai/call-transcriber';
25
27
 
@@ -42,18 +44,18 @@ describe('voice-interim-not-durable (RFC 0106 §F INV-1)', () => {
42
44
  if (!behaviorGate('openwop-voice-interim-not-durable', advertised)) return;
43
45
 
44
46
  const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' }, interimResults: true });
45
- if (res.status === 404) return; // seam unwired — soft-skip
46
- if (errCode(res.json) === 'transcription_unsupported') return; // §E live transport / no test-seam arm — soft-skip
47
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
48
+ if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (§E live transport / no test-seam arm — soft-skip)'); // §E live transport / no test-seam arm — soft-skip
47
49
 
48
50
  const events = eventsOf(res.json);
49
- if (events.length === 0) return; // host returned only the result envelope — nothing observable to assert
51
+ if (events.length === 0) return softSkip('blocked', 'precondition not met — `events.length === 0` returned early (host returned only the result envelope — nothing observable to assert) (seam, prior step, or fixture unavailable)'); // host returned only the result envelope — nothing observable to assert
50
52
 
51
53
  const commitIdx = events.findIndex((e) => e.type === 'voice.turn_commit');
52
- if (commitIdx < 0) return; // no commit observed — soft-skip
54
+ if (commitIdx < 0) return softSkip('blocked', 'precondition not met — `commitIdx < 0` returned early (no commit observed — soft-skip) (seam, prior step, or fixture unavailable)'); // no commit observed — soft-skip
53
55
  const afterCommit = events.slice(commitIdx + 1);
54
56
  expect(
55
57
  !afterCommit.some((e) => e.type === 'voice.transcript' && (e.payload ?? {}).isFinal === false),
56
- driver.describe('RFC 0106 §F INV-1', 'a provisional (isFinal:false) transcript MUST NOT appear after voice.turn_commit'),
58
+ req('openwop.it.voice-interim-not-durable.no-provisional-isfinal-false-transcript-is-durable-past-voice-turn-commit', 'RFC 0106 §F INV-1', 'a provisional (isFinal:false) transcript MUST NOT appear after voice.turn_commit'),
57
59
  ).toBe(true);
58
60
  });
59
61
  });
@@ -22,6 +22,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
22
22
  import { driver } from '../lib/driver.js';
23
23
  import { behaviorGate } from '../lib/behavior-gate.js';
24
24
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
25
+ import { req } from '../lib/requirement-ids.js';
26
+ import { softSkip } from '../lib/soft-skip.js';
25
27
 
26
28
  const SEAM = '/v1/host/sample/ai/call-transcriber';
27
29
 
@@ -44,8 +46,8 @@ describe('voice-streamref-tenant-bound (RFC 0106 §F INV-4)', () => {
44
46
  // conduit to bind cross-tenant — soft-skip (the invariant stays reference-impl
45
47
  // until a host with live streamRef transport proves it).
46
48
  const res = await driver.post(SEAM, { audio: { streamRef: 'stream:tenant-a/mic' } });
47
- if (res.status === 404) return;
48
- if (errCode(res.json) === 'transcription_unsupported') return; // §E — no live transport on this host
49
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
50
+ if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (§E — no live transport on this host)'); // §E — no live transport on this host
49
51
 
50
52
  // A host that DOES accept a live streamRef must bind it: a second tenant presenting
51
53
  // tenant-A's streamRef MUST be rejected (cross-handle read forbidden). Exercising the
@@ -54,7 +56,7 @@ describe('voice-streamref-tenant-bound (RFC 0106 §F INV-4)', () => {
54
56
  // another tenant's buffered audio for an unknown streamRef.
55
57
  expect(
56
58
  res.status !== 200 || (res.json as { finalText?: unknown })?.finalText !== undefined,
57
- driver.describe('RFC 0106 §F INV-4', 'a host honoring a live streamRef MUST bind it to its tenant+session'),
59
+ req('openwop.it.voice-streamref-tenant-bound.a-live-streamref-is-tenant-session-bound-host-internal-transport-per-e-soft-skip', 'RFC 0106 §F INV-4', 'a host honoring a live streamRef MUST bind it to its tenant+session'),
58
60
  ).toBe(true);
59
61
  });
60
62
  });
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
23
23
  import { driver } from '../lib/driver.js';
24
24
  import { behaviorGate } from '../lib/behavior-gate.js';
25
25
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
26
+ import { req } from '../lib/requirement-ids.js';
27
+ import { softSkip } from '../lib/soft-skip.js';
26
28
 
27
29
  const SEAM = '/v1/host/sample/ai/call-speech-synthesizer';
28
30
 
@@ -42,36 +44,36 @@ describe('voice-synthesis-streaming (RFC 0106 §C)', () => {
42
44
  if (!behaviorGate('openwop-voice-synthesis', advertised)) return;
43
45
 
44
46
  const res = await driver.post(SEAM, { text: 'Welcome to the weekly digest.', voiceId: 'host:narrator-test', stream: true });
45
- if (res.status === 404) return; // seam unwired — soft-skip
47
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
46
48
 
47
49
  expect(
48
50
  res.status === 200,
49
- driver.describe('RFC 0106 §C', 'an advertised host MUST resolve stream:true with 200'),
51
+ req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'an advertised host MUST resolve stream:true with 200'),
50
52
  ).toBe(true);
51
53
 
52
54
  const audio = (res.json as { audio?: Record<string, unknown> })?.audio;
53
- expect(audio !== undefined, driver.describe('RFC 0106 §C', 'the response MUST carry the finalized `audio` asset')).toBe(true);
55
+ expect(audio !== undefined, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'the response MUST carry the finalized `audio` asset')).toBe(true);
54
56
  if (audio) {
55
57
  const hasUrl = typeof audio.url === 'string' && (audio.url as string).length > 0;
56
58
  const hasB64 = typeof audio.base64 === 'string' && (audio.base64 as string).length > 0;
57
- expect(hasUrl !== hasB64, driver.describe('RFC 0106 §C', 'audio MUST carry EXACTLY ONE of url/base64')).toBe(true);
59
+ expect(hasUrl !== hasB64, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'audio MUST carry EXACTLY ONE of url/base64')).toBe(true);
58
60
  }
59
61
 
60
62
  const chunks = eventsOf(res.json).filter((e) => e.type === 'voice.synthesis_chunk');
61
- expect(chunks.length >= 1, driver.describe('RFC 0106 §C', 'MUST emit ≥1 voice.synthesis_chunk run-event')).toBe(true);
63
+ expect(chunks.length >= 1, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'MUST emit ≥1 voice.synthesis_chunk run-event')).toBe(true);
62
64
  for (const c of chunks) {
63
65
  const p = c.payload ?? {};
64
- expect(typeof p.seq === 'number', driver.describe('RFC 0106 §C', 'each chunk carries a numeric seq')).toBe(true);
65
- expect(typeof p.mimeType === 'string', driver.describe('RFC 0106 §C', 'each chunk carries a mimeType')).toBe(true);
66
+ expect(typeof p.seq === 'number', req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'each chunk carries a numeric seq')).toBe(true);
67
+ expect(typeof p.mimeType === 'string', req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'each chunk carries a mimeType')).toBe(true);
66
68
  // Metadata-only: bytes by reference. An inline base64 is permitted ONLY under the host cap;
67
69
  // a chunk over the RFC 0055 256 KiB inline cap MUST be a url/streamRef reference.
68
70
  if (typeof p.base64 === 'string') {
69
- expect((p.base64 as string).length <= 262144, driver.describe('RFC 0106 §C (G8)', 'inline chunk base64 MUST stay under the 256 KiB cap; else url/streamRef')).toBe(true);
71
+ expect((p.base64 as string).length <= 262144, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C (G8)', 'inline chunk base64 MUST stay under the 256 KiB cap; else url/streamRef')).toBe(true);
70
72
  }
71
73
  }
72
74
  expect(
73
75
  chunks.some((c) => (c.payload ?? {}).final === true),
74
- driver.describe('RFC 0106 §C', 'a terminal chunk MUST carry final:true'),
76
+ req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'a terminal chunk MUST carry final:true'),
75
77
  ).toBe(true);
76
78
  });
77
79
  });
@@ -23,6 +23,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
23
23
  import { driver } from '../lib/driver.js';
24
24
  import { behaviorGate } from '../lib/behavior-gate.js';
25
25
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
26
+ import { req } from '../lib/requirement-ids.js';
27
+ import { softSkip } from '../lib/soft-skip.js';
26
28
 
27
29
  const SEAM = '/v1/host/sample/ai/call-transcriber';
28
30
 
@@ -45,21 +47,21 @@ describe('voice-transcription-streaming (RFC 0106 §B)', () => {
45
47
  if (!behaviorGate('openwop-voice-transcription', advertised)) return;
46
48
 
47
49
  const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' }, languageCode: 'en-US' });
48
- if (res.status === 404) return; // seam unwired — soft-skip
50
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
49
51
  // §E: a stateless host with no live transport honestly rejects a live streamRef.
50
- if (errCode(res.json) === 'transcription_unsupported') return; // soft-skip (no live transport / no test-seam arm)
52
+ if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (soft-skip (no live transport / no test-seam arm))'); // soft-skip (no live transport / no test-seam arm)
51
53
 
52
- expect(res.status === 200, driver.describe('RFC 0106 §B', 'a produced turn MUST return 200')).toBe(true);
54
+ expect(res.status === 200, req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'a produced turn MUST return 200')).toBe(true);
53
55
 
54
56
  const finalText = (res.json as { finalText?: unknown })?.finalText;
55
- expect(typeof finalText === 'string' && (finalText as string).length > 0, driver.describe('RFC 0106 §B', 'the turn MUST resolve a non-empty finalText at turn_commit')).toBe(true);
57
+ expect(typeof finalText === 'string' && (finalText as string).length > 0, req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'the turn MUST resolve a non-empty finalText at turn_commit')).toBe(true);
56
58
 
57
59
  const events = eventsOf(res.json);
58
60
  if (events.length > 0) {
59
61
  for (const ev of events.filter((e) => e.type === 'voice.transcript')) {
60
- expect((ev.payload ?? {}).contentTrust === 'untrusted', driver.describe('RFC 0106 §F INV-2', 'every voice.transcript MUST carry contentTrust:"untrusted"')).toBe(true);
62
+ expect((ev.payload ?? {}).contentTrust === 'untrusted', req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §F INV-2', 'every voice.transcript MUST carry contentTrust:"untrusted"')).toBe(true);
61
63
  }
62
- expect(events.some((e) => e.type === 'voice.turn_commit'), driver.describe('RFC 0106 §B', 'the turn MUST terminate with voice.turn_commit')).toBe(true);
64
+ expect(events.some((e) => e.type === 'voice.turn_commit'), req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'the turn MUST terminate with voice.turn_commit')).toBe(true);
63
65
  }
64
66
  });
65
67
  });
@@ -18,6 +18,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
18
18
  import { driver } from '../lib/driver.js';
19
19
  import { behaviorGate } from '../lib/behavior-gate.js';
20
20
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
21
+ import { req } from '../lib/requirement-ids.js';
22
+ import { softSkip } from '../lib/soft-skip.js';
21
23
 
22
24
  const SEAM = '/v1/host/sample/ai/call-transcriber';
23
25
 
@@ -36,12 +38,12 @@ describe('voice-transcription-unadvertised (RFC 0106 §B)', () => {
36
38
  if (!behaviorGate('openwop-voice-transcription-unadvertised', !advertised)) return;
37
39
 
38
40
  const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' } });
39
- if (res.status === 404) return; // seam unwired — soft-skip
41
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
40
42
 
41
- expect(res.status !== 200, driver.describe('RFC 0106 §B', 'an unadvertising host MUST NOT return a 200 (never a no-op)')).toBe(true);
43
+ expect(res.status !== 200, req('openwop.it.voice-transcription-unadvertised.a-host-not-advertising-realtimevoice-transcription-must-reject-with-transcriptio', 'RFC 0106 §B', 'an unadvertising host MUST NOT return a 200 (never a no-op)')).toBe(true);
42
44
  expect(
43
45
  errCode(res.json) === 'transcription_unsupported',
44
- driver.describe('RFC 0106 §B', 'the call MUST be rejected with `transcription_unsupported`'),
46
+ req('openwop.it.voice-transcription-unadvertised.a-host-not-advertising-realtimevoice-transcription-must-reject-with-transcriptio', 'RFC 0106 §B', 'the call MUST be rejected with `transcription_unsupported`'),
45
47
  ).toBe(true);
46
48
  });
47
49
  });
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
28
28
  import { softSkip } from '../lib/soft-skip.js';
29
29
  import { driver } from '../lib/driver.js';
30
30
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
31
+ import { req } from '../lib/requirement-ids.js';
31
32
 
32
33
  const MISBEHAVING_PACK_NAME = 'vendor.openwop.misbehaving-abi';
33
34
  const WELL_BEHAVED_PACK_NAME = 'vendor.openwop.rust-hello';
@@ -40,7 +41,7 @@ describe('wasm-pack-abi-version-rejection: host advertises supported ABI version
40
41
 
41
42
  if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
42
43
 
43
- expect(Array.isArray(wasm.abiVersions), driver.describe(
44
+ expect(Array.isArray(wasm.abiVersions), req('openwop.it.wasm-pack-abi-version-rejection.abiversions-contains-positive-integers-loader-rejects-unsupported-versions',
44
45
  'RFCS/0008-wasm-abi.md §H',
45
46
  'capabilities.nodePackRuntimes.wasm.abiVersions MUST be an array',
46
47
  )).toBe(true);
@@ -90,7 +91,7 @@ describe('wasm-pack-abi-version-rejection: positive path via misbehaving pack',
90
91
 
91
92
  // Core assertion: ABI 999 pack MUST NOT be in loadedPacks[]
92
93
  // regardless of filesystem state. The host's loader rejected it.
93
- expect(wasm.loadedPacks.includes(MISBEHAVING_PACK_NAME), driver.describe(
94
+ expect(wasm.loadedPacks.includes(MISBEHAVING_PACK_NAME), req('openwop.it.wasm-pack-abi-version-rejection.misbehaving-abi-pack-declares-abi-999-must-not-appear-in-loadedpacks',
94
95
  'RFCS/0008-wasm-abi.md §H',
95
96
  `host MUST reject packs whose declared ABI is not in abiVersions[]; ${MISBEHAVING_PACK_NAME} declares 999 and MUST NOT appear in loadedPacks[]`,
96
97
  )).toBe(false);
@@ -18,6 +18,7 @@ import { driver } from '../lib/driver.js';
18
18
  import { pollUntilTerminal } from '../lib/polling.js';
19
19
  import { isFixtureAdvertised } from '../lib/fixtures.js';
20
20
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
21
+ import { req } from '../lib/requirement-ids.js';
21
22
 
22
23
  const FIXTURE = 'conformance-wasm-pack-roundtrip';
23
24
 
@@ -45,7 +46,7 @@ describe('wasm-pack-invoke-completed: round-trip output', () => {
45
46
  const runId = (create.json as { runId: string }).runId;
46
47
 
47
48
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 15_000 });
48
- expect(terminal.status, driver.describe(
49
+ expect(terminal.status, req('openwop.it.wasm-pack-invoke-completed.greet-node-returns-hello-name-and-run-reaches-completed',
49
50
  'RFCS/0008-wasm-abi.md §D',
50
51
  "WASM 'completed' outcome MUST drive terminal 'completed' run status",
51
52
  )).toBe('completed');
@@ -61,7 +62,7 @@ describe('wasm-pack-invoke-completed: round-trip output', () => {
61
62
  const fullLog = JSON.stringify(list).toLowerCase();
62
63
  expect(
63
64
  haystack.includes('hello, openwop') || fullLog.includes('hello, openwop'),
64
- driver.describe(
65
+ req('openwop.it.wasm-pack-invoke-completed.greet-node-returns-hello-name-and-run-reaches-completed',
65
66
  'RFCS/0008-wasm-abi.md §D',
66
67
  "WASM completion output MUST be surfaced somewhere in the run's event log so consumers can read it",
67
68
  ),
@@ -22,6 +22,7 @@ import { driver } from '../lib/driver.js';
22
22
  import { pollUntilTerminal } from '../lib/polling.js';
23
23
  import { isFixtureAdvertised } from '../lib/fixtures.js';
24
24
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
25
+ import { req } from '../lib/requirement-ids.js';
25
26
 
26
27
  const FIXTURE = 'conformance-wasm-pack-roundtrip';
27
28
 
@@ -60,11 +61,11 @@ describe('wasm-pack-invoke-suspended: suspend → resume round-trip', () => {
60
61
  const ok =
61
62
  haystack.includes('wasm_suspend_not_implemented') ||
62
63
  haystack.includes('suspend_not_supported');
63
- expect(ok, driver.describe(
64
+ expect(ok, req('openwop.it.wasm-pack-invoke-suspended.host-either-suspends-the-run-or-explicitly-reports-wasm-suspend-not-implemented',
64
65
  'RFCS/0008-wasm-abi.md §D',
65
66
  "if a host doesn't implement WASM-driven suspends it MUST surface a recognizable code",
66
67
  )).toBe(true);
67
- return;
68
+ return softSkip('blocked', 'precondition not met — `terminal.status === \'failed\'` returned early (seam, prior step, or fixture unavailable)');
68
69
  }
69
70
 
70
71
  // Completed path: the reference pack never suspends. Asserting
@@ -17,6 +17,7 @@ import { softSkip } from '../lib/soft-skip.js';
17
17
  import { driver } from '../lib/driver.js';
18
18
  import { isFixtureAdvertised } from '../lib/fixtures.js';
19
19
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
20
+ import { req } from '../lib/requirement-ids.js';
20
21
 
21
22
  const FIXTURE = 'conformance-wasm-pack-roundtrip';
22
23
 
@@ -42,11 +43,11 @@ describe('wasm-pack-load: discovery surfaces WASM runtime support', () => {
42
43
  console.warn('[wasm-pack-load] host does not advertise WASM support; skipping');
43
44
  return softSkip('inapplicable', '[wasm-pack-load] host does not advertise WASM support; skipping');
44
45
  }
45
- expect(Array.isArray(wasm.abiVersions), driver.describe(
46
+ expect(Array.isArray(wasm.abiVersions), req('openwop.it.wasm-pack-load.a-host-claiming-wasm-support-advertises-abiversions-including-1',
46
47
  'RFCS/0008-wasm-abi.md §H',
47
48
  'capabilities.nodePackRuntimes.wasm.abiVersions MUST be an array',
48
49
  )).toBe(true);
49
- expect(wasm.abiVersions?.includes(1), driver.describe(
50
+ expect(wasm.abiVersions?.includes(1), req('openwop.it.wasm-pack-load.a-host-claiming-wasm-support-advertises-abiversions-including-1',
50
51
  'RFCS/0008-wasm-abi.md §H',
51
52
  'abiVersions MUST include 1 (this RFC) when supported',
52
53
  )).toBe(true);
@@ -66,7 +67,7 @@ describe('wasm-pack-load: loaded pack typeIds are dispatchable', () => {
66
67
  // WASM-provided typeId. A host that loaded the pack accepts the
67
68
  // POST /v1/runs; one that didn't would return 400/404.
68
69
  const create = await driver.post('/v1/runs', { workflowId: FIXTURE, inputs: { name: 'world' } });
69
- expect(create.status, driver.describe(
70
+ expect(create.status, req('openwop.it.wasm-pack-load.host-accepts-a-workflow-whose-node-typeid-is-provided-by-a-loaded-wasm-pack',
70
71
  'RFCS/0008-wasm-abi.md §B + node-packs.md §Reserved typeIds',
71
72
  'host MUST accept runs whose nodes reference loaded-pack typeIds',
72
73
  )).toBe(201);
@@ -28,6 +28,7 @@ import { driver } from '../lib/driver.js';
28
28
  import { pollUntilTerminal } from '../lib/polling.js';
29
29
  import { isFixtureAdvertised } from '../lib/fixtures.js';
30
30
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
31
+ import { req } from '../lib/requirement-ids.js';
31
32
 
32
33
  const CAP_BREACH_FIXTURE = 'conformance-wasm-pack-memory-cap-breach';
33
34
 
@@ -41,7 +42,7 @@ describe('wasm-pack-memory-cap: host advertises maxMemoryBytes', () => {
41
42
 
42
43
  // The cap is REQUIRED to enforce §K. Hosts MUST surface the configured
43
44
  // ceiling so clients can size their packs accordingly.
44
- expect(typeof wasm.maxMemoryBytes, driver.describe(
45
+ expect(typeof wasm.maxMemoryBytes, req('openwop.it.wasm-pack-memory-cap.capabilities-nodepackruntimes-wasm-maxmemorybytes-is-a-plausible-number',
45
46
  'RFCS/0008-wasm-abi.md §K',
46
47
  'capabilities.nodePackRuntimes.wasm.maxMemoryBytes MUST be advertised as a number when WASM is supported',
47
48
  )).toBe('number');
@@ -75,7 +76,7 @@ describe('wasm-pack-memory-cap: positive path via misbehaving pack', () => {
75
76
  const runId = (create.json as { runId: string }).runId;
76
77
 
77
78
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 15_000 });
78
- expect(terminal.status, driver.describe(
79
+ expect(terminal.status, req('openwop.it.wasm-pack-memory-cap.misbehaving-pack-triggers-cap-breached-with-kind-wasm-memory-and-terminal-failed',
79
80
  'RFCS/0008-wasm-abi.md §K',
80
81
  'WASM memory-cap breach MUST drive terminal `failed` (RFC 0008 §K: "kill the instance, emit cap.breached")',
81
82
  )).toBe('failed');
@@ -83,14 +84,14 @@ describe('wasm-pack-memory-cap: positive path via misbehaving pack', () => {
83
84
  const events = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/events`);
84
85
  const list = (events.json as { events?: Array<{ type: string; payload?: unknown }> }).events ?? [];
85
86
  const breachEvent = list.find((e) => e.type === 'cap.breached');
86
- expect(breachEvent, driver.describe(
87
+ expect(breachEvent, req('openwop.it.wasm-pack-memory-cap.misbehaving-pack-triggers-cap-breached-with-kind-wasm-memory-and-terminal-failed',
87
88
  'RFCS/0008-wasm-abi.md §K',
88
89
  'host MUST emit cap.breached when a WASM module exceeds its memory ceiling',
89
90
  )).toBeDefined();
90
91
  // Event detail rides under the canonical `payload` envelope field (per
91
92
  // run-event-payloads.schema.json + every other event scenario), not `data`.
92
93
  const breachKind = (breachEvent?.payload as { kind?: string } | undefined)?.kind;
93
- expect(breachKind, driver.describe(
94
+ expect(breachKind, req('openwop.it.wasm-pack-memory-cap.misbehaving-pack-triggers-cap-breached-with-kind-wasm-memory-and-terminal-failed',
94
95
  'RFCS/0008-wasm-abi.md §K',
95
96
  'cap.breached payload MUST carry kind: "wasm-memory" for memory-ceiling breaches',
96
97
  )).toBe('wasm-memory');
@@ -16,6 +16,7 @@ import { driver } from '../lib/driver.js';
16
16
  import { pollUntilTerminal } from '../lib/polling.js';
17
17
  import { isFixtureAdvertised } from '../lib/fixtures.js';
18
18
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
19
+ import { req } from '../lib/requirement-ids.js';
19
20
 
20
21
  const FIXTURE = 'conformance-wasm-pack-roundtrip';
21
22
 
@@ -53,7 +54,7 @@ describe('wasm-pack-replay-determinism: same inputs → same output', () => {
53
54
  const a = await run();
54
55
  const b = await run();
55
56
 
56
- expect(a, driver.describe(
57
+ expect(a, req('openwop.it.wasm-pack-replay-determinism.two-independent-runs-with-same-inputs-produce-same-wasm-output',
57
58
  'RFCS/0008-wasm-abi.md §G',
58
59
  'WASM-node output MUST be reproducible given the same inputs',
59
60
  )).not.toBeNull();
@@ -24,6 +24,8 @@ import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
25
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
26
26
  import { discoverOwnedTenant } from '../lib/webhook-receiver.js';
27
+ import { req } from '../lib/requirement-ids.js';
28
+ import { softSkip } from '../lib/soft-skip.js';
27
29
 
28
30
  async function isWebhookSupported(): Promise<boolean> {
29
31
  const disco = await driver.get('/.well-known/openwop');
@@ -36,7 +38,7 @@ describe('webhook-negative: SSRF guard rejects private destinations', () => {
36
38
  if (!(await isWebhookSupported())) {
37
39
  // eslint-disable-next-line no-console
38
40
  console.warn('[webhook-negative] host does not advertise webhook support; skipping');
39
- return;
41
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWebhookSupported())` returned early ([webhook-negative] host does not advertise webhook support; skipping)');
40
42
  }
41
43
  // Spec-complete except for the private URL, so validation passes and the
42
44
  // request reaches the SSRF guard. `{ url }` alone 400s `validation_error`
@@ -59,9 +61,9 @@ describe('webhook-negative: SSRF guard rejects private destinations', () => {
59
61
  if (body.subscriptionId) {
60
62
  await driver.delete(`/v1/webhooks/${encodeURIComponent(body.subscriptionId)}`);
61
63
  }
62
- return;
64
+ return softSkip('blocked', 'precondition not met — `reg.status === 201` returned early ([webhook-negative] host accepts loopback destinations; SSRF guard not enforced) (seam, prior step, or fixture unavailable)');
63
65
  }
64
- expect(reg.status, driver.describe(
66
+ expect(reg.status, req('openwop.it.webhook-negative.host-with-ssrf-guard-returns-400-webhook-url-rejected-for-loopback',
65
67
  'webhooks.md + review §"Webhook SSRF guard"',
66
68
  'host with SSRF guard MUST return 400 for loopback / RFC1918 / link-local destinations',
67
69
  )).toBe(400);
@@ -72,17 +74,17 @@ describe('webhook-negative: SSRF guard rejects private destinations', () => {
72
74
 
73
75
  describe('webhook-negative: validation errors', () => {
74
76
  it('malformed url returns 400 validation_error', async () => {
75
- if (!(await isWebhookSupported())) return;
77
+ if (!(await isWebhookSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWebhookSupported())` returned early');
76
78
  const reg = await driver.post('/v1/webhooks', { url: 'not a url' });
77
- expect([400, 422]).toContain(reg.status);
79
+ expect([400, 422], req('openwop.it.webhook-negative.malformed-url-returns-400-validation-error', 'webhooks.md', 'malformed url returns 400 validation_error')).toContain(reg.status);
78
80
  const body = reg.json as { error?: string };
79
81
  expect(['validation_error', 'webhook_url_rejected']).toContain(body.error);
80
82
  });
81
83
 
82
84
  it('missing url returns 400 validation_error', async () => {
83
- if (!(await isWebhookSupported())) return;
85
+ if (!(await isWebhookSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWebhookSupported())` returned early');
84
86
  const reg = await driver.post('/v1/webhooks', { eventTypes: ['run.completed'] });
85
- expect(reg.status).toBe(400);
87
+ expect(reg.status, req('openwop.it.webhook-negative.missing-url-returns-400-validation-error', 'webhooks.md', 'missing url returns 400 validation_error')).toBe(400);
86
88
  const body = reg.json as { error?: string };
87
89
  expect(body.error).toBe('validation_error');
88
90
  });
@@ -90,9 +92,9 @@ describe('webhook-negative: validation errors', () => {
90
92
 
91
93
  describe('webhook-negative: unregister of unknown subscription', () => {
92
94
  it('DELETE /v1/webhooks/{unknown} returns 404 subscription_not_found', async () => {
93
- if (!(await isWebhookSupported())) return;
95
+ if (!(await isWebhookSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWebhookSupported())` returned early');
94
96
  const del = await driver.delete('/v1/webhooks/wh-does-not-exist');
95
- expect(del.status).toBe(404);
97
+ expect(del.status, req('openwop.it.webhook-negative.delete-v1-webhooks-unknown-returns-404-subscription-not-found', 'webhooks.md', 'DELETE /v1/webhooks/{unknown} returns 404 subscription_not_found')).toBe(404);
96
98
  const body = del.json as { error?: string };
97
99
  expect(body.error).toBe('subscription_not_found');
98
100
  });
@@ -44,6 +44,7 @@ import {
44
44
  verifyWebhookDelivery,
45
45
  SIGNATURE_PREFIX,
46
46
  } from '../lib/webhook-receiver.js';
47
+ import { req } from '../lib/requirement-ids.js';
47
48
 
48
49
  describe('webhook-receiver-adversarial: receiver rejects five canonical attacks', () => {
49
50
  const secret = 'test-secret-do-not-use-in-prod';
@@ -65,7 +66,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
65
66
  );
66
67
  expect(
67
68
  result.accepted,
68
- 'webhooks.md §"Signature recipe": valid signature + fresh timestamp + correct algorithm MUST be accepted',
69
+ req('openwop.it.webhook-receiver-adversarial.positive-control-receiver-accepts-a-freshly-signed-valid-delivery', 'spec/v1/webhooks.md', 'webhooks.md §"Signature recipe": valid signature + fresh timestamp + correct algorithm MUST be accepted'),
69
70
  ).toBe(true);
70
71
  });
71
72
 
@@ -86,7 +87,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
86
87
  if (!result.accepted) {
87
88
  expect(
88
89
  result.reason,
89
- 'webhooks.md §"Signature recipe": tampered body MUST be rejected with signature_mismatch',
90
+ req('openwop.it.webhook-receiver-adversarial.case-1-tampered-body-signature-mismatch', 'spec/v1/webhooks.md', 'webhooks.md §"Signature recipe": tampered body MUST be rejected with signature_mismatch'),
90
91
  ).toBe('signature_mismatch');
91
92
  }
92
93
  });
@@ -113,7 +114,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
113
114
  state,
114
115
  { nowSeconds: nowSec },
115
116
  );
116
- expect(result.accepted).toBe(false);
117
+ expect(result.accepted, req('openwop.it.webhook-receiver-adversarial.case-2-tampered-hmac-signature-mismatch', 'spec/v1/webhooks.md', 'case 2: tampered HMAC → signature_mismatch')).toBe(false);
117
118
  if (!result.accepted) {
118
119
  expect(result.reason).toBe('signature_mismatch');
119
120
  }
@@ -136,7 +137,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
136
137
  if (!result.accepted) {
137
138
  expect(
138
139
  result.reason,
139
- 'webhooks.md §"Replay-attack resistance": timestamp older than freshness window MUST be rejected with timestamp_expired',
140
+ req('openwop.it.webhook-receiver-adversarial.case-3-stale-timestamp-timestamp-expired', 'spec/v1/webhooks.md', 'webhooks.md §"Replay-attack resistance": timestamp older than freshness window MUST be rejected with timestamp_expired'),
140
141
  ).toBe('timestamp_expired');
141
142
  }
142
143
  });
@@ -170,7 +171,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
170
171
  if (!replay.accepted) {
171
172
  expect(
172
173
  replay.reason,
173
- 'webhooks.md §"Replay-attack resistance": replay of an already-accepted signature MUST be rejected with duplicate_signature',
174
+ req('openwop.it.webhook-receiver-adversarial.case-4-replayed-signature-duplicate-signature', 'spec/v1/webhooks.md', 'webhooks.md §"Replay-attack resistance": replay of an already-accepted signature MUST be rejected with duplicate_signature'),
174
175
  ).toBe('duplicate_signature');
175
176
  }
176
177
  });
@@ -191,7 +192,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
191
192
  if (!result.accepted) {
192
193
  expect(
193
194
  result.reason,
194
- 'webhooks.md §"Signature algorithm versioning": algorithm other than v1 MUST be rejected with wrong_algorithm by a v1-only receiver',
195
+ req('openwop.it.webhook-receiver-adversarial.case-5-wrong-algorithm-wrong-algorithm', 'spec/v1/webhooks.md', 'webhooks.md §"Signature algorithm versioning": algorithm other than v1 MUST be rejected with wrong_algorithm by a v1-only receiver'),
195
196
  ).toBe('wrong_algorithm');
196
197
  }
197
198
  });
@@ -208,7 +209,7 @@ describe('webhook-receiver-adversarial: receiver rejects five canonical attacks'
208
209
  state,
209
210
  { nowSeconds: nowSec },
210
211
  );
211
- expect(result.accepted).toBe(false);
212
+ expect(result.accepted, req('openwop.it.webhook-receiver-adversarial.case-6-malformed-signature-header-malformed-signature-header', 'spec/v1/webhooks.md', 'case 6: malformed signature header → malformed_signature_header')).toBe(false);
212
213
  if (!result.accepted) {
213
214
  expect(result.reason).toBe('malformed_signature_header');
214
215
  }
@@ -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 DiscoveryWebhooks {
21
23
  webhooks?: {
@@ -33,7 +35,7 @@ describe('webhook-sig-algorithm: host advertises supported algorithm set', () =>
33
35
  if (!webhooks?.supported) {
34
36
  // eslint-disable-next-line no-console
35
37
  console.warn('[webhook-sig-algorithm] host does not advertise webhook support; skipping');
36
- return;
38
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!webhooks?.supported` returned early ([webhook-sig-algorithm] host does not advertise webhook support; skipping)');
37
39
  }
38
40
 
39
41
  const algos = webhooks.signatureAlgorithms;
@@ -45,10 +47,10 @@ describe('webhook-sig-algorithm: host advertises supported algorithm set', () =>
45
47
  console.warn(
46
48
  '[webhook-sig-algorithm] host does not advertise webhooks.signatureAlgorithms (pre-v1.1); skipping shape check',
47
49
  );
48
- return;
50
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!Array.isArray(algos)` returned early ([webhook-sig-algorithm] host does not advertise webhooks.signatureAlgorithms (pre-v1.1); skipping shape check)');
49
51
  }
50
52
 
51
- expect(algos.includes('v1'), driver.describe(
53
+ expect(algos.includes('v1'), req('openwop.it.webhook-sig-algorithm.discovery-surfaces-a-webhooks-signaturealgorithms-array-including-v1',
52
54
  'webhooks.md §"Signature algorithm versioning"',
53
55
  'webhooks.signatureAlgorithms MUST include "v1" when surfaced (canonical baseline)',
54
56
  )).toBe(true);