@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
@@ -60,6 +60,8 @@ import { describe, it, expect } from 'vitest';
60
60
  import { driver } from '../lib/driver.js';
61
61
  import { semanticRequestDigestV2, callCacheKeySeam as callSeam } from '../lib/llm-cache-key-recipe.js';
62
62
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
63
+ import { req } from '../lib/requirement-ids.js';
64
+ import { softSkip } from '../lib/soft-skip.js';
63
65
 
64
66
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
65
67
 
@@ -99,12 +101,12 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: intra-host reproducib
99
101
  const result = await callSeam(input);
100
102
  if (result.status === 404) {
101
103
  ctx.skip(); // host doesn't expose the test seam
102
- return;
104
+ return softSkip('blocked', 'precondition not met — `result.status === 404` returned early (seam, prior step, or fixture unavailable)');
103
105
  }
104
106
  expect(result.status).toBe(200);
105
107
  expect(
106
108
  result.cacheKey,
107
- driver.describe(
109
+ req('openwop.it.replay-llm-cache-key-portable.host-cache-key-must-equal-locally-recomputed-sha-256-over-canonical-json-reprodu',
108
110
  'SECURITY/invariants.yaml §replay-llm-cache-key-portable + replay.md §B',
109
111
  'host cache key MUST be reproducible offline from the recipe alone — no host-internal state',
110
112
  ),
@@ -121,12 +123,12 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: intra-host reproducib
121
123
  const a = await callSeam(input);
122
124
  if (a.status === 404) {
123
125
  ctx.skip(); // host doesn't expose the test seam
124
- return;
126
+ return softSkip('blocked', 'precondition not met — `a.status === 404` returned early (seam, prior step, or fixture unavailable)');
125
127
  }
126
128
  const b = await callSeam(input);
127
129
  expect(
128
130
  a.cacheKey,
129
- driver.describe(
131
+ req('openwop.it.replay-llm-cache-key-portable.two-identical-probes-must-yield-byte-identical-keys-intra-host-determinism',
130
132
  'SECURITY/invariants.yaml §replay-llm-cache-key-portable',
131
133
  'two byte-identical recipe inputs MUST yield byte-identical keys (no per-request entropy)',
132
134
  ),
@@ -145,7 +147,7 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: non-recipe-field inva
145
147
  const baseResult = await callSeam(base);
146
148
  if (baseResult.status === 404) {
147
149
  ctx.skip(); // host doesn't expose the test seam
148
- return;
150
+ return softSkip('blocked', 'precondition not met — `baseResult.status === 404` returned early (seam, prior step, or fixture unavailable)');
149
151
  }
150
152
 
151
153
  // The security boundary: ANY of these fields leaking into the key
@@ -163,7 +165,7 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: non-recipe-field inva
163
165
  const pollutedResult = await callSeam(polluted);
164
166
  expect(
165
167
  pollutedResult.cacheKey,
166
- driver.describe(
168
+ req('openwop.it.replay-llm-cache-key-portable.transport-only-fields-request-id-trace-context-tenant-id-must-not-influence-the',
167
169
  'SECURITY/invariants.yaml §replay-llm-cache-key-portable + replay.md §A',
168
170
  'transport-only fields (request id, trace context, tenant id, run id, timeout) MUST NOT influence the cache key — leaking them defeats the portability invariant',
169
171
  ),
@@ -178,13 +180,13 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: Phase 4 advertisement
178
180
  const version = em?.version;
179
181
  if (typeof version !== 'number' || version < 4) {
180
182
  ctx.skip(); // pre-Phase-4 or no multiAgent advertisement
181
- return;
183
+ return softSkip('blocked', 'precondition not met — `typeof version !== \'number\' || version < 4` returned early (seam, prior step, or fixture unavailable)');
182
184
  }
183
185
 
184
186
  const recipe = em?.replayDeterminism?.llmCacheKeyRecipe;
185
187
  expect(
186
188
  typeof recipe === 'string',
187
- driver.describe(
189
+ req('openwop.it.replay-llm-cache-key-portable.hosts-advertising-version-4-must-advertise-replaydeterminism-llmcachekeyrecipe',
188
190
  'RFCS/0041-multi-agent-replay-under-nondeterminism.md §D',
189
191
  'Phase 4 host MUST advertise replayDeterminism.llmCacheKeyRecipe (`spec-rfc-0041` or `x-host-<host>-<recipe>`)',
190
192
  ),
@@ -195,7 +197,7 @@ describe.skipIf(HTTP_SKIP)('replay-llm-cache-key-portable: Phase 4 advertisement
195
197
  const vendor = /^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$/.test(r);
196
198
  expect(
197
199
  canonical || vendor,
198
- driver.describe(
200
+ req('openwop.it.replay-llm-cache-key-portable.hosts-advertising-version-4-must-advertise-replaydeterminism-llmcachekeyrecipe',
199
201
  'schemas/capabilities.schema.json §replayDeterminism.llmCacheKeyRecipe',
200
202
  'llmCacheKeyRecipe MUST be `spec-rfc-0041` OR match `^x-host-<host>-<recipe>$` per host-extensions.md',
201
203
  ),
@@ -28,8 +28,9 @@
28
28
  */
29
29
 
30
30
  import { describe, it, expect } from 'vitest';
31
- import { driver } from '../lib/driver.js';
32
31
  import { semanticRequestDigestV2, callCacheKeySeam as callSeam } from '../lib/llm-cache-key-recipe.js';
32
+ import { req } from '../lib/requirement-ids.js';
33
+ import { softSkip } from '../lib/soft-skip.js';
33
34
 
34
35
  describe('replay-llm-cache-key: SHA-256-over-JCS recipe, v2 (replay.md §B, RFC 0150 §C)', () => {
35
36
  it('host cache key MUST equal the locally-recomputed v2 semantic-request digest', async () => {
@@ -43,11 +44,11 @@ describe('replay-llm-cache-key: SHA-256-over-JCS recipe, v2 (replay.md §B, RFC
43
44
  temperature: 0.7,
44
45
  };
45
46
  const result = await callSeam(input);
46
- if (result.status === 404) return; // seam not exposed
47
+ if (result.status === 404) return softSkip('blocked', 'precondition not met — `result.status === 404` returned early (seam not exposed) (seam, prior step, or fixture unavailable)'); // seam not exposed
47
48
  expect(result.status).toBe(200);
48
49
  expect(
49
50
  result.cacheKey,
50
- driver.describe(
51
+ req('openwop.it.replay-llm-cache-key.host-cache-key-must-equal-the-locally-recomputed-v2-semantic-request-digest',
51
52
  'replay.md §B (RFC 0150 §C)',
52
53
  'host cache key MUST be lowercase-hex SHA-256 of the JCS-canonical v2 semantic request ' +
53
54
  '(stamped `recipe: "openwop-semantic-request-v2"`); a v1 key here is a host that has ' +
@@ -62,8 +63,8 @@ describe('replay-llm-cache-key: SHA-256-over-JCS recipe, v2 (replay.md §B, RFC
62
63
  model: 'gpt-4',
63
64
  messages: [{ role: 'user', content: 'hi' }],
64
65
  });
65
- if (result.status === 404) return;
66
- expect(result.cacheKey).toMatch(/^[0-9a-f]{64}$/);
66
+ if (result.status === 404) return softSkip('blocked', 'precondition not met — `result.status === 404` returned early (seam, prior step, or fixture unavailable)');
67
+ expect(result.cacheKey, req('openwop.it.replay-llm-cache-key.cache-key-must-be-64-lowercase-hex-characters-sha-256-output-shape', 'replay.md §"LLM cache-key recipe', 'cache key MUST be 64 lowercase-hex characters (SHA-256 output shape)')).toMatch(/^[0-9a-f]{64}$/);
67
68
  });
68
69
  });
69
70
 
@@ -76,7 +77,7 @@ describe('replay-llm-cache-key: transport-only fields are EXCLUDED (replay.md §
76
77
  temperature: 0.5,
77
78
  };
78
79
  const baseResult = await callSeam(base);
79
- if (baseResult.status === 404) return;
80
+ if (baseResult.status === 404) return softSkip('blocked', 'precondition not met — `baseResult.status === 404` returned early (seam, prior step, or fixture unavailable)');
80
81
 
81
82
  // Transport / bookkeeping only. None of these can change what the model
82
83
  // returns, so none may change the key. (`max_tokens`, `stop`, and `seed`
@@ -95,7 +96,7 @@ describe('replay-llm-cache-key: transport-only fields are EXCLUDED (replay.md §
95
96
  const noisyResult = await callSeam(noisy);
96
97
  expect(
97
98
  noisyResult.cacheKey,
98
- driver.describe(
99
+ req('openwop.it.replay-llm-cache-key.stream-metadata-user-request-ids-trace-context-must-not-influence-the-cache-key',
99
100
  'replay.md §A (v2)',
100
101
  'cache key MUST be invariant under transport-only fields (stream, metadata, user, request ids, trace context, tenant, timeout)',
101
102
  ),
@@ -111,11 +112,11 @@ describe('replay-llm-cache-key: transport-only fields are EXCLUDED (replay.md §
111
112
  };
112
113
  const hotInput = { ...baseInput, temperature: 1.0 };
113
114
  const baseResult = await callSeam(baseInput);
114
- if (baseResult.status === 404) return;
115
+ if (baseResult.status === 404) return softSkip('blocked', 'precondition not met — `baseResult.status === 404` returned early (seam, prior step, or fixture unavailable)');
115
116
  const hotResult = await callSeam(hotInput);
116
117
  expect(
117
118
  baseResult.cacheKey === hotResult.cacheKey,
118
- driver.describe('replay.md §A', 'changing a recipe field MUST yield a different cache key (no false collisions)'),
119
+ req('openwop.it.replay-llm-cache-key.changing-a-recipe-field-temperature-must-yield-a-different-cache-key', 'replay.md §A', 'changing a recipe field MUST yield a different cache key (no false collisions)'),
119
120
  ).toBe(false);
120
121
  });
121
122
  });
@@ -139,11 +140,11 @@ describe('replay-llm-cache-key: outcome-affecting fields are INCLUDED (RFC 0150
139
140
  ['maxOutputTokens', { maxOutputTokens: 100 }, { maxOutputTokens: 1000 }],
140
141
  ])('%s DOES change the cache key', async (_field, a, b) => {
141
142
  const ra = await callSeam({ ...base, ...a });
142
- if (ra.status === 404) return;
143
+ if (ra.status === 404) return softSkip('blocked', 'precondition not met — `ra.status === 404` returned early (seam, prior step, or fixture unavailable)');
143
144
  const rb = await callSeam({ ...base, ...b });
144
145
  expect(
145
146
  ra.cacheKey === rb.cacheKey,
146
- driver.describe(
147
+ req('openwop.it.replay-llm-cache-key.s-does-change-the-cache-key',
147
148
  'replay.md §A (RFC 0150 §C)',
148
149
  `\`${_field}\` decides the completion, so two requests differing only in it MUST NOT share a cache key — ` +
149
150
  'sharing one returns a response the caller never asked for, deterministically',
@@ -151,10 +152,10 @@ describe('replay-llm-cache-key: outcome-affecting fields are INCLUDED (RFC 0150
151
152
  ).toBe(false);
152
153
  // And each side MUST equal the locally-recomputed v2 digest, so a host cannot
153
154
  // pass this leg by salting the key with something arbitrary.
154
- expect(ra.cacheKey, driver.describe('replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
155
+ expect(ra.cacheKey, req('openwop.it.replay-llm-cache-key.s-does-change-the-cache-key', 'replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
155
156
  semanticRequestDigestV2({ ...base, ...a }),
156
157
  );
157
- expect(rb.cacheKey, driver.describe('replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
158
+ expect(rb.cacheKey, req('openwop.it.replay-llm-cache-key.s-does-change-the-cache-key', 'replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
158
159
  semanticRequestDigestV2({ ...base, ...b }),
159
160
  );
160
161
  });
@@ -163,17 +164,17 @@ describe('replay-llm-cache-key: outcome-affecting fields are INCLUDED (RFC 0150
163
164
  const withOpts = { ...base, providerOptions: { 'vendor.openai.logitBias': { '50256': -100 } } };
164
165
  const withOtherOpts = { ...base, providerOptions: { 'vendor.openai.logitBias': { '50256': 100 } } };
165
166
  const r1 = await callSeam(withOpts);
166
- if (r1.status === 404) return;
167
+ if (r1.status === 404) return softSkip('blocked', 'precondition not met — `r1.status === 404` returned early (seam, prior step, or fixture unavailable)');
167
168
  const r2 = await callSeam(withOtherOpts);
168
169
  expect(
169
170
  r1.cacheKey === r2.cacheKey,
170
- driver.describe(
171
+ req('openwop.it.replay-llm-cache-key.provideroptions-are-carried-into-the-key-not-dropped',
171
172
  'replay.md §B step 1 (RFC 0150 §C)',
172
173
  'an unknown provider option MUST be carried into `providerOptions` before hashing — a dropped option ' +
173
174
  'that alters output is indistinguishable from one that was never set',
174
175
  ),
175
176
  ).toBe(false);
176
- expect(r1.cacheKey, driver.describe('replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
177
+ expect(r1.cacheKey, req('openwop.it.replay-llm-cache-key.provideroptions-are-carried-into-the-key-not-dropped', 'replay.md §B (v2)', 'key MUST equal the v2 digest')).toBe(
177
178
  semanticRequestDigestV2(withOpts),
178
179
  );
179
180
  });
@@ -182,7 +183,7 @@ describe('replay-llm-cache-key: outcome-affecting fields are INCLUDED (RFC 0150
182
183
  describe('replay-llm-cache-key: cross-host parity (replay.md §D)', () => {
183
184
  it('two hosts compute the same cache key for the same input (when OPENWOP_BASE_URL_B is configured)', async () => {
184
185
  const otherBaseUrl = process.env['OPENWOP_BASE_URL_B'];
185
- if (!otherBaseUrl) return; // operator-supplied second host not configured
186
+ if (!otherBaseUrl) return softSkip('blocked', 'precondition not met — `!otherBaseUrl` returned early (operator-supplied second host not configured) (seam, prior step, or fixture unavailable)'); // operator-supplied second host not configured
186
187
  const input = {
187
188
  provider: 'openai',
188
189
  model: 'gpt-4',
@@ -191,19 +192,19 @@ describe('replay-llm-cache-key: cross-host parity (replay.md §D)', () => {
191
192
  seed: 7,
192
193
  };
193
194
  const resA = await callSeam(input);
194
- if (resA.status === 404) return;
195
+ if (resA.status === 404) return softSkip('blocked', 'precondition not met — `resA.status === 404` returned early (seam, prior step, or fixture unavailable)');
195
196
  const resB = await fetch(`${otherBaseUrl.replace(/\/$/, '')}/v1/host/sample/test/llm-cache-key`, {
196
197
  method: 'POST',
197
198
  headers: { 'content-type': 'application/json' },
198
199
  body: JSON.stringify(input),
199
200
  });
200
- if (resB.status === 404) return;
201
+ if (resB.status === 404) return softSkip('blocked', 'precondition not met — `resB.status === 404` returned early (seam, prior step, or fixture unavailable)');
201
202
  const jsonB = (await resB.json()) as { cacheKey?: string };
202
203
  expect(
203
204
  jsonB.cacheKey,
204
- driver.describe('replay.md §D', 'two compliant hosts MUST compute byte-identical cache keys for the same recipe input'),
205
+ req('openwop.it.replay-llm-cache-key.two-hosts-compute-the-same-cache-key-for-the-same-input-when-openwop-base-url-b', 'replay.md §D', 'two compliant hosts MUST compute byte-identical cache keys for the same recipe input'),
205
206
  ).toBe(resA.cacheKey);
206
- expect(resA.cacheKey, driver.describe('replay.md §B (v2)', 'and both MUST equal the v2 digest')).toBe(
207
+ expect(resA.cacheKey, req('openwop.it.replay-llm-cache-key.two-hosts-compute-the-same-cache-key-for-the-same-input-when-openwop-base-url-b', 'replay.md §B (v2)', 'and both MUST equal the v2 digest')).toBe(
207
208
  semanticRequestDigestV2(input),
208
209
  );
209
210
  });
@@ -44,6 +44,7 @@ import { describe, it, expect } from 'vitest';
44
44
  import { softSkip, seamAbsent } from '../lib/soft-skip.js';
45
45
  import { driver } from '../lib/driver.js';
46
46
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
47
+ import { req } from '../lib/requirement-ids.js';
47
48
 
48
49
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
49
50
  const FIXTURE = 'conformance-phase4-nondet-tool';
@@ -186,7 +187,7 @@ describe.skipIf(HTTP_SKIP)(
186
187
  const replayNorm = replayEvents.map(stripVolatile);
187
188
  expect(
188
189
  replayNorm,
189
- driver.describe(
190
+ req('openwop.it.replay-observable-sequence-determinism.original-and-replay-event-log-prefixes-must-be-byte-equivalent-modulo-per-event',
190
191
  'RFCS/0041-multi-agent-replay-under-nondeterminism.md §C',
191
192
  'a mode:replay fork MUST reproduce the original observable event-log sequence byte-for-byte modulo volatile per-event fields (eventId/ULID entropy, per-region observedAt clock)',
192
193
  ),
@@ -211,7 +212,7 @@ describe.skipIf(HTTP_SKIP)(
211
212
  const sourceNodeEvents = sourceEvents.filter((e) => e.nodeId === NONDET_NODE_ID).map(stripVolatile);
212
213
  expect(
213
214
  sourceNodeEvents.length,
214
- driver.describe(
215
+ req('openwop.it.replay-observable-sequence-determinism.replay-of-a-nondeterministic-tool-node-reproduces-the-original-observable-result',
215
216
  'RFCS/0041-multi-agent-replay-under-nondeterminism.md §C',
216
217
  `the fixture's nondeterministic node \`${NONDET_NODE_ID}\` MUST emit at least one observable event`,
217
218
  ),
@@ -229,7 +230,7 @@ describe.skipIf(HTTP_SKIP)(
229
230
 
230
231
  expect(
231
232
  replayNodeEvents,
232
- driver.describe(
233
+ req('openwop.it.replay-observable-sequence-determinism.replay-of-a-nondeterministic-tool-node-reproduces-the-original-observable-result',
233
234
  'RFCS/0041-multi-agent-replay-under-nondeterminism.md §C',
234
235
  'the nondeterministic tool node MUST replay its ORIGINAL observable result (cached event-log entry) rather than re-executing — bit-equivalent re-execution would require unbounded caching, rejected per RFC 0041 §"Alternatives considered" #2',
235
236
  ),
@@ -33,6 +33,8 @@
33
33
  import { describe, it, expect } from 'vitest';
34
34
  import { driver } from '../lib/driver.js';
35
35
  import { behaviorGate } from '../lib/behavior-gate.js';
36
+ import { req } from '../lib/requirement-ids.js';
37
+ import { softSkip } from '../lib/soft-skip.js';
36
38
 
37
39
  interface ReplayRetentionCaps {
38
40
  windowSeconds?: number;
@@ -66,14 +68,14 @@ describe('replay-retention-expiry: capability shape', () => {
66
68
  return;
67
69
  }
68
70
 
69
- expect(replay?.supported, driver.describe(
71
+ expect(replay?.supported, req('openwop.it.replay-retention-expiry.host-advertising-replay-surfaces-well-formed-retention-metadata-when-present',
70
72
  'replay.md §"Retention and garbage collection"',
71
73
  'replay.supported MUST be true when the host claims the openwop-replay-fork profile',
72
74
  )).toBe(true);
73
75
 
74
76
  expect(
75
77
  Array.isArray(replay?.modes) && (replay?.modes?.length ?? 0) > 0,
76
- driver.describe(
78
+ req('openwop.it.replay-retention-expiry.host-advertising-replay-surfaces-well-formed-retention-metadata-when-present',
77
79
  'profiles.md §`openwop-replay-fork`',
78
80
  'replay.modes MUST be a non-empty array',
79
81
  ),
@@ -86,7 +88,7 @@ describe('replay-retention-expiry: capability shape', () => {
86
88
  expect(
87
89
  Number.isInteger(replay.retention.windowSeconds) &&
88
90
  replay.retention.windowSeconds >= 0,
89
- driver.describe(
91
+ req('openwop.it.replay-retention-expiry.host-advertising-replay-surfaces-well-formed-retention-metadata-when-present',
90
92
  'replay.md §"Retention and garbage collection"',
91
93
  'replay.retention.windowSeconds MUST be a non-negative integer when advertised',
92
94
  ),
@@ -109,7 +111,7 @@ describe('replay-retention-expiry: 410/422 on expired-range fork', () => {
109
111
  console.warn(
110
112
  '[replay-retention-expiry] OPENWOP_TEST_EXPIRED_REPLAY_RUN_ID not supplied; skipping envelope assertion (operator must produce a known-expired run id and pass it via env)',
111
113
  );
112
- return;
114
+ return softSkip('blocked', 'precondition not met — `!expiredRunId` returned early ([replay-retention-expiry] OPENWOP_TEST_EXPIRED_REPLAY_RUN_ID not supplied; skipping envelope assertion (operator must produce a known-expired run id and pass it v…');
113
115
  }
114
116
 
115
117
  const fromSeqEnv = process.env.OPENWOP_TEST_EXPIRED_REPLAY_FROM_SEQ;
@@ -119,7 +121,7 @@ describe('replay-retention-expiry: 410/422 on expired-range fork', () => {
119
121
  console.warn(
120
122
  `[replay-retention-expiry] OPENWOP_TEST_EXPIRED_REPLAY_FROM_SEQ=${String(fromSeqEnv)} is not a non-negative integer; skipping`,
121
123
  );
122
- return;
124
+ return softSkip('blocked', 'precondition not met — `!Number.isFinite(fromSeq) || fromSeq < 0` returned early ([replay-retention-expiry] OPENWOP_TEST_EXPIRED_REPLAY_FROM_SEQ=… is not a non-negative integer; skipping) (seam, prior step, or fixture…');
123
125
  }
124
126
 
125
127
  // Pick a mode the host advertises. Per replay.md the envelope
@@ -134,7 +136,7 @@ describe('replay-retention-expiry: 410/422 on expired-range fork', () => {
134
136
 
135
137
  expect(
136
138
  res.status === 410 || res.status === 422,
137
- driver.describe(
139
+ req('openwop.it.replay-retention-expiry.post-v1-runs-expiredrunid-fork-returns-410-or-422-with-canonical-envelope',
138
140
  'replay.md §"Retention and garbage collection"',
139
141
  'fork against expired event range MUST return 410 Gone or 422 Unprocessable Entity',
140
142
  ),
@@ -150,7 +152,7 @@ describe('replay-retention-expiry: 410/422 on expired-range fork', () => {
150
152
  };
151
153
  };
152
154
 
153
- expect(typeof body.error, driver.describe(
155
+ expect(typeof body.error, req('openwop.it.replay-retention-expiry.post-v1-runs-expiredrunid-fork-returns-410-or-422-with-canonical-envelope',
154
156
  'replay.md §"Retention and garbage collection"',
155
157
  'expired-fork response MUST use the canonical error envelope ({error, message, details?})',
156
158
  )).toBe('string');
@@ -162,14 +164,14 @@ describe('replay-retention-expiry: 410/422 on expired-range fork', () => {
162
164
  // details.{sourceRunId, fromSeq, retentionBoundary} are SHOULD —
163
165
  // soft-check when present, MUST NOT mismatch when present.
164
166
  if (body.details?.sourceRunId !== undefined) {
165
- expect(body.details.sourceRunId, driver.describe(
167
+ expect(body.details.sourceRunId, req('openwop.it.replay-retention-expiry.post-v1-runs-expiredrunid-fork-returns-410-or-422-with-canonical-envelope',
166
168
  'replay.md §"Retention and garbage collection"',
167
169
  'details.sourceRunId (when present) MUST match the runId in the request path',
168
170
  )).toBe(expiredRunId);
169
171
  }
170
172
 
171
173
  if (body.details?.fromSeq !== undefined) {
172
- expect(body.details.fromSeq, driver.describe(
174
+ expect(body.details.fromSeq, req('openwop.it.replay-retention-expiry.post-v1-runs-expiredrunid-fork-returns-410-or-422-with-canonical-envelope',
173
175
  'replay.md §"Retention and garbage collection"',
174
176
  'details.fromSeq (when present) MUST match the fromSeq supplied in the request body',
175
177
  )).toBe(fromSeq);
@@ -54,6 +54,8 @@ import { isFixtureAdvertised } from '../lib/fixtures.js';
54
54
  import { readFileSync } from 'node:fs';
55
55
  import { join } from 'node:path';
56
56
  import { V1_DIR } from '../lib/paths.js';
57
+ import { req } from '../lib/requirement-ids.js';
58
+ import { softSkip } from '../lib/soft-skip.js';
57
59
 
58
60
  const WORKFLOW_ID = 'conformance-replay-side-effect';
59
61
  const EFFECT_NODE = 'effect';
@@ -98,10 +100,10 @@ function errorCode(e: RawEvent): string | undefined {
98
100
  describe('replay-side-effect-suppression: capability shape (RFC 0140 §A)', () => {
99
101
  it('sideEffectSuppression, when present, is one of the two defined values', async () => {
100
102
  const replay = await fetchReplay();
101
- if (replay?.sideEffectSuppression === undefined) return; // absent ⇒ "none"; nothing to check
103
+ if (replay?.sideEffectSuppression === undefined) return softSkip('blocked', 'precondition not met — `replay?.sideEffectSuppression === undefined` returned early (absent ⇒ "none"; nothing to check) (seam, prior step, or fixture unavailable)'); // absent ⇒ "none"; nothing to check
102
104
  expect(
103
105
  replay.sideEffectSuppression,
104
- driver.describe(
106
+ req('openwop.it.replay-side-effect-suppression.sideeffectsuppression-when-present-is-one-of-the-two-defined-values',
105
107
  'capabilities.schema.json §replay.sideEffectSuppression',
106
108
  'sideEffectSuppression MUST be "recorded-outcome" or "none" when advertised',
107
109
  ),
@@ -132,11 +134,11 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
132
134
  /* already recorded */
133
135
  }
134
136
  ctx.skip();
135
- return;
137
+ return softSkip('blocked', 'precondition not met — `replay?.sideEffectSuppression !== \'recorded-outcome\'` returned early (seam, prior step, or fixture unavailable)');
136
138
  }
137
139
  if (!replay.modes?.includes('replay')) {
138
140
  ctx.skip(); // suppression is scoped to replay mode
139
- return;
141
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!replay.modes?.includes(\'replay\')` returned early');
140
142
  }
141
143
 
142
144
  // 1. Start the run with a delay long enough to cancel mid-flight, so the
@@ -151,13 +153,13 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
151
153
  workflowId: WORKFLOW_ID,
152
154
  inputs: { delayMs: 5_000 },
153
155
  });
154
- expect(create.status, `Failed to start ${WORKFLOW_ID}`).toBe(201);
156
+ expect(create.status, req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne', 'replay.md §"Side-effect suppression in replay" requirement 1', `Failed to start ${WORKFLOW_ID}`)).toBe(201);
155
157
  const sourceRunId = (create.json as { runId: string }).runId;
156
158
 
157
159
  const cancel = await driver.post(`/v1/runs/${encodeURIComponent(sourceRunId)}/cancel`, {});
158
160
  expect(
159
161
  [200, 202, 204].includes(cancel.status),
160
- `cancel returned ${cancel.status}`,
162
+ req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne', 'replay.md §"Side-effect suppression in replay" requirement 1', `cancel returned ${cancel.status}`),
161
163
  ).toBe(true);
162
164
  await pollUntilTerminal(sourceRunId, { timeoutMs: 15_000 });
163
165
 
@@ -167,7 +169,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
167
169
  const sourceEvents = await readEvents(sourceRunId);
168
170
  expect(
169
171
  sourceEvents.some((e) => e.type === 'node.completed' && e.nodeId === EFFECT_NODE),
170
- 'precondition: the cancelled source run must NOT have completed the effect node',
172
+ req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne', 'replay.md §"Side-effect suppression in replay" requirement 1', 'precondition: the cancelled source run must NOT have completed the effect node'),
171
173
  ).toBe(false);
172
174
 
173
175
  // 2. Fork it in replay mode.
@@ -176,9 +178,9 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
176
178
  });
177
179
  if (forkDeclined(fork.status, 'side-effect-suppression replay fork')) {
178
180
  ctx.skip();
179
- return;
181
+ return softSkip('blocked', 'precondition not met — `forkDeclined(fork.status, \'side-effect-suppression replay fork\')` returned early (seam, prior step, or fixture unavailable)');
180
182
  }
181
- expect(fork.status, 'fork should be accepted').toBe(201);
183
+ expect(fork.status, req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne', 'replay.md §"Side-effect suppression in replay" requirement 1', 'fork should be accepted')).toBe(201);
182
184
  const forkRunId = (fork.json as { runId: string }).runId;
183
185
  await pollUntilTerminal(forkRunId, { timeoutMs: 45_000 }); // re-runs the 5s delay before reaching `effect`
184
186
 
@@ -190,7 +192,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
190
192
 
191
193
  expect(
192
194
  effectEvents.some((e) => e.type === 'node.completed'),
193
- driver.describe(
195
+ req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne',
194
196
  'replay.md §"Side-effect suppression in replay" requirement 1',
195
197
  'the side-effecting node MUST NOT complete during a replay — completing it means the effect was performed',
196
198
  ),
@@ -198,7 +200,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
198
200
 
199
201
  expect(
200
202
  effectEvents.some((e) => e.type === 'node.failed' && errorCode(e) === 'replay_source_missing'),
201
- driver.describe(
203
+ req('openwop.it.replay-side-effect-suppression.fails-a-side-effecting-node-closed-with-replay-source-missing-when-the-source-ne',
202
204
  'replay.md §"Side-effect suppression in replay" requirement 3',
203
205
  'a side-effecting node with no recorded source outcome MUST fail closed with replay_source_missing',
204
206
  ),
@@ -240,9 +242,9 @@ describe.skipIf(V1_DIR === null)('replay.md req 4 — the manifest role is a cla
240
242
  // binds a value nothing can declare — a rule with no reachable trigger.
241
243
  expect(
242
244
  manifest().includes('side-effect'),
243
- 'node-pack-manifest.schema.json §role MUST still describe the `side-effect` value that ' +
245
+ req('openwop.it.replay-side-effect-suppression.the-manifest-still-offers-the-role-value-the-requirement-binds', 'RFC 0140', 'node-pack-manifest.schema.json §role MUST still describe the `side-effect` value that ' +
244
246
  'replay.md requirement 4 makes binding. A requirement whose trigger no longer exists is ' +
245
- 'not enforcement, it is decoration.',
247
+ 'not enforcement, it is decoration.'),
246
248
  ).toBe(true);
247
249
  });
248
250
 
@@ -250,9 +252,9 @@ describe.skipIf(V1_DIR === null)('replay.md req 4 — the manifest role is a cla
250
252
  const doc = replay();
251
253
  expect(
252
254
  /MUST\*{0,2} be treated as side-effecting/.test(doc) && doc.includes('node-pack-manifest.schema.json'),
253
- 'replay.md §"Requirements when a host declares `sideEffectSuppression: \\"recorded-outcome\\"`" ' +
255
+ req('openwop.it.replay-side-effect-suppression.replay-md-binds-that-declaration-naming-the-schema-it-comes-from', 'replay.md', 'replay.md §"Requirements when a host declares `sideEffectSuppression: \\"recorded-outcome\\"`" ' +
254
256
  'MUST bind a manifest-declared `role: "side-effect"` to the suppression obligation, and MUST ' +
255
- 'name the schema the declaration comes from so a reader can find it.',
257
+ 'name the schema the declaration comes from so a reader can find it.'),
256
258
  ).toBe(true);
257
259
  });
258
260
 
@@ -267,10 +269,10 @@ describe.skipIf(V1_DIR === null)('replay.md req 4 — the manifest role is a cla
267
269
  const doc = replay();
268
270
  expect(
269
271
  doc.includes('backstop, not a discharge'),
270
- 'replay.md requirement 4 MUST state that a guarded-seam throw is a backstop rather than a ' +
272
+ req('openwop.it.replay-side-effect-suppression.a-throw-is-named-a-backstop-not-a-discharge', 'RFC 0140', 'replay.md requirement 4 MUST state that a guarded-seam throw is a backstop rather than a ' +
271
273
  'discharge. It satisfies requirement 1 (no effect) and not requirement 2 (resolve the ' +
272
274
  'recorded outcome), and a host reading the floor as "make it throw" ships a replay that ' +
273
- 'fails where this section says it must succeed.',
275
+ 'fails where this section says it must succeed.'),
274
276
  ).toBe(true);
275
277
  expect(
276
278
  /safe and\s+non-conformant/.test(doc),
@@ -285,9 +287,9 @@ describe.skipIf(V1_DIR === null)('replay.md req 4 — the manifest role is a cla
285
287
  // manifest is wrong." The requirement is one-directional and says so.
286
288
  expect(
287
289
  replay().includes('MUST NOT classify fewer'),
288
- 'replay.md requirement 4 MUST state the direction: a host classifier may treat MORE nodes as ' +
290
+ req('openwop.it.replay-side-effect-suppression.the-floor-direction-is-stated-not-left-to-inference', 'RFC 0140', 'replay.md requirement 4 MUST state the direction: a host classifier may treat MORE nodes as ' +
289
291
  'side-effecting and never fewer. Without the direction, a host that trusts its own list over ' +
290
- 'the manifest can read the clause as permission to disagree.',
292
+ 'the manifest can read the clause as permission to disagree.'),
291
293
  ).toBe(true);
292
294
  });
293
295
  });
@@ -22,6 +22,7 @@ import { softSkip } from '../lib/soft-skip.js';
22
22
  import { forkDeclined } from '../lib/fork-availability.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 NOOP_WORKFLOW_ID = 'conformance-noop';
27
28
  const SKIP_NO_NOOP = !isFixtureAdvertised(NOOP_WORKFLOW_ID);
@@ -73,13 +74,13 @@ describe('replay-determinism: openwop-replay-fork profile gate', () => {
73
74
  const replay = await fetchReplayCapability();
74
75
  if (replay === null || replay.supported !== true) return softSkip('inapplicable', 'host does not advertise `replay.supported: true` — the replay contract does not apply to it');
75
76
 
76
- expect(Array.isArray(replay.modes), driver.describe(
77
+ expect(Array.isArray(replay.modes), req('openwop.it.replayDeterminism.host-advertising-replay-supported-must-also-advertise-replay-modes',
77
78
  'spec/v1/replay.md',
78
79
  'host advertising replay.supported MUST advertise replay.modes as an array',
79
80
  )).toBe(true);
80
81
  if (Array.isArray(replay.modes)) {
81
82
  for (const m of replay.modes) {
82
- expect(typeof m, driver.describe(
83
+ expect(typeof m, req('openwop.it.replayDeterminism.host-advertising-replay-supported-must-also-advertise-replay-modes',
83
84
  'spec/v1/replay.md',
84
85
  'each replay.modes entry MUST be a string',
85
86
  )).toBe('string');
@@ -98,7 +99,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay-determinism: same fromSeq + same workflow
98
99
 
99
100
  // Phase 1: complete an original run.
100
101
  const create = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
101
- if (create.status !== 201) return;
102
+ if (create.status !== 201) return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
102
103
  const originalRunId = (create.json as { runId: string }).runId;
103
104
  await pollUntilTerminal(originalRunId, { timeoutMs: 10_000 });
104
105
 
@@ -107,8 +108,8 @@ describe.skipIf(SKIP_NO_NOOP)('replay-determinism: same fromSeq + same workflow
107
108
  mode: 'replay',
108
109
  fromSeq: 0,
109
110
  });
110
- if (forkDeclined(fork1.status, 'determinism fork 1')) return;
111
- expect(fork1.status, driver.describe(
111
+ if (forkDeclined(fork1.status, 'determinism fork 1')) return softSkip('blocked', 'precondition not met — `forkDeclined(fork1.status, \'determinism fork 1\')` returned early (seam, prior step, or fixture unavailable)');
112
+ expect(fork1.status, req('openwop.it.replayDeterminism.two-replay-forks-of-the-same-point-produce-structurally-identical-event-lists',
112
113
  'spec/v1/replay.md',
113
114
  'POST /v1/runs/{runId}:fork with mode=replay MUST return 201',
114
115
  )).toBe(201);
@@ -120,7 +121,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay-determinism: same fromSeq + same workflow
120
121
  mode: 'replay',
121
122
  fromSeq: 0,
122
123
  });
123
- if (forkDeclined(fork2.status, 'determinism fork 2')) return;
124
+ if (forkDeclined(fork2.status, 'determinism fork 2')) return softSkip('blocked', 'precondition not met — `forkDeclined(fork2.status, \'determinism fork 2\')` returned early (seam, prior step, or fixture unavailable)');
124
125
  expect(fork2.status).toBe(201);
125
126
  const fork2Id = (fork2.json as { runId: string }).runId;
126
127
  await pollUntilTerminal(fork2Id, { timeoutMs: 10_000 });
@@ -128,21 +129,21 @@ describe.skipIf(SKIP_NO_NOOP)('replay-determinism: same fromSeq + same workflow
128
129
  // Phase 4: fetch both fork event streams.
129
130
  const fork1Events = await driver.get(`/v1/runs/${encodeURIComponent(fork1Id)}/events/poll`);
130
131
  const fork2Events = await driver.get(`/v1/runs/${encodeURIComponent(fork2Id)}/events/poll`);
131
- if (fork1Events.status !== 200 || fork2Events.status !== 200) return;
132
+ if (fork1Events.status !== 200 || fork2Events.status !== 200) return softSkip('blocked', 'precondition not met — `fork1Events.status !== 200 || fork2Events.status !== 200` returned early (seam, prior step, or fixture unavailable)');
132
133
 
133
134
  const fork1Body = fork1Events.json as { events?: RawEvent[] };
134
135
  const fork2Body = fork2Events.json as { events?: RawEvent[] };
135
- if (!fork1Body.events || !fork2Body.events) return;
136
+ if (!fork1Body.events || !fork2Body.events) return softSkip('blocked', 'precondition not met — `!fork1Body.events || !fork2Body.events` returned early (seam, prior step, or fixture unavailable)');
136
137
 
137
138
  // Phase 5: assert structural identity (modulo timestamps + IDs).
138
- expect(fork1Body.events.length, driver.describe(
139
+ expect(fork1Body.events.length, req('openwop.it.replayDeterminism.two-replay-forks-of-the-same-point-produce-structurally-identical-event-lists',
139
140
  'spec/v1/replay.md §"Replay determinism"',
140
141
  'two replay forks MUST produce the same number of events',
141
142
  )).toBe(fork2Body.events.length);
142
143
 
143
144
  const shape1 = structuralShape(fork1Body.events);
144
145
  const shape2 = structuralShape(fork2Body.events);
145
- expect(shape1, driver.describe(
146
+ expect(shape1, req('openwop.it.replayDeterminism.two-replay-forks-of-the-same-point-produce-structurally-identical-event-lists',
146
147
  'spec/v1/replay.md §"Replay determinism"',
147
148
  'event sequence (type/nodeId/data) MUST be identical across two replay forks of the same point',
148
149
  )).toEqual(shape2);
@@ -155,14 +156,14 @@ describe.skipIf(SKIP_NO_NOOP)('replay-determinism: branch-mode is permitted to d
155
156
  it('branch mode does NOT need to produce identical event sequences (negative-control)', async () => {
156
157
  const replay = await fetchReplayCapability();
157
158
  if (replay === null || replay.supported !== true) return softSkip('inapplicable', 'host does not advertise `replay.supported: true` — the replay contract does not apply to it');
158
- if (!Array.isArray(replay.modes) || !replay.modes.includes('branch')) return;
159
+ if (!Array.isArray(replay.modes) || !replay.modes.includes('branch')) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!Array.isArray(replay.modes) || !replay.modes.includes(\'branch\')` returned early');
159
160
 
160
161
  // Self-test on the spec interpretation: branch and replay are
161
162
  // SEMANTICALLY DIFFERENT modes per spec/v1/replay.md. Branch may
162
163
  // diverge by design (variable overlay, runOptionsOverlay). This
163
164
  // assertion just pins the interpretation; no actual round-trip
164
165
  // needed.
165
- expect((replay.modes as string[]).includes('branch'), driver.describe(
166
+ expect((replay.modes as string[]).includes('branch'), req('openwop.it.replayDeterminism.branch-mode-does-not-need-to-produce-identical-event-sequences-negative-control',
166
167
  'spec/v1/replay.md',
167
168
  'branch mode is documented; this self-test ensures the suite does not assume branch determinism',
168
169
  )).toBe(true);