@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
@@ -49,6 +49,7 @@ import { expandChain, expandChainWithCompensation, type WorkflowChain, type Work
49
49
  import { capabilityFamily, discoveryFamilies } from '../lib/discovery-capabilities.js';
50
50
  import { softSkip } from '../lib/soft-skip.js';
51
51
  import { readErrorCode } from '../lib/error-envelope.js';
52
+ import { req } from '../lib/requirement-ids.js';
52
53
 
53
54
  const PROFILE = 'workflowChainPacks.hostExpansionSeam';
54
55
  const EXPAND_PATH = '/v1/host/sample/workflow-chain:expand';
@@ -106,7 +107,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
106
107
  const caps = (discoveryFamilies(disco.json) as { workflowChainPacks?: ChainCaps }).workflowChainPacks;
107
108
  expect(
108
109
  caps,
109
- driver.describe(
110
+ req('openwop.it.workflow-chain-host-expansion.host-discovery-advertises-workflowchainpacks-hostexpansionseam-when-the-expand-s',
110
111
  'capabilities.md §workflowChainPacks',
111
112
  'a host serving the RFC 0013 host-expansion test seam MUST set `hostExpansionSeam: true` (and, being a chain-pack consumer, `supported: true`) in the discovery block',
112
113
  ),
@@ -133,7 +134,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
133
134
  const probe = await driver.post(EXPAND_PATH, { packName: SAMPLE_PACK, chainId: CHAIN_1_NODE, parameters: {} });
134
135
  expect(
135
136
  probe.status,
136
- driver.describe(
137
+ req('openwop.it.workflow-chain-host-expansion.host-discovery-advertises-workflowchainpacks-hostexpansionseam-when-the-expand-s',
137
138
  'capabilities.md §workflowChainPacks',
138
139
  `a host advertising \`hostExpansionSeam: true\` MUST serve ${EXPAND_PATH}. Got ${probe.status} — ` +
139
140
  'the discovery document promises a seam the host does not route. Advertising a capability ' +
@@ -167,7 +168,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
167
168
  const [hm, hn] = body.packVersion.split('.').map(Number);
168
169
  const [fm, fn] = PACK.version.split('.').map(Number);
169
170
  const older = hm! < fm! || (hm === fm && hn! < fn!);
170
- expect(older, driver.describe('workflow-chain-host-expansion', `host bundles workflow-chain-sample ${body.packVersion}; this suite's fixture is ${PACK.version} — a host pack NEWER than the suite is unaccounted for`)).toBe(true);
171
+ expect(older, req('openwop.it.workflow-chain-host-expansion.positive-1-node-chain-expansion-matches-the-reference-library-for-the-bundled-pa', 'workflow-chain-host-expansion', `host bundles workflow-chain-sample ${body.packVersion}; this suite's fixture is ${PACK.version} — a host pack NEWER than the suite is unaccounted for`)).toBe(true);
171
172
  softSkip('blocked', `host bundles workflow-chain-sample ${body.packVersion} (suite fixture ${PACK.version}) — the RFC 0157 chains are absent there until its conformance pin catches up`);
172
173
  }
173
174
  expect(typeof body.expansionId).toBe('string');
@@ -188,16 +189,16 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
188
189
  const ref = expected.nodes[0]!;
189
190
  expect(
190
191
  node.id,
191
- driver.describe('workflow-chain-packs.md §Expansion semantics', 'host rewrites the node id exactly as the reference library (chainId dots → underscores + expansionId prefix)'),
192
+ req('openwop.it.workflow-chain-host-expansion.positive-1-node-chain-expansion-matches-the-reference-library-for-the-bundled-pa', 'workflow-chain-packs.md §Expansion semantics', 'host rewrites the node id exactly as the reference library (chainId dots → underscores + expansionId prefix)'),
192
193
  ).toBe(ref.id);
193
194
  expect(node.typeId).toBe(ref.typeId);
194
195
  expect(
195
196
  node.config?.systemPrompt,
196
- driver.describe('workflow-chain-packs.md §Expansion semantics', 'host performs the same literal {{params.*}} substitution as the reference library'),
197
+ req('openwop.it.workflow-chain-host-expansion.positive-1-node-chain-expansion-matches-the-reference-library-for-the-bundled-pa', 'workflow-chain-packs.md §Expansion semantics', 'host performs the same literal {{params.*}} substitution as the reference library'),
197
198
  ).toBe((ref.config as { systemPrompt?: string } | undefined)?.systemPrompt);
198
199
  expect(
199
200
  node.capabilities,
200
- driver.describe('workflow-chain-packs.md §Capability propagation', 'chain capabilities propagate to the expanded node'),
201
+ req('openwop.it.workflow-chain-host-expansion.positive-1-node-chain-expansion-matches-the-reference-library-for-the-bundled-pa', 'workflow-chain-packs.md §Capability propagation', 'chain capabilities propagate to the expanded node'),
201
202
  ).toEqual(ref.capabilities);
202
203
  });
203
204
 
@@ -222,14 +223,14 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
222
223
  const refEdge = expected.edges[0]!;
223
224
  expect(
224
225
  { from: edge.from, to: edge.to },
225
- driver.describe('workflow-chain-packs.md §Expansion semantics', 'host rewrites fragment-internal edge endpoints (port suffix preserved) exactly as the reference library'),
226
+ req('openwop.it.workflow-chain-host-expansion.positive-2-node-chain-matches-the-reference-library-edge-rewrite-capability-prop', 'workflow-chain-packs.md §Expansion semantics', 'host rewrites fragment-internal edge endpoints (port suffix preserved) exactly as the reference library'),
226
227
  ).toEqual({ from: refEdge.from, to: refEdge.to });
227
228
 
228
229
  // side-effectful capability propagated to BOTH expanded nodes (per the ref).
229
230
  const refCaps = expected.nodes.map((n) => n.capabilities);
230
231
  expect(
231
232
  body.nodes.map((n) => n.capabilities),
232
- driver.describe('workflow-chain-packs.md §Capability propagation', 'chain capability propagates uniformly to every expanded node'),
233
+ req('openwop.it.workflow-chain-host-expansion.positive-2-node-chain-matches-the-reference-library-edge-rewrite-capability-prop', 'workflow-chain-packs.md §Capability propagation', 'chain capability propagates uniformly to every expanded node'),
233
234
  ).toEqual(refCaps);
234
235
  });
235
236
 
@@ -241,7 +242,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
241
242
  chainId: 'whatever',
242
243
  parameters: {},
243
244
  });
