@openwop/openwop-conformance 1.163.0 → 2.0.0-rc.1

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 (611) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +262 -14
  3. package/dist/lib/certification-bundle-v3.js +142 -0
  4. package/dist/lib/paths.js +25 -3
  5. package/dist/lib/requirement-ids.js +57 -4
  6. package/dist/lib/requirement-ledger.js +1 -0
  7. package/dist/lib/scenario-disposition.js +6 -1
  8. package/dist/lib/spec-coherence.js +13 -32
  9. package/dist/spec-artifacts.lock.json +5 -0
  10. package/package.json +11 -33
  11. package/requirements.json +22892 -11701
  12. package/scenario-majors.json +1493 -0
  13. package/schemas/CORPUS-STAMP.json +137 -5
  14. package/src/cli.ts +236 -19
  15. package/src/global-setup.ts +3 -2
  16. package/src/lib/certification-bundle-v3.ts +175 -0
  17. package/src/lib/corpus-stamp.ts +29 -1
  18. package/src/lib/driver.ts +9 -1
  19. package/src/lib/era2-seed.ts +197 -0
  20. package/src/lib/paths.ts +25 -3
  21. package/src/lib/requirement-ids.ts +54 -4
  22. package/src/lib/requirement-ledger.ts +7 -1
  23. package/src/lib/scenario-disposition.ts +6 -1
  24. package/src/lib/seams.ts +45 -0
  25. package/src/lib/spec-coherence.ts +15 -32
  26. package/src/lib/v2.ts +62 -0
  27. package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
  28. package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
  29. package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
  30. package/src/scenarios/a2a-peer-authority.test.ts +7 -6
  31. package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
  32. package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
  33. package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
  34. package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
  35. package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
  36. package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
  37. package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
  38. package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
  39. package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
  40. package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
  41. package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
  42. package/src/scenarios/agent-deployment-shape.test.ts +22 -24
  43. package/src/scenarios/agent-eval-run.test.ts +19 -18
  44. package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
  45. package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
  46. package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
  47. package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
  48. package/src/scenarios/agent-live-structured-output.test.ts +7 -6
  49. package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
  50. package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
  51. package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
  52. package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
  53. package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
  54. package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
  55. package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
  56. package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
  57. package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
  58. package/src/scenarios/agent-platform-profile.test.ts +18 -19
  59. package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
  60. package/src/scenarios/agent-roster-attribution.test.ts +18 -17
  61. package/src/scenarios/agent-roster-shape.test.ts +17 -19
  62. package/src/scenarios/agent-verifier-shape.test.ts +11 -11
  63. package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
  64. package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
  65. package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
  66. package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
  67. package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
  68. package/src/scenarios/agentMessageReducer.test.ts +2 -1
  69. package/src/scenarios/agentMetadata.test.ts +2 -1
  70. package/src/scenarios/agentPackCatalog.test.ts +23 -21
  71. package/src/scenarios/agentPackExport.test.ts +4 -2
  72. package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
  73. package/src/scenarios/agentPackInstall.test.ts +4 -2
  74. package/src/scenarios/agentPackProvenance.test.ts +2 -1
  75. package/src/scenarios/agentReasoningEvents.test.ts +3 -2
  76. package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
  77. package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
  78. package/src/scenarios/ai-envelope-shape.test.ts +31 -29
  79. package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
  80. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
  81. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
  82. package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
  83. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
  84. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
  85. package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
  86. package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
  87. package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
  88. package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
  89. package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
  90. package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
  91. package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
  92. package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
  93. package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
  94. package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
  95. package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
  96. package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
  97. package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
  98. package/src/scenarios/append-ordering.test.ts +7 -5
  99. package/src/scenarios/approval-gate-events.test.ts +4 -3
  100. package/src/scenarios/approval-gate-flow.test.ts +4 -3
  101. package/src/scenarios/approval-payload.test.ts +5 -4
  102. package/src/scenarios/artifact-auth.test.ts +7 -6
  103. package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
  104. package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
  105. package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
  106. package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
  107. package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
  108. package/src/scenarios/audit-log-integrity.test.ts +8 -6
  109. package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
  110. package/src/scenarios/auth-mtls.test.ts +22 -20
  111. package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
  112. package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
  113. package/src/scenarios/auth-saml-profile.test.ts +14 -12
  114. package/src/scenarios/auth-scim-profile.test.ts +3 -2
  115. package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
  116. package/src/scenarios/auth-subject-link.test.ts +11 -10
  117. package/src/scenarios/auth.test.ts +5 -4
  118. package/src/scenarios/authorization-fail-closed.test.ts +3 -2
  119. package/src/scenarios/authorization-roles-shape.test.ts +9 -7
  120. package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
  121. package/src/scenarios/blob-presign-expiry.test.ts +12 -10
  122. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  123. package/src/scenarios/budget-enforcement.test.ts +15 -14
  124. package/src/scenarios/budget-policy-shape.test.ts +18 -19
  125. package/src/scenarios/bulk-cancel.test.ts +9 -8
  126. package/src/scenarios/byok-auth-modes.test.ts +13 -14
  127. package/src/scenarios/byok-roundtrip.test.ts +12 -10
  128. package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
  129. package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
  130. package/src/scenarios/callai-multimodal.test.ts +5 -3
  131. package/src/scenarios/cancellation.test.ts +6 -5
  132. package/src/scenarios/cap-breach.test.ts +15 -14
  133. package/src/scenarios/capability-arm-witness.test.ts +5 -3
  134. package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
  135. package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
  136. package/src/scenarios/certification-bundle-v2.test.ts +11 -10
  137. package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
  138. package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
  139. package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
  140. package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
  141. package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
  142. package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
  143. package/src/scenarios/channel-presence-shape.test.ts +11 -12
  144. package/src/scenarios/channel-ttl.test.ts +6 -5
  145. package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
  146. package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
  147. package/src/scenarios/commitment-fired.test.ts +6 -5
  148. package/src/scenarios/compensation-behavior.test.ts +24 -23
  149. package/src/scenarios/compensation-recovery.test.ts +28 -27
  150. package/src/scenarios/configurable-schema.test.ts +8 -6
  151. package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
  152. package/src/scenarios/conformance-execution-witness.test.ts +9 -8
  153. package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
  154. package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
  155. package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
  156. package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
  157. package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
  158. package/src/scenarios/connection-provider-resolution.test.ts +18 -16
  159. package/src/scenarios/connector-manifest-validity.test.ts +8 -7
  160. package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
  161. package/src/scenarios/context-summarization-replay.test.ts +14 -12
  162. package/src/scenarios/contract-provenance.test.ts +18 -18
  163. package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
  164. package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
  165. package/src/scenarios/conversationLifecycle.test.ts +2 -1
  166. package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
  167. package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
  168. package/src/scenarios/core-standard-profile.test.ts +8 -9
  169. package/src/scenarios/cost-attribution.test.ts +23 -21
  170. package/src/scenarios/credential-payload-redaction.test.ts +4 -3
  171. package/src/scenarios/credentials-capability-shape.test.ts +5 -4
  172. package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
  173. package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
  174. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
  175. package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
  176. package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
  177. package/src/scenarios/data-residency-admission.test.ts +15 -14
  178. package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
  179. package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
  180. package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
  181. package/src/scenarios/debugBundle.test.ts +25 -23
  182. package/src/scenarios/discovery-families-view.test.ts +5 -4
  183. package/src/scenarios/discovery.test.ts +30 -29
  184. package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
  185. package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
  186. package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
  187. package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
  188. package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
  189. package/src/scenarios/dispatchLoop.test.ts +3 -2
  190. package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
  191. package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
  192. package/src/scenarios/distillation-shape.test.ts +4 -4
  193. package/src/scenarios/distillation-stable-archive.test.ts +6 -6
  194. package/src/scenarios/distillation-token-budget.test.ts +5 -5
  195. package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
  196. package/src/scenarios/egress-audience-binding.test.ts +11 -10
  197. package/src/scenarios/egress-decision-content-free.test.ts +6 -5
  198. package/src/scenarios/egress-provenance-shape.test.ts +17 -18
  199. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
  200. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
  201. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
  202. package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
  203. package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
  204. package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
  205. package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
  206. package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
  207. package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
  208. package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
  209. package/src/scenarios/envelope-truncated.test.ts +19 -17
  210. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
  211. package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
  212. package/src/scenarios/errors.test.ts +20 -19
  213. package/src/scenarios/eventOrdering.test.ts +16 -14
  214. package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
  215. package/src/scenarios/experimental-tier-shape.test.ts +17 -15
  216. package/src/scenarios/export-bundle-portability.test.ts +17 -17
  217. package/src/scenarios/failure-path.test.ts +7 -6
  218. package/src/scenarios/feedback-capability-shape.test.ts +4 -3
  219. package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
  220. package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
  221. package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
  222. package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
  223. package/src/scenarios/feedback-record-and-list.test.ts +2 -1
  224. package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
  225. package/src/scenarios/fixtures-gating.test.ts +29 -28
  226. package/src/scenarios/fixtures-valid.test.ts +16 -15
  227. package/src/scenarios/form-content-instantiation.test.ts +15 -14
  228. package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
  229. package/src/scenarios/fs-path-traversal.test.ts +14 -12
  230. package/src/scenarios/goal-standing-continuation.test.ts +21 -21
  231. package/src/scenarios/grpc-transport.test.ts +9 -7
  232. package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
  233. package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
  234. package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
  235. package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
  236. package/src/scenarios/highConcurrency.test.ts +14 -13
  237. package/src/scenarios/host-callback-declaration.test.ts +8 -7
  238. package/src/scenarios/http-client-ssrf.test.ts +7 -5
  239. package/src/scenarios/i18n-negotiation.test.ts +14 -12
  240. package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
  241. package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
  242. package/src/scenarios/idempotency.test.ts +8 -7
  243. package/src/scenarios/idempotencyRetry.test.ts +13 -11
  244. package/src/scenarios/identity-owner-shape.test.ts +6 -5
  245. package/src/scenarios/identity-passthrough.test.ts +4 -3
  246. package/src/scenarios/interrupt-approval.test.ts +6 -5
  247. package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
  248. package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
  249. package/src/scenarios/interrupt-clarification.test.ts +4 -3
  250. package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
  251. package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
  252. package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
  253. package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
  254. package/src/scenarios/interruptRace.test.ts +12 -10
  255. package/src/scenarios/kv-atomic-increment.test.ts +11 -9
  256. package/src/scenarios/kv-cas.test.ts +14 -12
  257. package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
  258. package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
  259. package/src/scenarios/localized-content-delivery.test.ts +24 -26
  260. package/src/scenarios/maliciousManifest.test.ts +10 -8
  261. package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
  262. package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
  263. package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
  264. package/src/scenarios/mcp-discoverability.test.ts +9 -7
  265. package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
  266. package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
  267. package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
  268. package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
  269. package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
  270. package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
  271. package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
  272. package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
  273. package/src/scenarios/mcp-stateless-request.test.ts +11 -10
  274. package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
  275. package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
  276. package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
  277. package/src/scenarios/media-url-inline-cap.test.ts +21 -19
  278. package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
  279. package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
  280. package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
  281. package/src/scenarios/memory-attribution-shape.test.ts +4 -3
  282. package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
  283. package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
  284. package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
  285. package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
  286. package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
  287. package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
  288. package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
  289. package/src/scenarios/memory-degraded-projection.test.ts +10 -9
  290. package/src/scenarios/memory-injection-budget.test.ts +15 -14
  291. package/src/scenarios/metric-emission.test.ts +4 -3
  292. package/src/scenarios/model-capability-insufficient.test.ts +19 -17
  293. package/src/scenarios/model-capability-substituted.test.ts +20 -18
  294. package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
  295. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
  296. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
  297. package/src/scenarios/multi-node-ordering.test.ts +4 -3
  298. package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
  299. package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
  300. package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
  301. package/src/scenarios/multi-region-idempotency.test.ts +6 -5
  302. package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
  303. package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
  304. package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
  305. package/src/scenarios/oauth-capability-shape.test.ts +5 -4
  306. package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
  307. package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
  308. package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
  309. package/src/scenarios/orchestratorDispatch.test.ts +2 -1
  310. package/src/scenarios/orchestratorTermination.test.ts +2 -1
  311. package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
  312. package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
  313. package/src/scenarios/otel-emission-grpc.test.ts +3 -2
  314. package/src/scenarios/otel-emission.test.ts +6 -5
  315. package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
  316. package/src/scenarios/otel-trace-propagation.test.ts +2 -1
  317. package/src/scenarios/owner-subject-echo.test.ts +13 -12
  318. package/src/scenarios/owner-subject-shape.test.ts +11 -10
  319. package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
  320. package/src/scenarios/pack-registry-isolation.test.ts +4 -3
  321. package/src/scenarios/pack-registry-publish.test.ts +65 -63
  322. package/src/scenarios/pack-registry.test.ts +38 -36
  323. package/src/scenarios/pause-resume.test.ts +18 -16
  324. package/src/scenarios/policies.test.ts +20 -18
  325. package/src/scenarios/production-backpressure.test.ts +18 -16
  326. package/src/scenarios/production-retention-expiry.test.ts +8 -6
  327. package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
  328. package/src/scenarios/profileDerivation.test.ts +34 -33
  329. package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
  330. package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
  331. package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
  332. package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
  333. package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
  334. package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
  335. package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
  336. package/src/scenarios/prompt-pack-install.test.ts +14 -12
  337. package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
  338. package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
  339. package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
  340. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
  341. package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
  342. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
  343. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
  344. package/src/scenarios/prompt-template-shape.test.ts +30 -28
  345. package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
  346. package/src/scenarios/protocol-versions-array.test.ts +10 -9
  347. package/src/scenarios/provider-usage.test.ts +17 -15
  348. package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
  349. package/src/scenarios/purpose-propagation.test.ts +23 -21
  350. package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
  351. package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
  352. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
  353. package/src/scenarios/rate-limit-envelope.test.ts +6 -5
  354. package/src/scenarios/redaction.test.ts +13 -11
  355. package/src/scenarios/redactionAdversarial.test.ts +11 -9
  356. package/src/scenarios/registry-public.test.ts +12 -11
  357. package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
  358. package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
  359. package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
  360. package/src/scenarios/replay-fork.test.ts +20 -19
  361. package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
  362. package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
  363. package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
  364. package/src/scenarios/replay-retention-expiry.test.ts +11 -9
  365. package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
  366. package/src/scenarios/replayDeterminism.test.ts +13 -12
  367. package/src/scenarios/requirement-ledger.test.ts +15 -14
  368. package/src/scenarios/restart-during-run.test.ts +3 -2
  369. package/src/scenarios/route-coverage.test.ts +20 -19
  370. package/src/scenarios/run-diff.test.ts +22 -20
  371. package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
  372. package/src/scenarios/run-transport-economy.test.ts +13 -11
  373. package/src/scenarios/runner-ledger.test.ts +17 -16
  374. package/src/scenarios/runs-lifecycle.test.ts +7 -6
  375. package/src/scenarios/runtime-capabilities.test.ts +12 -10
  376. package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
  377. package/src/scenarios/runtime-requires-shape.test.ts +7 -6
  378. package/src/scenarios/safefetch-behavior.test.ts +22 -21
  379. package/src/scenarios/safefetch-live-audit.test.ts +14 -13
  380. package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
  381. package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
  382. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
  383. package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
  384. package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
  385. package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
  386. package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
  387. package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
  388. package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
  389. package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
  390. package/src/scenarios/self-hosted-runner.test.ts +26 -24
  391. package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
  392. package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
  393. package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
  394. package/src/scenarios/sql-injection-rejection.test.ts +8 -6
  395. package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
  396. package/src/scenarios/staleClaim.test.ts +5 -4
  397. package/src/scenarios/stream-modes-buffer.test.ts +8 -7
  398. package/src/scenarios/stream-modes-mixed.test.ts +10 -9
  399. package/src/scenarios/stream-modes.test.ts +12 -11
  400. package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
  401. package/src/scenarios/stream-text-fixture.test.ts +14 -13
  402. package/src/scenarios/streamReconnect.test.ts +13 -11
  403. package/src/scenarios/strict-behavior-gate.test.ts +9 -8
  404. package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
  405. package/src/scenarios/subrun-approval-gate.test.ts +3 -3
  406. package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
  407. package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
  408. package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
  409. package/src/scenarios/subworkflow.test.ts +10 -9
  410. package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
  411. package/src/scenarios/table-cursor-pagination.test.ts +8 -6
  412. package/src/scenarios/table-schema-enforcement.test.ts +7 -5
  413. package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
  414. package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
  415. package/src/scenarios/tool-catalog-projection.test.ts +11 -9
  416. package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
  417. package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
  418. package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
  419. package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
  420. package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
  421. package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
  422. package/src/scenarios/tool-hooks-shape.test.ts +3 -3
  423. package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
  424. package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
  425. package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
  426. package/src/scenarios/trigger-ingestion.test.ts +19 -17
  427. package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
  428. package/src/scenarios/v2-approver-enforced.test.ts +97 -0
  429. package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
  430. package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
  431. package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
  432. package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
  433. package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
  434. package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
  435. package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
  436. package/src/scenarios/v2-configurable-closed.test.ts +67 -0
  437. package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
  438. package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
  439. package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
  440. package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
  441. package/src/scenarios/v2-era-key.test.ts +86 -0
  442. package/src/scenarios/v2-error-registry.test.ts +89 -0
  443. package/src/scenarios/v2-event-type-closed.test.ts +97 -0
  444. package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
  445. package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
  446. package/src/scenarios/v2-header-scheme.test.ts +67 -0
  447. package/src/scenarios/v2-id-grammar.test.ts +77 -0
  448. package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
  449. package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
  450. package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
  451. package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
  452. package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
  453. package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
  454. package/src/scenarios/v2-min-client-version.test.ts +48 -0
  455. package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
  456. package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
  457. package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
  458. package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
  459. package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
  460. package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
  461. package/src/scenarios/v2-pack-isolation.test.ts +147 -0
  462. package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
  463. package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
  464. package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
  465. package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
  466. package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
  467. package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
  468. package/src/scenarios/v2-provider-conflict.test.ts +115 -0
  469. package/src/scenarios/v2-refresh-sla.test.ts +78 -0
  470. package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
  471. package/src/scenarios/v2-revocation-honored.test.ts +66 -0
  472. package/src/scenarios/v2-subject-link-record.test.ts +102 -0
  473. package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
  474. package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
  475. package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
  476. package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
  477. package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
  478. package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
  479. package/src/scenarios/verifier-gating.test.ts +8 -6
  480. package/src/scenarios/version-fold.test.ts +9 -8
  481. package/src/scenarios/version-negotiation.test.ts +12 -11
  482. package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
  483. package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
  484. package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
  485. package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
  486. package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
  487. package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
  488. package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
  489. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
  490. package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
  491. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
  492. package/src/scenarios/wasm-pack-load.test.ts +4 -3
  493. package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
  494. package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
  495. package/src/scenarios/webhook-negative.test.ts +11 -9
  496. package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
  497. package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
  498. package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
  499. package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
  500. package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
  501. package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
  502. package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
  503. package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
  504. package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
  505. package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
  506. package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
  507. package/src/scenarios/workflow-variable-format.test.ts +24 -24
  508. package/src/scenarios/workload-identity-behavior.test.ts +15 -13
  509. package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
  510. package/src/scenarios/workspace-behavior.test.ts +19 -18
  511. package/src/scenarios/workspace-capability-shape.test.ts +3 -2
  512. package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
  513. package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
  514. package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
  515. package/src/setup.ts +44 -6
  516. package/vitest.config.ts +5 -1
  517. package/api/.redocly.lint-ignore.yaml +0 -22
  518. package/api/asyncapi.yaml +0 -834
  519. package/api/grpc/openwop.proto +0 -251
  520. package/api/openapi.yaml +0 -2693
  521. package/api/redocly.yaml +0 -23
  522. package/schemas/README.md +0 -144
  523. package/schemas/a2a-task-state.schema.json +0 -78
  524. package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
  525. package/schemas/agent-deployment-transition.schema.json +0 -49
  526. package/schemas/agent-deployment.schema.json +0 -54
  527. package/schemas/agent-eval-suite.schema.json +0 -140
  528. package/schemas/agent-inventory-response.schema.json +0 -115
  529. package/schemas/agent-manifest.schema.json +0 -156
  530. package/schemas/agent-org-chart.schema.json +0 -82
  531. package/schemas/agent-ref.schema.json +0 -63
  532. package/schemas/agent-roster-entry.schema.json +0 -81
  533. package/schemas/agent-roster-response.schema.json +0 -21
  534. package/schemas/ai-envelope.schema.json +0 -134
  535. package/schemas/annotation-create.schema.json +0 -37
  536. package/schemas/annotation.schema.json +0 -56
  537. package/schemas/artifact-type-pack-manifest.schema.json +0 -244
  538. package/schemas/audit-verify-result.schema.json +0 -90
  539. package/schemas/budget-policy.schema.json +0 -18
  540. package/schemas/capabilities.schema.json +0 -4160
  541. package/schemas/certification-bundle-v2.schema.json +0 -118
  542. package/schemas/channel-presence-payload.schema.json +0 -41
  543. package/schemas/channel-written-payload.schema.json +0 -55
  544. package/schemas/chat-card-pack-manifest.schema.json +0 -253
  545. package/schemas/compact-tool-descriptor.schema.json +0 -51
  546. package/schemas/compensation-policy.schema.json +0 -64
  547. package/schemas/conformance-certification-bundle.schema.json +0 -86
  548. package/schemas/connection-pack-manifest.schema.json +0 -353
  549. package/schemas/conversation-event.schema.json +0 -168
  550. package/schemas/conversation-turn.schema.json +0 -117
  551. package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
  552. package/schemas/credential-provenance.schema.json +0 -18
  553. package/schemas/credential-reference.schema.json +0 -21
  554. package/schemas/debug-bundle.schema.json +0 -196
  555. package/schemas/dispatch-config.schema.json +0 -112
  556. package/schemas/envelopes/clarification.request.schema.json +0 -52
  557. package/schemas/envelopes/error.schema.json +0 -30
  558. package/schemas/envelopes/media.audio.schema.json +0 -38
  559. package/schemas/envelopes/media.file.schema.json +0 -37
  560. package/schemas/envelopes/media.image.schema.json +0 -33
  561. package/schemas/envelopes/schema.request.schema.json +0 -26
  562. package/schemas/envelopes/schema.response.schema.json +0 -22
  563. package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
  564. package/schemas/error-envelope.schema.json +0 -25
  565. package/schemas/eval-summary.schema.json +0 -92
  566. package/schemas/export-bundle.schema.json +0 -66
  567. package/schemas/form-content-pack-manifest.schema.json +0 -243
  568. package/schemas/frontend-plugin-manifest.schema.json +0 -109
  569. package/schemas/goal.schema.json +0 -104
  570. package/schemas/heartbeat-evaluated.schema.json +0 -14
  571. package/schemas/heartbeat-state-changed.schema.json +0 -14
  572. package/schemas/localized-content-language-settings.schema.json +0 -26
  573. package/schemas/localized-content-page-response.schema.json +0 -60
  574. package/schemas/localized-content-page.schema.json +0 -62
  575. package/schemas/localized-content-section.schema.json +0 -51
  576. package/schemas/memory-entry.schema.json +0 -36
  577. package/schemas/memory-list-options.schema.json +0 -37
  578. package/schemas/node-pack-manifest.schema.json +0 -654
  579. package/schemas/orchestrator-decision.schema.json +0 -90
  580. package/schemas/org-chart-responsibility-view.schema.json +0 -26
  581. package/schemas/pack-lockfile.schema.json +0 -108
  582. package/schemas/prompt-kind.schema.json +0 -8
  583. package/schemas/prompt-pack-manifest.schema.json +0 -117
  584. package/schemas/prompt-ref.schema.json +0 -40
  585. package/schemas/prompt-template.schema.json +0 -149
  586. package/schemas/proposal.schema.json +0 -84
  587. package/schemas/registry-version-manifest.schema.json +0 -208
  588. package/schemas/residency.schema.json +0 -16
  589. package/schemas/run-ancestry-response.schema.json +0 -54
  590. package/schemas/run-diff-response.schema.json +0 -64
  591. package/schemas/run-event-payloads.schema.json +0 -4452
  592. package/schemas/run-event.schema.json +0 -211
  593. package/schemas/run-options.schema.json +0 -80
  594. package/schemas/run-orchestrator-decided-event.schema.json +0 -20
  595. package/schemas/run-snapshot.schema.json +0 -148
  596. package/schemas/security-advisory.schema.json +0 -109
  597. package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
  598. package/schemas/self-hosted-runner-registration.schema.json +0 -53
  599. package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
  600. package/schemas/subject.schema.json +0 -56
  601. package/schemas/suspend-request.schema.json +0 -207
  602. package/schemas/tool-descriptor.schema.json +0 -63
  603. package/schemas/trigger-event.schema.json +0 -222
  604. package/schemas/trigger-subscription-registration.schema.json +0 -67
  605. package/schemas/trigger-subscription.schema.json +0 -26
  606. package/schemas/ui-plugin-message.schema.json +0 -90
  607. package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
  608. package/schemas/workflow-definition.schema.json +0 -850
  609. package/schemas/workload-identity.schema.json +0 -79
  610. package/schemas/workspace-file-create.schema.json +0 -20
  611. package/schemas/workspace-file.schema.json +0 -39
