@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
@@ -47,6 +47,8 @@ import { SCHEMAS_DIR, FIXTURES_DIR } from '../lib/paths.js';
47
47
  import { driver } from '../lib/driver.js';
48
48
  import { behaviorGate } from '../lib/behavior-gate.js';
49
49
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
50
+ import { req } from '../lib/requirement-ids.js';
51
+ import { softSkip } from '../lib/soft-skip.js';
50
52
 
51
53
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
52
54
 
@@ -74,7 +76,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
74
76
  const ev = JSON.parse(readFileSync(EVENT_FIXTURE, 'utf8'));
75
77
  expect(
76
78
  validate(ev),
77
- `trigger-event.schema.json MUST accept a conforming email TriggerEvent. Errors: ${JSON.stringify(validate.errors)}`,
79
+ req('openwop.it.trigger-ingestion.the-canonical-email-triggerevent-fixture-validates', 'RFC 0099', `trigger-event.schema.json MUST accept a conforming email TriggerEvent. Errors: ${JSON.stringify(validate.errors)}`),
78
80
  ).toBe(true);
79
81
  });
80
82
 
@@ -83,7 +85,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
83
85
  ev.webhook = { method: 'POST', body: { x: 1 } };
84
86
  expect(
85
87
  validate(ev),
86
- 'trigger-bridge.md §F.1 — a TriggerEvent MUST carry exactly the per-source sub-object matching its `source` and MUST NOT carry the others',
88
+ req('openwop.it.trigger-ingestion.the-f-1-one-of-rule-holds-a-source-email-event-carrying-a-webhook-sub-object-fai', 'RFC 0099', 'trigger-bridge.md §F.1 — a TriggerEvent MUST carry exactly the per-source sub-object matching its `source` and MUST NOT carry the others'),
87
89
  ).toBe(false);
88
90
  });
89
91
 
@@ -92,7 +94,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
92
94
  ev.contentTrust = 'trusted';
93
95
  expect(
94
96
  validate(ev),
95
- 'trigger-bridge.md §F.1 — `contentTrust` MUST be `"untrusted"`',
97
+ req('openwop.it.trigger-ingestion.contenttrust-must-be-the-const-untrusted', 'RFC 0099', 'trigger-bridge.md §F.1 — `contentTrust` MUST be `"untrusted"`'),
96
98
  ).toBe(false);
97
99
  });
98
100
 
@@ -102,7 +104,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
102
104
  noRef.email.attachments = [{ filename: 'x.png' }];
103
105
  expect(
104
106
  validate(noRef),
105
- 'SECURITY invariant trigger-ingestion-ssrf — an AttachmentRef MUST carry a host-internal `ref`',
107
+ req('openwop.it.trigger-ingestion.attachmentref-requires-a-host-internal-ref-and-rejects-a-raw-external-url-trigge', 'RFC 0099', 'SECURITY invariant trigger-ingestion-ssrf — an AttachmentRef MUST carry a host-internal `ref`'),
106
108
  ).toBe(false);
107
109
 
108
110
  // A raw external `url` the run would fetch itself → invalid
@@ -111,7 +113,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
111
113
  rawUrl.email.attachments = [{ ref: 'blob_a1', url: 'http://169.254.169.254/latest/meta-data/' }];
112
114
  expect(
113
115
  validate(rawUrl),
114
- 'SECURITY invariant trigger-ingestion-ssrf — the host MUST NOT hand the run an external URL to fetch itself; AttachmentRef is a host-internal handle only',
116
+ req('openwop.it.trigger-ingestion.attachmentref-requires-a-host-internal-ref-and-rejects-a-raw-external-url-trigge', 'RFC 0099', 'SECURITY invariant trigger-ingestion-ssrf — the host MUST NOT hand the run an external URL to fetch itself; AttachmentRef is a host-internal handle only'),
115
117
  ).toBe(false);
116
118
  });
117
119
 
@@ -127,7 +129,7 @@ describe('trigger-ingestion: TriggerEvent schema (always-on, server-free)', () =
127
129
  };