244
- expect(res.status).toBe(404);
245
+ expect(res.status, req('openwop.it.workflow-chain-host-expansion.negative-unknown-pack-returns-404-pack-not-found', 'RFC 0013', 'negative — unknown pack returns 404 pack_not_found')).toBe(404);
245
246
  expect((res.json as { error: string }).error).toBe('pack_not_found');
246
247
  });
247
248
 
@@ -253,7 +254,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
253
254
  chainId: 'vendor.openwop.workflow-chain-sample.does-not-exist',
254
255
  parameters: {},
255
256
  });
256
- expect(res.status).toBe(404);
257
+ expect(res.status, req('openwop.it.workflow-chain-host-expansion.negative-known-pack-but-unknown-chainid-returns-404-chain-not-found', 'RFC 0013', 'negative — known pack but unknown chainId returns 404 chain_not_found')).toBe(404);
257
258
  expect((res.json as { error: string }).error).toBe('chain_not_found');
258
259
  });
259
260
 
@@ -262,7 +263,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
262
263
 
263
264
  // Missing chainId.
264
265
  const res = await driver.post(EXPAND_PATH, { packName: SAMPLE_PACK, parameters: {} });
265
- expect(res.status).toBe(422);
266
+ expect(res.status, req('openwop.it.workflow-chain-host-expansion.negative-malformed-request-body-returns-422-invalid-request', 'RFC 0013', 'negative — malformed request body returns 422 invalid_request')).toBe(422);
266
267
  expect((res.json as { error: string }).error).toBe('invalid_request');
267
268
  });
