@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
@@ -35,6 +35,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
35
35
  import { tmpdir } from 'node:os';
36
36
  import { join } from 'node:path';
37
37
  import { spawnHost, type SpawnedHost } from '../lib/multiProcess.js';
38
+ import { req } from '../lib/requirement-ids.js';
38
39
 
39
40
  // Default off: scenario must be opted in via env. The opt-in lists
40
41
  // the host package dir relative to repo root that exposes the
@@ -193,7 +194,7 @@ describe.skipIf(!RUN_THIS_SCENARIO)(
193
194
  15_000,
194
195
  );
195
196
 
196
- expect(terminal.status, 'orphaned run MUST resume to a terminal status under host B').toBe(
197
+ expect(terminal.status, req('openwop.it.staleClaim.process-b-picks-up-the-orphaned-run-after-process-a-dies-claim-expires', 'spec/v1/scale-profiles.md', 'orphaned run MUST resume to a terminal status under host B')).toBe(
197
198
  'completed',
198
199
  );
199
200
 
@@ -203,12 +204,12 @@ describe.skipIf(!RUN_THIS_SCENARIO)(
203
204
  // SOMETHING that distinguishes resume from fresh start MUST
204
205
  // exist in the event log).
205
206
  const events = await fetchEvents(hostB.baseUrl, APIKEY_B, runId);
206
- expect(Array.isArray(events.events), 'events poll MUST return an events array').toBe(true);
207
+ expect(Array.isArray(events.events), req('openwop.it.staleClaim.process-b-picks-up-the-orphaned-run-after-process-a-dies-claim-expires', 'spec/v1/scale-profiles.md', 'events poll MUST return an events array')).toBe(true);
207
208
  if (events.events && events.events.length > 0) {
208
209
  const types = events.events.map((e) => e.type);
209
210
  expect(
210
211
  types.includes('run.resumed') || types.includes('run.started'),
211
- 'event log MUST contain at least run.started; resume hosts SHOULD also emit run.resumed',
212
+ req('openwop.it.staleClaim.process-b-picks-up-the-orphaned-run-after-process-a-dies-claim-expires', 'spec/v1/scale-profiles.md', 'event log MUST contain at least run.started; resume hosts SHOULD also emit run.resumed'),
212
213
  ).toBe(true);
213
214
  }
214
215
  },
@@ -221,6 +222,6 @@ describe.skipIf(!RUN_THIS_SCENARIO)(
221
222
  // when the scenario is gated off.
222
223
  describe('staleClaim lib: spawnHost surface contract', () => {
223
224
  it('spawnHost is exported and has the expected shape', async () => {
224
- expect(typeof spawnHost).toBe('function');
225
+ expect(typeof spawnHost, req('openwop.it.staleClaim.spawnhost-is-exported-and-has-the-expected-shape', 'spec/v1/scale-profiles.md', 'spawnHost is exported and has the expected shape')).toBe('function');
225
226
  });
226
227
  });
@@ -22,6 +22,7 @@ import { driver } from '../lib/driver.js';
22
22
  import { subscribe } from '../lib/sse.js';
23
23
  import { 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-delay';
27
28
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
@@ -42,13 +43,13 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
42
43
  { timeoutMs: 30_000 },
43
44
  );
44
45
 
45
- expect(result.status, driver.describe(
46
+ expect(result.status, req('openwop.it.stream-modes-buffer.accepts-bufferms-in-range-and-emits-at-least-one-event-batch-frame',
46
47
  'stream-modes.md §Aggregation hint',
47
48
  'GET /v1/runs/{runId}/events with valid bufferMs MUST return 200 SSE',
48
49
  )).toBe(200);
49
50
 
50
51
  const batchEvents = result.events.filter((e) => e.event === 'batch');
51
- expect(batchEvents.length, driver.describe(
52
+ expect(batchEvents.length, req('openwop.it.stream-modes-buffer.accepts-bufferms-in-range-and-emits-at-least-one-event-batch-frame',
52
53
  'stream-modes.md §Aggregation hint',
53
54
  'buffered mode MUST emit at least one `event: batch` SSE frame',
54
55
  )).toBeGreaterThan(0);
@@ -56,7 +57,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
56
57
  // Each batch's data is a JSON array of RunEventDoc.
57
58
  for (const batch of batchEvents) {
58
59
  const parsed = JSON.parse(batch.data);
59
- expect(Array.isArray(parsed), driver.describe(
60
+ expect(Array.isArray(parsed), req('openwop.it.stream-modes-buffer.accepts-bufferms-in-range-and-emits-at-least-one-event-batch-frame',
60
61
  'stream-modes.md §batch data shape',
61
62
  'event: batch data MUST parse to a JSON array',
62
63
  )).toBe(true);
@@ -77,7 +78,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
77
78
  { timeoutMs: 5_000 },
78
79
  );
79
80
 
80
- expect(result.status, driver.describe(
81
+ expect(result.status, req('openwop.it.stream-modes-buffer.rejects-out-of-range-bufferms-with-400-validation-error',
81
82
  'stream-modes.md §Aggregation hint range',
82
83
  'bufferMs > 5000 MUST return 400',
83
84
  )).toBe(400);
@@ -114,7 +115,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
114
115
  (e) => e.type === 'run.completed' || e.type === 'run.failed' || e.type === 'run.cancelled',
115
116
  );
116
117
 
117
- expect(hasTerminal, driver.describe(
118
+ expect(hasTerminal, req('openwop.it.stream-modes-buffer.forces-flush-on-terminal-run-completed-arrives-bundled-in-a-batch-before-the-tim',
118
119
  'stream-modes.md §Aggregation hint — force-flush triggers',
119
120
  'terminal events MUST be force-flushed; the stream MUST NOT close before delivering run.completed',
120
121
  )).toBe(true);
@@ -124,7 +125,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
124
125
  // bufferMs/2 as headroom for cold-start latency on the conformance
125
126
  // server, but failing here proves the timer fired before terminal
126
127
  // arrived (i.e., force-flush is broken).
127
- expect(elapsedMs, driver.describe(
128
+ expect(elapsedMs, req('openwop.it.stream-modes-buffer.forces-flush-on-terminal-run-completed-arrives-bundled-in-a-batch-before-the-tim',
128
129
  'stream-modes.md §Aggregation hint — force-flush is immediate',
129
130
  `terminal SHOULD arrive in well under bufferMs (${BUFFER_MS}ms); observed ${elapsedMs}ms — if elapsed is close to bufferMs, force-flush is not firing`,
130
131
  )).toBeLessThan(BUFFER_MS / 2);
@@ -140,7 +141,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-buffer: ?bufferMs= aggregation hi
140
141
  );
141
142
 
142
143
  const batchEvents = result.events.filter((e) => e.event === 'batch');
143
- expect(batchEvents.length, driver.describe(
144
+ expect(batchEvents.length, req('openwop.it.stream-modes-buffer.bufferms-0-behaves-identically-to-omitting-per-event-mode',
144
145
  'stream-modes.md §Aggregation hint — bufferMs=0 sentinel',
145
146
  'bufferMs=0 MUST behave identically to omitting (no batch frames)',
146
147
  )).toBe(0);
@@ -21,6 +21,7 @@ import { driver } from '../lib/driver.js';
21
21
  import { subscribe, type SseEvent } from '../lib/sse.js';
22
22
  import { 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 WORKFLOW_ID = 'conformance-delay';
26
27
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
@@ -43,18 +44,18 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-mixed: comma-separated subsets',
43
44
  { timeoutMs: 15_000 },
44
45
  );
45
46
 
46
- expect(result.status, driver.describe(
47
+ expect(result.status, req('openwop.it.stream-modes-mixed.accepts-streammode-updates-messages-and-emits-a-server-closed-stream',
47
48
  'stream-modes.md §Mixed mode',
48
49
  'streamMode=updates,messages MUST return 200',
49
50
  )).toBe(200);
50
51
 
51
- expect(result.closedBy, driver.describe(
52
+ expect(result.closedBy, req('openwop.it.stream-modes-mixed.accepts-streammode-updates-messages-and-emits-a-server-closed-stream',
52
53
  'stream-modes.md §Mixed mode + §updates',
53
54
  'server MUST close the stream on terminal run event',
54
55
  )).toBe('server');
55
56
 
56
57
  const types = eventTypes(result.events);
57
- expect(types, driver.describe(
58
+ expect(types, req('openwop.it.stream-modes-mixed.accepts-streammode-updates-messages-and-emits-a-server-closed-stream',
58
59
  'stream-modes.md §Mixed mode (union semantics)',
59
60
  'mixed updates,messages MUST include run.completed (admitted by updates)',
60
61
  )).toContain('run.completed');
@@ -70,7 +71,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-mixed: comma-separated subsets',
70
71
  const res = await driver.get(
71
72
  `/v1/runs/${encodeURIComponent(runId)}/events?streamMode=values,updates`,
72
73
  );
73
- expect(res.status, driver.describe(
74
+ expect(res.status, req('openwop.it.stream-modes-mixed.rejects-streammode-values-updates-with-400-unsupported-stream-mode',
74
75
  'stream-modes.md §Mixed mode',
75
76
  'values combined with another mode MUST return 400',
76
77
  )).toBe(400);
@@ -78,15 +79,15 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-mixed: comma-separated subsets',
78
79
  const body = res.json as
79
80
  | { error?: string; message?: string; details?: { supported?: string[] } }
80
81
  | undefined;
81
- expect(body?.error, driver.describe(
82
+ expect(body?.error, req('openwop.it.stream-modes-mixed.rejects-streammode-values-updates-with-400-unsupported-stream-mode',
82
83
  'stream-modes.md §Mode selection error envelope + error-envelope.schema.json',
83
84
  'unsupported_stream_mode error envelope MUST carry an `error` string discriminator',
84
85
  )).toBe('unsupported_stream_mode');
85
- expect(typeof body?.message, driver.describe(
86
+ expect(typeof body?.message, req('openwop.it.stream-modes-mixed.rejects-streammode-values-updates-with-400-unsupported-stream-mode',
86
87
  'error-envelope.schema.json',
87
88
  'error envelope MUST carry a human-readable `message` string',
88
89
  )).toBe('string');
89
- expect(Array.isArray(body?.details?.supported), driver.describe(
90
+ expect(Array.isArray(body?.details?.supported), req('openwop.it.stream-modes-mixed.rejects-streammode-values-updates-with-400-unsupported-stream-mode',
90
91
  'stream-modes.md §Mode selection error envelope',
91
92
  'error body MUST carry `details.supported` array (NOT top-level — `details` is the canonical contextual-data slot per error-envelope.schema.json)',
92
93
  )).toBe(true);
@@ -104,7 +105,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-mixed: comma-separated subsets',
104
105
  const res = await driver.get(
105
106
  `/v1/runs/${encodeURIComponent(runId)}/events?streamMode=updates,bogus`,
106
107
  );
107
- expect(res.status, driver.describe(
108
+ expect(res.status, req('openwop.it.stream-modes-mixed.rejects-streammode-updates-bogus-one-bad-mode-fails-the-whole-list',
108
109
  'stream-modes.md §Mixed mode + §Mode selection',
109
110
  'partial-unknown lists MUST return 400',
110
111
  )).toBe(400);
@@ -140,7 +141,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes-mixed: comma-separated subsets',
140
141
  const mixedTypes = new Set(eventTypes(mixed.events));
141
142
 
142
143
  for (const t of updatesTypes) {
143
- expect(mixedTypes.has(t), driver.describe(
144
+ expect(mixedTypes.has(t), req('openwop.it.stream-modes-mixed.mixed-mode-union-updates-debug-sees-every-event-updates-sees',
144
145
  'stream-modes.md §Mixed mode (union)',
145
146
  `updates,debug MUST include every event type updates produces (missing: ${t})`,
146
147
  )).toBe(true);
@@ -11,6 +11,7 @@ import { describe, it, expect } from 'vitest';
11
11
  import { driver } from '../lib/driver.js';
12
12
  import { subscribe, type SseEvent } from '../lib/sse.js';
13
13
  import { isFixtureAdvertised } from '../lib/fixtures.js';
14
+ import { req } from '../lib/requirement-ids.js';
14
15
 
15
16
  const WORKFLOW_ID = 'conformance-delay';
16
17
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
@@ -38,17 +39,17 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes: updates (default) closes on term
38
39
  { timeoutMs: 15_000 },
39
40
  );
40
41
 
41
- expect(closedBy, driver.describe(
42
+ expect(closedBy, req('openwop.it.stream-modes.emits-at-least-run-started-run-completed-and-server-closes-the-stream',
42
43
  'stream-modes.md §updates',
43
44
  'server MUST close the connection on terminal run event',
44
45
  )).toBe('server');
45
46
 
46
47
  const types = eventTypes(events);
47
- expect(types, driver.describe(
48
+ expect(types, req('openwop.it.stream-modes.emits-at-least-run-started-run-completed-and-server-closes-the-stream',
48
49
  'stream-modes.md §updates',
49
50
  'updates stream MUST include run.started',
50
51
  )).toContain('run.started');
51
- expect(types, driver.describe(
52
+ expect(types, req('openwop.it.stream-modes.emits-at-least-run-started-run-completed-and-server-closes-the-stream',
52
53
  'stream-modes.md §updates',
53
54
  'updates stream MUST include run.completed for a successful run',
54
55
  )).toContain('run.completed');
@@ -62,7 +63,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes: invalid streamMode is rejected',
62
63
  `/v1/runs/${encodeURIComponent(runId)}/events?streamMode=does-not-exist`,
63
64
  );
64
65
 
65
- expect(res.status, driver.describe(
66
+ expect(res.status, req('openwop.it.stream-modes.returns-400-and-a-structured-error-body',
66
67
  'stream-modes.md §Mode selection',
67
68
  'unsupported streamMode MUST return 400',
68
69
  )).toBe(400);
@@ -70,15 +71,15 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes: invalid streamMode is rejected',
70
71
  const body = res.json as
71
72
  | { error?: unknown; message?: unknown; details?: { supported?: unknown } }
72
73
  | undefined;
73
- expect(typeof body?.error, driver.describe(
74
+ expect(typeof body?.error, req('openwop.it.stream-modes.returns-400-and-a-structured-error-body',
74
75
  'stream-modes.md §Mode selection + error-envelope.schema.json',
75
76
  'unsupported_stream_mode error body MUST include `error` string discriminator',
76
77
  )).toBe('string');
77
- expect(typeof body?.message, driver.describe(
78
+ expect(typeof body?.message, req('openwop.it.stream-modes.returns-400-and-a-structured-error-body',
78
79
  'error-envelope.schema.json',
79
80
  'error envelope MUST include a human-readable `message` string',
80
81
  )).toBe('string');
81
- expect(Array.isArray(body?.details?.supported), driver.describe(
82
+ expect(Array.isArray(body?.details?.supported), req('openwop.it.stream-modes.returns-400-and-a-structured-error-body',
82
83
  'stream-modes.md §Mode selection',
83
84
  'error body MUST include `details.supported` array of mode names (under `details` per error-envelope.schema.json)',
84
85
  )).toBe(true);
@@ -97,12 +98,12 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes: values mode is reachable + close
97
98
  // spec gap S1, so we don't assert payload shape here. What's
98
99
  // canonical: the connection MUST be reachable, MUST emit at least
99
100
  // one event before terminal, AND the server MUST close on terminal.
100
- expect(result.closedBy, driver.describe(
101
+ expect(result.closedBy, req('openwop.it.stream-modes.returns-200-emits-at-least-one-event-server-closes-per-stream-modes-md-values',
101
102
  'stream-modes.md §values',
102
103
  'server MUST close the connection on terminal run event',
103
104
  )).toBe('server');
104
105
 
105
- expect(result.events.length, driver.describe(
106
+ expect(result.events.length, req('openwop.it.stream-modes.returns-200-emits-at-least-one-event-server-closes-per-stream-modes-md-values',
106
107
  'stream-modes.md §values',
107
108
  'values mode MUST emit at least one event before terminal',
108
109
  )).toBeGreaterThan(0);
@@ -126,12 +127,12 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-modes: debug emits at least as many eve
126
127
  // Both runs are conformance-delay with the same input, so updates
127
128
  // events (run.started, node.started not in updates per spec, node.completed,
128
129
  // run.completed) should be a subset of debug events.
129
- expect(debugResult.events.length, driver.describe(
130
+ expect(debugResult.events.length, req('openwop.it.stream-modes.debug-stream-is-a-superset-of-updates-per-stream-modes-md-mode-mapping',
130
131
  'stream-modes.md mode-to-event mapping',
131
132
  'debug stream event count MUST be >= updates stream event count',
132
133
  )).toBeGreaterThanOrEqual(updatesResult.events.length);
133
134
 
134
- expect(debugResult.closedBy, driver.describe(
135
+ expect(debugResult.closedBy, req('openwop.it.stream-modes.debug-stream-is-a-superset-of-updates-per-stream-modes-md-mode-mapping',
135
136
  'stream-modes.md §debug',
136
137
  'debug stream MUST close on terminal event',
137
138
  )).toBe('server');
@@ -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('stream-subscribe-from-beginning: advertisement shape (RFC 0017)', () => {
33
35
  it('capabilities.queueBus 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.stream-subscribe-from-beginning.capabilities-queuebus-is-either-absent-or-a-well-formed-object',
39
41
  'capabilities.schema.json §queueBus',
40
42
  'capabilities.queueBus.supported MUST be a boolean when present',
41
43
  ),
@@ -44,17 +46,17 @@ describe('stream-subscribe-from-beginning: advertisement shape (RFC 0017)', () =
44
46
 
45
47
  it('stream.supported is a boolean when set', async () => {
46
48
  const cap = await readCap();
47
- if (!cap || cap.supported !== true) return;
49
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
48
50
  const subParts = ["stream","supported"];
49
51
  let sub: unknown = cap;
50
52
  for (const p of subParts) {
51
53
  if (sub && typeof sub === 'object') sub = (sub as Record<string, unknown>)[p];
52
54
  else { sub = undefined; break; }
53
55
  }
54
- if (sub === undefined) return; // optional sub-field
56
+ if (sub === undefined) return softSkip('blocked', 'precondition not met — `sub === undefined` returned early (optional sub-field) (seam, prior step, or fixture unavailable)'); // optional sub-field
55
57
  expect(
56
58
  typeof sub,
57
- driver.describe(
59
+ req('openwop.it.stream-subscribe-from-beginning.stream-supported-is-a-boolean-when-set',
58
60
  'RFC 0017 §A',
59
61
  'queueBus.stream.supported MUST be boolean when present',
60
62
  ),
@@ -69,7 +71,7 @@ async function call(op: string, args: Record<string, unknown>) {
69
71
  describe('stream-subscribe-from-beginning: behavioral (RFC 0017 §A stream.fromBeginning)', () => {
70
72
  it('streamPublish 5 records then streamSubscribe({fromBeginning:true}) MUST surface all 5 in the snapshot', async () => {
71
73
  const probe = await call('streamSubscribe', { stream: '__probe__', fromBeginning: true });
72
- if (probe.status === 404) return; // seam not exposed
74
+ 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
73
75
  const stream = `s-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
74
76
  for (let i = 1; i <= 5; i++) {
75
77
  const r = await call('streamPublish', { stream, record: { seq: i, value: `rec-${i}` } });
@@ -80,7 +82,7 @@ describe('stream-subscribe-from-beginning: behavioral (RFC 0017 §A stream.fromB
80
82
  const body = sub.json as { records?: Array<{ payload?: { seq?: number } }>; fromBeginningSnapshot?: boolean };
81
83
  expect(
82
84
  Array.isArray(body.records) && body.records.length === 5,
83
- driver.describe('RFC 0017 §A.stream.fromBeginning', 'subscribe with fromBeginning:true MUST return ALL records previously published on the stream'),
85
+ req('openwop.it.stream-subscribe-from-beginning.streampublish-5-records-then-streamsubscribe-frombeginning-true-must-surface-all', 'RFC 0017 §A.stream.fromBeginning', 'subscribe with fromBeginning:true MUST return ALL records previously published on the stream'),
84
86
  ).toBe(true);
85
87
  // Order MUST be preserved (publish-order = sequential on the same stream).
86
88
  const seqs = body.records!.map((r) => r.payload?.seq);
@@ -90,14 +92,14 @@ describe('stream-subscribe-from-beginning: behavioral (RFC 0017 §A stream.fromB
90
92
 
91
93
  it('streamSubscribe({fromBeginning:false}) MUST NOT include pre-subscribe records (live-tail semantics)', async () => {
92
94
  const probe = await call('streamSubscribe', { stream: '__probe__', fromBeginning: true });
93
- if (probe.status === 404) return;
95
+ if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
94
96
  const stream = `s-live-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
95
97
  await call('streamPublish', { stream, record: { v: 'before' } });
96
98
  const sub = await call('streamSubscribe', { stream, fromBeginning: false });
97
99
  const body = sub.json as { records?: unknown[]; fromBeginningSnapshot?: boolean };
98
100
  expect(
99
101
  Array.isArray(body.records) && body.records.length === 0,
100
- driver.describe('RFC 0017 §A.stream.fromBeginning', 'subscribe with fromBeginning:false MUST omit pre-subscribe records'),
102
+ req('openwop.it.stream-subscribe-from-beginning.streamsubscribe-frombeginning-false-must-not-include-pre-subscribe-records-live', 'RFC 0017 §A.stream.fromBeginning', 'subscribe with fromBeginning:false MUST omit pre-subscribe records'),
101
103
  ).toBe(true);
102
104
  expect(body.fromBeginningSnapshot).toBe(false);
103
105
  });
@@ -38,6 +38,7 @@ import { subscribe } from '../lib/sse.js';
38
38
  import { pollUntilTerminal } from '../lib/polling.js';
39
39
  import { isFixtureAdvertised } from '../lib/fixtures.js';
40
40
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
41
+ import { req } from '../lib/requirement-ids.js';
41
42
 
42
43
  const FIXTURE_ID = 'conformance-stream-text';
43
44
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(FIXTURE_ID);
@@ -105,7 +106,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
105
106
  }
106
107
  expect(
107
108
  create.status,
108
- driver.describe(
109
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close',
109
110
  'fixtures.md §conformance-stream-text',
110
111
  'a test key MUST be able to start the fixture with configurable.mockProvider',
111
112
  ),
@@ -120,7 +121,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
120
121
  // 3) server-closed, not timeout.
121
122
  expect(
122
123
  result.closedBy,
123
- driver.describe('stream-modes.md §messages', 'server MUST close the messages stream on terminal run status'),
124
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'stream-modes.md §messages', 'server MUST close the messages stream on terminal run status'),
124
125
  ).toBe('server');
125
126
 
126
127
  // Collect ai.message.chunk payloads. Per stream-modes.md the SSE event
@@ -141,7 +142,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
141
142
 
142
143
  expect(
143
144
  chunks.length,
144
- driver.describe(
145
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close',
145
146
  'stream-modes.md §messages',
146
147
  'messages mode MUST emit ai.message.chunk SSE events for the streaming AI node',
147
148
  ),
@@ -150,7 +151,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
150
151
  // 1) Token order matches the mock config exactly.
151
152
  expect(
152
153
  chunks.map((c) => c.chunk),
153
- driver.describe(
154
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close',
154
155
  'fixtures.md §conformance-stream-text',
155
156
  'chunk arrival order MUST match the mock token order',
156
157
  ),
@@ -160,32 +161,32 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
160
161
  const last = chunks[chunks.length - 1]!;
161
162
  expect(
162
163
  last.isLast,
163
- driver.describe(
164
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close',
164
165
  'stream-modes.md §messages + RFC 0094 §D',
165
166
  'the final ai.message.chunk MUST carry isLast: true',
166
167
  ),
167
168
  ).toBe(true);
168
169
  expect(
169
170
  last.meta?.finishReason,
170
- driver.describe('stream-modes.md §messages (Tier 1)', 'final chunk meta.finishReason MUST be "stop"'),
171
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'stream-modes.md §messages (Tier 1)', 'final chunk meta.finishReason MUST be "stop"'),
171
172
  ).toBe('stop');
172
173
  expect(
173
174
  last.meta?.usage?.completionTokens,
174
- driver.describe('stream-modes.md §messages (Tier 1)', 'final chunk meta.usage.completionTokens MUST echo the mock usage'),
175
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'stream-modes.md §messages (Tier 1)', 'final chunk meta.usage.completionTokens MUST echo the mock usage'),
175
176
  ).toBe(4);
176
177
 
177
178
  // Minimum compliant payload fields are present on every chunk.
178
179
  for (const c of chunks) {
179
- expect(typeof c.nodeId, driver.describe('run-event-payloads.schema.json §outputChunk', 'nodeId MUST be a string')).toBe('string');
180
- expect(typeof c.runId, driver.describe('run-event-payloads.schema.json §outputChunk', 'runId MUST be a string')).toBe('string');
181
- expect(typeof c.isLast, driver.describe('run-event-payloads.schema.json §outputChunk', 'isLast MUST be a boolean')).toBe('boolean');
180
+ expect(typeof c.nodeId, req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'run-event-payloads.schema.json §outputChunk', 'nodeId MUST be a string')).toBe('string');
181
+ expect(typeof c.runId, req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'run-event-payloads.schema.json §outputChunk', 'runId MUST be a string')).toBe('string');
182
+ expect(typeof c.isLast, req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'run-event-payloads.schema.json §outputChunk', 'isLast MUST be a boolean')).toBe('boolean');
182
183
  }
183
184
 
184
185
  // 4) Terminal completed.
185
186
  const terminal = await pollUntilTerminal(runId);
186
187
  expect(
187
188
  terminal.status,
188
- driver.describe('fixtures.md §conformance-stream-text', 'the fixture run MUST reach terminal completed'),
189
+ req('openwop.it.stream-text-fixture.delivers-the-mocked-tokens-in-order-terminates-with-islast-meta-and-server-close', 'fixtures.md §conformance-stream-text', 'the fixture run MUST reach terminal completed'),
189
190
  ).toBe('completed');
190
191
  });
191
192
 
@@ -203,11 +204,11 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
203
204
  }
204
205
  expect(
205
206
  create.status,
206
- driver.describe('fixtures.md §conformance-stream-text', 'an unknown mockProvider.id MUST be rejected with 400'),
207
+ req('openwop.it.stream-text-fixture.an-unknown-mockprovider-id-is-rejected-with-400-unsupported-mock-provider', 'fixtures.md §conformance-stream-text', 'an unknown mockProvider.id MUST be rejected with 400'),
207
208
  ).toBe(400);
208
209
  expect(
209
210
  errCode(create.json),
210
- driver.describe('fixtures.md §conformance-stream-text', 'the refusal MUST carry the canonical unsupported_mock_provider code'),
211
+ req('openwop.it.stream-text-fixture.an-unknown-mockprovider-id-is-rejected-with-400-unsupported-mock-provider', 'fixtures.md §conformance-stream-text', 'the refusal MUST carry the canonical unsupported_mock_provider code'),
211
212
  ).toBe('unsupported_mock_provider');
212
213
  });
213
214
  });
@@ -21,6 +21,8 @@ import { driver } from '../lib/driver.js';
21
21
  import { subscribe, type SseEvent } from '../lib/sse.js';
22
22
  import { pollUntilTerminal } from '../lib/polling.js';
23
23
  import { isFixtureAdvertised } from '../lib/fixtures.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
24
26
 
25
27
  const WORKFLOW_ID = 'conformance-cancellable';
26
28
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
@@ -57,7 +59,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
57
59
  workflowId: WORKFLOW_ID,
58
60
  inputs: { delayMs: 2000 },
59
61
  });
60
- if (create.status !== 201) return; // host doesn't seed cancellable fixture; skip-equivalent
62
+ if (create.status !== 201) return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (host doesn\'t seed cancellable fixture; skip-equivalent) (seam, prior step, or fixture unavailable)'); // host doesn't seed cancellable fixture; skip-equivalent
61
63
 
62
64
  const runId = (create.json as { runId: string }).runId;
63
65
 
@@ -65,7 +67,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
65
67
  const firstHalf = await subscribe(`/v1/runs/${encodeURIComponent(runId)}/events`, {
66
68
  timeoutMs: 1000, // disconnect after ~1s
67
69
  });
68
- expect(firstHalf.status, driver.describe(
70
+ expect(firstHalf.status, req('openwop.it.streamReconnect.reconnect-with-last-event-id-resumes-without-loss-or-duplication',
69
71
  'spec/v1/stream-modes.md',
70
72
  'SSE endpoint MUST return 200',
71
73
  )).toBe(200);
@@ -82,7 +84,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
82
84
  // because the run already completed and the server closed before we
83
85
  // got events. Skip the rest of this scenario; the host is fast enough
84
86
  // that the reconnect path doesn't apply.
85
- return;
87
+ return softSkip('blocked', 'precondition not met — `lastSeen < 0` returned early (First connection emitted no events with a parseable sequence — e.g. because the run already completed and the server closed before we got events. Skip the rest of …');
86
88
  }
87
89
 
88
90
  // Phase 3: reconnect with Last-Event-ID set to the last seq we saw.
@@ -91,7 +93,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
91
93
  timeoutMs: 5000,
92
94
  lastEventId: String(lastSeen),
93
95
  });
94
- expect(resume.status, driver.describe(
96
+ expect(resume.status, req('openwop.it.streamReconnect.reconnect-with-last-event-id-resumes-without-loss-or-duplication',
95
97
  'spec/v1/stream-modes.md §"Reconnection"',
96
98
  'reconnection with Last-Event-ID MUST return 200',
97
99
  )).toBe(200);
@@ -102,7 +104,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
102
104
  // Hosts MAY replay the boundary event (some impls do; spec is
103
105
  // permissive). The strict assertion is "no event with seq <
104
106
  // lastSeen-1" — i.e., no events from before the resume point.
105
- expect(s, driver.describe(
107
+ expect(s, req('openwop.it.streamReconnect.reconnect-with-last-event-id-resumes-without-loss-or-duplication',
106
108
  'spec/v1/stream-modes.md §"Reconnection"',
107
109
  `resume MUST NOT yield events with seq < lastSeen-1; got ${s} after lastSeen=${lastSeen}`,
108
110
  )).toBeGreaterThanOrEqual(lastSeen - 1);
@@ -120,21 +122,21 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
120
122
  // Quick run, observe terminal seq, then attempt a reconnect after
121
123
  // terminal — server SHOULD close immediately with no events.
122
124
  const create = await driver.post('/v1/runs', { workflowId: 'conformance-noop' });
123
- if (create.status !== 201) return;
125
+ if (create.status !== 201) return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
124
126
  const runId = (create.json as { runId: string }).runId;
125
127
 
126
128
  const initial = await subscribe(`/v1/runs/${encodeURIComponent(runId)}/events`, {
127
129
  timeoutMs: 5000,
128
130
  });
129
- if (initial.status !== 200 || initial.events.length === 0) return;
131
+ if (initial.status !== 200 || initial.events.length === 0) return softSkip('blocked', 'precondition not met — `initial.status !== 200 || initial.events.length === 0` returned early (seam, prior step, or fixture unavailable)');
130
132
 
131
133
  const terminalEvent = initial.events.find(
132
134
  (e) => TERMINAL_TYPES.has(e.event) && e.id !== null && Number.isFinite(Number(e.id)),
133
135
  );
134
- if (!terminalEvent || terminalEvent.id === null) return;
136
+ if (!terminalEvent || terminalEvent.id === null) return softSkip('blocked', 'precondition not met — `!terminalEvent || terminalEvent.id === null` returned early (seam, prior step, or fixture unavailable)');
135
137
 
136
138
  const lastSeq = Number(terminalEvent.id);
137
- if (!Number.isFinite(lastSeq)) return;
139
+ if (!Number.isFinite(lastSeq)) return softSkip('blocked', 'precondition not met — `!Number.isFinite(lastSeq)` returned early (seam, prior step, or fixture unavailable)');
138
140
 
139
141
  const reconnect = await subscribe(`/v1/runs/${encodeURIComponent(runId)}/events`, {
140
142
  timeoutMs: 5000,
@@ -144,7 +146,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
144
146
  // Reconnect MUST succeed (200) and SHOULD close quickly with no
145
147
  // additional events beyond the terminal boundary. Permissive: the
146
148
  // host MAY replay the terminal event itself.
147
- expect(reconnect.status, driver.describe(
149
+ expect(reconnect.status, req('openwop.it.streamReconnect.reconnect-with-last-event-id-equal-to-terminal-seq-closes-immediately',
148
150
  'spec/v1/stream-modes.md §"Reconnection"',
149
151
  'reconnect after terminal MUST return 200',
150
152
  )).toBe(200);
@@ -152,7 +154,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-reconnect: Last-Event-ID resume per spe
152
154
  const newSeqs = reconnect.events
153
155
  .map(getSeq)
154
156
  .filter((s): s is number => s !== null && s > lastSeq);
155
- expect(newSeqs.length, driver.describe(
157
+ expect(newSeqs.length, req('openwop.it.streamReconnect.reconnect-with-last-event-id-equal-to-terminal-seq-closes-immediately',
156
158
  'spec/v1/stream-modes.md §"Reconnection"',
157
159
  'reconnect after terminal MUST NOT yield events with seq > lastSeq',
158
160
  )).toBe(0);
@@ -30,6 +30,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
30
30
  import { behaviorGate } from '../lib/behavior-gate.js';
31
31
  import { dispositionOf, resetLedger } from '../lib/requirement-ledger.js';
32
32
  import { __resetEnvCacheForTests } from '../lib/env.js';
33
+ import { req } from '../lib/requirement-ids.js';
33
34
 
34
35
  const ENV_KEYS = ['OPENWOP_REQUIRE_BEHAVIOR', 'OPENWOP_OPTED_OUT_PROFILES', 'OPENWOP_BASE_URL', 'OPENWOP_API_KEY'] as const;
35
36
  let saved: Record<string, string | undefined> = {};
@@ -65,16 +66,16 @@ describe('RFC 0148 §B — advertise and opt-out are mutually exclusive', () =>
65
66
  __resetEnvCacheForTests();
66
67
  expect(
67
68
  () => behaviorGate('openwop-audit-log-integrity', true),
68
- 'RFC 0148 §B: "A host MUST NOT both advertise and opt out of the same profile." ' +
69
+ req('openwop.it.strict-behavior-gate.advertising-and-opting-out-of-the-same-profile-fails', 'RFC 0148 §B', 'RFC 0148 §B: "A host MUST NOT both advertise and opt out of the same profile." ' +
69
70
  'The two claims are opposite in kind — one says the host implements the profile, the ' +
70
71
  'other says the operator declares it does not. A run where both hold has no defensible ' +
71
72
  'reading, and resolving it in favour of advertisement extracts MORE certification claim ' +
72
- 'from a MORE contradictory input.',
73
+ 'from a MORE contradictory input.'),
73
74
  ).toThrow(/MUST NOT both advertise and opt out/);
74
75
  });
75
76
 
76
77
  it('advertising alone proceeds', () => {
77
- expect(behaviorGate('openwop-audit-log-integrity', true)).toBe(true);
78
+ expect(behaviorGate('openwop-audit-log-integrity', true), req('openwop.it.strict-behavior-gate.advertising-alone-proceeds', 'RFC 0148 §B', 'advertising alone proceeds')).toBe(true);
78
79
  });
79
80
 
80
81
  it('opting out alone skips, in strict mode too', () => {
@@ -82,13 +83,13 @@ describe('RFC 0148 §B — advertise and opt-out are mutually exclusive', () =>
82
83
  __resetEnvCacheForTests();
83
84
  process.env['OPENWOP_REQUIRE_BEHAVIOR'] = 'true';
84
85
  __resetEnvCacheForTests();
85
- expect(behaviorGate('openwop-audit-log-integrity', false)).toBe(false);
86
+ expect(behaviorGate('openwop-audit-log-integrity', false), req('openwop.it.strict-behavior-gate.opting-out-alone-skips-in-strict-mode-too', 'RFC 0148 §B', 'opting out alone skips, in strict mode too')).toBe(false);
86
87
  });
87
88
 
88
89
  it('strict mode fails an unadvertised, non-opted-out profile', () => {
89
90
  process.env['OPENWOP_REQUIRE_BEHAVIOR'] = 'true';
90
91
  __resetEnvCacheForTests();
91
- expect(() => behaviorGate('openwop-audit-log-integrity', false)).toThrow();
92
+ expect(() => behaviorGate('openwop-audit-log-integrity', false), req('openwop.it.strict-behavior-gate.strict-mode-fails-an-unadvertised-non-opted-out-profile', 'RFC 0148 §B', 'strict mode fails an unadvertised, non-opted-out profile')).toThrow();
92
93
  });
93
94
  });
94
95
 
@@ -100,7 +101,7 @@ describe('RFC 0148 §B — gate decisions record a ledger disposition', () => {
100
101
  process.env['OPENWOP_OPTED_OUT_PROFILES'] = 'openwop-audit-log-integrity';
101
102
  __resetEnvCacheForTests();
102
103
  behaviorGate('openwop-audit-log-integrity', false);
103
- expect(dispositionOf('openwop.profile.openwop-audit-log-integrity')).toBe('skipped');
104
+ expect(dispositionOf('openwop.profile.openwop-audit-log-integrity'), req('openwop.it.strict-behavior-gate.an-honest-opt-out-records-skipped-not-silence', 'RFC 0148 §B', 'an honest opt-out records `skipped`, not silence')).toBe('skipped');
104
105
  });
105
106
 
106
107
  it('a default-mode soft-skip records `inapplicable`', () => {
@@ -109,12 +110,12 @@ describe('RFC 0148 §B — gate decisions record a ledger disposition', () => {
109
110
  // statement from "we could not check", and it is certifiable where
110
111
  // `blocked` is not.
111
112
  behaviorGate('openwop-audit-log-integrity', false);
112
- expect(dispositionOf('openwop.profile.openwop-audit-log-integrity')).toBe('inapplicable');
113
+ expect(dispositionOf('openwop.profile.openwop-audit-log-integrity'), req('openwop.it.strict-behavior-gate.a-default-mode-soft-skip-records-inapplicable', 'RFC 0148 §B', 'a default-mode soft-skip records `inapplicable`')).toBe('inapplicable');
113
114
  });
114
115
 
115
116
  it('an unexercised profile stays `blocked`', () => {
116
117
  // Nothing called the gate at all. §A's default holds: silence is not a pass,
117
118
  // and it is not certifiable either.
118
- expect(dispositionOf('openwop.profile.openwop-never-touched')).toBe('blocked');
119
+ expect(dispositionOf('openwop.profile.openwop-never-touched'), req('openwop.it.strict-behavior-gate.an-unexercised-profile-stays-blocked', 'RFC 0148 §B', 'an unexercised profile stays `blocked`')).toBe('blocked');
119
120
  });
120
121
  });
@@ -14,8 +14,8 @@
14
14
 
15
15
  import { describe, it, expect } from 'vitest';
16
16
  import { softSkip } from '../lib/soft-skip.js';
17
- import { driver } from '../lib/driver.js';
18
17
  import { readSubRunAttestationCap, invokeSubRunAttest } from '../lib/subRunAttestation.js';
18
+ import { req } from '../lib/requirement-ids.js';
19
19
 
20
20
  describe('subrun-approval-fail-closed (RFC 0063 §C)', () => {
21
21
  it('no accept/edit-accept (terminated or expired) MUST NOT merge', async () => {
@@ -28,7 +28,7 @@ describe('subrun-approval-fail-closed (RFC 0063 §C)', () => {
28
28
  if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
29
29
  expect(
30
30
  res.merged,
31
- driver.describe('RFC 0063 §C', 'an unresolved approval MUST fail closed — outputs MUST NOT be merged'),
31
+ req('openwop.it.subrun-approval-fail-closed.no-accept-edit-accept-terminated-or-expired-must-not-merge', 'RFC 0063 §C', 'an unresolved approval MUST fail closed — outputs MUST NOT be merged'),
32
32
  ).toBe(false);
33
33
  });
34
34
  });