@@ -50,6 +50,8 @@ import {
50
50
  type WorkflowChain,
51
51
  type DeferredExpansionContext,
52
52
  } from '../lib/workflow-chain-expansion.js';
53
+ import { req } from '../lib/requirement-ids.js';
54
+ import { softSkip } from '../lib/soft-skip.js';
53
55
 
54
56
  const CAPS = join(SCHEMAS_DIR, 'capabilities.schema.json');
55
57
  const MANIFEST = join(SCHEMAS_DIR, 'workflow-chain-pack-manifest.schema.json');
@@ -59,10 +61,6 @@ const MANIFEST = join(SCHEMAS_DIR, 'workflow-chain-pack-manifest.schema.json');
59
61
  // repo-layout only: `null` in the published layout and skipped, never thrown.
60
62
  const CHAIN_DOC: string | null = V1_DIR === null ? null : join(V1_DIR, 'workflow-chain-packs.md');
61
63
 
62
- /** Spec-cited assertion message. Unlike `driver.describe`, this does NOT load
63
- * env, so it is safe in always-on server-free legs (no OPENWOP_BASE_URL). */
64
- const cite = (section: string, requirement: string): string => `${section} — ${requirement}`;
65
-
66
64
  const resolvable = () => true;
67
65
  const HOST_FULL = { promptVariableSource: true, secretsSupported: true };