128
130
  expect(
129
131
  validate(ev),
130
- `a conforming webhook TriggerEvent MUST validate. Errors: ${JSON.stringify(validate.errors)}`,
132
+ req('openwop.it.trigger-ingestion.a-webhook-triggerevent-with-an-allowlisted-header-validates', 'RFC 0099', `a conforming webhook TriggerEvent MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
131
133
  ).toBe(true);
132
134
  });
133
135
  });
@@ -143,7 +145,7 @@ describe('trigger-ingestion: content-freeness of the durable trigger.delivery.at
143
145
  const deliveryDef = payloads.$defs?.triggerDeliveryAttempted;
144
146
 
145
147
  it('trigger.delivery.attempted declares only the content-free RFC 0083 §C fields', () => {
146
- expect(deliveryDef, 'run-event-payloads.schema.json MUST define triggerDeliveryAttempted').toBeDefined();
148
+ expect(deliveryDef, req('openwop.it.trigger-ingestion.trigger-delivery-attempted-declares-only-the-content-free-rfc-0083-c-fields', 'RFC 0083 §C', 'run-event-payloads.schema.json MUST define triggerDeliveryAttempted')).toBeDefined();
147
149
  const props = Object.keys(deliveryDef.properties ?? {});
148
150
  // The complete content-free field set — no `body`, `headers`, `email`,
149
151
  // `form`, `fields`, or any inbound-content carrier.
@@ -151,7 +153,7 @@ describe('trigger-ingestion: content-freeness of the durable trigger.delivery.at
151
153
  for (const banned of ['body', 'headers', 'email', 'form', 'fields', 'html', 'text', 'subject']) {
152
154
  expect(
153
155
  props.includes(banned),
154
- `trigger-ingestion-content-redaction — the durable trigger.delivery.attempted payload MUST NOT carry an inbound-content field ("${banned}")`,
156
+ req('openwop.it.trigger-ingestion.trigger-delivery-attempted-declares-only-the-content-free-rfc-0083-c-fields', 'RFC 0083 §C', `trigger-ingestion-content-redaction — the durable trigger.delivery.attempted payload MUST NOT carry an inbound-content field ("${banned}")`),
155
157
  ).toBe(false);
156
158
  }
157
159
  });
@@ -165,16 +167,16 @@ describe('trigger-ingestion: TriggerSubscriptionRegistration schema (always-on,
165
167
  const reg = JSON.parse(readFileSync(REG_FIXTURE, 'utf8'));
166
168
  expect(
167
169
  validate(reg),
168
- `trigger-subscription-registration.schema.json MUST accept a conforming registration. Errors: ${JSON.stringify(validate.errors)}`,
170
+ req('openwop.it.trigger-ingestion.the-canonical-registration-fixture-validates', 'RFC 0099', `trigger-subscription-registration.schema.json MUST accept a conforming registration. Errors: ${JSON.stringify(validate.errors)}`),
169
171
  ).toBe(true);
170
172
  });
171
173
 
172
174
  it('requires source + workflowId and rejects an out-of-enum source', () => {
173
- expect(validate({ workflowId: 'w' }), 'registration MUST require `source`').toBe(false);
174
- expect(validate({ source: 'email' }), 'registration MUST require `workflowId`').toBe(false);
175
+ expect(validate({ workflowId: 'w' }), req('openwop.it.trigger-ingestion.requires-source-workflowid-and-rejects-an-out-of-enum-source', 'RFC 0099', 'registration MUST require `source`')).toBe(false);
176
+ expect(validate({ source: 'email' }), req('openwop.it.trigger-ingestion.requires-source-workflowid-and-rejects-an-out-of-enum-source', 'RFC 0099', 'registration MUST require `workflowId`')).toBe(false);
175
177
  expect(
176
178
  validate({ source: 'schedule', workflowId: 'w' }),
177
- 'registration `source` MUST be one of webhook/email/form (schedule is not externally registerable)',
179
+ req('openwop.it.trigger-ingestion.requires-source-workflowid-and-rejects-an-out-of-enum-source', 'RFC 0099', 'registration `source` MUST be one of webhook/email/form (schedule is not externally registerable)'),
178
180
  ).toBe(false);
179
181
  });
180
182
  });
@@ -192,13 +194,13 @@ describe.skipIf(HTTP_SKIP)('trigger-ingestion: behavioral ingestion + SSRF (capa
192
194
  verification: { mode: 'none' },
193
195
  attachmentUrl: 'http://169.254.169.254/latest/meta-data/',
194
196
  });
195
- if (ssrf.status === 404 || ssrf.status === 403) return; // seam unwired — soft-skip
197
+ if (ssrf.status === 404 || ssrf.status === 403) return softSkip('blocked', 'precondition not met — `ssrf.status === 404 || ssrf.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
196
198
 
197
199
  const ssrfBody = ssrf.json as { triggerEvent?: { email?: { attachments?: unknown[] } }; ssrfRefused?: boolean } | undefined;
198
200
  expect(
199
201
  ssrfBody?.ssrfRefused === true ||
200
202
  (ssrfBody?.triggerEvent?.email?.attachments ?? []).length === 0,
201
- driver.describe(
203
+ req('openwop.it.trigger-ingestion.an-ingestion-path-fetch-to-a-private-address-is-refused-a-delivered-event-is-con',
202
204
  'trigger-bridge.md §F.4',
203
205
  'trigger-ingestion-ssrf — an ingestion-path fetch to a private address MUST be refused (attachment dropped), the run still starting on the rest of the event',
204
206
  ),
@@ -211,14 +213,14 @@ describe.skipIf(HTTP_SKIP)('trigger-ingestion: behavioral ingestion + SSRF (capa
211
213
  verification: { mode: 'none' },
212
214
  webhook: { method: 'POST', headers: { Authorization: 'Bearer canary' }, body: { x: 1 } },
213
215
  });
214
- if (del.status === 404 || del.status === 403) return;
216
+ if (del.status === 404 || del.status === 403) return softSkip('blocked', 'precondition not met — `del.status === 404 || del.status === 403` returned early (seam, prior step, or fixture unavailable)');
215
217
  const delBody = del.json as
216
218
  | { deliveryEvent?: Record<string, unknown>; triggerEvent?: { webhook?: { headers?: Record<string, string> } } }
217
219
  | undefined;
218
220
  const evtJson = JSON.stringify(delBody?.deliveryEvent ?? {});
219
221
  expect(
220
222
  evtJson.includes('Bearer canary') === false && evtJson.includes('Authorization') === false,
221
- driver.describe(
223
+ req('openwop.it.trigger-ingestion.an-ingestion-path-fetch-to-a-private-address-is-refused-a-delivered-event-is-con',
222
224
  'trigger-bridge.md §F.4',
223
225
  'trigger-ingestion-content-redaction — the durable trigger.delivery.attempted MUST NOT carry inbound body/header content',
224
226
  ),
@@ -226,7 +228,7 @@ describe.skipIf(HTTP_SKIP)('trigger-ingestion: behavioral ingestion + SSRF (capa
226
228
  const passedHeaders = delBody?.triggerEvent?.webhook?.headers ?? {};
227
229
  expect(
228
230
  Object.keys(passedHeaders).every((k) => k.toLowerCase() !== 'authorization'),
229
- driver.describe(
231
+ req('openwop.it.trigger-ingestion.an-ingestion-path-fetch-to-a-private-address-is-refused-a-delivered-event-is-con',
230
232
  'trigger-bridge.md §F.1',
231
233
  'webhook.headers MUST be a host-curated allowlist — Authorization MUST NOT pass through',
232
234
  ),
@@ -48,6 +48,8 @@ import { driver } from '../lib/driver.js';
48
48
  import { behaviorGate } from '../lib/behavior-gate.js';
49
49
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
50
50
  import { driveDelivery } from '../lib/triggerBridge.js';
51
+ import { req } from '../lib/requirement-ids.js';
52
+ import { softSkip } from '../lib/soft-skip.js';
51
53
 
52
54
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
53
55
 
@@ -71,7 +73,7 @@ describe('trigger-stream-cdc: TriggerEvent schema for stream/change (always-on,
71
73
  const ev = JSON.parse(readFileSync(STREAM_FIXTURE, 'utf8'));
72
74
  expect(
73
75
  validate(ev),
74
- `trigger-event.schema.json MUST accept a conforming stream TriggerEvent (RFC 0127 §2). Errors: ${JSON.stringify(validate.errors)}`,
76
+ req('openwop.it.trigger-stream-cdc-sources.the-canonical-stream-triggerevent-fixture-validates', 'RFC 0127', `trigger-event.schema.json MUST accept a conforming stream TriggerEvent (RFC 0127 §2). Errors: ${JSON.stringify(validate.errors)}`),
75
77
  ).toBe(true);
76
78
  });
77
79
 
@@ -79,7 +81,7 @@ describe('trigger-stream-cdc: TriggerEvent schema for stream/change (always-on,
79
81
  const ev = JSON.parse(readFileSync(CHANGE_FIXTURE, 'utf8'));
80
82
  expect(
81
83
  validate(ev),
82
- `trigger-event.schema.json MUST accept a conforming change TriggerEvent (RFC 0127 §2 / RFC 0128 §1). Errors: ${JSON.stringify(validate.errors)}`,
84
+ req('openwop.it.trigger-stream-cdc-sources.the-canonical-change-triggerevent-fixture-validates-op-permittedpurposes-present', 'RFC 0127', `trigger-event.schema.json MUST accept a conforming change TriggerEvent (RFC 0127 §2 / RFC 0128 §1). Errors: ${JSON.stringify(validate.errors)}`),
83
85
  ).toBe(true);
84
86
  });
85
87
 
@@ -88,7 +90,7 @@ describe('trigger-stream-cdc: TriggerEvent schema for stream/change (always-on,
88
90
  delete ev.change.op;
89
91
  expect(
90
92
  validate(ev),
91
- 'RFC 0127 §2 — `op` (insert|update|delete) is REQUIRED on a change event (schema-enforced in the ChangeEvent $def)',
93
+ req('openwop.it.trigger-stream-cdc-sources.a-change-event-without-op-fails-changeevent-requires-the-operation-discriminator', 'RFC 0127', 'RFC 0127 §2 — `op` (insert|update|delete) is REQUIRED on a change event (schema-enforced in the ChangeEvent $def)'),
92
94
  ).toBe(false);
93
95
  });
94
96
 
@@ -97,7 +99,7 @@ describe('trigger-stream-cdc: TriggerEvent schema for stream/change (always-on,
97
99
  ev.change.op = 'upsert';
98
100
  expect(
99
101
  validate(ev),
100
- 'RFC 0127 §2 — `op` MUST be one of insert|update|delete',
102
+ req('openwop.it.trigger-stream-cdc-sources.an-out-of-enum-op-fails', 'RFC 0127', 'RFC 0127 §2 — `op` MUST be one of insert|update|delete'),
101
103
  ).toBe(false);
102
104
  });
103
105
 
@@ -106,7 +108,7 @@ describe('trigger-stream-cdc: TriggerEvent schema for stream/change (always-on,
106
108
  ev.change = { op: 'insert', table: 't' };
107
109
  expect(
108
110
  validate(ev),
109
- 'trigger-bridge.md §F.1 — a TriggerEvent MUST carry exactly the per-source sub-object matching its `source` and MUST NOT carry the others (extends to stream/change per RFC 0127)',
111
+ req('openwop.it.trigger-stream-cdc-sources.the-f-1-exactly-one-rule-extends-a-source-stream-event-carrying-a-change-sub-obj', 'RFC 0127', 'trigger-bridge.md §F.1 — a TriggerEvent MUST carry exactly the per-source sub-object matching its `source` and MUST NOT carry the others (extends to stream/change per RFC 0127)'),
110
112
  ).toBe(false);
111
113
  });
112
114
  });
@@ -121,7 +123,7 @@ describe('trigger-stream-cdc: registration + capabilities vocabulary (always-on,
121
123
  for (const source of ['stream', 'change']) {
122
124
  expect(
123
125
  validateReg({ source, workflowId: 'wf_1' }),
124
- `trigger-subscription-registration.schema.json MUST accept source:"${source}" (RFC 0127 §1). Errors: ${JSON.stringify(validateReg.errors)}`,
126
+ req('openwop.it.trigger-stream-cdc-sources.a-registration-accepts-source-stream-and-source-change', 'RFC 0127', `trigger-subscription-registration.schema.json MUST accept source:"${source}" (RFC 0127 §1). Errors: ${JSON.stringify(validateReg.errors)}`),
125
127
  ).toBe(true);
126
128
  }
127
129
  });