268
269
  it('RFC 0157 — a compensating chain expands through the live path with `compensation` and `irreversibleEffect` carried verbatim onto the expanded nodes', async () => {
@@ -275,7 +276,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
275
276
  // the chain does not exist there yet — unobservable, not a failure.
276
277
  return softSkip('blocked', `host's bundled workflow-chain-sample pack predates 1.1.0 (chain ${CHAIN_COMP} answered chain_not_found) — the RFC 0157 carry is unobservable until the host's conformance pin reaches 1.133.0`);
277
278
  }
278
- expect(res.status, driver.describe('workflow-chain-packs.md §"Compensation (RFC 0157)"', 'a chain whose nodes declare an inverse action / irreversibleEffect (no policy) is acceptable on ANY host — the declaration describes, only the policy requests an unwind')).toBe(200);
279
+ expect(res.status, req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-compensating-chain-expands-through-the-live-path-with-compensation-an', 'workflow-chain-packs.md §"Compensation (RFC 0157)"', 'a chain whose nodes declare an inverse action / irreversibleEffect (no policy) is acceptable on ANY host — the declaration describes, only the policy requests an unwind')).toBe(200);
279
280
  const body = res.json as unknown as {
280
281
  expansionId: string;
281
282
  nodes: Array<{ id: string; compensation?: unknown; irreversibleEffect?: boolean }>;
@@ -288,15 +289,15 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
288
289
  expect(body.nodes).toHaveLength(expected.nodes.length);
289
290
  for (const ref of expected.nodes) {
290
291
  const node = body.nodes.find((n) => n.id === ref.id);
291
- expect(node, driver.describe('workflow-chain-packs.md §Expansion semantics', `expanded node ${ref.id} present`)).toBeDefined();
292
+ expect(node, req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-compensating-chain-expands-through-the-live-path-with-compensation-an', 'workflow-chain-packs.md §Expansion semantics', `expanded node ${ref.id} present`)).toBeDefined();
292
293
  const refC = (ref as unknown as { compensation?: unknown }).compensation;
293
294
  expect(
294
295
  node?.compensation,
295
- driver.describe('workflow-chain-packs.md §"Compensation (RFC 0157)" rules 5b/6b', `node ${ref.id}: the inverse-action declaration MUST survive expansion verbatim (params substituted, node-id refs re-prefixed) — a node-rebuilding allowlist that drops it silently loses the unwind`),
296
+ req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-compensating-chain-expands-through-the-live-path-with-compensation-an', 'workflow-chain-packs.md §"Compensation (RFC 0157)" rules 5b/6b', `node ${ref.id}: the inverse-action declaration MUST survive expansion verbatim (params substituted, node-id refs re-prefixed) — a node-rebuilding allowlist that drops it silently loses the unwind`),
296
297
  ).toEqual(refC);
297
298
  expect(
298
299
  node?.irreversibleEffect,
299
- driver.describe('workflow-chain-packs.md §"Compensation (RFC 0157)" rule 6c', `node ${ref.id}: irreversibleEffect MUST be copied unchanged`),
300
+ req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-compensating-chain-expands-through-the-live-path-with-compensation-an', 'workflow-chain-packs.md §"Compensation (RFC 0157)" rule 6c', `node ${ref.id}: irreversibleEffect MUST be copied unchanged`),
300
301
  ).toEqual((ref as unknown as { irreversibleEffect?: boolean }).irreversibleEffect);
301
302
  }
302
303
  // Non-vacuity: the fixture DOES declare both, so at least one node of each kind was compared.
@@ -318,11 +319,11 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
318
319
  // MUST refuse a chain carrying a policy rather than accept a promise it will
319
320
  // never honour. Accepting silently is the advertise-and-opt-out failure with
320
321
  // the sign flipped.
321
- expect(res.status >= 400, driver.describe('compensation.md §"Workflow policy"', 'a non-advertising host MUST refuse a chain carrying `compensation` (policy) — 4xx, not 200')).toBe(true);
322
- expect(readErrorCode(res.json), driver.describe('capabilities.md §"Unsupported capability — refusal contract"', '`capability_required`')).toBe('capability_required');
323
- return;
322
+ expect(res.status >= 400, req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-chain-carrying-an-unwind-policy-is-refused-with-capability-required-o', 'compensation.md §"Workflow policy"', 'a non-advertising host MUST refuse a chain carrying `compensation` (policy) — 4xx, not 200')).toBe(true);
323
+ expect(readErrorCode(res.json), req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-chain-carrying-an-unwind-policy-is-refused-with-capability-required-o', 'capabilities.md §"Unsupported capability — refusal contract"', '`capability_required`')).toBe('capability_required');
324
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!advertises` returned early');
324
325
  }
325
- expect(res.status, driver.describe('workflow-chain-packs.md §"Compensation (RFC 0157)"', 'an advertising host expands the policy-carrying chain')).toBe(200);
326
+ expect(res.status, req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-chain-carrying-an-unwind-policy-is-refused-with-capability-required-o', 'workflow-chain-packs.md §"Compensation (RFC 0157)"', 'an advertising host expands the policy-carrying chain')).toBe(200);
326
327
  const body = res.json as unknown as { expansionId: string; nodes: unknown[]; settings?: { compensation?: unknown } };
327
328
  const expected = expandChainWithCompensation(chainById(CHAIN_COMP_POLICY) as unknown as WorkflowChainWithCompensation, {
328
329
  expansionId: body.expansionId,
@@ -335,7 +336,7 @@ describe('workflow-chain-host-expansion: live host wraps expansion algorithm cor
335
336
  // `settings` is host-optional, so the policy carry is asserted when visible
336
337
  // and noted when not — never assumed.
337
338
  if (body.settings?.compensation !== undefined) {
338
- expect(body.settings.compensation, driver.describe('workflow-chain-packs.md §"Compensation (RFC 0157)" rule 9b', 'the chain policy becomes settings.compensation, copied verbatim')).toEqual(expected.settingsCompensation);
339
+ expect(body.settings.compensation, req('openwop.it.workflow-chain-host-expansion.rfc-0157-a-chain-carrying-an-unwind-policy-is-refused-with-capability-required-o', 'workflow-chain-packs.md §"Compensation (RFC 0157)" rule 9b', 'the chain policy becomes settings.compensation, copied verbatim')).toEqual(expected.settingsCompensation);
339
340
  } else {
340
341
  softSkip('blocked', 'the expand seam does not echo `settings`, so the policy → settings.compensation carry (rule 9b) is unobservable through it; the node carry above was witnessed');
341
342
  }
@@ -34,6 +34,8 @@ import Ajv2020 from 'ajv/dist/2020.js';
34
34
  import addFormats from 'ajv-formats';
35
35
  import type { ErrorObject } from 'ajv';
36
36
  import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
37
+ import { req } from '../lib/requirement-ids.js';
38
+ import { softSkip } from '../lib/soft-skip.js';
37
39
 
38
40
  const SCHEMA_PATH = join(SCHEMAS_DIR, 'workflow-chain-pack-manifest.schema.json');
39
41
  // In-repo example pack — proves the schema validates a non-trivial
@@ -100,7 +102,7 @@ describe('category: workflow-chain-pack manifest validation', () => {
100
102
  .join('\n');
101
103
  expect(
102
104
  ok,
103
- `Positive sample MUST validate against workflow-chain-pack-manifest.schema.json — got:\n${errs}`,
105
+ req('openwop.it.workflow-chain-pack-manifest-validation.positive-a-valid-workflow-chain-pack-manifest-validates-cleanly', 'workflow-chain-packs.md', `Positive sample MUST validate against workflow-chain-pack-manifest.schema.json — got:\n${errs}`),
104
106
  ).toBe(true);
105
107
  });
106
108
 
@@ -134,7 +136,7 @@ describe('category: workflow-chain-pack manifest validation', () => {
134
136
  };
135
137
  const ok = validate(conditionalChain);
136
138
  const errs = (validate.errors ?? []).map((e: ErrorObject) => `${e.instancePath || '/'}: ${e.message}`).join('\n');
137
- expect(ok, `Object-shaped edge condition MUST validate — got:\n${errs}`).toBe(true);
139
+ expect(ok, req('openwop.it.workflow-chain-pack-manifest-validation.positive-a-fragmentedge-condition-takes-the-top-level-edgecondition-shape-rfc-00', 'RFC 0013', `Object-shaped edge condition MUST validate — got:\n${errs}`)).toBe(true);
138
140
  });
139
141
 
140
142
  it('negative: a bare-string FragmentEdge condition is rejected (the pre-2026-07-03 shape)', () => {
@@ -160,7 +162,7 @@ describe('category: workflow-chain-pack manifest validation', () => {
160
162
  },
161
163
  ],
162
164
  };
163
- expect(validate(stringCondition), 'A string edge condition MUST NOT validate under the corrected schema').toBe(false);
165
+ expect(validate(stringCondition), req('openwop.it.workflow-chain-pack-manifest-validation.negative-a-bare-string-fragmentedge-condition-is-rejected-the-pre-2026-07-03-sha', 'workflow-chain-packs.md', 'A string edge condition MUST NOT validate under the corrected schema')).toBe(false);
164
166
  });
165
167
 
166
168
  it('negative: manifest mixing chains[] AND nodes[] is rejected (pack_kind_invalid)', () => {
@@ -192,14 +194,14 @@ describe('category: workflow-chain-pack manifest validation', () => {
192
194
  const ok = validate(manifest);
193
195
  expect(
194
196
  ok,
195
- 'Manifest with both nodes[] and chains[] MUST fail workflow-chain schema validation (pack_kind_invalid at the registry surface).',
197
+ req('openwop.it.workflow-chain-pack-manifest-validation.negative-manifest-mixing-chains-and-nodes-is-rejected-pack-kind-invalid', 'workflow-chain-packs.md', 'Manifest with both nodes[] and chains[] MUST fail workflow-chain schema validation (pack_kind_invalid at the registry surface).'),
196
198
  ).toBe(false);
197
199
  const hasAdditionalPropertiesErr = (validate.errors ?? []).some(
198
200
  (e: ErrorObject) => e.keyword === 'additionalProperties',
199
201
  );
200
202
  expect(
201
203
  hasAdditionalPropertiesErr,
202
- 'Expected an `additionalProperties` violation flagging the unexpected `nodes` field.',
204
+ req('openwop.it.workflow-chain-pack-manifest-validation.negative-manifest-mixing-chains-and-nodes-is-rejected-pack-kind-invalid', 'workflow-chain-packs.md', 'Expected an `additionalProperties` violation flagging the unexpected `nodes` field.'),
203
205
  ).toBe(true);
204
206
  });
205
207
 
@@ -228,7 +230,7 @@ describe('category: workflow-chain-pack manifest validation', () => {
228
230
  const ok = validate(manifest);
229
231
  expect(
230
232
  ok,
231
- 'Manifest with invalid chainId MUST fail workflow-chain schema validation.',
233
+ req('openwop.it.workflow-chain-pack-manifest-validation.negative-chain-entry-with-invalid-chainid-is-rejected-pattern-violation', 'workflow-chain-packs.md', 'Manifest with invalid chainId MUST fail workflow-chain schema validation.'),
232
234
  ).toBe(false);
233
235
  const hasPatternErr = (validate.errors ?? []).some(
234
236
  (e: ErrorObject) =>
@@ -236,14 +238,14 @@ describe('category: workflow-chain-pack manifest validation', () => {
236
238
  );
237
239
  expect(
238
240
  hasPatternErr,
239
- 'Expected a `pattern` violation on the chains[].chainId field.',
241
+ req('openwop.it.workflow-chain-pack-manifest-validation.negative-chain-entry-with-invalid-chainid-is-rejected-pattern-violation', 'workflow-chain-packs.md', 'Expected a `pattern` violation on the chains[].chainId field.'),
240
242
  ).toBe(true);
241
243
  });
242
244
 
243
245
  it('positive: the in-repo example pack at examples/packs/workflow-chain-sample/ validates against the schema', () => {
244
246
  if (!EXAMPLE_PACK_PATH || !existsSync(EXAMPLE_PACK_PATH)) {
245
247
  // Published-tarball layout doesn't ship examples/; skip cleanly.
246
- return;
248
+ return softSkip('blocked', 'precondition not met — `!EXAMPLE_PACK_PATH || !existsSync(EXAMPLE_PACK_PATH)` returned early (Published-tarball layout doesn\'t ship examples/; skip cleanly.) (seam, prior step, or fixture unavailable)');
247
249
  }
248
250
  const manifest = JSON.parse(readFileSync(EXAMPLE_PACK_PATH, 'utf8'));
249
251
  const ok = validate(manifest);
@@ -252,15 +254,15 @@ describe('category: workflow-chain-pack manifest validation', () => {
252
254
  .join('\n');
253
255
  expect(
254
256
  ok,
255
- `examples/packs/workflow-chain-sample/pack.json MUST validate against workflow-chain-pack-manifest.schema.json (closes RFC 0013 Phase 4 in-tree path). Errors:\n${errs}`,
257
+ req('openwop.it.workflow-chain-pack-manifest-validation.positive-the-in-repo-example-pack-at-examples-packs-workflow-chain-sample-valida', 'workflow-chain-packs.md', `examples/packs/workflow-chain-sample/pack.json MUST validate against workflow-chain-pack-manifest.schema.json (closes RFC 0013 Phase 4 in-tree path). Errors:\n${errs}`),
256
258
  ).toBe(true);
257
259
  // Spot-check the structural claims the example README makes:
258
- expect(manifest.kind, 'example pack MUST declare kind: "workflow-chain"').toBe(
260
+ expect(manifest.kind, req('openwop.it.workflow-chain-pack-manifest-validation.positive-the-in-repo-example-pack-at-examples-packs-workflow-chain-sample-valida', 'workflow-chain-packs.md', 'example pack MUST declare kind: "workflow-chain"')).toBe(
259
261
  'workflow-chain',
260
262
  );
261
263
  expect(
262
264
  Array.isArray(manifest.chains) && manifest.chains.length === 2,
263
- 'example pack MUST ship exactly 2 chains (1-node + 2-node shapes) per its README contract',
265
+ req('openwop.it.workflow-chain-pack-manifest-validation.positive-the-in-repo-example-pack-at-examples-packs-workflow-chain-sample-valida', 'workflow-chain-packs.md', 'example pack MUST ship exactly 2 chains (1-node + 2-node shapes) per its README contract'),
264
266
  ).toBe(true);
265
267
  });
266
268
 
@@ -285,7 +287,7 @@ describe('category: workflow-chain-pack manifest validation', () => {
285
287
  const ok = validate(manifest);
286
288
  expect(
287
289
  ok,
288
- 'Manifest without kind: "workflow-chain" MUST fail this schema (the other path is node-pack-manifest.schema.json).',
290
+ req('openwop.it.workflow-chain-pack-manifest-validation.negative-omitting-kind-field-rejects-kind-is-required', 'workflow-chain-packs.md', 'Manifest without kind: "workflow-chain" MUST fail this schema (the other path is node-pack-manifest.schema.json).'),
289
291
  ).toBe(false);
290
292
  });
291
293
  });
@@ -30,6 +30,7 @@
30
30
 
31
31
  import { describe, it, expect } from 'vitest';
32
32
  import { generateKeyPairSync, sign, verify } from 'node:crypto';
33
+ import { req } from '../lib/requirement-ids.js';
33
34
 
34
35
  /** Canonical workflow-chain pack manifest used as the signing target.
35
36
  * Mirrors the spec doc's Positive example, kept tight so the test
@@ -76,7 +77,7 @@ describe('category: workflow-chain pack signature — Ed25519 verification reuse
76
77
  const ok = verify(null, manifest, publicKey, signature);
77
78
  expect(
78
79
  ok,
79
- 'Per workflow-chain-packs.md §"Expansion semantics" step 2: the signature recipe is IDENTICAL to node-packs (Ed25519 over pack.json bytes). A valid pair MUST verify with the canonical recipe.',
80
+ req('openwop.it.workflow-chain-pack-signature-verification.valid-manifest-valid-signature-must-verify-positive-path', 'workflow-chain-packs.md', 'Per workflow-chain-packs.md §"Expansion semantics" step 2: the signature recipe is IDENTICAL to node-packs (Ed25519 over pack.json bytes). A valid pair MUST verify with the canonical recipe.'),
80
81
  ).toBe(true);
81
82
  });
82
83
 
@@ -92,7 +93,7 @@ describe('category: workflow-chain pack signature — Ed25519 verification reuse
92
93
  const ok = verify(null, tampered, publicKey, signature);
93
94
  expect(
94
95
  ok,
95
- 'Per node-packs.md §Signing (reused unchanged for chain packs): Ed25519 verification MUST detect any byte-level tamper to the signed payload.',
96
+ req('openwop.it.workflow-chain-pack-signature-verification.tampered-manifest-must-fail-verification-sha-level-tamper-detection', 'workflow-chain-packs.md', 'Per node-packs.md §Signing (reused unchanged for chain packs): Ed25519 verification MUST detect any byte-level tamper to the signed payload.'),
96
97
  ).toBe(false);
97
98
  });
98
99
 
@@ -108,7 +109,7 @@ describe('category: workflow-chain pack signature — Ed25519 verification reuse
108
109
  const ok = verify(null, manifest, attackerPubKey, signature);
109
110
  expect(
110
111
  ok,
111
- 'Ed25519 verification MUST fail when the public key doesn\'t match the private key that produced the signature — the spec\'s trust model depends on this property.',
112
+ req('openwop.it.workflow-chain-pack-signature-verification.wrong-key-signature-must-fail-verification', 'workflow-chain-packs.md', 'Ed25519 verification MUST fail when the public key doesn\'t match the private key that produced the signature — the spec\'s trust model depends on this property.'),
112
113
  ).toBe(false);
113
114
  });
114
115
 
@@ -130,7 +131,7 @@ describe('category: workflow-chain pack signature — Ed25519 verification reuse
130
131
  };
131
132
  expect(
132
133
  signedManifest.signing.method,
133
- 'workflow-chain packs MUST accept the same signing block keys as node packs (publicKeyRef + signatureRef + method) per spec design.',
134
+ req('openwop.it.workflow-chain-pack-signature-verification.chain-pack-manifests-carry-the-same-signing-block-shape-as-node-packs', 'workflow-chain-packs.md', 'workflow-chain packs MUST accept the same signing block keys as node packs (publicKeyRef + signatureRef + method) per spec design.'),
134
135
  ).toBe('manual');
135
136
  expect(signedManifest.signing.publicKeyRef).toBe('keys/2026-05.pem');
136
137
  expect(signedManifest.signing.signatureRef).toBe('pack.json.sig');
@@ -36,6 +36,7 @@ import {
36
36
  ChainUnresolvableTypeIdError,
37
37
  type WorkflowChain,
38
38
  } from '../lib/workflow-chain-expansion.js';
39
+ import { req } from '../lib/requirement-ids.js';
39
40
 
40
41
  const CHAIN_WITH_UNKNOWN_TYPEID: WorkflowChain = {
41
42
  chainId: 'vendor.acme.someChain',
@@ -66,7 +67,7 @@ describe('category: workflow-chain expansion — unresolvable typeId rejection',
66
67
  params: {},
67
68
  isTypeIdResolvable: isKnown,
68
69
  }),
69
- 'Per spec §"Expansion semantics" step 3: hosts MUST reject expansion with `chain_unresolvable_typeid` when any fragment node\'s typeId can\'t be resolved by the destination host.',
70
+ req('openwop.it.workflow-chain-unresolvable-typeid.throws-chainunresolvabletypeiderror-when-chain-references-an-unknown-typeid', 'workflow-chain-packs.md', 'Per spec §"Expansion semantics" step 3: hosts MUST reject expansion with `chain_unresolvable_typeid` when any fragment node\'s typeId can\'t be resolved by the destination host.'),
70
71
  ).toThrow(ChainUnresolvableTypeIdError);
71
72
  });
72
73
 
@@ -79,21 +80,21 @@ describe('category: workflow-chain expansion — unresolvable typeId rejection',
79
80
  });
80
81
  expect.fail('expandChain MUST have thrown ChainUnresolvableTypeIdError');
81
82
  } catch (err) {
82
- expect(err, 'expected ChainUnresolvableTypeIdError').toBeInstanceOf(
83
+ expect(err, req('openwop.it.workflow-chain-unresolvable-typeid.error-carries-the-offending-typeid-and-the-chainid-in-details', 'workflow-chain-packs.md', 'expected ChainUnresolvableTypeIdError')).toBeInstanceOf(
83
84
  ChainUnresolvableTypeIdError,
84
85
  );
85
86
  const e = err as ChainUnresolvableTypeIdError;
86
87
  expect(
87
88
  e.code,
88
- 'Per spec §"Error codes": the wire-level error code MUST be `chain_unresolvable_typeid`.',
89
+ req('openwop.it.workflow-chain-unresolvable-typeid.error-carries-the-offending-typeid-and-the-chainid-in-details', 'workflow-chain-packs.md', 'Per spec §"Error codes": the wire-level error code MUST be `chain_unresolvable_typeid`.'),
89
90
  ).toBe('chain_unresolvable_typeid');
90
91
  expect(
91
92
  e.typeId,
92
- 'The error MUST surface the offending typeId so the host editor can render an actionable diagnostic.',
93
+ req('openwop.it.workflow-chain-unresolvable-typeid.error-carries-the-offending-typeid-and-the-chainid-in-details', 'workflow-chain-packs.md', 'The error MUST surface the offending typeId so the host editor can render an actionable diagnostic.'),
93
94
  ).toBe('made.up.foo');
94
95
  expect(
95
96
  e.chainId,
96
- 'The error MUST surface the chainId so the host editor knows which chain-pack tile triggered the rejection.',
97
+ req('openwop.it.workflow-chain-unresolvable-typeid.error-carries-the-offending-typeid-and-the-chainid-in-details', 'workflow-chain-packs.md', 'The error MUST surface the chainId so the host editor knows which chain-pack tile triggered the rejection.'),
97
98
  ).toBe('vendor.acme.someChain');
98
99
  }
99
100
  });
@@ -115,7 +116,7 @@ describe('category: workflow-chain expansion — unresolvable typeId rejection',
115
116
  }
116
117
  expect(
117
118
  threw,
118
- 'Expansion MUST throw before producing any output — host editors rely on the "no partial expansion" guarantee to keep parent workflows clean on rejection.',
119
+ req('openwop.it.workflow-chain-unresolvable-typeid.rejection-happens-before-any-id-rewriting-or-placeholder-substitution', 'workflow-chain-packs.md', 'Expansion MUST throw before producing any output — host editors rely on the "no partial expansion" guarantee to keep parent workflows clean on rejection.'),
119
120
  ).toBe(true);
120
121
  });
121
122
 
@@ -134,7 +135,7 @@ describe('category: workflow-chain expansion — unresolvable typeId rejection',
134
135
  params: {},
135
136
  isTypeIdResolvable: isKnown,
136
137
  }),
137
- 'Sanity: when every typeId resolves, expansion MUST proceed without throwing.',
138
+ req('openwop.it.workflow-chain-unresolvable-typeid.accepts-the-chain-when-every-typeid-is-resolvable', 'workflow-chain-packs.md', 'Sanity: when every typeId resolves, expansion MUST proceed without throwing.'),
138
139
  ).not.toThrow();
139
140
  });
140
141
 
@@ -163,7 +164,7 @@ describe('category: workflow-chain expansion — unresolvable typeId rejection',
163
164
  const e = err as ChainUnresolvableTypeIdError;
164
165
  expect(
165
166
  e.typeId,
166
- 'When multiple nodes have unknown typeIds, the throw MUST identify the first unknown one encountered in declaration order.',
167
+ req('openwop.it.workflow-chain-unresolvable-typeid.throws-on-the-first-unknown-typeid-encountered-fail-fast', 'workflow-chain-packs.md', 'When multiple nodes have unknown typeIds, the throw MUST identify the first unknown one encountered in declaration order.'),
167
168
  ).toBe('made.up.foo');
168
169
  }
169
170
  });
@@ -23,6 +23,7 @@ import addFormats from 'ajv-formats';
23
23
  import { readFileSync, readdirSync } from 'node:fs';
24
24
  import { join } from 'node:path';
25
25
  import { SCHEMAS_DIR } from '../lib/paths.js';
26
+ import { req } from '../lib/requirement-ids.js';
26
27
 
27
28
  function compileWorkflowDefinition(): ReturnType<Ajv2020['compile']> {
28
29
  const ajv = new Ajv2020({ strict: false, allErrors: true });
@@ -78,7 +79,7 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
78
79
  baseNode('b'),
79
80
  ]);
80
81
  const ok = validate(def);
81
- expect(ok, JSON.stringify(validate.errors, null, 2)).toBe(true);
82
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.accepts-a-workflow-with-one-node-declaring-outputrole-primary', 'RFC 0065', JSON.stringify(validate.errors, null, 2))).toBe(true);
82
83
  });
83
84
 
84
85
  it('accepts primary AND secondary annotations on different nodes', () => {
@@ -88,7 +89,7 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
88
89
  baseNode('c'),
89
90
  ]);
90
91
  const ok = validate(def);
91
- expect(ok, JSON.stringify(validate.errors, null, 2)).toBe(true);
92
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.accepts-primary-and-secondary-annotations-on-different-nodes', 'RFC 0065', JSON.stringify(validate.errors, null, 2))).toBe(true);
92
93
  });
93
94
 
94
95
  it('accepts a workflow with the field absent (additive promise)', () => {
@@ -97,7 +98,7 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
97
98
  baseNode('b'),
98
99
  ]);
99
100
  const ok = validate(def);
100
- expect(ok, JSON.stringify(validate.errors, null, 2)).toBe(true);
101
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.accepts-a-workflow-with-the-field-absent-additive-promise', 'RFC 0065', JSON.stringify(validate.errors, null, 2))).toBe(true);
101
102
  });
102
103
 
103
104
  it('rejects an unknown outputRole enum value', () => {
@@ -105,7 +106,7 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
105
106
  baseNode('a', { outputRole: 'tertiary' }),
106
107
  ]);
107
108
  const ok = validate(def);
108
- expect(ok).toBe(false);
109
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.rejects-an-unknown-outputrole-enum-value', 'RFC 0065', 'rejects an unknown outputRole enum value')).toBe(false);
109
110
  expect(validate.errors).toBeTruthy();
110
111
  });
111
112
 
@@ -114,7 +115,7 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
114
115
  baseNode('a', { outputRole: 1 }),
115
116
  ]);
116
117
  const ok = validate(def);
117
- expect(ok).toBe(false);
118
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.rejects-outputrole-set-to-a-non-string', 'RFC 0065', 'rejects outputRole set to a non-string')).toBe(false);
118
119
  });
119
120
 
120
121
  it('permits multiple nodes declaring outputRole="primary" (tooling decides)', () => {
@@ -127,6 +128,6 @@ describe('workflow-primary-output-annotation: outputRole shape (RFC 0065)', () =
127
128
  baseNode('b', { outputRole: 'primary' }),
128
129
  ]);
129
130
  const ok = validate(def);
130
- expect(ok, JSON.stringify(validate.errors, null, 2)).toBe(true);
131
+ expect(ok, req('openwop.it.workflow-primary-output-annotation.permits-multiple-nodes-declaring-outputrole-primary-tooling-decides', 'RFC 0065', JSON.stringify(validate.errors, null, 2))).toBe(true);
131
132
  });
132
133
  });
@@ -48,8 +48,8 @@ import { behaviorGate } from '../lib/behavior-gate.js';
48
48
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
49
49
  import { isFixtureAdvertised } from '../lib/fixtures.js';
50
50
  import { driver } from '../lib/driver.js';
51
-
52
- const cite = (section: string, requirement: string): string => `${section} — ${requirement}`;
51
+ import { softSkip } from '../lib/soft-skip.js';
52
+ import { req } from '../lib/requirement-ids.js';
53
53
  const WORKFLOW_DEF = join(SCHEMAS_DIR, 'workflow-definition.schema.json');
54
54
  // S38 (2026-08-17): `spec/` is NOT in the published package (`files`), so a path built
55
55
  // from SCHEMAS_DIR/../spec ENOENTs for every npm consumer — five always-on legs reddened
@@ -83,11 +83,11 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
83
83
  const wv = defs.WorkflowVariable;
84
84
  const props = wv.properties as Record<string, Record<string, unknown>>;
85
85
 
86
- expect(props.format, cite('§WorkflowVariable', '`format` is declared')).toBeDefined();
87
- expect(props.format.type, cite('§WorkflowVariable', '`format` is a string')).toBe('string');
86
+ expect(props.format, req('openwop.it.workflow-variable-format.a1-workflowvariable-declares-format-as-an-advisory-string', '§WorkflowVariable', '`format` is declared')).toBeDefined();
87
+ expect(props.format.type, req('openwop.it.workflow-variable-format.a1-workflowvariable-declares-format-as-an-advisory-string', '§WorkflowVariable', '`format` is a string')).toBe('string');
88
88
  expect(
89
89
  (wv.required as string[] | undefined)?.includes('format') ?? false,
90
- cite('§WorkflowVariable', '`format` is OPTIONAL — additive per COMPATIBILITY.md §2.1'),
90
+ req('openwop.it.workflow-variable-format.a1-workflowvariable-declares-format-as-an-advisory-string', '§WorkflowVariable', '`format` is OPTIONAL — additive per COMPATIBILITY.md §2.1'),
91
91
  ).toBe(false);
92
92
  });
93
93
 
@@ -98,7 +98,7 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
98
98
  const recognised = { name: 'recipientEmail', type: 'string', format: 'email' };
99
99
  expect(
100
100
  validate(recognised),
101
- cite('§WorkflowVariable', `recognised format validates: ${JSON.stringify(validate.errors)}`),
101
+ req('openwop.it.workflow-variable-format.a2-an-unrecognised-format-validates-requirement-2-unknown-plain-text-never-an-er', '§WorkflowVariable', `recognised format validates: ${JSON.stringify(validate.errors)}`),
102
102
  ).toBe(true);
103
103
 
104
104
  // OUTSIDE the table. This is the whole point: the property must NOT be an enum, or a
@@ -107,7 +107,7 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
107
107
  const unrecognised = { name: 'ipAddress', type: 'string', format: 'vendor.acme.ipv4-or-hostname' };
108
108
  expect(
109
109
  validate(unrecognised),
110
- cite('§WorkflowVariable', `unrecognised format validates (RFC 0136 req 2): ${JSON.stringify(validate.errors)}`),
110
+ req('openwop.it.workflow-variable-format.a2-an-unrecognised-format-validates-requirement-2-unknown-plain-text-never-an-er', '§WorkflowVariable', `unrecognised format validates (RFC 0136 req 2): ${JSON.stringify(validate.errors)}`),
111
111
  ).toBe(true);
112
112
  });
113
113
 
@@ -116,21 +116,21 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
116
116
  const both = { name: 'notifyAddress', type: 'string', format: 'email', sensitive: true };
117
117
  expect(
118
118
  validate(both),
119
- cite('§WorkflowVariable', `format + sensitive compose: ${JSON.stringify(validate.errors)}`),
119
+ req('openwop.it.workflow-variable-format.a3-format-and-sensitive-compose-on-one-variable-no-interaction', '§WorkflowVariable', `format + sensitive compose: ${JSON.stringify(validate.errors)}`),
120
120
  ).toBe(true);
121
121
  });
122
122
 
123
123
  it.skipIf(CHAIN_DOC === null)('A4 — chain-pack spec documents deferred-mode `format` propagation as mode-scoped', () => {
124
124
  const doc = readFileSync(CHAIN_DOC as string, 'utf8');
125
125
  const step1 = doc.slice(doc.indexOf('Materialize parameters as variables'));
126
- expect(step1.length > 0, cite('§Deferred-parameter expansion', 'step 1 present')).toBe(true);
126
+ expect(step1.length > 0, req('openwop.it.workflow-variable-format.a4-chain-pack-spec-documents-deferred-mode-format-propagation-as-mode-scoped', '§Deferred-parameter expansion', 'step 1 present')).toBe(true);
127
127
  expect(
128
128
  /`format`/.test(step1.slice(0, 1400)),
129
- cite('§Deferred-parameter expansion', 'step 1 copy-list names `format`'),
129
+ req('openwop.it.workflow-variable-format.a4-chain-pack-spec-documents-deferred-mode-format-propagation-as-mode-scoped', '§Deferred-parameter expansion', 'step 1 copy-list names `format`'),
130
130
  ).toBe(true);
131
131
  expect(
132
132
  /this mode only|mode only/i.test(step1.slice(0, 1400)),
133
- cite('§Deferred-parameter expansion', 'the `format` MUST is scoped to deferred mode, not universal'),
133
+ req('openwop.it.workflow-variable-format.a4-chain-pack-spec-documents-deferred-mode-format-propagation-as-mode-scoped', '§Deferred-parameter expansion', 'the `format` MUST is scoped to deferred mode, not universal'),
134
134
  ).toBe(true);
135
135
  });
136
136
 
@@ -138,7 +138,7 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
138
138
  const rfc = readFileSync(RFC_DOC as string, 'utf8');
139
139
  expect(
140
140
  /configurableSchema/.test(rfc),
141
- cite('RFC 0136', 'names the configurableSchema propagation path'),
141
+ req('openwop.it.workflow-variable-format.a5-the-rfc-forbids-format-participating-in-a-configurable-validation-decision', 'RFC 0136', 'names the configurableSchema propagation path'),
142
142
  ).toBe(true);
143
143
  // The trap: run-options.md §1 makes validating `configurable` against
144
144
  // `configurableSchema` a MUST with `validation_error` on failure. A format-asserting
@@ -147,7 +147,7 @@ describe('workflow-variable-format §A: corpus (RFC 0136, always-on)', () => {
147
147
  // closes it: annotation permitted, assertion forbidden.
148
148
  expect(
149
149
  /requirement 3[\s\S]{0,600}(back door|surface-independent)/i.test(rfc),
150
- cite('RFC 0136 req 8', 'states requirement 3 is surface-independent'),
150
+ req('openwop.it.workflow-variable-format.a5-the-rfc-forbids-format-participating-in-a-configurable-validation-decision', 'RFC 0136 req 8', 'states requirement 3 is surface-independent'),
151
151
  ).toBe(true);
152
152
  });
153
153
  });
@@ -171,7 +171,7 @@ describe('workflow-variable-format §B: host behaviour (RFC 0136, capability-gat
171
171
  }
172
172
 
173
173
  it('B1 — deferred expansion mints `format` onto the WorkflowVariable: string copied (req 7), unknown copied (req 2), non-string omits it (req 1)', async () => {
174
- if (!(await deferredParamsGateOpen())) return;
174
+ if (!(await deferredParamsGateOpen())) return softSkip('blocked', 'precondition not met — `!(await deferredParamsGateOpen())` returned early (seam, prior step, or fixture unavailable)');
175
175
 
176
176
  // Drive the RFC 0124 deferred-expand seam with a chain whose parameters exercise all
177
177
  // three propagation rules in one expansion; assert the minted variables[] carry (or omit)
@@ -190,15 +190,15 @@ describe('workflow-variable-format §B: host behaviour (RFC 0136, capability-gat
190
190
  });
191
191
  // A host advertising deferredParameters but not yet serving the variables[]-returning
192
192
  // seam extension soft-skips (404), as does a host with the seam disabled in this boot.
193
- if (res.status === 404) return;
194
- expect(res.status, cite('§Deferred-parameter expansion', 'the deferred-expand seam returns 200')).toBe(200);
193
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (A host advertising deferredParameters but not yet serving the variables[]-returning seam extension soft-skips (404), as does a host with the seam disabled in…');
194
+ expect(res.status, req('openwop.it.workflow-variable-format.b1-deferred-expansion-mints-format-onto-the-workflowvariable-string-copied-req-7', '§Deferred-parameter expansion', 'the deferred-expand seam returns 200')).toBe(200);
195
195
  const variables = (res.json as { variables?: Array<{ name: string; type?: string; format?: string }> }).variables;
196
- if (!Array.isArray(variables)) return; // seam present but not returning variables[] yet — soft-skip
196
+ if (!Array.isArray(variables)) return softSkip('blocked', 'precondition not met — `!Array.isArray(variables)` returned early (seam present but not returning variables[] yet — soft-skip) (seam, prior step, or fixture unavailable)'); // seam present but not returning variables[] yet — soft-skip
197
197
  const fmt = (n: string): string | undefined => variables.find((v) => v.name === n)?.format;
198
198
 
199
- expect(fmt('email'), cite('§WorkflowVariable', 'req 7: a string param\'s recognised `format` is minted verbatim')).toBe('email');
200
- expect(fmt('note'), cite('§WorkflowVariable', 'req 2: an UNRECOGNISED `format` is minted verbatim, never dropped')).toBe('vendor.acme.freeform');
201
- expect(fmt('count'), cite('§WorkflowVariable', 'req 1: a NON-STRING param mints no `format`')).toBeUndefined();
199
+ expect(fmt('email'), req('openwop.it.workflow-variable-format.b1-deferred-expansion-mints-format-onto-the-workflowvariable-string-copied-req-7', '§WorkflowVariable', 'req 7: a string param\'s recognised `format` is minted verbatim')).toBe('email');
200
+ expect(fmt('note'), req('openwop.it.workflow-variable-format.b1-deferred-expansion-mints-format-onto-the-workflowvariable-string-copied-req-7', '§WorkflowVariable', 'req 2: an UNRECOGNISED `format` is minted verbatim, never dropped')).toBe('vendor.acme.freeform');
201
+ expect(fmt('count'), req('openwop.it.workflow-variable-format.b1-deferred-expansion-mints-format-onto-the-workflowvariable-string-copied-req-7', '§WorkflowVariable', 'req 1: a NON-STRING param mints no `format`')).toBeUndefined();
202
202
  });
203
203
 
204
204
  const B2_FIXTURE = 'conformance-workflow-variable-format-advisory';
@@ -210,13 +210,13 @@ describe('workflow-variable-format §B: host behaviour (RFC 0136, capability-gat
210
210
  // endpoint, since registration is "POST /v1/workflows or equivalent" (capabilities.md)
211
211
  // and the create path is not a mandated portable surface. Gate on fixture advertisement:
212
212
  // req 3 is universal (not deferred-mode-specific), so it rides the host loading the fixture.
213
- if (!isFixtureAdvertised(B2_FIXTURE)) return;
213
+ if (!isFixtureAdvertised(B2_FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(B2_FIXTURE)` returned early (Portable pre-registered-workflow pattern (cf. agentPackHandoffSchemaValidation): the fixture `conformance-wor…');
214
214
 
215
215
  const run = await driver.post('/v1/runs', { workflowId: B2_FIXTURE });
216
- if (run.status === 404) return; // no run surface — soft-skip
216
+ if (run.status === 404) return softSkip('blocked', 'precondition not met — `run.status === 404` returned early (no run surface — soft-skip) (seam, prior step, or fixture unavailable)'); // no run surface — soft-skip
217
217
  expect(
218
218
  [200, 201],
219
- cite('POST /v1/runs', 'req 3: a run whose variable value violates its advisory `format` is accepted, not rejected'),
219
+ req('openwop.it.workflow-variable-format.b2-a-run-whose-variable-value-does-not-match-its-declared-format-is-accepted-and', 'POST /v1/runs', 'req 3: a run whose variable value violates its advisory `format` is accepted, not rejected'),
220
220
  ).toContain(run.status);
221
221
  const runId = (run.json as { runId: string }).runId;
222
222
 
@@ -232,7 +232,7 @@ describe('workflow-variable-format §B: host behaviour (RFC 0136, capability-gat
232
232
  }
233
233
  expect(
234
234
  snap?.status,
235
- cite('§WorkflowVariable', 'req 3: the run COMPLETES — `format` is advisory, a value mismatch MUST NOT fail the run'),
235
+ req('openwop.it.workflow-variable-format.b2-a-run-whose-variable-value-does-not-match-its-declared-format-is-accepted-and', '§WorkflowVariable', 'req 3: the run COMPLETES — `format` is advisory, a value mismatch MUST NOT fail the run'),
236
236
  ).toBe('completed');
237
237
  });
238
238
  });