68
66
 
@@ -112,13 +110,13 @@ describe('workflow-chain-deferred: non-sensitive deferral (server-free, RFC 0124
112
110
 
113
111
  expect(
114
112
  hasResidualToken({ nodes: out.nodes, edges: out.edges }),
115
- cite('workflow-chain-packs.md §Deferred-parameter expansion', 'the persisted fragment MUST contain zero {{params.*}} tokens (R3 portability)'),
113
+ req('openwop.it.workflow-chain-deferred-parameters.materializes-variables-with-defaultvalue-type-and-leaves-zero-params-tokens-r3', 'workflow-chain-packs.md §Deferred-parameter expansion', 'the persisted fragment MUST contain zero {{params.*}} tokens (R3 portability)'),
116
114
  ).toBe(false);
117
115
 
118
116
  const topicVar = out.variables.find((v) => v.name === 'topic');
119
- expect(topicVar, 'topic MUST be materialized as a top-level variable').toBeDefined();
120
- expect(topicVar!.defaultValue, 'author input becomes defaultValue').toBe('sales');
121
- expect(topicVar!.type, 'type copied from the parameter schema').toBe('string');
117
+ expect(topicVar, req('openwop.it.workflow-chain-deferred-parameters.materializes-variables-with-defaultvalue-type-and-leaves-zero-params-tokens-r3', 'workflow-chain-packs.md', 'topic MUST be materialized as a top-level variable')).toBeDefined();
118
+ expect(topicVar!.defaultValue, req('openwop.it.workflow-chain-deferred-parameters.materializes-variables-with-defaultvalue-type-and-leaves-zero-params-tokens-r3', 'workflow-chain-packs.md', 'author input becomes defaultValue')).toBe('sales');
119
+ expect(topicVar!.type, req('openwop.it.workflow-chain-deferred-parameters.materializes-variables-with-defaultvalue-type-and-leaves-zero-params-tokens-r3', 'workflow-chain-packs.md', 'type copied from the parameter schema')).toBe('string');
122
120
 
123
121
  // prompt token → {{varName}} + source:"variable"
124
122
  expect((out.nodes[0].config as { systemPrompt: string }).systemPrompt).toBe('Hello {{topic}}');
@@ -133,7 +131,7 @@ describe('workflow-chain-deferred: non-sensitive deferral (server-free, RFC 0124
133
131
  const out = expandChainDeferred(c, deferCtx({ count: 5 }, c.parameters as never));
134
132
  expect(
135
133
  out.nodes[0].inputs!.limit,
136
- cite('workflow-chain-packs.md §Deferred-parameter expansion', 'a whole-value {{params.x}} input rewrites to a variable-sourced PortValue, not a stringified token'),
134
+ req('openwop.it.workflow-chain-deferred-parameters.a-whole-value-input-token-becomes-a-variable-sourced-portvalue-wcp2-raw-typed', 'workflow-chain-packs.md §Deferred-parameter expansion', 'a whole-value {{params.x}} input rewrites to a variable-sourced PortValue, not a stringified token'),
137
135
  ).toEqual({ source: 'variable', variable: 'count' });
138
136
  });