@@ -132,8 +134,8 @@ describe('trigger-stream-cdc: registration + capabilities vocabulary (always-on,
132
134
  const sources: string[] = tb.sources?.items?.enum ?? [];
133
135
  const external: string[] = tb.ingestion?.properties?.externalSources?.items?.enum ?? [];
134
136
  for (const v of ['stream', 'change']) {
135
- expect(sources.includes(v), `RFC 0127 §1 — triggerBridge.sources[] enum MUST include "${v}"`).toBe(true);
136
- expect(external.includes(v), `RFC 0127 §3 — ingestion.externalSources[] enum MUST include "${v}"`).toBe(true);
137
+ expect(sources.includes(v), req('openwop.it.trigger-stream-cdc-sources.the-capabilities-source-enums-include-stream-change-regression-pin', 'RFC 0127', `RFC 0127 §1 — triggerBridge.sources[] enum MUST include "${v}"`)).toBe(true);
138
+ expect(external.includes(v), req('openwop.it.trigger-stream-cdc-sources.the-capabilities-source-enums-include-stream-change-regression-pin', 'RFC 0127', `RFC 0127 §3 — ingestion.externalSources[] enum MUST include "${v}"`)).toBe(true);
137
139
  }
138
140
  });
139
141
  });
@@ -169,7 +171,7 @@ describe.skipIf(HTTP_SKIP)('trigger-stream-cdc: behavioral ingestion + dedup (ca
169
171
  if ((res.status === 404 || res.status === 405 || res.status === 400 || res.status === 422) && !advertisesNew) continue; // pre-0127 host — soft-skip this source
170
172
  expect(
171
173
  res.status < 400,
172
- driver.describe(
174
+ req('openwop.it.trigger-stream-cdc-sources.a-stream-and-a-change-event-each-ingest-to-a-run-with-a-schema-valid-envelope-an',
173
175
  'trigger-bridge.md §F.5',
174
176
  `a host advertising ingestion of "${body.source as string}" MUST ingest it (advertise-only-what-you-honor, RFC 0127 §Negative example) — got HTTP ${res.status}`,
175
177
  ),
@@ -178,7 +180,7 @@ describe.skipIf(HTTP_SKIP)('trigger-stream-cdc: behavioral ingestion + dedup (ca
178
180
  const out = res.json as { triggerEvent?: Record<string, unknown>; deliveryEvent?: Record<string, unknown> } | undefined;
179
181
  expect(
180
182
  validate(out?.triggerEvent),
181
- driver.describe(
183
+ req('openwop.it.trigger-stream-cdc-sources.a-stream-and-a-change-event-each-ingest-to-a-run-with-a-schema-valid-envelope-an',
182
184
  'trigger-bridge.md §F.5',
183
185
  `the delivered ${body.source as string} envelope MUST validate against trigger-event.schema.json. Errors: ${JSON.stringify(validate.errors)}`,
184
186
  ),
@@ -188,7 +190,7 @@ describe.skipIf(HTTP_SKIP)('trigger-stream-cdc: behavioral ingestion + dedup (ca
188
190
  const durable = JSON.stringify(out?.deliveryEvent ?? {});
189
191
  expect(
190
192
  !durable.includes('CANARY-STREAM-BODY') && !durable.includes('CANARY-CHANGE-BODY'),
191
- driver.describe(
193
+ req('openwop.it.trigger-stream-cdc-sources.a-stream-and-a-change-event-each-ingest-to-a-run-with-a-schema-valid-envelope-an',
192
194
  'trigger-bridge.md §F.5 (SR-1)',
193
195
  'the durable trigger.delivery.attempted MUST be content-free — the broker message / CDC row body has no slot on the event log',
194
196
  ),
@@ -202,11 +204,11 @@ describe.skipIf(HTTP_SKIP)('trigger-stream-cdc: behavioral ingestion + dedup (ca
202
204
  if (!behaviorGate('triggerBridge.ingestion', (external.length ?? 0) > 0)) return;
203
205
 
204
206
  const first = await driveDelivery({ scenario: 'dedup', dedupKey: 'events:3:99001', source: 'stream' });
205
- if (first === null) return; // delivery seam unwired — soft-skip
206
- if (first.outcome === undefined && !external.includes('stream')) return; // pre-0127 host — soft-skip
207
+ if (first === null) return softSkip('blocked', 'precondition not met — `first === null` returned early (delivery seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // delivery seam unwired — soft-skip
208
+ if (first.outcome === undefined && !external.includes('stream')) return softSkip('blocked', 'precondition not met — `first.outcome === undefined && !external.includes(\'stream\')` returned early (pre-0127 host — soft-skip) (seam, prior step, or fixture unavailable)'); // pre-0127 host — soft-skip
207
209
  expect(
208
210
  first.deliveredCount === 1 || first.outcome === 'delivered',
209
- driver.describe(
211
+ req('openwop.it.trigger-stream-cdc-sources.stream-dedup-the-same-broker-coordinates-delivered-twice-are-effectively-once-c',
210
212
  'trigger-bridge.md §F.5 / §C-1',
211
213
  'a stream event dedup-keyed on (topic,partition,offset) redelivered within the window MUST be effectively-once — reuses the RFC 0083 §C-1 ≥24h floor unchanged',
212
214
  ),
@@ -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('vector-knn-roundtrip: advertisement shape (RFC 0018)', () => {
33
35
  it('capabilities.vectorStore 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.vector-knn-roundtrip.capabilities-vectorstore-is-either-absent-or-a-well-formed-object',
39
41
  'capabilities.schema.json §vectorStore',
40
42
  'capabilities.vectorStore.supported MUST be a boolean when present',
41
43
  ),
@@ -50,7 +52,7 @@ async function call(op: string, args: Record<string, unknown>) {
50
52
  describe('vector-knn-roundtrip: behavioral (RFC 0018 §A.vectorStore)', () => {
51
53
  it('upsert 10 vectors → query with one of them returns it as the top match', async () => {
52
54
  const probe = await call('query', { namespace: '__probe__', vector: [1, 0], topK: 1 });
53
- if (probe.status === 404) return; // seam not exposed
55
+ 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
54
56
  const namespace = `knn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
55
57
  const items = Array.from({ length: 10 }, (_, i) => ({
56
58
  id: `vec-${i}`,
@@ -62,17 +64,17 @@ describe('vector-knn-roundtrip: behavioral (RFC 0018 §A.vectorStore)', () => {
62
64
  const queryRes = await call('query', { namespace, vector: items[3]!.vector, topK: 1 });
63
65
  expect(queryRes.status).toBe(200);
64
66
  const body = queryRes.json as { matches?: Array<{ id?: string; score?: number }> };
65
- expect(Array.isArray(body.matches), 'matches MUST be an array').toBe(true);
67
+ expect(Array.isArray(body.matches), req('openwop.it.vector-knn-roundtrip.upsert-10-vectors-query-with-one-of-them-returns-it-as-the-top-match', 'RFC 0018 §A.vectorStore', 'matches MUST be an array')).toBe(true);
66
68
  expect(body.matches!.length).toBeGreaterThan(0);
67
69
  expect(
68
70
  body.matches![0]!.id,
69
- driver.describe('RFC 0018 §A.vectorStore', 'query with an indexed vector MUST return it as the top match'),
71
+ req('openwop.it.vector-knn-roundtrip.upsert-10-vectors-query-with-one-of-them-returns-it-as-the-top-match', 'RFC 0018 §A.vectorStore', 'query with an indexed vector MUST return it as the top match'),
70
72
  ).toBe('vec-3');
71
73
  });
72
74
 
73
75
  it('topK respects the configured limit', async () => {
74
76
  const probe = await call('query', { namespace: '__probe__', vector: [1, 0], topK: 1 });
75
- if (probe.status === 404) return;
77
+ if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
76
78
  const namespace = `topk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
77
79
  const items = Array.from({ length: 8 }, (_, i) => ({
78
80
  id: `t-${i}`,
@@ -83,7 +85,7 @@ describe('vector-knn-roundtrip: behavioral (RFC 0018 §A.vectorStore)', () => {
83
85
  const body = r3.json as { matches?: unknown[] };
84
86
  expect(
85
87
  Array.isArray(body.matches) && body.matches.length <= 3,
86
- driver.describe('RFC 0018 §A.vectorStore', 'query MUST return at most topK matches'),
88
+ req('openwop.it.vector-knn-roundtrip.topk-respects-the-configured-limit', 'RFC 0018 §A.vectorStore', 'query MUST return at most topK matches'),
87
89
  ).toBe(true);
88
90
  });
89
91
  });
@@ -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/agents/verify-run';
28
30
 
@@ -48,26 +50,26 @@ describe('verifier-gating (RFC 0090 §B)', () => {
48
50
 
49
51
  // FAIL verdict → must NOT complete as success; agent.verified{fail} emitted.
50
52
  const failRes = await driver.post(SEAM, { simulateVerdict: 'fail' });
51
- if (failRes.status === 404) return; // seam unwired — soft-skip
53
+ if (failRes.status === 404) return softSkip('blocked', 'precondition not met — `failRes.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
52
54
  expect(
53
55
  verifiedVerdict(failRes.json) === 'fail',
54
- driver.describe('RFC 0090 §A', 'a verify-run forcing a fail MUST emit agent.verified{verdict:"fail"}'),
56
+ req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §A', 'a verify-run forcing a fail MUST emit agent.verified{verdict:"fail"}'),
55
57
  ).toBe(true);
56
58
  expect(
57
59
  !isSuccess(failRes.json),
58
- driver.describe('RFC 0090 §B', 'on a gating host a fail verdict MUST block commit/terminate-as-success'),
60
+ req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §B', 'on a gating host a fail verdict MUST block commit/terminate-as-success'),
59
61
  ).toBe(true);
60
62
 
61
63
  // PASS verdict → completes normally.
62
64
  const passRes = await driver.post(SEAM, { simulateVerdict: 'pass' });
63
- if (passRes.status === 404) return;
65
+ if (passRes.status === 404) return softSkip('blocked', 'precondition not met — `passRes.status === 404` returned early (seam, prior step, or fixture unavailable)');
64
66
  expect(
65
67
  verifiedVerdict(passRes.json) === 'pass',
66
- driver.describe('RFC 0090 §A', 'a verify-run forcing a pass MUST emit agent.verified{verdict:"pass"}'),
68
+ req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §A', 'a verify-run forcing a pass MUST emit agent.verified{verdict:"pass"}'),
67
69
  ).toBe(true);
68
70
  expect(
69
71
  isSuccess(passRes.json),
70
- driver.describe('RFC 0090 §B', 'a pass verdict MUST allow the turn to complete'),
72
+ req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §B', 'a pass verdict MUST allow the turn to complete'),
71
73
  ).toBe(true);
72
74
  });
73
75
  });
@@ -39,6 +39,7 @@ import { driver, type OpenWOPResponse } from '../lib/driver.js';
39
39
  import { pollUntilTerminal } from '../lib/polling.js';
40
40
  import { isFixtureAdvertised } from '../lib/fixtures.js';
41
41
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
42
+ import { req } from '../lib/requirement-ids.js';
42
43
 
43
44
  const FIXTURE_ID = 'conformance-version-fold';
44
45
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(FIXTURE_ID);
@@ -94,7 +95,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
94
95
  );
95
96
  expect(
96
97
  versions.length,
97
- driver.describe(
98
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
98
99
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
99
100
  'forceEngineVersionRange MUST describe a non-empty integer range (min <= max)',
100
101
  ),
@@ -109,7 +110,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
109
110
  }
110
111
  expect(
111
112
  create.status,
112
- driver.describe(
113
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
113
114
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
114
115
  `POST /v1/runs with X-Force-Engine-Version: ${v} (within the advertised range) MUST be accepted on a test key`,
115
116
  ),
@@ -120,7 +121,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
120
121
  const terminal = await pollUntilTerminal(runId);
121
122
  expect(
122
123
  terminal.status,
123
- driver.describe(
124
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
124
125
  'version-negotiation.md §Cross-version interop matrix',
125
126
  `the conformance-version-fold noop run MUST complete under forced engine version ${v} (fold-best-effort)`,
126
127
  ),
@@ -130,7 +131,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
130
131
  const snap = await driver.get(`/v1/runs/${encodeURIComponent(runId)}`);
131
132
  expect(
132
133
  snap.status,
133
- driver.describe(
134
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
134
135
  'version-negotiation.md §Cross-version interop matrix',
135
136
  `GET /v1/runs/{runId} MUST return a readable RunSnapshot under forced engine version ${v}`,
136
137
  ),
@@ -145,7 +146,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
145
146
  );
146
147
  expect(
147
148
  events.status,
148
- driver.describe(
149
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
149
150
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
150
151
  `the event log MUST be readable via events/poll under forced engine version ${v}`,
151
152
  ),
@@ -153,7 +154,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
153
154
  const eventList = (events.json as { events?: unknown[] } | undefined)?.events ?? [];
154
155
  expect(
155
156
  eventList.length,
156
- driver.describe(
157
+ req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
157
158
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
158
159
  `events/poll MUST return a non-empty events[] for the forced-version run (v=${v})`,
159
160
  ),
@@ -178,14 +179,14 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
178
179
  }
179
180
  expect(
180
181
  create.status,
181
- driver.describe(
182
+ req('openwop.it.version-fold.a-forced-version-outside-the-advertised-range-is-rejected-with-400-unsupported-f',
182
183
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
183
184
  `X-Force-Engine-Version: ${outOfRange} (outside the advertised range) MUST return 400`,
184
185
  ),
185
186
  ).toBe(400);
186
187
  expect(
187
188
  errCode(create.json),
188
- driver.describe(
189
+ req('openwop.it.version-fold.a-forced-version-outside-the-advertised-range-is-rejected-with-400-unsupported-f',
189
190
  'version-negotiation.md §Conformance via X-Force-Engine-Version',
190
191
  'the out-of-range refusal MUST carry the canonical unsupported_force_engine_version code',
191
192
  ),
@@ -26,6 +26,7 @@ import { describe, it, expect } from 'vitest';
26
26
  import { driver } from '../lib/driver.js';
27
27
  import { pollUntilTerminal } from '../lib/polling.js';
28
28
  import { isFixtureAdvertised } from '../lib/fixtures.js';
29
+ import { req } from '../lib/requirement-ids.js';
29
30
 
30
31
  const NOOP_WORKFLOW_ID = 'conformance-noop';
31
32
  const SKIP_NO_NOOP = !isFixtureAdvertised(NOOP_WORKFLOW_ID);
@@ -47,7 +48,7 @@ describe('version-negotiation: Capabilities advertises a protocolVersion', () =>
47
48
  expect(res.status).toBe(200);
48
49
 
49
50
  const caps = res.json as { protocolVersion?: unknown };
50
- expect(typeof caps.protocolVersion, driver.describe(
51
+ expect(typeof caps.protocolVersion, req('openwop.it.version-negotiation.get-well-known-openwop-returns-capabilities-with-protocolversion-string',
51
52
  'capabilities.md §3 + version-negotiation.md',
52
53
  'Capabilities.protocolVersion MUST be a non-empty string',
53
54
  )).toBe('string');
@@ -69,34 +70,34 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: persisted events carry the c
69
70
  expect(eventsRes.status).toBe(200);
70
71
 
71
72
  const events = (eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? [];
72
- expect(events.length, 'noop run MUST emit at least one event').toBeGreaterThan(0);
73
+ expect(events.length, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json', 'run-event.schema.json §required', 'noop run MUST emit at least one event')).toBeGreaterThan(0);
73
74
 
74
75
  for (const e of events) {
75
- expect(typeof e.eventId, driver.describe(
76
+ expect(typeof e.eventId, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
76
77
  'run-event.schema.json §required',
77
78
  'eventId MUST be a string',
78
79
  )).toBe('string');
79
- expect(typeof e.runId, driver.describe(
80
+ expect(typeof e.runId, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
80
81
  'run-event.schema.json §required',
81
82
  'runId MUST be a string',
82
83
  )).toBe('string');
83
- expect(typeof e.type, driver.describe(
84
+ expect(typeof e.type, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
84
85
  'run-event.schema.json §required',
85
86
  'type MUST be a string (RunEventType discriminator)',
86
87
  )).toBe('string');
87
- expect(e.payload, driver.describe(
88
+ expect(e.payload, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
88
89
  'run-event.schema.json §required',
89
90
  'payload MUST be present (any JSON value, including null)',
90
91
  )).not.toBe(undefined);
91
- expect(typeof e.timestamp, driver.describe(
92
+ expect(typeof e.timestamp, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
92
93
  'run-event.schema.json §required',
93
94
  'timestamp MUST be an ISO 8601 string',
94
95
  )).toBe('string');
95
- expect(Number.isInteger(e.sequence), driver.describe(
96
+ expect(Number.isInteger(e.sequence), req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
96
97
  'run-event.schema.json §required',
97
98
  'sequence MUST be a non-negative integer',
98
99
  )).toBe(true);
99
- expect(e.sequence, 'sequence MUST be >= 0').toBeGreaterThanOrEqual(0);
100
+ expect(e.sequence, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json', 'run-event.schema.json §required', 'sequence MUST be >= 0')).toBeGreaterThanOrEqual(0);
100
101
  }
101
102
  });
102
103
 
@@ -118,7 +119,7 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: persisted events carry the c
118
119
  const curr = sequences[i] ?? -1;
119
120
  expect(
120
121
  curr,
121
- driver.describe(
122
+ req('openwop.it.version-negotiation.event-sequences-within-a-run-are-strictly-monotonic',
122
123
  'run-event.schema.json §sequence + idempotency.md',
123
124
  `event[${i}].sequence (${curr}) MUST be > event[${i - 1}].sequence (${prev}) — strictly monotonic per run`,
124
125
  ),
@@ -144,7 +145,7 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: events/poll forward-compat t
144
145
 
145
146
  expect(
146
147
  eventsRes.status,
147
- driver.describe(
148
+ req('openwop.it.version-negotiation.events-poll-with-lastsequence-past-current-end-returns-empty-events-iscomplete',
148
149
  'rest-endpoints.md GET /v1/runs/{runId}/events/poll',
149
150
  'lastSequence beyond the current end MUST return 200 with empty events, not 4xx',
150
151
  ),
@@ -21,6 +21,8 @@ import { describe, it, expect } from 'vitest';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { behaviorGate } from '../lib/behavior-gate.js';
23
23
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
24
26
 
25
27
  const SEAM = '/v1/host/sample/voice/barge-in';
26
28
 
@@ -40,22 +42,22 @@ describe('voice-bargein-no-partial-leak (RFC 0106 §F INV-3)', () => {
40
42
  if (!behaviorGate('openwop-voice-bargein', advertised)) return;
41
43
 
42
44
  const res = await driver.post(SEAM, {});
43
- if (res.status === 404) return; // seam unwired — soft-skip
45
+ 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
44
46
 
45
- expect(res.status === 200, driver.describe('RFC 0106 §F', 'the barge-in seam MUST return 200')).toBe(true);
47
+ expect(res.status === 200, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §F', 'the barge-in seam MUST return 200')).toBe(true);
46
48
 
47
49
  const types = eventsOf(res.json).map((e) => e.type);
48
50
  const bargeIdx = types.indexOf('voice.barge_in');
49
51
  const cancelIdx = types.indexOf('voice.cancelled');
50
- expect(bargeIdx >= 0, driver.describe('RFC 0106 §D', 'a barge-in MUST emit voice.barge_in')).toBe(true);
51
- expect(cancelIdx >= 0, driver.describe('RFC 0106 §D', 'a barge-in that cancels work MUST emit voice.cancelled')).toBe(true);
52
- expect(cancelIdx > bargeIdx, driver.describe('RFC 0106 §D', 'voice.cancelled MUST follow voice.barge_in')).toBe(true);
52
+ expect(bargeIdx >= 0, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'a barge-in MUST emit voice.barge_in')).toBe(true);
53
+ expect(cancelIdx >= 0, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'a barge-in that cancels work MUST emit voice.cancelled')).toBe(true);
54
+ expect(cancelIdx > bargeIdx, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'voice.cancelled MUST follow voice.barge_in')).toBe(true);
53
55
 
54
56
  // The load-bearing INV-3 assertion: nothing partial after the cancel.
55
57
  const afterCancel = types.slice(cancelIdx + 1);
56
58
  expect(
57
59
  !afterCancel.includes('voice.synthesis_chunk'),
58
- driver.describe('RFC 0106 §F INV-3', 'NO voice.synthesis_chunk (partial output) may be emitted AFTER voice.cancelled'),
60
+ req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §F INV-3', 'NO voice.synthesis_chunk (partial output) may be emitted AFTER voice.cancelled'),
59
61
  ).toBe(true);
60
62
  });
61
63
  });
@@ -32,8 +32,7 @@ import { join } from 'node:path';
32
32
  import Ajv2020 from 'ajv/dist/2020.js';
33
33
  import addFormats from 'ajv-formats';
34
34
  import { SCHEMAS_DIR } from '../lib/paths.js';
35
-
36
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
35
+ import { req } from '../lib/requirement-ids.js';
37
36
 
38
37
  function loadSchema(name: string): Record<string, any> {
39
38
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, any>;
@@ -63,7 +62,7 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
63
62
  it('all seven voice.* types are in the RunEventType enum', () => {
64
63
  const enumVals: string[] = loadSchema('run-event.schema.json').$defs.RunEventType.enum;
65
64
  for (const t of VOICE_TYPES) {
66
- expect(enumVals.includes(t), why('run-event.schema.json §RunEventType', `${t} MUST be a RunEventType`)).toBe(true);
65
+ expect(enumVals.includes(t), req('openwop.it.voice-event-payloads-shape.all-seven-voice-types-are-in-the-runeventtype-enum', 'run-event.schema.json §RunEventType', `${t} MUST be a RunEventType`)).toBe(true);
67
66
  }
68
67
  });
69
68
 
@@ -71,8 +70,8 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
71
70
  const payloads = loadSchema('run-event-payloads.schema.json');
72
71
  const typeIndex = payloads.$defs._typeIndex.properties as Record<string, { $ref: string }>;
73
72
  for (const t of VOICE_TYPES) {
74
- expect(typeIndex[t], why('run-event-payloads.schema.json §typeIndex', `${t} MUST map to a $def`)).toBeDefined();
75
- expect(payloads.$defs[DEF_KEY[t]], why('run-event-payloads.schema.json', `$defs.${DEF_KEY[t]} MUST exist`)).toBeDefined();
73
+ expect(typeIndex[t], req('openwop.it.voice-event-payloads-shape.each-voice-type-has-a-payload-def-reachable-via-typeindex', 'run-event-payloads.schema.json §typeIndex', `${t} MUST map to a $def`)).toBeDefined();
74
+ expect(payloads.$defs[DEF_KEY[t]], req('openwop.it.voice-event-payloads-shape.each-voice-type-has-a-payload-def-reachable-via-typeindex', 'run-event-payloads.schema.json', `$defs.${DEF_KEY[t]} MUST exist`)).toBeDefined();
76
75
  }
77
76
  });
78
77
 
@@ -84,15 +83,15 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
84
83
 
85
84
  expect(
86
85
  validate({ text: 'book a table', isFinal: true, atMs: 1200, contentTrust: 'untrusted' }),
87
- why('RFC 0106 §F INV-2', 'a transcript marked untrusted MUST validate'),
86
+ req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2', 'a transcript marked untrusted MUST validate'),
88
87
  ).toBe(true);
89
88
  expect(
90
89
  validate({ text: 'book a table', isFinal: true, atMs: 1200 }),
91
- why('RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'a transcript WITHOUT contentTrust MUST be rejected'),
90
+ req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'a transcript WITHOUT contentTrust MUST be rejected'),
92
91
  ).toBe(false);
93
92
  expect(
94
93
  validate({ text: 'book a table', isFinal: true, atMs: 1200, contentTrust: 'trusted' }),
95
- why('RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'contentTrust MUST be the const "untrusted" — never promoted'),
94
+ req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'contentTrust MUST be the const "untrusted" — never promoted'),
96
95
  ).toBe(false);
97
96
  });
98
97
 
@@ -104,11 +103,11 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
104
103
 
105
104
  expect(
106
105
  validate({ seq: 0, mimeType: 'audio/mpeg', durationMs: 240, url: 'https://host/seg/0', final: false }),
107
- why('RFC 0106 §C', 'a metadata chunk referencing bytes by url MUST validate'),
106
+ req('openwop.it.voice-event-payloads-shape.voice-synthesis-chunk-is-metadata-shaped-seq-mimetype-required-bytes-by-referenc', 'RFC 0106 §C', 'a metadata chunk referencing bytes by url MUST validate'),
108
107
  ).toBe(true);
109
108
  expect(
110
109
  validate({ mimeType: 'audio/mpeg' }),
111
- why('RFC 0106 §C', 'a chunk without seq MUST be rejected'),
110
+ req('openwop.it.voice-event-payloads-shape.voice-synthesis-chunk-is-metadata-shaped-seq-mimetype-required-bytes-by-referenc', 'RFC 0106 §C', 'a chunk without seq MUST be rejected'),
112
111
  ).toBe(false);
113
112
  });
114
113
 
@@ -120,7 +119,7 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
120
119
  const validate = ajv.compile(payloads.$defs[key]);
121
120
  expect(
122
121
  validate({ atMs: 100, transcriptBody: 'should not be here' }),
123
- why('RFC 0106 §D', `${key} MUST reject an unknown (content-bearing) property`),
122
+ req('openwop.it.voice-event-payloads-shape.content-free-voice-events-reject-unknown-properties-additionalproperties-false', 'RFC 0106 §D', `${key} MUST reject an unknown (content-bearing) property`),
124
123
  ).toBe(false);
125
124
  }
126
125
  });