@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
@@ -20,6 +20,8 @@
20
20
  import { describe, it, expect } from 'vitest';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
23
+ import { req } from '../lib/requirement-ids.js';
24
+ import { softSkip } from '../lib/soft-skip.js';
23
25
 
24
26
  interface DiscoveryDeadLetter {
25
27
  supported?: boolean;
@@ -39,10 +41,10 @@ async function readDeadLetter(): Promise<DiscoveryDeadLetter | null> {
39
41
  describe('deadletter-capability-shape: advertisement shape (RFC 0053 §A)', () => {
40
42
  it('capabilities.deadLetter is either absent or well-formed', async () => {
41
43
  const dl = await readDeadLetter();
42
- if (dl === null) return; // host doesn't advertise deadLetter at all
44
+ if (dl === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `dl === null` returned early (host doesn\'t advertise deadLetter at all)'); // host doesn't advertise deadLetter at all
43
45
  expect(
44
46
  typeof dl.supported,
45
- driver.describe(
47
+ req('openwop.it.deadletter-capability-shape.capabilities-deadletter-is-either-absent-or-well-formed',
46
48
  'capabilities.schema.json §deadLetter',
47
49
  'capabilities.deadLetter.supported MUST be a boolean when deadLetter is advertised',
48
50
  ),
@@ -51,10 +53,10 @@ describe('deadletter-capability-shape: advertisement shape (RFC 0053 §A)', () =
51
53
 
52
54
  it('retentionDays is an integer >= 1 when present + supported', async () => {
53
55
  const dl = await readDeadLetter();
54
- if (!dl?.supported || dl.retentionDays === undefined) return;
56
+ if (!dl?.supported || dl.retentionDays === undefined) return softSkip('blocked', 'precondition not met — `!dl?.supported || dl.retentionDays === undefined` returned early (seam, prior step, or fixture unavailable)');
55
57
  expect(
56
58
  Number.isInteger(dl.retentionDays) && dl.retentionDays >= 1,
57
- driver.describe('RFC 0053 §A', `capabilities.deadLetter.retentionDays MUST be an integer >= 1, got: ${dl.retentionDays}`),
59
+ req('openwop.it.deadletter-capability-shape.retentiondays-is-an-integer-1-when-present-supported', 'RFC 0053 §A', `capabilities.deadLetter.retentionDays MUST be an integer >= 1, got: ${dl.retentionDays}`),
58
60
  ).toBe(true);
59
61
  });
60
62
  });
@@ -25,6 +25,7 @@ import { describe, it, expect } from 'vitest';
25
25
  import { softSkip } from '../lib/soft-skip.js';
26
26
  import { driver } from '../lib/driver.js';
27
27
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
28
+ import { req } from '../lib/requirement-ids.js';
28
29
 
29
30
  interface DiscoveryDoc {
30
31
  capabilities?: { deadLetter?: { supported?: boolean } };
@@ -43,11 +44,11 @@ describe('deadletter-retry-exhaustion: retry exhaustion → dead-lettered + fork
43
44
  const body = res.json as { event?: { type?: string; payload?: { attempts?: number; runId?: string } } } | undefined;
44
45
  expect(
45
46
  body?.event?.type,
46
- driver.describe('RFC 0053 §C.1', 'retry exhaustion MUST emit a run.dead_lettered event'),
47
+ req('openwop.it.deadletter-retry-exhaustion.a-retry-exhausted-run-emits-run-dead-lettered-with-attempts', 'RFC 0053 §C.1', 'retry exhaustion MUST emit a run.dead_lettered event'),
47
48
  ).toBe('run.dead_lettered');
48
49
  expect(
49
50
  typeof body?.event?.payload?.attempts === 'number' && body.event.payload.attempts >= 1,
50
- driver.describe('RFC 0053 §C.1', 'run.dead_lettered MUST carry the total attempts (>= 1)'),
51
+ req('openwop.it.deadletter-retry-exhaustion.a-retry-exhausted-run-emits-run-dead-lettered-with-attempts', 'RFC 0053 §C.1', 'run.dead_lettered MUST carry the total attempts (>= 1)'),
51
52
  ).toBe(true);
52
53
  });
53
54
 
@@ -58,7 +59,7 @@ describe('deadletter-retry-exhaustion: retry exhaustion → dead-lettered + fork
58
59
  const body = res.json as { forkEligible?: boolean } | undefined;
59
60
  expect(
60
61
  body?.forkEligible,
61
- driver.describe('RFC 0053 §C.2', 'a dead-lettered run MUST remain fork-eligible within the retention window'),
62
+ req('openwop.it.deadletter-retry-exhaustion.the-dead-lettered-run-is-fork-eligible-rfc-0011', 'RFC 0053 §C.2', 'a dead-lettered run MUST remain fork-eligible within the retention window'),
62
63
  ).toBe(true);
63
64
  });
64
65
  });
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
23
23
  import { driver } from '../lib/driver.js';
24
24
  import { pollUntilTerminal } from '../lib/polling.js';
25
25
  import { isFixtureAdvertised } from '../lib/fixtures.js';
26
+ import { req } from '../lib/requirement-ids.js';
27
+ import { softSkip } from '../lib/soft-skip.js';
26
28
 
27
29
  // `conformance-multi-node` produces enough events (run.started, three
28
30
  // node.started/completed pairs, run.completed = ~8 events) that
@@ -36,7 +38,7 @@ describe('debug-bundle-truncation: truncated: true contract', () => {
36
38
  console.warn(
37
39
  `[debug-bundle-truncation] ${FIXTURE} not advertised; skipping (host doesn't seed a multi-event fixture)`,
38
40
  );
39
- return;
41
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE)` returned early ([debug-bundle-truncation] … not advertised; skipping (host doesn\'t seed a multi-event fixture))');
40
42
  }
41
43
 
42
44
  const create = await driver.post('/v1/runs', { workflowId: FIXTURE });
@@ -49,8 +51,8 @@ describe('debug-bundle-truncation: truncated: true contract', () => {
49
51
  expect(full.status).toBe(200);
50
52
  const fullBody = full.json as { events?: unknown[]; truncated?: boolean };
51
53
  const fullEventCount = (fullBody.events ?? []).length;
52
- expect(fullEventCount, 'multi-node fixture MUST emit ≥ 3 events').toBeGreaterThanOrEqual(3);
53
- expect(fullBody.truncated ?? false, 'baseline bundle MUST NOT be truncated').toBe(false);
54
+ expect(fullEventCount, req('openwop.it.debug-bundle-truncation.host-that-supports-maxevents-n-or-otherwise-caps-surfaces-truncated-truncatedrea', 'debug-bundle.md §"Bundle size limits"', 'multi-node fixture MUST emit ≥ 3 events')).toBeGreaterThanOrEqual(3);
55
+ expect(fullBody.truncated ?? false, req('openwop.it.debug-bundle-truncation.host-that-supports-maxevents-n-or-otherwise-caps-surfaces-truncated-truncatedrea', 'debug-bundle.md §"Bundle size limits"', 'baseline bundle MUST NOT be truncated')).toBe(false);
54
56
 
55
57
  // Force truncation via the host's optional maxEvents override.
56
58
  const truncated = await driver.get(
@@ -73,21 +75,21 @@ describe('debug-bundle-truncation: truncated: true contract', () => {
73
75
  console.warn(
74
76
  '[debug-bundle-truncation] host does not honor ?maxEvents=; skipping truncated-shape assertions',
75
77
  );
76
- return;
78
+ return softSkip('blocked', 'precondition not met — `body.truncated !== true` returned early ([debug-bundle-truncation] host does not honor ?maxEvents=; skipping truncated-shape assertions) (seam, prior step, or fixture unavailable)');
77
79
  }
78
80
 
79
- expect(typeof body.truncatedReason, driver.describe(
81
+ expect(typeof body.truncatedReason, req('openwop.it.debug-bundle-truncation.host-that-supports-maxevents-n-or-otherwise-caps-surfaces-truncated-truncatedrea',
80
82
  'debug-bundle.md §"Bundle size limits"',
81
83
  'truncated: true MUST be accompanied by a non-empty truncatedReason string',
82
84
  )).toBe('string');
83
85
  expect((body.truncatedReason ?? '').length).toBeGreaterThan(0);
84
86
 
85
- expect((body.events ?? []).length, driver.describe(
87
+ expect((body.events ?? []).length, req('openwop.it.debug-bundle-truncation.host-that-supports-maxevents-n-or-otherwise-caps-surfaces-truncated-truncatedrea',
86
88
  'debug-bundle.md §"Bundle size limits"',
87
89
  'truncated events array MUST be a prefix (≤ maxEvents)',
88
90
  )).toBeLessThanOrEqual(2);
89
91
 
90
- expect(body.metrics?.eventCount, driver.describe(
92
+ expect(body.metrics?.eventCount, req('openwop.it.debug-bundle-truncation.host-that-supports-maxevents-n-or-otherwise-caps-surfaces-truncated-truncatedrea',
91
93
  'debug-bundle.md §"Bundle size limits"',
92
94
  'metrics.eventCount MUST reflect the TOTAL event count, not the truncated length',
93
95
  )).toBe(fullEventCount);
@@ -35,6 +35,8 @@ import { driver } from '../lib/driver.js';
35
35
  import { pollUntilTerminal } from '../lib/polling.js';
36
36
  import { CANARY_MARKER, getCanary } from '../lib/canaries.js';
37
37
  import { isFixtureAdvertised } from '../lib/fixtures.js';
38
+ import { req } from '../lib/requirement-ids.js';
39
+ import { softSkip } from '../lib/soft-skip.js';
38
40
 
39
41
  const NOOP_WORKFLOW_ID = 'conformance-noop';
40
42
  const SKIP_NO_NOOP = !isFixtureAdvertised(NOOP_WORKFLOW_ID);
@@ -61,7 +63,7 @@ async function isAdvertised(): Promise<boolean> {
61
63
 
62
64
  describe.skipIf(SKIP_NO_NOOP)('debug-bundle: GET /v1/runs/{runId}/debug-bundle response shape', () => {
63
65
  it('host advertising capabilities.debugBundle.supported returns 200 with valid bundle', async () => {
64
- if (!(await isAdvertised())) return; // skip-equivalent
66
+ if (!(await isAdvertised())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isAdvertised())` returned early (skip-equivalent)'); // skip-equivalent
65
67
 
66
68
  const create = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
67
69
  expect(create.status).toBe(201);
@@ -69,58 +71,58 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: GET /v1/runs/{runId}/debug-bundle r
69
71
  await pollUntilTerminal(runId);
70
72
 
71
73
  const res = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/debug-bundle`);
72
- expect(res.status, driver.describe(
74
+ expect(res.status, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
73
75
  'spec/v1/debug-bundle.md §Endpoint',
74
76
  'host advertising debugBundle.supported MUST return 200 on /debug-bundle',
75
77
  )).toBe(200);
76
78
 
77
79
  const bundle = res.json as DebugBundleShape | undefined;
78
- expect(bundle, driver.describe(
80
+ expect(bundle, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
79
81
  'spec/v1/debug-bundle.md',
80
82
  'response MUST be JSON',
81
83
  )).toBeDefined();
82
84
 
83
- expect(typeof bundle?.bundleVersion, driver.describe(
85
+ expect(typeof bundle?.bundleVersion, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
84
86
  'debug-bundle.md §Field reference',
85
87
  'bundleVersion MUST be a string',
86
88
  )).toBe('string');
87
- expect(typeof bundle?.generatedAt, driver.describe(
89
+ expect(typeof bundle?.generatedAt, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
88
90
  'debug-bundle.md',
89
91
  'generatedAt MUST be a string',
90
92
  )).toBe('string');
91
- expect(typeof bundle?.host?.name, driver.describe(
93
+ expect(typeof bundle?.host?.name, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
92
94
  'debug-bundle.md',
93
95
  'host.name MUST be a string',
94
96
  )).toBe('string');
95
- expect(typeof bundle?.host?.version, driver.describe(
97
+ expect(typeof bundle?.host?.version, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
96
98
  'debug-bundle.md',
97
99
  'host.version MUST be a string',
98
100
  )).toBe('string');
99
- expect(typeof bundle?.run?.runId, driver.describe(
101
+ expect(typeof bundle?.run?.runId, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
100
102
  'debug-bundle.md',
101
103
  'run.runId MUST be a string',
102
104
  )).toBe('string');
103
- expect(Array.isArray(bundle?.events), driver.describe(
105
+ expect(Array.isArray(bundle?.events), req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
104
106
  'debug-bundle.md',
105
107
  'events MUST be an array',
106
108
  )).toBe(true);
107
- expect(typeof bundle?.redactionApplied, driver.describe(
109
+ expect(typeof bundle?.redactionApplied, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
108
110
  'debug-bundle.md',
109
111
  'redactionApplied MUST be a boolean',
110
112
  )).toBe('boolean');
111
- expect(typeof bundle?.redactionMode, driver.describe(
113
+ expect(typeof bundle?.redactionMode, req('openwop.it.debugBundle.host-advertising-capabilities-debugbundle-supported-returns-200-with-valid-bundl',
112
114
  'debug-bundle.md',
113
115
  'redactionMode MUST be a string',
114
116
  )).toBe('string');
115
117
  });
116
118
 
117
119
  it('hosts not advertising debugBundle return 404 on the endpoint', async () => {
118
- if (await isAdvertised()) return; // skip-equivalent for hosts that DO advertise
120
+ if (await isAdvertised()) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `await isAdvertised()` returned early (skip-equivalent for hosts that DO advertise)'); // skip-equivalent for hosts that DO advertise
119
121
 
120
122
  // Use any runId — even a synthetic one — since the host should 404
121
123
  // on the endpoint regardless of run existence.
122
124
  const res = await driver.get('/v1/runs/openwop-conformance-no-such-run/debug-bundle');
123
- expect(res.status, driver.describe(
125
+ expect(res.status, req('openwop.it.debugBundle.hosts-not-advertising-debugbundle-return-404-on-the-endpoint',
124
126
  'debug-bundle.md §Endpoint',
125
127
  'host NOT advertising debugBundle.supported MUST return 404',
126
128
  )).toBe(404);
@@ -129,7 +131,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: GET /v1/runs/{runId}/debug-bundle r
129
131
 
130
132
  describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', () => {
131
133
  it('metrics.eventCount equals events.length', async () => {
132
- if (!(await isAdvertised())) return;
134
+ if (!(await isAdvertised())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isAdvertised())` returned early');
133
135
 
134
136
  const create = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
135
137
  expect(create.status).toBe(201);
@@ -141,7 +143,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
141
143
  const bundle = res.json as DebugBundleShape;
142
144
 
143
145
  if (bundle.metrics?.eventCount !== undefined) {
144
- expect(bundle.metrics.eventCount, driver.describe(
146
+ expect(bundle.metrics.eventCount, req('openwop.it.debugBundle.metrics-eventcount-equals-events-length',
145
147
  'debug-bundle.md §"Field reference"',
146
148
  'metrics.eventCount MUST equal events.length',
147
149
  )).toBe(bundle.events?.length ?? 0);
@@ -149,7 +151,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
149
151
  });
150
152
 
151
153
  it('redactionApplied=true is incompatible with redactionMode=passthrough', async () => {
152
- if (!(await isAdvertised())) return;
154
+ if (!(await isAdvertised())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isAdvertised())` returned early');
153
155
 
154
156
  const create = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
155
157
  expect(create.status).toBe(201);
@@ -161,7 +163,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
161
163
  const bundle = res.json as DebugBundleShape;
162
164
 
163
165
  if (bundle.redactionApplied === true) {
164
- expect(bundle.redactionMode, driver.describe(
166
+ expect(bundle.redactionMode, req('openwop.it.debugBundle.redactionapplied-true-is-incompatible-with-redactionmode-passthrough',
165
167
  'debug-bundle.md §"Redaction guarantees"',
166
168
  'redactionApplied=true MUST NOT coexist with redactionMode=passthrough — that combination is malformed',
167
169
  )).not.toBe('passthrough');
@@ -169,7 +171,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
169
171
  });
170
172
 
171
173
  it('bundle events agree with /events/poll for the same run', async () => {
172
- if (!(await isAdvertised())) return;
174
+ if (!(await isAdvertised())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isAdvertised())` returned early');
173
175
 
174
176
  const create = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
175
177
  expect(create.status).toBe(201);
@@ -178,12 +180,12 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
178
180
 
179
181
  const bundleRes = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/debug-bundle`);
180
182
  const eventsRes = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/events/poll`);
181
- if (eventsRes.status !== 200) return; // host without polling
183
+ if (eventsRes.status !== 200) return softSkip('blocked', 'precondition not met — `eventsRes.status !== 200` returned early (host without polling) (seam, prior step, or fixture unavailable)'); // host without polling
182
184
 
183
185
  const bundle = bundleRes.json as DebugBundleShape;
184
186
  const polledEvents = (eventsRes.json as { events?: unknown[] }).events ?? [];
185
187
 
186
- expect(bundle.events?.length, driver.describe(
188
+ expect(bundle.events?.length, req('openwop.it.debugBundle.bundle-events-agree-with-events-poll-for-the-same-run',
187
189
  'debug-bundle.md',
188
190
  'bundle event count MUST agree with /events/poll for the same run',
189
191
  )).toBe(polledEvents.length);
@@ -192,7 +194,7 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: invariants per debug-bundle.md', ()
192
194
 
193
195
  describe.skipIf(SKIP_NO_NOOP)('debug-bundle: redaction inheritance per SECURITY/invariants.yaml secret-leakage-debug-bundle', () => {
194
196
  it('canary in workflow inputs MUST NOT appear verbatim in the bundle response', async () => {
195
- if (!(await isAdvertised())) return;
197
+ if (!(await isAdvertised())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isAdvertised())` returned early');
196
198
 
197
199
  const canary = getCanary('byok-credential-ref').value;
198
200
 
@@ -210,11 +212,11 @@ describe.skipIf(SKIP_NO_NOOP)('debug-bundle: redaction inheritance per SECURITY/
210
212
  expect(res.status).toBe(200);
211
213
 
212
214
  const bundleText = res.text;
213
- expect(bundleText.includes(canary), driver.describe(
215
+ expect(bundleText.includes(canary), req('openwop.it.debugBundle.canary-in-workflow-inputs-must-not-appear-verbatim-in-the-bundle-response',
214
216
  'SECURITY/invariants.yaml secret-leakage-debug-bundle',
215
217
  'BYOK-shaped canary submitted as workflow input MUST NOT appear verbatim in the debug bundle',
216
218
  )).toBe(false);
217
- expect(bundleText.includes(CANARY_MARKER), driver.describe(
219
+ expect(bundleText.includes(CANARY_MARKER), req('openwop.it.debugBundle.canary-in-workflow-inputs-must-not-appear-verbatim-in-the-bundle-response',
218
220
  'SECURITY/invariants.yaml secret-leakage-debug-bundle',
219
221
  'canary marker MUST NOT appear in the debug bundle',
220
222
  )).toBe(false);
@@ -13,25 +13,26 @@
13
13
 
14
14
  import { describe, it, expect } from 'vitest';
15
15
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
16
+ import { req } from '../lib/requirement-ids.js';
16
17
 
17
18
  describe('RFC 0073 — discoveryFamilies is root-first with the deprecated wrapper as fallback', () => {
18
19
  it('a root-only document is read as-is (the RFC 0073 shape)', () => {
19
- expect(discoveryFamilies({ protocolVersion: '1.0', kvStorage: { supported: true } })).toEqual({ protocolVersion: '1.0', kvStorage: { supported: true } });
20
+ expect(discoveryFamilies({ protocolVersion: '1.0', kvStorage: { supported: true } }), req('openwop.it.discovery-families-view.a-root-only-document-is-read-as-is-the-rfc-0073-shape', 'RFC 0073', 'a root-only document is read as-is (the RFC 0073 shape)')).toEqual({ protocolVersion: '1.0', kvStorage: { supported: true } });
20
21
  });
21
22
 
22
23
  it('a wrapper-only family is still visible, and the wrapper key itself is not a family', () => {
23
24
  const v = discoveryFamilies({ protocolVersion: '1.0', capabilities: { heartbeat: { supported: true } } });
24
- expect(v['heartbeat']).toEqual({ supported: true });
25
+ expect(v['heartbeat'], req('openwop.it.discovery-families-view.a-wrapper-only-family-is-still-visible-and-the-wrapper-key-itself-is-not-a-famil', 'RFC 0073', 'a wrapper-only family is still visible, and the wrapper key itself is not a family')).toEqual({ supported: true });
25
26
  expect('capabilities' in v).toBe(false);
26
27
  });
27
28
 
28
29
  it('when both carry a family, the root wins', () => {
29
30
  const v = discoveryFamilies({ feedback: { supported: true, root: true }, capabilities: { feedback: { supported: false, root: false } } });
30
- expect(v['feedback']).toEqual({ supported: true, root: true });
31
+ expect(v['feedback'], req('openwop.it.discovery-families-view.when-both-carry-a-family-the-root-wins', 'RFC 0073', 'when both carry a family, the root wins')).toEqual({ supported: true, root: true });
31
32
  });
32
33
 
33
34
  it('a non-object document reads as empty', () => {
34
- expect(discoveryFamilies(null)).toEqual({});
35
+ expect(discoveryFamilies(null), req('openwop.it.discovery-families-view.a-non-object-document-reads-as-empty', 'RFC 0073', 'a non-object document reads as empty')).toEqual({});
35
36
  expect(discoveryFamilies('nope')).toEqual({});
36
37
  expect(discoveryFamilies({ capabilities: ['not', 'an', 'object'] })).toEqual({});
37
38
  });
@@ -11,22 +11,23 @@ import { driver } from '../lib/driver.js';
11
11
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
12
12
  import { behaviorGate } from '../lib/behavior-gate.js';
13
13
  import { softSkip } from '../lib/soft-skip.js';
14
+ import { req } from '../lib/requirement-ids.js';
14
15
 
15
16
  describe('discovery: /.well-known/openwop', () => {
16
17
  it('returns 200 with required Capabilities fields per capabilities.md §2', async () => {
17
18
  const res = await driver.get('/.well-known/openwop', { authenticated: false });
18
19
 
19
- expect(res.status, driver.describe(
20
+ expect(res.status, req('openwop.it.discovery.returns-200-with-required-capabilities-fields-per-capabilities-md-2',
20
21
  'capabilities.md §2',
21
22
  'discovery endpoint MUST be reachable without auth and return 200',
22
23
  )).toBe(200);
23
24
 
24
25
  const body = res.json as Record<string, unknown> | undefined;
25
- expect(body, driver.describe('capabilities.md §2', 'response MUST be JSON')).toBeDefined();
26
+ expect(body, req('openwop.it.discovery.returns-200-with-required-capabilities-fields-per-capabilities-md-2', 'capabilities.md §2', 'response MUST be JSON')).toBeDefined();
26
27
 
27
28
  // Per capabilities.md §3 (in-package shape), these 4 fields are REQUIRED.
28
29
  for (const required of ['protocolVersion', 'supportedEnvelopes', 'schemaVersions', 'limits']) {
29
- expect(body?.[required], driver.describe(
30
+ expect(body?.[required], req('openwop.it.discovery.returns-200-with-required-capabilities-fields-per-capabilities-md-2',
30
31
  'capabilities.md §3',
31
32
  `Capabilities.${required} MUST be present`,
32
33
  )).toBeDefined();
@@ -37,7 +38,7 @@ describe('discovery: /.well-known/openwop', () => {
37
38
  const res = await driver.get('/.well-known/openwop', { authenticated: false });
38
39
  const cacheControl = res.headers.get('cache-control');
39
40
 
40
- expect(cacheControl, driver.describe(
41
+ expect(cacheControl, req('openwop.it.discovery.serves-cache-control-per-capabilities-md-4-caching-guidance',
41
42
  'capabilities.md §4',
42
43
  'response SHOULD carry a Cache-Control header to allow client caching',
43
44
  )).toBeTruthy();
@@ -49,9 +50,9 @@ describe('discovery: /.well-known/openwop', () => {
49
50
  if (etag === null) {
50
51
  return softSkip('inapplicable', 'host does not send a standard ETag on the discovery document (RFC 0165 §C.2 — SHOULD, presence-gated)');
51
52
  }
52
- expect(etag.trim().length, driver.describe('RFC 0165 §C.2', 'ETag, when present, MUST be a non-empty validator')).toBeGreaterThan(0);
53
+ expect(etag.trim().length, req('openwop.it.discovery.if-a-standard-etag-is-present-a-matching-if-none-match-yields-304-rfc-0165-c-2-p', 'RFC 0165 §C.2', 'ETag, when present, MUST be a non-empty validator')).toBeGreaterThan(0);
53
54
  const second = await driver.get('/.well-known/openwop', { authenticated: false, headers: { 'If-None-Match': etag } });
54
- expect(second.status, driver.describe('capabilities-change-detection.md §"Cache validators"', 'a matching If-None-Match SHOULD yield 304 Not Modified')).toBe(304);
55
+ expect(second.status, req('openwop.it.discovery.if-a-standard-etag-is-present-a-matching-if-none-match-yields-304-rfc-0165-c-2-p', 'capabilities-change-detection.md §"Cache validators"', 'a matching If-None-Match SHOULD yield 304 Not Modified')).toBe(304);
55
56
  });
56
57
 
57
58
  it('IF Capabilities-Etag is present, it is non-empty and stable within the cache window', async () => {
@@ -59,14 +60,14 @@ describe('discovery: /.well-known/openwop', () => {
59
60
  const firstEtag = first.headers.get('capabilities-etag');
60
61
 
61
62
  if (firstEtag === null) {
62
- expect(firstEtag, driver.describe(
63
+ expect(firstEtag, req('openwop.it.discovery.if-capabilities-etag-is-present-it-is-non-empty-and-stable-within-the-cache-wind',
63
64
  'capabilities-change-detection.md §Capabilities-Etag',
64
65
  'Capabilities-Etag is optional; hosts that omit it remain conformant',
65
66
  )).toBeNull();
66
- return;
67
+ return softSkip('blocked', 'precondition not met — `firstEtag === null` returned early (seam, prior step, or fixture unavailable)');
67
68
  }
68
69
 
69
- expect(firstEtag.trim().length, driver.describe(
70
+ expect(firstEtag.trim().length, req('openwop.it.discovery.if-capabilities-etag-is-present-it-is-non-empty-and-stable-within-the-cache-wind',
70
71
  'capabilities-change-detection.md §Capabilities-Etag',
71
72
  'Capabilities-Etag, when present, MUST be a non-empty opaque string',
72
73
  )).toBeGreaterThan(0);
@@ -74,7 +75,7 @@ describe('discovery: /.well-known/openwop', () => {
74
75
  const second = await driver.get('/.well-known/openwop', { authenticated: false });
75
76
  const secondEtag = second.headers.get('capabilities-etag');
76
77
 
77
- expect(secondEtag, driver.describe(
78
+ expect(secondEtag, req('openwop.it.discovery.if-capabilities-etag-is-present-it-is-non-empty-and-stable-within-the-cache-wind',
78
79
  'capabilities-change-detection.md §Conformance expectations',
79
80
  'repeated discovery calls without host changes SHOULD return the same Capabilities-Etag within the cache window',
80
81
  )).toBe(firstEtag);
@@ -84,18 +85,18 @@ describe('discovery: /.well-known/openwop', () => {
84
85
  const res = await driver.get('/.well-known/openwop', { authenticated: false });
85
86
  const limits = (res.json as { limits?: Record<string, number> } | undefined)?.limits;
86
87
 
87
- expect(limits, driver.describe(
88
+ expect(limits, req('openwop.it.discovery.declares-non-zero-limits-per-capabilities-md-3-capabilitylimiter-shape',
88
89
  'capabilities.md §3',
89
90
  'Capabilities.limits MUST be present',
90
91
  )).toBeDefined();
91
92
 
92
93
  for (const k of ['clarificationRounds', 'schemaRounds', 'envelopesPerTurn']) {
93
94
  const v = limits?.[k];
94
- expect(typeof v, driver.describe(
95
+ expect(typeof v, req('openwop.it.discovery.declares-non-zero-limits-per-capabilities-md-3-capabilitylimiter-shape',
95
96
  'capabilities.md §3',
96
97
  `limits.${k} MUST be a non-negative integer`,
97
98
  )).toBe('number');
98
- expect(v ?? -1, driver.describe(
99
+ expect(v ?? -1, req('openwop.it.discovery.declares-non-zero-limits-per-capabilities-md-3-capabilitylimiter-shape',
99
100
  'capabilities.md §3',
100
101
  `limits.${k} MUST be >= 0`,
101
102
  )).toBeGreaterThanOrEqual(0);
@@ -115,28 +116,28 @@ describe('discovery: /.well-known/openwop fixtures field shape per RFC 0003', ()
115
116
  // RFC 0003 makes the field OPTIONAL — pre-RFC hosts and hosts
116
117
  // that opt out advertise nothing. Assertion passes trivially.
117
118
  expect(fixtures).toBeUndefined();
118
- return;
119
+ return softSkip('blocked', 'precondition not met — `fixtures === undefined` returned early (seam, prior step, or fixture unavailable)');
119
120
  }
120
121
 
121
- expect(Array.isArray(fixtures), driver.describe(
122
+ expect(Array.isArray(fixtures), req('openwop.it.discovery.if-fixtures-is-present-it-must-be-a-string-of-unique-non-empty-entries',
122
123
  'capabilities.md §`fixtures` (RFC 0003)',
123
124
  'fixtures MUST be an array when present',
124
125
  )).toBe(true);
125
126
 
126
127
  const arr = fixtures as unknown[];
127
128
  for (const entry of arr) {
128
- expect(typeof entry, driver.describe(
129
+ expect(typeof entry, req('openwop.it.discovery.if-fixtures-is-present-it-must-be-a-string-of-unique-non-empty-entries',
129
130
  'capabilities.md §`fixtures` (RFC 0003)',
130
131
  'every fixtures entry MUST be a string',
131
132
  )).toBe('string');
132
- expect((entry as string).length, driver.describe(
133
+ expect((entry as string).length, req('openwop.it.discovery.if-fixtures-is-present-it-must-be-a-string-of-unique-non-empty-entries',
133
134
  'capabilities.md §`fixtures` (RFC 0003)',
134
135
  'every fixtures entry MUST be non-empty',
135
136
  )).toBeGreaterThan(0);
136
137
  }
137
138
 
138
139
  const unique = new Set(arr as string[]);
139
- expect(unique.size, driver.describe(
140
+ expect(unique.size, req('openwop.it.discovery.if-fixtures-is-present-it-must-be-a-string-of-unique-non-empty-entries',
140
141
  'capabilities.md §`fixtures` (RFC 0003)',
141
142
  'fixtures entries SHOULD be unique (consumers MUST tolerate duplicates by deduplicating)',
142
143
  )).toBe(arr.length);
@@ -147,13 +148,13 @@ describe('discovery: /v1/openapi.json', () => {
147
148
  it('returns 200 with a parseable OpenAPI 3.1 document', async () => {
148
149
  const res = await driver.get('/v1/openapi.json', { authenticated: false });
149
150
 
150
- expect(res.status, driver.describe(
151
+ expect(res.status, req('openwop.it.discovery.returns-200-with-a-parseable-openapi-3-1-document',
151
152
  'rest-endpoints.md',
152
153
  'self-describing OpenAPI endpoint MUST return 200',
153
154
  )).toBe(200);
154
155
 
155
156
  const body = res.json as { openapi?: string } | undefined;
156
- expect(body?.openapi, driver.describe(
157
+ expect(body?.openapi, req('openwop.it.discovery.returns-200-with-a-parseable-openapi-3-1-document',
157
158
  'rest-endpoints.md',
158
159
  'response MUST declare openapi >= 3.1',
159
160
  )).toMatch(/^3\.[1-9]/);
@@ -210,7 +211,7 @@ describe('discovery: auth-scoped capability shape', () => {
210
211
  return;
211
212
  }
212
213
 
213
- expect(disc?.authScoped?.supported, driver.describe(
214
+ expect(disc?.authScoped?.supported, req('openwop.it.discovery.host-claiming-auth-scoped-discovery-advertises-required-fields',
214
215
  'capabilities-change-detection.md §"Scoped capability views"',
215
216
  'capabilities.discovery.authScoped.supported MUST be true when the profile is claimed',
216
217
  )).toBe(true);
@@ -218,7 +219,7 @@ describe('discovery: auth-scoped capability shape', () => {
218
219
  if (disc?.authScoped?.mode !== undefined) {
219
220
  expect(
220
221
  ['same-endpoint', 'extension-endpoint'].includes(disc.authScoped.mode),
221
- driver.describe(
222
+ req('openwop.it.discovery.host-claiming-auth-scoped-discovery-advertises-required-fields',
222
223
  'capabilities.schema.json discovery.authScoped.mode',
223
224
  'mode MUST be one of same-endpoint / extension-endpoint when advertised',
224
225
  ),
@@ -229,7 +230,7 @@ describe('discovery: auth-scoped capability shape', () => {
229
230
  expect(
230
231
  typeof disc.authScoped.endpointPath === 'string' &&
231
232
  disc.authScoped.endpointPath.startsWith('/'),
232
- driver.describe(
233
+ req('openwop.it.discovery.host-claiming-auth-scoped-discovery-advertises-required-fields',
233
234
  'RFCS/0011-auth-scoped-discovery.md §A',
234
235
  'extension-endpoint mode MUST advertise endpointPath as a leading-slash relative path',
235
236
  ),
@@ -254,13 +255,13 @@ describe('discovery: auth-scoped view satisfies base schema', () => {
254
255
 
255
256
  const res = await driver.get(path);
256
257
 
257
- expect(res.status, driver.describe(
258
+ expect(res.status, req('openwop.it.discovery.authenticated-discovery-preserves-required-capabilities-fields',
258
259
  'capabilities-change-detection.md §"Scoped capability views"',
259
260
  'authenticated discovery MUST return 200',
260
261
  )).toBe(200);
261
262
 
262
263
  const body = res.json as Record<string, unknown> | undefined;
263
- expect(body, 'authenticated discovery body MUST be JSON').toBeDefined();
264
+ expect(body, req('openwop.it.discovery.authenticated-discovery-preserves-required-capabilities-fields', 'capabilities-change-detection.md §"Scoped capability views"', 'authenticated discovery body MUST be JSON')).toBeDefined();
264
265
 
265
266
  // Required fields per capabilities.md §3 preserved in the
266
267
  // authenticated view (per spec annex: "MUST still satisfy the
@@ -271,7 +272,7 @@ describe('discovery: auth-scoped view satisfies base schema', () => {
271
272
  'schemaVersions',
272
273
  'limits',
273
274
  ]) {
274
- expect(body?.[required], driver.describe(
275
+ expect(body?.[required], req('openwop.it.discovery.authenticated-discovery-preserves-required-capabilities-fields',
275
276
  'capabilities-change-detection.md §"Scoped capability views"',
276
277
  `auth-scoped view MUST preserve required field "${required}" from capabilities.md §3`,
277
278
  )).toBeDefined();
@@ -293,7 +294,7 @@ describe('discovery: auth-scoped is not an authorization oracle', () => {
293
294
  console.warn(
294
295
  '[discovery: auth-scoped] OPENWOP_TEST_UNAUTHORIZED_API_KEY not supplied; skipping authorization-oracle probe',
295
296
  );
296
- return;
297
+ return softSkip('blocked', 'precondition not met — `!unauthorizedKey` returned early ([discovery: auth-scoped] OPENWOP_TEST_UNAUTHORIZED_API_KEY not supplied; skipping authorization-oracle probe) (seam, prior step, or fixture unavailable)');
297
298
  }
298
299
 
299
300
  const mode = disc?.authScoped?.mode ?? 'same-endpoint';
@@ -314,7 +315,7 @@ describe('discovery: auth-scoped is not an authorization oracle', () => {
314
315
  if (unauthorized.status === 401 || unauthorized.status === 403) {
315
316
  // Host rejected the unauthorized key outright — that's fine.
316
317
  // The oracle probe is moot when the host refuses the bearer.
317
- return;
318
+ return softSkip('blocked', 'precondition not met — `unauthorized.status === 401 || unauthorized.status === 403` returned early (Host rejected the unauthorized key outright — that\'s fine. The oracle probe is moot when the host refuses the bearer.…');
318
319
  }
319
320
  expect(unauthorized.status).toBe(200);
320
321
 
@@ -330,7 +331,7 @@ describe('discovery: auth-scoped is not an authorization oracle', () => {
330
331
  // primary view's keys (no capabilities the unauthorized caller
331
332
  // can use that the primary cannot).
332
333
  const extras = unauthorizedCaps.filter((c) => !primaryCaps.includes(c));
333
- expect(extras.length, driver.describe(
334
+ expect(extras.length, req('openwop.it.discovery.unauthorized-key-must-not-reveal-capabilities-outside-its-authorization',
334
335
  'capabilities-change-detection.md §"Scoped capability views"',
335
336
  'unauthorized view MUST NOT expose capability keys absent from the primary (authorized) view',
336
337
  )).toBe(0);
@@ -25,6 +25,8 @@ import { describe, it, expect } from 'vitest';
25
25
  import { driver } from '../lib/driver.js';
26
26
  import { pollUntilTerminal } from '../lib/polling.js';
27
27
  import { isFixtureAdvertised } from '../lib/fixtures.js';
28
+ import { req } from '../lib/requirement-ids.js';
29
+ import { softSkip } from '../lib/soft-skip.js';
28
30
 
29
31
  const PARENT = 'conformance-dispatch-cross-worker-handoff';
30
32
  const CHILD_A = 'conformance-dispatch-cross-worker-handoff-child-a';
@@ -53,14 +55,14 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
53
55
  const parentRunId = (create.json as { runId: string }).runId;
54
56
 
55
57
  const parentTerminal = (await pollUntilTerminal(parentRunId)) as RunSnapshot;
56
- expect(parentTerminal.status, driver.describe(
58
+ expect(parentTerminal.status, req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-child-a-writes-via-perworkeroutputmappings-child-b-reads-via-perworkeri',
57
59
  'RFCS/0022-dispatch-input-output-mapping.md §D',
58
60
  'parent run MUST reach terminal `completed` once both children finish sequentially',
59
61
  )).toBe('completed');
60
62
 
61
63
  // Parent's sharedVar MUST be 'hello' — set by child-a's outputMapping.
62
64
  const parentVars = parentTerminal.variables ?? {};
63
- expect(parentVars.sharedVar, driver.describe(
65
+ expect(parentVars.sharedVar, req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-child-a-writes-via-perworkeroutputmappings-child-b-reads-via-perworkeri',
64
66
  'RFCS/0022-dispatch-input-output-mapping.md §A',
65
67
  'parent `sharedVar` MUST be child-a\'s `output` projection ("hello") via perWorkerOutputMappings',
66
68
  )).toBe('hello');
@@ -72,7 +74,7 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
72
74
  const dispatchedB = events.find(
73
75
  (e) => e.type === 'node.dispatched' && e.payload?.childWorkflowId === CHILD_B,
74
76
  );
75
- expect(dispatchedB, driver.describe(
77
+ expect(dispatchedB, req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-child-a-writes-via-perworkeroutputmappings-child-b-reads-via-perworkeri',
76
78
  'RFCS/0022-dispatch-input-output-mapping.md §D',
77
79
  'parent event log MUST contain a `node.dispatched` event for child-b after child-a completes (sequential fan-out)',
78
80
  )).toBeDefined();
@@ -86,7 +88,7 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
86
88
  const childBSnapshot = childBSnapshotRes.json as RunSnapshot;
87
89
  expect(childBSnapshot.status).toBe('completed');
88
90
  const childBInputs = childBSnapshot.inputs ?? {};
89
- expect(childBInputs.input, driver.describe(
91
+ expect(childBInputs.input, req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-child-a-writes-via-perworkeroutputmappings-child-b-reads-via-perworkeri',
90
92
  'RFCS/0022-dispatch-input-output-mapping.md §A + §D',
91
93
  'child-b `inputs.input` MUST be parent\'s `sharedVar` ("hello") — written by child-a, read by child-b via shared parent variable bag',
92
94
  )).toBe('hello');
@@ -94,7 +96,7 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
94
96
 
95
97
  it('HVMAP-1c-override: per-worker mapping overrides default mapping per §A effectiveInputMapping precedence', async () => {
96
98
  const PARENT_OVERRIDE = 'conformance-dispatch-per-worker-override';
97
- if (!isFixtureAdvertised(PARENT_OVERRIDE)) return; // fixture not seeded — soft-skip
99
+ if (!isFixtureAdvertised(PARENT_OVERRIDE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(PARENT_OVERRIDE)` returned early (fixture not seeded — soft-skip)'); // fixture not seeded — soft-skip
98
100
  const create = await driver.post('/v1/runs', { workflowId: PARENT_OVERRIDE });
99
101
  expect(create.status).toBe(201);
100
102
  const parentRunId = (create.json as { runId: string }).runId;
@@ -104,7 +106,7 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
104
106
  const events = ((eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? []);
105
107
  const dispatchedA = events.find((e) => e.type === 'node.dispatched' && e.payload?.childWorkflowId === CHILD_A);
106
108
  const dispatchedB = events.find((e) => e.type === 'node.dispatched' && e.payload?.childWorkflowId === CHILD_B);
107
- if (!dispatchedA || !dispatchedB) return;
109
+ if (!dispatchedA || !dispatchedB) return softSkip('blocked', 'precondition not met — `!dispatchedA || !dispatchedB` returned early (seam, prior step, or fixture unavailable)');
108
110
 
109
111
  const childARes = await driver.get(`/v1/runs/${encodeURIComponent(dispatchedA.payload!.childRunId!)}`);
110
112
  const childBRes = await driver.get(`/v1/runs/${encodeURIComponent(dispatchedB.payload!.childRunId!)}`);
@@ -113,14 +115,14 @@ describe.skipIf(SKIP)('dispatch-cross-worker-handoff: sequential child→parent
113
115
 
114
116
  expect(
115
117
  childAInputs.input,
116
- driver.describe(
118
+ req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-override-per-worker-mapping-overrides-default-mapping-per-a-effectivein',
117
119
  'RFCS/0022-dispatch-input-output-mapping.md §A',
118
120
  'child-a uses the DEFAULT inputMapping; input MUST come from parent.defaultX',
119
121
  ),
120
122
  ).toBe('default-x-value');
121
123
  expect(
122
124
  childBInputs.input,
123
- driver.describe(
125
+ req('openwop.it.dispatch-cross-worker-handoff.hvmap-1c-override-per-worker-mapping-overrides-default-mapping-per-a-effectivein',
124
126
  'RFCS/0022-dispatch-input-output-mapping.md §A',
125
127
  'child-b uses the per-worker OVERRIDE; input MUST come from parent.sharedVar (NOT defaultX)',
126
128
  ),