139
137
 
@@ -145,7 +143,7 @@ describe('workflow-chain-deferred: non-sensitive deferral (server-free, RFC 0124
145
143
  const out = expandChainDeferred(c, deferCtx({ topic: 't' }, c.parameters as never));
146
144
  expect(
147
145
  out.configurableSchema.properties.topic,
148
- cite('workflow-chain-packs.md §Override key + variable naming', 'the bare parameter name is the normative override key'),
146
+ req('openwop.it.workflow-chain-deferred-parameters.the-bare-param-name-is-the-override-key-in-the-auto-generated-configurableschema', 'workflow-chain-packs.md §Override key + variable naming', 'the bare parameter name is the normative override key'),
149
147
  ).toEqual({ type: 'string' });
150
148
  });
151
149
  });
@@ -162,14 +160,14 @@ describe('workflow-chain-deferred: §Security sensitive-parameter MUSTs (server-
162
160
 
163
161
  expect(
164
162
  out.promptVariables.find((p) => p.name === 'apiKey')?.source,
165
- cite('workflow-chain-packs.md §Security', 'a sensitive prompt-body param MUST bind source:"secret" (not source:"variable")'),
163
+ req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-in-a-prompt-body-materializes-as-source-secret-no-plaintext-de', 'workflow-chain-packs.md §Security', 'a sensitive prompt-body param MUST bind source:"secret" (not source:"variable")'),
166
164
  ).toBe('secret');
167
165
  // The plaintext secret MUST appear NOWHERE — not as a variable defaultValue, not in the fragment.
168
166
  expect(
169
167
  JSON.stringify(out).includes('sk-PLAINTEXT-SECRET'),
170
- cite('workflow-chain-packs.md §Security', 'the sensitive value MUST NOT be materialized into variables[] or the persisted fragment (never bagged, SR-1)'),
168
+ req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-in-a-prompt-body-materializes-as-source-secret-no-plaintext-de', 'workflow-chain-packs.md §Security', 'the sensitive value MUST NOT be materialized into variables[] or the persisted fragment (never bagged, SR-1)'),
171
169
  ).toBe(false);
172
- expect(out.variables.find((v) => v.name === 'apiKey'), 'sensitive param is NOT a plaintext top-level variable').toBeUndefined();
170
+ expect(out.variables.find((v) => v.name === 'apiKey'), req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-in-a-prompt-body-materializes-as-source-secret-no-plaintext-de', 'workflow-chain-packs.md', 'sensitive param is NOT a plaintext top-level variable')).toBeUndefined();
173
171
  });
174
172
 
175
173
  it('a sensitive param in a whole-value node.input FAILS CLOSED (sensitive_param_not_deferrable, 422)', () => {
@@ -183,10 +181,10 @@ describe('workflow-chain-deferred: §Security sensitive-parameter MUSTs (server-
183
181
  } catch (e) {
184
182
  err = e;
185
183
  }
186
- expect(err, 'a sensitive whole-value input MUST throw, not defer').toBeInstanceOf(SensitiveParamNotDeferrableError);
184
+ expect(err, req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-in-a-whole-value-node-input-fails-closed-sensitive-param-not-d', 'workflow-chain-packs.md', 'a sensitive whole-value input MUST throw, not defer')).toBeInstanceOf(SensitiveParamNotDeferrableError);
187
185
  expect(
188
186
  (err as SensitiveParamNotDeferrableError).code,
189
- cite('workflow-chain-packs.md §Security', 'a sensitive param outside a prompt body MUST fail closed with sensitive_param_not_deferrable'),
187
+ req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-in-a-whole-value-node-input-fails-closed-sensitive-param-not-d', 'workflow-chain-packs.md §Security', 'a sensitive param outside a prompt body MUST fail closed with sensitive_param_not_deferrable'),
190
188
  ).toBe('sensitive_param_not_deferrable');
191
189
  expect((err as SensitiveParamNotDeferrableError).httpStatus).toBe(422);
192
190
  });
@@ -204,7 +202,7 @@ describe('workflow-chain-deferred: §Security sensitive-parameter MUSTs (server-
204
202
  }
205
203
  expect(
206
204
  err,
207
- cite('workflow-chain-packs.md §Security', 'a host lacking capabilities.secrets MUST NOT plaintext-defer a sensitive param — fail closed'),
205
+ req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-prompt-body-param-on-a-host-without-secrets-support-fails-closed-422', 'workflow-chain-packs.md §Security', 'a host lacking capabilities.secrets MUST NOT plaintext-defer a sensitive param — fail closed'),
208
206
  ).toBeInstanceOf(SensitiveParamNotDeferrableError);
209
207
  });
210
208
 
@@ -219,7 +217,7 @@ describe('workflow-chain-deferred: §Security sensitive-parameter MUSTs (server-
219
217
  );
220
218
  // Fallback resolves the token at expansion time — no {{topic}} slot, value inlined, still zero {{params.*}}.
221
219
  expect((out.nodes[0].config as { systemPrompt: string }).systemPrompt).toBe('Hi sales');
222
- expect(hasResidualToken({ nodes: out.nodes }), 'no residual {{params.*}} even on the fallback path').toBe(false);
220
+ expect(hasResidualToken({ nodes: out.nodes }), req('openwop.it.workflow-chain-deferred-parameters.negative-capability-no-prompts-variable-source-prompt-token-falls-back-to-expans', 'workflow-chain-packs.md', 'no residual {{params.*}} even on the fallback path')).toBe(false);
223
221
  });
224
222
  });
225
223
 
@@ -227,29 +225,29 @@ describe('workflow-chain-deferred: schema + spec surface (always-on, server-free
227
225
  it('capabilities.schema.json §workflowChainPacks.deferredParameters requires supported:boolean', () => {
228
226
  const raw = readFileSync(CAPS, 'utf8');
229
227
  // The deferredParameters block MUST parse as part of the capabilities schema.
230
- expect(() => JSON.parse(raw), 'capabilities.schema.json MUST be valid JSON').not.toThrow();
231
- expect(raw.includes('"deferredParameters"'), 'the deferredParameters capability block MUST exist').toBe(true);
228
+ expect(() => JSON.parse(raw), req('openwop.it.workflow-chain-deferred-parameters.capabilities-schema-json-workflowchainpacks-deferredparameters-requires-supporte', 'workflow-chain-packs.md', 'capabilities.schema.json MUST be valid JSON')).not.toThrow();
229
+ expect(raw.includes('"deferredParameters"'), req('openwop.it.workflow-chain-deferred-parameters.capabilities-schema-json-workflowchainpacks-deferredparameters-requires-supporte', 'workflow-chain-packs.md', 'the deferredParameters capability block MUST exist')).toBe(true);
232
230
  expect(
233
231
  raw.includes('sensitive_param_not_deferrable'),
234
- cite('capabilities.schema.json §deferredParameters', 'the capability description MUST reference the fail-closed sensitive rule'),
232
+ req('openwop.it.workflow-chain-deferred-parameters.capabilities-schema-json-workflowchainpacks-deferredparameters-requires-supporte', 'capabilities.schema.json §deferredParameters', 'the capability description MUST reference the fail-closed sensitive rule'),
235
233
  ).toBe(true);
236
234
  });
237
235
 
238
236
  it('workflow-chain-pack-manifest.schema.json documents x-openwop-sensitive with the source:"secret" MUST', () => {
239
237
  const raw = readFileSync(MANIFEST, 'utf8');
240
- expect(raw.includes('x-openwop-sensitive'), 'the manifest schema MUST recognize x-openwop-sensitive').toBe(true);
238
+ expect(raw.includes('x-openwop-sensitive'), req('openwop.it.workflow-chain-deferred-parameters.workflow-chain-pack-manifest-schema-json-documents-x-openwop-sensitive-with-the', 'workflow-chain-packs.md', 'the manifest schema MUST recognize x-openwop-sensitive')).toBe(true);
241
239
  expect(
242
240
  raw.includes('source:"secret"') || raw.includes('source:\\"secret\\"'),
243
- cite('workflow-chain-pack-manifest.schema.json', 'the x-openwop-sensitive description MUST reflect the amended source:"secret" MUST, not the stale plaintext-variable wording'),
241
+ req('openwop.it.workflow-chain-deferred-parameters.workflow-chain-pack-manifest-schema-json-documents-x-openwop-sensitive-with-the', 'workflow-chain-pack-manifest.schema.json', 'the x-openwop-sensitive description MUST reflect the amended source:"secret" MUST, not the stale plaintext-variable wording'),
244
242
  ).toBe(true);
245
243
  });
246
244
 
247
245
  it.skipIf(CHAIN_DOC === null)('the spec pins the error code + the per-run credentialRef (not plaintext) supply shape', () => {
248
246
  const spec = readFileSync(CHAIN_DOC as string, 'utf8');
249
- expect(spec.includes('sensitive_param_not_deferrable'), 'error code MUST be documented').toBe(true);
247
+ expect(spec.includes('sensitive_param_not_deferrable'), req('openwop.it.workflow-chain-deferred-parameters.the-spec-pins-the-error-code-the-per-run-credentialref-not-plaintext-supply-shap', 'workflow-chain-packs.md', 'error code MUST be documented')).toBe(true);
250
248
  expect(
251
249
  spec.includes('credentialRef'),
252
- cite('workflow-chain-packs.md §Security', 'per-run supply of a sensitive param MUST be a credentialRef, not plaintext'),
250
+ req('openwop.it.workflow-chain-deferred-parameters.the-spec-pins-the-error-code-the-per-run-credentialref-not-plaintext-supply-shap', 'workflow-chain-packs.md §Security', 'per-run supply of a sensitive param MUST be a credentialRef, not plaintext'),
253
251
  ).toBe(true);
254
252
  });
255
253
  });
@@ -265,20 +263,20 @@ describe('workflow-chain-deferred: host behavior (capability-gated, RFC 0124)',
265
263
  override: { topic: 'run-topic' },
266
264
  fork: true,
267
265
  });
268
- if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
266
+ if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
269
267
 
270
268
  const body = res.json as { resolved?: string; forkResolved?: string; contentTrust?: string } | undefined;
271
269
  expect(
272
270
  body?.resolved,
273
- cite('workflow-chain-packs.md §Deferred-parameter expansion', 'a bare-param configurable override rebinds the resolved value'),
271
+ req('openwop.it.workflow-chain-deferred-parameters.a-deferred-round-trip-bare-param-configurable-override-changes-the-value-fork-re', 'workflow-chain-packs.md §Deferred-parameter expansion', 'a bare-param configurable override rebinds the resolved value'),
274
272
  ).toBe('run-topic');
275
273
  expect(
276
274
  body?.forkResolved,
277
- cite('replay.md §Determinism', ':fork replays the same bound value (RunSnapshot.variables byte-equivalence, R4)'),
275
+ req('openwop.it.workflow-chain-deferred-parameters.a-deferred-round-trip-bare-param-configurable-override-changes-the-value-fork-re', 'replay.md §Determinism', ':fork replays the same bound value (RunSnapshot.variables byte-equivalence, R4)'),
278
276
  ).toBe('run-topic');
279
277
  expect(
280
278
  body?.contentTrust,
281
- cite('workflow-chain-packs.md §Deferred-parameter expansion step 4', 'a deferred-variable prompt binding composes contentTrust:"untrusted" (R1)'),
279
+ req('openwop.it.workflow-chain-deferred-parameters.a-deferred-round-trip-bare-param-configurable-override-changes-the-value-fork-re', 'workflow-chain-packs.md §Deferred-parameter expansion step 4', 'a deferred-variable prompt binding composes contentTrust:"untrusted" (R1)'),
282
280
  ).toBe('untrusted');
283
281
  });
284
282
 
@@ -291,12 +289,12 @@ describe('workflow-chain-deferred: host behavior (capability-gated, RFC 0124)',
291
289
  sensitiveParam: 'apiKey',
292
290
  credentialRef: 'cred-123',
293
291
  });
294
- if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
292
+ if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
295
293
 
296
294
  const body = res.json as { composed?: string } | undefined;
297
295
  expect(
298
296
  body?.composed?.includes('[REDACTED'),
299
- cite('workflow-chain-packs.md §Security', 'a source:"secret" sensitive var MUST redact to [REDACTED:<credentialRef>] in prompt.composed'),
297
+ req('openwop.it.workflow-chain-deferred-parameters.a-sensitive-param-composes-as-redacted-credentialref-and-the-plaintext-appears-n', 'workflow-chain-packs.md §Security', 'a source:"secret" sensitive var MUST redact to [REDACTED:<credentialRef>] in prompt.composed'),
300
298
  ).toBe(true);
301
299
  });
302
300
  });
@@ -34,6 +34,7 @@
34
34
 
35
35
  import { describe, it, expect } from 'vitest';
36
36
  import { expandChain, type WorkflowChain } from '../lib/workflow-chain-expansion.js';
37
+ import { req } from '../lib/requirement-ids.js';
37
38
 
38
39
  /** Index helper that narrows away the `T | undefined` from `noUncheckedIndexedAccess`
39
40
  * with an actionable error message — replaces `arr[i]!` non-null assertions so a
@@ -95,7 +96,7 @@ describe('category: workflow-chain expansion — placeholder substitution', () =
95
96
  const config = at(fragment.nodes, 0, 'fragment.nodes').config as { systemPrompt: string };
96
97
  expect(
97
98
  config.systemPrompt,
98
- 'Per workflow-chain-packs.md §"Parameter substitution": placeholders MUST be substituted literally at expansion time.',
99
+ req('openwop.it.workflow-chain-expansion.substitutes-params-x-placeholders-literally-in-config-strings', 'workflow-chain-packs.md', 'Per workflow-chain-packs.md §"Parameter substitution": placeholders MUST be substituted literally at expansion time.'),
99
100
  ).toBe('Write a PRD for: AI-powered toaster\nAudience: restaurant chains');
100
101
  });
101
102
 
@@ -130,11 +131,11 @@ describe('category: workflow-chain expansion — placeholder substitution', () =
130
131
  };
131
132
  expect(
132
133
  config.outer.middle.message,
133
- 'Recursive substitution MUST walk into nested objects (per spec §Parameter substitution: "Substitution MUST recurse into nested string values within `config` and `inputs`").',
134
+ req('openwop.it.workflow-chain-expansion.recurses-into-nested-object-structures-in-config', 'workflow-chain-packs.md', 'Recursive substitution MUST walk into nested objects (per spec §Parameter substitution: "Substitution MUST recurse into nested string values within `config` and `inputs`").'),
134
135
  ).toBe('Hello world');
135
136
  expect(
136
137
  config.outer.middle.tags,
137
- 'Recursive substitution MUST also walk into array elements when those elements are strings.',
138
+ req('openwop.it.workflow-chain-expansion.recurses-into-nested-object-structures-in-config', 'workflow-chain-packs.md', 'Recursive substitution MUST also walk into array elements when those elements are strings.'),
138
139
  ).toEqual(['static', 'world-tag']);
139
140
  });
140
141
 
@@ -156,7 +157,7 @@ describe('category: workflow-chain expansion — placeholder substitution', () =
156
157
  { expansionId: 'x', params: {}, isTypeIdResolvable: RESOLVE_ALL },
157
158
  );
158
159
  const config = at(fragment.nodes, 0, 'fragment.nodes').config as { literal: string; empty: string };
159
- expect(config.literal).toBe('no placeholders here');
160
+ expect(config.literal, req('openwop.it.workflow-chain-expansion.leaves-non-placeholder-strings-untouched', 'workflow-chain-packs.md', 'leaves non-placeholder strings untouched')).toBe('no placeholders here');
160
161
  expect(config.empty).toBe('');
161
162
  });
162
163
 
@@ -178,7 +179,7 @@ describe('category: workflow-chain expansion — placeholder substitution', () =
178
179
  { expansionId: 'x', params: { who: 'Ada' }, isTypeIdResolvable: RESOLVE_ALL },
179
180
  );
180
181
  const config = at(fragment.nodes, 0, 'fragment.nodes').config as { a: string; b: string; joined: string };
181
- expect(config.a).toBe('Ada');
182
+ expect(config.a, req('openwop.it.workflow-chain-expansion.substitutes-the-same-placeholder-name-in-multiple-positions', 'workflow-chain-packs.md', 'substitutes the same placeholder name in multiple positions')).toBe('Ada');
182
183
  expect(config.b).toBe('Ada');
183
184
  expect(config.joined).toBe('hi Ada, hi again Ada');
184
185
  });
@@ -231,7 +232,7 @@ describe('category: workflow-chain expansion — whole-value typed resolution',
231
232
  };
232
233
  expect(
233
234
  config.retryPolicy,
234
- 'Per workflow-chain-packs.md §"Parameter substitution": a value that is EXACTLY one `{{params.x}}` token MUST resolve to the raw typed value — an object param MUST NOT be stringified to "[object Object]".',
235
+ req('openwop.it.workflow-chain-expansion.resolves-a-whole-value-params-x-token-to-the-raw-typed-value-object-array-number', 'workflow-chain-packs.md', 'Per workflow-chain-packs.md §"Parameter substitution": a value that is EXACTLY one `{{params.x}}` token MUST resolve to the raw typed value — an object param MUST NOT be stringified to "[object Object]".'),
235
236
  ).toEqual({ attempts: 3, backoff: 'exponential' });
236
237
  expect(config.allowlist).toEqual(['a', 'b']);
237
238
  expect(config.maxTokens).toBe(4096);
@@ -255,7 +256,7 @@ describe('category: workflow-chain expansion — whole-value typed resolution',
255
256
  const config = at(fragment.nodes, 0, 'fragment.nodes').config as { label: string };
256
257
  expect(
257
258
  config.label,
258
- 'A token embedded in surrounding text MUST do literal string substitution (the numeric param coerces to its string form).',
259
+ req('openwop.it.workflow-chain-expansion.does-literal-string-coercion-for-an-embedded-token-in-surrounding-text', 'workflow-chain-packs.md', 'A token embedded in surrounding text MUST do literal string substitution (the numeric param coerces to its string form).'),
259
260
  ).toBe('items: 42');
260
261
  });
261
262
  });
@@ -290,7 +291,7 @@ describe('category: workflow-chain expansion — inputs preservation', () => {
290
291
  };
291
292
  expect(
292
293
  inputs.prompt,
293
- 'Per workflow-chain-packs.md §"Parameter substitution": expansion MUST preserve a present `node.inputs` (PortValue references) verbatim — only `{{params.*}}` tokens inside its string leaves are substituted.',
294
+ req('openwop.it.workflow-chain-expansion.preserves-a-present-node-inputs-portvalue-references-through-expansion', 'workflow-chain-packs.md', 'Per workflow-chain-packs.md §"Parameter substitution": expansion MUST preserve a present `node.inputs` (PortValue references) verbatim — only `{{params.*}}` tokens inside its string leaves are substituted.'),
294
295
  ).toEqual({ sourceNodeId: 'upstream', sourcePort: 'text' });
295
296
  expect(inputs.seed).toBe('xyz');
296
297
  });
@@ -310,7 +311,7 @@ describe('category: workflow-chain expansion — node id collision avoidance', (
310
311
  });
311
312
  expect(
312
313
  at(first.nodes, 0, 'first.nodes').id,
313
- 'Per spec §"Expansion semantics" step 6: each expansion MUST use a unique `expansionId` prefix so multi-expansion DAGs do not collide.',
314
+ req('openwop.it.workflow-chain-expansion.same-chain-expanded-twice-in-one-parent-workflow-produces-non-colliding-node-ids', 'workflow-chain-packs.md', 'Per spec §"Expansion semantics" step 6: each expansion MUST use a unique `expansionId` prefix so multi-expansion DAGs do not collide.'),
314
315
  ).not.toBe(at(second.nodes, 0, 'second.nodes').id);
315
316
  expect(at(first.nodes, 0, 'first.nodes').id).toBe('vendor_acme_generatePRD_a8f3_prd-call');
316
317
  expect(at(second.nodes, 0, 'second.nodes').id).toBe('vendor_acme_generatePRD_b9e4_prd-call');
@@ -324,7 +325,7 @@ describe('category: workflow-chain expansion — node id collision avoidance', (
324
325
  });
325
326
  expect(
326
327
  at(fragment.nodes, 0, 'fragment.nodes').id,
327
- 'chainId `vendor.acme.generatePRD` MUST be slugged (dots → underscores) so the resulting id is safe to use in storage backends that reserve `.` for hierarchical keys.',
328
+ req('openwop.it.workflow-chain-expansion.rewritten-ids-replace-dots-in-chainid-with-underscores-for-storage-key-safety', 'workflow-chain-packs.md', 'chainId `vendor.acme.generatePRD` MUST be slugged (dots → underscores) so the resulting id is safe to use in storage backends that reserve `.` for hierarchical keys.'),
328
329
  ).toMatch(/^vendor_acme_generatePRD_/);
329
330
  expect(at(fragment.nodes, 0, 'fragment.nodes').id).not.toMatch(/\./);
330
331
  });
@@ -337,7 +338,7 @@ describe('category: workflow-chain expansion — node id collision avoidance', (
337
338
  });
338
339
  expect(
339
340
  fragment.idMap.get('prd-call'),
340
- 'The expansion contract MUST surface the original-id → rewritten-id map so the caller can route adjacent parent-workflow edges to the right expanded node.',
341
+ req('openwop.it.workflow-chain-expansion.exposes-idmap-so-the-caller-can-wire-parent-workflow-edges-into-the-expansion', 'workflow-chain-packs.md', 'The expansion contract MUST surface the original-id → rewritten-id map so the caller can route adjacent parent-workflow edges to the right expanded node.'),
341
342
  ).toBe('vendor_acme_generatePRD_a8f3_prd-call');
342
343
  });
343
344
  });
@@ -367,7 +368,7 @@ describe('category: workflow-chain expansion — edge rewriting', () => {
367
368
  expect(fragment.edges).toHaveLength(1);
368
369
  expect(
369
370
  at(fragment.edges, 0, 'fragment.edges').from,
370
- 'Edge `from` ids that match fragment node ids MUST be rewritten with the same prefix as the nodes themselves.',
371
+ req('openwop.it.workflow-chain-expansion.rewrites-from-and-to-ids-that-reference-fragment-nodes', 'workflow-chain-packs.md', 'Edge `from` ids that match fragment node ids MUST be rewritten with the same prefix as the nodes themselves.'),
371
372
  ).toBe('vendor_acme_twoStep_e1_first');
372
373
  expect(at(fragment.edges, 0, 'fragment.edges').to).toBe('vendor_acme_twoStep_e1_second');
373
374
  });
@@ -387,7 +388,7 @@ describe('category: workflow-chain expansion — edge rewriting', () => {
387
388
  });
388
389
  expect(
389
390
  at(fragment.edges, 0, 'fragment.edges').from,
390
- 'Port-name suffix (after the `.`) MUST be preserved verbatim during id rewriting.',
391
+ req('openwop.it.workflow-chain-expansion.preserves-port-name-suffix-nodeid-portname-when-rewriting-edge-refs', 'workflow-chain-packs.md', 'Port-name suffix (after the `.`) MUST be preserved verbatim during id rewriting.'),
391
392
  ).toBe('vendor_acme_twoStep_e2_first.out');
392
393
  expect(at(fragment.edges, 0, 'fragment.edges').to).toBe('vendor_acme_twoStep_e2_second.in');
393
394
  });
@@ -413,7 +414,7 @@ describe('category: workflow-chain expansion — edge rewriting', () => {
413
414
  });
414
415
  expect(
415
416
  at(fragment.edges, 0, 'fragment.edges').from,
416
- 'Edge refs to nodes OUTSIDE the fragment MUST pass through unchanged so the parent host can wire adjacent edges post-splice.',
417
+ req('openwop.it.workflow-chain-expansion.leaves-edge-refs-alone-when-they-don-t-match-a-fragment-node-id', 'workflow-chain-packs.md', 'Edge refs to nodes OUTSIDE the fragment MUST pass through unchanged so the parent host can wire adjacent edges post-splice.'),
417
418
  ).toBe('parent-upstream');
418
419
  expect(at(fragment.edges, 0, 'fragment.edges').to).toBe('vendor_acme_twoStep_e3_first');
419
420
  expect(at(fragment.edges, 1, 'fragment.edges').from).toBe('vendor_acme_twoStep_e3_second');
@@ -449,11 +450,11 @@ describe('category: workflow-chain expansion — edge rewriting', () => {
449
450
  expect(edge.to).toBe('vendor_acme_twoStep_e4_second');
450
451
  expect(
451
452
  edge.condition,
452
- 'Per RFC 0013 amendment (2026-07-03): a present `FragmentEdge.condition` MUST be carried onto the expanded WorkflowEdge (not dropped at expansion).',
453
+ req('openwop.it.workflow-chain-expansion.preserves-edge-condition-and-triggerrule-onto-the-expanded-workflowedge-rfc-0013', 'RFC 0013', 'Per RFC 0013 amendment (2026-07-03): a present `FragmentEdge.condition` MUST be carried onto the expanded WorkflowEdge (not dropped at expansion).'),
453
454
  ).toEqual({ type: 'equals', left: 'status', right: 'ok' });
454
455
  expect(
455
456
  edge.triggerRule,
456
- 'Per RFC 0125 / workflow-chain-packs.md §"Expansion semantics": expansion MUST preserve `FragmentEdge.triggerRule` onto the resulting WorkflowEdge so the scheduler honors the fan-in / error-routing rule.',
457
+ req('openwop.it.workflow-chain-expansion.preserves-edge-condition-and-triggerrule-onto-the-expanded-workflowedge-rfc-0013', 'RFC 0013', 'Per RFC 0125 / workflow-chain-packs.md §"Expansion semantics": expansion MUST preserve `FragmentEdge.triggerRule` onto the resulting WorkflowEdge so the scheduler honors the fan-in / error-routing rule.'),
457
458
  ).toBe('all_complete');
458
459
  });
459
460
 
@@ -465,7 +466,7 @@ describe('category: workflow-chain expansion — edge rewriting', () => {
465
466
  });
466
467
  expect(
467
468
  at(fragment.edges, 0, 'fragment.edges').triggerRule,
468
- 'When a fragment edge declares no `triggerRule`, the expanded edge MUST NOT carry one — omission is identical to the `all_success` default (preserves wire-shape minimality + prior behavior).',
469
+ req('openwop.it.workflow-chain-expansion.omits-triggerrule-on-the-expanded-edge-when-the-fragment-edge-declares-none-defa', 'workflow-chain-packs.md', 'When a fragment edge declares no `triggerRule`, the expanded edge MUST NOT carry one — omission is identical to the `all_success` default (preserves wire-shape minimality + prior behavior).'),
469
470
  ).toBeUndefined();
470
471
  });
471
472
  });
@@ -491,7 +492,7 @@ describe('category: workflow-chain expansion — capability propagation', () =>
491
492
  for (const node of fragment.nodes) {
492
493
  expect(
493
494
  node.capabilities,
494
- 'Per spec §"Expansion semantics" step 8: chain-level `capabilities[]` MUST be copied to every expanded node so existing capability gates (side-effect, streamable) apply uniformly.',
495
+ req('openwop.it.workflow-chain-expansion.copies-chain-capabilities-into-every-expanded-node-s-capabilities', 'workflow-chain-packs.md', 'Per spec §"Expansion semantics" step 8: chain-level `capabilities[]` MUST be copied to every expanded node so existing capability gates (side-effect, streamable) apply uniformly.'),
495
496
  ).toEqual(['side-effectful', 'cacheable']);
496
497
  }
497
498
  });
@@ -504,7 +505,7 @@ describe('category: workflow-chain expansion — capability propagation', () =>
504
505
  });
505
506
  expect(
506
507
  at(fragment.nodes, 0, 'fragment.nodes').capabilities,
507
- 'When the chain declares no `capabilities[]`, expanded nodes MUST NOT carry an empty array (preserves wire-shape minimality).',
508
+ req('openwop.it.workflow-chain-expansion.omits-capabilities-on-expanded-nodes-when-the-chain-declares-none', 'workflow-chain-packs.md', 'When the chain declares no `capabilities[]`, expanded nodes MUST NOT carry an empty array (preserves wire-shape minimality).'),
508
509
  ).toBeUndefined();
509
510
  });
510
511
  });
@@ -519,7 +520,7 @@ describe('category: workflow-chain expansion — runtime-invariance contract', (
519
520
  for (const node of fragment.nodes) {
520
521
  expect(
521
522
  node.typeId,
522
- 'Per workflow-chain-packs.md §"What hosts dispatch": dispatching runtimes see only concrete `core.*`/published-vendor typeIds — the chain reference MUST NOT be preserved at runtime.',
523
+ req('openwop.it.workflow-chain-expansion.expanded-fragment-carries-only-concrete-typeids-no-chain-reference-survives', 'workflow-chain-packs.md', 'Per workflow-chain-packs.md §"What hosts dispatch": dispatching runtimes see only concrete `core.*`/published-vendor typeIds — the chain reference MUST NOT be preserved at runtime.'),
523
524
  ).not.toMatch(/^vendor\.acme\.generatePRD$/);
524
525
  expect(node.typeId).toBe('core.ai.callPrompt');
525
526
  }
@@ -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
  }