@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
@@ -36,6 +36,8 @@ import { driver } from '../lib/driver.js';
36
36
  import { pollUntilTerminal } from '../lib/polling.js';
37
37
  import { isFixtureAdvertised } from '../lib/fixtures.js';
38
38
  import { getCollector, waitForRunSpans } from '../lib/otel-collector.js';
39
+ import { req } from '../lib/requirement-ids.js';
40
+ import { softSkip } from '../lib/soft-skip.js';
39
41
 
40
42
  /**
41
43
  * Callback-shaped: the host exports OTLP metrics to the suite's collector.
@@ -91,14 +93,14 @@ describe.skipIf(SKIP_NO_NOOP)('cost-attribution: metrics.openwopCost forward-com
91
93
  // passes trivially; don't force a value on a workflow that produces
92
94
  // no cost.
93
95
  expect(openwopCost).toBeUndefined();
94
- return;
96
+ return softSkip('blocked', 'precondition not met — `openwopCost === undefined` returned early (seam, prior step, or fixture unavailable)');
95
97
  }
96
98
 
97
99
  // When present, validate the canonical shape per
98
100
  // run-snapshot.schema.json §metrics.openwopCost.
99
101
  if ('usd' in openwopCost) {
100
- expect(typeof openwopCost.usd, 'metrics.openwopCost.usd MUST be a number').toBe('number');
101
- expect(openwopCost.usd!, 'metrics.openwopCost.usd MUST be >= 0').toBeGreaterThanOrEqual(0);
102
+ expect(typeof openwopCost.usd, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.usd MUST be a number')).toBe('number');
103
+ expect(openwopCost.usd!, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.usd MUST be >= 0')).toBeGreaterThanOrEqual(0);
102
104
  }
103
105
  if ('tokens' in openwopCost && openwopCost.tokens) {
104
106
  if ('input' in openwopCost.tokens) {
@@ -115,10 +117,10 @@ describe.skipIf(SKIP_NO_NOOP)('cost-attribution: metrics.openwopCost forward-com
115
117
  expect(openwopCost.duration_ms!).toBeGreaterThanOrEqual(0);
116
118
  }
117
119
  if ('model' in openwopCost) {
118
- expect(typeof openwopCost.model, 'metrics.openwopCost.model MUST be a string').toBe('string');
120
+ expect(typeof openwopCost.model, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.model MUST be a string')).toBe('string');
119
121
  }
120
122
  if ('provider' in openwopCost) {
121
- expect(typeof openwopCost.provider, 'metrics.openwopCost.provider MUST be a string').toBe('string');
123
+ expect(typeof openwopCost.provider, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.provider MUST be a string')).toBe('string');
122
124
  }
123
125
  });
124
126
  });
@@ -140,23 +142,23 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
140
142
  // Fixture absent — host does not opt into OPENWOP_CONFORMANCE_FIXTURES.
141
143
  // That's spec-allowed; the scenario passes trivially.
142
144
  if (create.status === 404 || create.status === 422) {
143
- return;
145
+ return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (Fixture absent — host does not opt into OPENWOP_CONFORMANCE_FIXTURES. That\'s spec-allowed; the scenario passes trivially.) (seam,…');
144
146
  }
145
147
 
146
- expect(create.status, driver.describe(
148
+ expect(create.status, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
147
149
  'rest-endpoints.md POST /v1/runs',
148
150
  'starting openwop-smoke-cost-emit MUST succeed when OPENWOP_CONFORMANCE_FIXTURES=1 is advertised',
149
151
  )).toBe(201);
150
152
  const runId = (create.json as { runId: string }).runId;
151
153
 
152
154
  const terminal = await pollUntilTerminal(runId);
153
- expect(terminal.status, driver.describe(
155
+ expect(terminal.status, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
154
156
  'observability.md §AI cost',
155
157
  'cost-emit fixture run MUST reach terminal completed',
156
158
  )).toBe('completed');
157
159
 
158
160
  const openwopCost = terminal.metrics?.openwopCost;
159
- expect(openwopCost, driver.describe(
161
+ expect(openwopCost, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
160
162
  'run-snapshot.schema.json §metrics.openwopCost',
161
163
  'metrics.openwopCost MUST be populated after a node calls ctx.recordCost()',
162
164
  )).toBeDefined();
@@ -176,14 +178,14 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
176
178
  // Tokens — MUST be non-negative integers when present.
177
179
  if ('tokens' in openwopCost! && openwopCost!.tokens) {
178
180
  if ('input' in openwopCost!.tokens) {
179
- expect(Number.isInteger(openwopCost!.tokens.input), driver.describe(
181
+ expect(Number.isInteger(openwopCost!.tokens.input), req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
180
182
  'observability.md §openwop.cost.tokens.input',
181
183
  'tokens.input MUST be a non-negative integer',
182
184
  )).toBe(true);
183
185
  expect(openwopCost!.tokens.input!).toBeGreaterThanOrEqual(0);
184
186
  }
185
187
  if ('output' in openwopCost!.tokens) {
186
- expect(Number.isInteger(openwopCost!.tokens.output), driver.describe(
188
+ expect(Number.isInteger(openwopCost!.tokens.output), req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
187
189
  'observability.md §openwop.cost.tokens.output',
188
190
  'tokens.output MUST be a non-negative integer',
189
191
  )).toBe(true);
@@ -193,11 +195,11 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
193
195
 
194
196
  // USD — MUST be non-negative number (fractional allowed).
195
197
  if ('usd' in openwopCost!) {
196
- expect(typeof openwopCost!.usd, driver.describe(
198
+ expect(typeof openwopCost!.usd, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
197
199
  'observability.md §openwop.cost.usd',
198
200
  'usd MUST be a number',
199
201
  )).toBe('number');
200
- expect(openwopCost!.usd!, driver.describe(
202
+ expect(openwopCost!.usd!, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
201
203
  'observability.md §openwop.cost.usd',
202
204
  'usd MUST be >= 0',
203
205
  )).toBeGreaterThanOrEqual(0);
@@ -209,7 +211,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
209
211
  workflowId: 'openwop-smoke-cost-emit',
210
212
  });
211
213
  if (create.status === 404 || create.status === 422) {
212
- return;
214
+ return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (seam, prior step, or fixture unavailable)');
213
215
  }
214
216
  expect(create.status).toBe(201);
215
217
  const runId = (create.json as { runId: string }).runId;
@@ -224,7 +226,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
224
226
  const completed = events.filter(
225
227
  (e) => e.type === 'node.completed' && e.nodeId === 'emit-cost',
226
228
  );
227
- expect(completed.length, driver.describe(
229
+ expect(completed.length, req('openwop.it.cost-attribution.cost-emit-fixture-run-must-emit-a-node-completed-event-for-the-cost-emitting-nod',
228
230
  'event-log.md §node.completed',
229
231
  'cost-emit fixture node MUST emit exactly one node.completed event',
230
232
  )).toBe(1);
@@ -247,7 +249,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
247
249
  if (!getCollector()) {
248
250
  // eslint-disable-next-line no-console
249
251
  console.warn('[cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run');
250
- return;
252
+ return softSkip('blocked', 'precondition not met — `!getCollector()` returned early ([cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run) (seam, prior step, or fixture unavailable)');
251
253
  }
252
254
  const collector = getCollector()!;
253
255
  collector.reset();
@@ -258,7 +260,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
258
260
  await pollUntilTerminal(runId, { timeoutMs: 15_000 });
259
261
 
260
262
  const runSpans = await waitForRunSpans(runId, { timeoutMs: 5_000, minCount: 1 });
261
- expect(runSpans.length, driver.describe(
263
+ expect(runSpans.length, req('openwop.it.cost-attribution.only-allowlisted-openwop-cost-attributes-reach-the-otel-span-g6-close-criteria-a',
262
264
  'observability.md §"Span attributes"',
263
265
  'host MUST emit at least one span for the cost-emit run',
264
266
  )).toBeGreaterThan(0);
@@ -276,7 +278,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
276
278
  }
277
279
  }
278
280
  }
279
- expect(stray, driver.describe(
281
+ expect(stray, req('openwop.it.cost-attribution.only-allowlisted-openwop-cost-attributes-reach-the-otel-span-g6-close-criteria-a',
280
282
  'observability.md §"Cost attribution attributes" (allowlist enforcement)',
281
283
  'host MUST NOT emit any openwop.cost.* attribute outside OPENWOP_COST_ATTRIBUTE_NAMES; defense-in-depth against accidental leakage of upstream provider fields under unfamiliar key names',
282
284
  )).toEqual([]);
@@ -286,7 +288,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
286
288
  if (!getCollector()) {
287
289
  // eslint-disable-next-line no-console
288
290
  console.warn('[cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run');
289
- return;
291
+ return softSkip('blocked', 'precondition not met — `!getCollector()` returned early ([cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run) (seam, prior step, or fixture unavailable)');
290
292
  }
291
293
  const collector = getCollector()!;
292
294
  collector.reset();
@@ -309,7 +311,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
309
311
 
310
312
  expect(
311
313
  corpus.includes('CANARY-openwop-CONFORMANCE-NEVER-SECRET'),
312
- driver.describe(
314
+ req('openwop.it.cost-attribution.credential-shaped-canaries-do-not-leak-to-any-otel-attribute-g6-close-criteria-r',
313
315
  'SECURITY/invariants.yaml cost-attribution-allowlist-redaction',
314
316
  'no canary plaintext substring may survive the allowlist sanitizer on its way to OTel spans',
315
317
  ),
@@ -320,7 +322,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
320
322
  // through non-canary keys that the allowlist still happens to let
321
323
  // through (none today, but the regression test is cheap).
322
324
  const byokMatches = corpus.match(CREDENTIAL_SHAPE_RE) ?? [];
323
- expect(byokMatches, driver.describe(
325
+ expect(byokMatches, req('openwop.it.cost-attribution.credential-shaped-canaries-do-not-leak-to-any-otel-attribute-g6-close-criteria-r',
324
326
  'SECURITY/invariants.yaml cost-attribution-allowlist-redaction',
325
327
  'no credential-shape substring may appear in cost-attribute span values',
326
328
  )).toEqual([]);
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
28
28
  import { softSkip } from '../lib/soft-skip.js';
29
29
  import { driver } from '../lib/driver.js';
30
30
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
31
+ import { req } from '../lib/requirement-ids.js';
31
32
 
32
33
  interface DiscoveryCredentials {
33
34
  supported?: boolean;
@@ -54,7 +55,7 @@ describe('credential-payload-redaction: advertisement shape (RFC 0046 §A)', ()
54
55
  if (cred === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cred === null` returned early');
55
56
  expect(
56
57
  typeof cred.supported,
57
- driver.describe(
58
+ req('openwop.it.credential-payload-redaction.capabilities-credentials-supported-is-a-boolean-when-advertised',
58
59
  'capabilities.schema.json §credentials',
59
60
  'capabilities.credentials.supported MUST be a boolean when credentials is advertised',
60
61
  ),
@@ -75,7 +76,7 @@ describe('credential-payload-redaction: resolved material MUST NOT cross the wir
75
76
 
76
77
  expect(
77
78
  res.status,
78
- driver.describe(
79
+ req('openwop.it.credential-payload-redaction.canary-plaintext-is-absent-from-every-observable-run-surface',
79
80
  'SECURITY/invariants.yaml credential-payload-redaction',
80
81
  'the credentials echo seam MUST resolve the seeded credential and return its observable surfaces',
81
82
  ),
@@ -86,7 +87,7 @@ describe('credential-payload-redaction: resolved material MUST NOT cross the wir
86
87
  const serialized = JSON.stringify(res.json ?? {});
87
88
  expect(
88
89
  serialized.includes(CANARY),
89
- driver.describe(
90
+ req('openwop.it.credential-payload-redaction.canary-plaintext-is-absent-from-every-observable-run-surface',
90
91
  'SECURITY/invariants.yaml credential-payload-redaction',
91
92
  'resolved credential material MUST NOT appear in inputs, variables, channels, events, snapshot, or debug bundle — only the reference may cross the wire',
92
93
  ),
@@ -23,6 +23,7 @@ import { describe, it, expect } from 'vitest';
23
23
  import { softSkip } from '../lib/soft-skip.js';
24
24
  import { driver } from '../lib/driver.js';
25
25
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
26
+ import { req } from '../lib/requirement-ids.js';
26
27
 
27
28
  interface DiscoveryCredentials {
28
29
  supported?: boolean;
@@ -53,7 +54,7 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
53
54
  if (cred === null) return softSkip('inapplicable', 'host doesn\'t advertise host.credentials at all');
54
55
  expect(
55
56
  typeof cred.supported,
56
- driver.describe(
57
+ req('openwop.it.credentials-capability-shape.capabilities-credentials-is-either-absent-or-well-formed',
57
58
  'capabilities.schema.json §credentials',
58
59
  'capabilities.credentials.supported MUST be a boolean when credentials is advertised',
59
60
  ),
@@ -65,12 +66,12 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
65
66
  if (!cred?.supported || cred.scopes === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cred?.supported || cred.scopes === undefined` returned early');
66
67
  expect(
67
68
  Array.isArray(cred.scopes),
68
- driver.describe('RFC 0046 §A', 'capabilities.credentials.scopes MUST be an array'),
69
+ req('openwop.it.credentials-capability-shape.scopes-is-a-subset-of-user-workspace-tenant-when-supported', 'RFC 0046 §A', 'capabilities.credentials.scopes MUST be an array'),
69
70
  ).toBe(true);
70
71
  for (const scope of cred.scopes) {
71
72
  expect(
72
73
  VALID_SCOPES.has(scope),
73
- driver.describe(
74
+ req('openwop.it.credentials-capability-shape.scopes-is-a-subset-of-user-workspace-tenant-when-supported',
74
75
  'RFC 0046 §A',
75
76
  `capabilities.credentials.scopes entries MUST be one of {${[...VALID_SCOPES].join(', ')}}, got: ${scope}`,
76
77
  ),
@@ -83,7 +84,7 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
83
84
  if (!cred?.supported || cred.rotation === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cred?.supported || cred.rotation === undefined` returned early');
84
85
  expect(
85
86
  VALID_ROTATION.has(cred.rotation),
86
- driver.describe(
87
+ req('openwop.it.credentials-capability-shape.rotation-is-one-of-none-two-key-overlap-when-present',
87
88
  'RFC 0046 §A',
88
89
  `capabilities.credentials.rotation MUST be one of {${[...VALID_ROTATION].join(', ')}}, got: ${cred.rotation}`,
89
90
  ),
@@ -32,6 +32,7 @@ import { describe, it, expect } from 'vitest';
32
32
  import { softSkip, seamAbsent } from '../lib/soft-skip.js';
33
33
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
34
34
  import { driver } from '../lib/driver.js';
35
+ import { req } from '../lib/requirement-ids.js';
35
36
 
36
37
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
37
38
 
@@ -92,7 +93,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
92
93
  if (resetStatus === 404) {
93
94
  await noteHarnessAbsent();
94
95
  ctx.skip(); // host doesn't expose the cross-engine harness seam
95
- return;
96
+ return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
96
97
  }
97
98
  expect(resetStatus).toBe(200);
98
99
 
@@ -115,7 +116,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
115
116
 
116
117
  expect(
117
118
  read.entries.length,
118
- driver.describe(
119
+ req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
119
120
  'channels-and-reducers.md §"Cross-engine ordering"',
120
121
  'all appends across all engines MUST appear in the linearized read',
121
122
  ),
@@ -126,14 +127,14 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
126
127
  const engineBEntries = read.entries.filter((e) => e.engineId === 'engine-B').map((e) => e.value);
127
128
  expect(
128
129
  engineAEntries,
129
- driver.describe(
130
+ req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
130
131
  'channels-and-reducers.md §"Cross-engine ordering"',
131
132
  'engine-A submissions MUST appear in submission order within the linearization',
132
133
  ),
133
134
  ).toEqual(['a-1', 'a-2', 'a-3']);
134
135
  expect(
135
136
  engineBEntries,
136
- driver.describe(
137
+ req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
137
138
  'channels-and-reducers.md §"Cross-engine ordering"',
138
139
  'engine-B submissions MUST appear in submission order within the linearization',
139
140
  ),
@@ -145,7 +146,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
145
146
  if (resetStatus === 404) {
146
147
  await noteHarnessAbsent();
147
148
  ctx.skip();
148
- return;
149
+ return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
149
150
  }
150
151
  expect(resetStatus).toBe(200);
151
152
 
@@ -162,7 +163,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
162
163
  // channel MUST have strictly-higher clock than the previous.
163
164
  expect(
164
165
  a2.entry!.lamport > b1.entry!.lamport && b1.entry!.lamport > a1.entry!.lamport,
165
- driver.describe(
166
+ req('openwop.it.cross-engine-append-behavior.lamport-clocks-monotonically-advance-across-engines',
166
167
  'channels-and-reducers.md §"Cross-engine ordering" — Lamport',
167
168
  'lamport clocks MUST be strictly monotonic on the shared channel',
168
169
  ),
@@ -174,7 +175,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
174
175
  if (resetStatus === 404) {
175
176
  await noteHarnessAbsent();
176
177
  ctx.skip();
177
- return;
178
+ return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
178
179
  }
179
180
  expect(resetStatus).toBe(200);
180
181
 
@@ -190,7 +191,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
190
191
  expect(b1.status).toBe(200);
191
192
  expect(
192
193
  b1.entry!.lamport > seen,
193
- driver.describe(
194
+ req('openwop.it.cross-engine-append-behavior.lamport-hint-from-engine-a-advances-engine-b-past-it',
194
195
  'channels-and-reducers.md §"Cross-engine ordering" — Lamport receive rule',
195
196
  'when engine B sees engine A\'s clock at L, B\'s next append MUST have clock > L',
196
197
  ),
@@ -202,7 +203,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
202
203
  if (resetStatus === 404) {
203
204
  await noteHarnessAbsent();
204
205
  ctx.skip();
205
- return;
206
+ return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
206
207
  }
207
208
  expect(resetStatus).toBe(200);
208
209
 
@@ -217,7 +218,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
217
218
  expect(r2.status).toBe(200);
218
219
  expect(
219
220
  r1.entries.map((e) => `${e.engineId}:${String(e.value)}`),
220
- driver.describe(
221
+ req('openwop.it.cross-engine-append-behavior.linearization-is-deterministic-same-appends-same-total-order',
221
222
  'channels-and-reducers.md §"Cross-engine ordering" — determinism',
222
223
  'two reads MUST produce the same linearization (deterministic merge)',
223
224
  ),
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
28
28
  import { softSkip } from '../lib/soft-skip.js';
29
29
  import { driver } from '../lib/driver.js';
30
30
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
31
+ import { req } from '../lib/requirement-ids.js';
31
32
 
32
33
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
33
34
  const ORDERING_MODELS = new Set(['lamport', 'vector-clock', 'global-sequencer']);
@@ -62,7 +63,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
62
63
 
63
64
  expect(
64
65
  typeof ceo.supported,
65
- driver.describe(
66
+ req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
66
67
  'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
67
68
  'capabilities.eventLog.crossEngineOrdering.supported MUST be boolean when present',
68
69
  ),
@@ -71,7 +72,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
71
72
  if (ceo.orderingModel !== undefined) {
72
73
  expect(
73
74
  ORDERING_MODELS.has(ceo.orderingModel as string),
74
- driver.describe(
75
+ req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
75
76
  'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
76
77
  'orderingModel MUST be one of {lamport, vector-clock, global-sequencer}',
77
78
  ),
@@ -81,7 +82,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
81
82
  if (ceo.supported === true) {
82
83
  expect(
83
84
  ceo.orderingModel,
84
- driver.describe(
85
+ req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
85
86
  'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
86
87
  'when supported: true, orderingModel MUST be present (the categorical claim has no operational meaning without an advertised mechanism)',
87
88
  ),
@@ -37,6 +37,7 @@ import { describe, it, expect } from 'vitest';
37
37
  import { softSkip } from '../lib/soft-skip.js';
38
38
  import { driver } from '../lib/driver.js';
39
39
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
40
+ import { req } from '../lib/requirement-ids.js';
40
41
 
41
42
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
42
43
 
@@ -71,7 +72,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
71
72
  if (chc?.ancestryEndpointSupported !== true) {
72
73
  softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.ancestryEndpointSupported !== true` returned early');
73
74
  ctx.skip();
74
- return;
75
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.ancestryEndpointSupported !== true` returned early');
75
76
  }
76
77
 
77
78
  // Create a fresh top-level run via the host's conformance-dispatch-loop
@@ -81,33 +82,33 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
81
82
  if (create.status !== 201) {
82
83
  softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
83
84
  ctx.skip();
84
- return;
85
+ return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
85
86
  }
86
87
  const runId = (create.json as { runId: string }).runId;
87
88
 
88
89
  const ancestryRes = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/ancestry`);
89
- expect(ancestryRes.status, driver.describe(
90
+ expect(ancestryRes.status, req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr',
90
91
  'RFCS/0040-multi-agent-cross-host-causation.md §C',
91
92
  'host advertising ancestryEndpointSupported MUST serve the endpoint (200) — 404 is non-conformant',
92
93
  )).toBe(200);
93
94
 
94
95
  const body = ancestryRes.json as { runId?: string; hostId?: string; parent?: unknown };
95
- expect(body.runId, 'runId in response MUST match the request path').toBe(runId);
96
+ expect(body.runId, req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'runId in response MUST match the request path')).toBe(runId);
96
97
  expect(
97
98
  typeof body.hostId === 'string' && (body.hostId as string).length >= 1,
98
- 'hostId MUST be present + non-empty',
99
+ req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'hostId MUST be present + non-empty'),
99
100
  ).toBe(true);
100
101
  if (chc.hostId !== undefined) {
101
102
  expect(
102
103
  body.hostId,
103
- 'hostId in response MUST equal the host\'s advertised crossHostCausation.hostId',
104
+ req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'hostId in response MUST equal the host\'s advertised crossHostCausation.hostId'),
104
105
  ).toBe(chc.hostId);
105
106
  }
106
107
 
107
108
  // Top-level run: parent is null.
108
109
  expect(
109
110
  body.parent,
110
- driver.describe(
111
+ req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr',
111
112
  'RFCS/0040-multi-agent-cross-host-causation.md §C + schemas/run-ancestry-response.schema.json',
112
113
  'a top-level run (not dispatched from any other run) MUST return parent: null',
113
114
  ),
@@ -120,12 +121,12 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
120
121
  if (chc?.supported !== true) {
121
122
  softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.supported !== true` returned early');
122
123
  ctx.skip();
123
- return;
124
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.supported !== true` returned early');
124
125
  }
125
126
  if (chc.ancestryEndpointSupported === true) {
126
127
  softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc.ancestryEndpointSupported === true` returned early');
127
128
  ctx.skip(); // covered by the test above
128
- return;
129
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc.ancestryEndpointSupported === true` returned early');
129
130
  }
130
131
 
131
132
  // Use any runId — even a synthetic non-existent one. The endpoint should
@@ -133,7 +134,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
133
134
  const ancestryRes = await driver.get('/v1/runs/synthetic-test-run-id/ancestry');
134
135
  expect(
135
136
  ancestryRes.status,
136
- driver.describe(
137
+ req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-crosshostcausation-supported-but-not-ancestryendpointsupported',
137
138
  'spec/v1/multi-agent-execution.md §"GET /v1/runs/{runId}/ancestry endpoint"',
138
139
  'hosts that advertise crossHostCausation.supported: true but NOT ancestryEndpointSupported MUST return 404 — the endpoint is opt-in even within Phase 3',
139
140
  ),
@@ -29,6 +29,7 @@ import { describe, it, expect } from 'vitest';
29
29
  import { softSkip } from '../lib/soft-skip.js';
30
30
  import { driver } from '../lib/driver.js';
31
31
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
32
+ import { req } from '../lib/requirement-ids.js';
32
33
 
33
34
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
34
35
 
@@ -64,18 +65,18 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
64
65
  if (d === null) {
65
66
  softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
66
67
  ctx.skip();
67
- return;
68
+ return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
68
69
  }
69
70
  const chc = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.crossHostCausation;
70
71
  if (chc === undefined) {
71
72
  softSkip('inapplicable', 'optional advertisement — `multiAgent.executionModel.crossHostCausation` not advertised by this host (RFC 0040 §D)');
72
73
  ctx.skip(); // host doesn't advertise — soft-skip
73
- return;
74
+ return softSkip('blocked', 'precondition not met — `chc === undefined` returned early (seam, prior step, or fixture unavailable)');
74
75
  }
75
76
 
76
77
  expect(
77
78
  typeof chc.supported,
78
- driver.describe(
79
+ req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
79
80
  'RFCS/0040-multi-agent-cross-host-causation.md §D',
80
81
  'crossHostCausation.supported MUST be boolean when present',
81
82
  ),
@@ -85,7 +86,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
85
86
  const version = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.version as number | undefined;
86
87
  expect(
87
88
  typeof version === 'number' && version >= 3,
88
- driver.describe(
89
+ req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
89
90
  'RFCS/0040-multi-agent-cross-host-causation.md §D',
90
91
  'when crossHostCausation.supported: true, multiAgent.executionModel.version MUST be >= 3',
91
92
  ),
@@ -93,7 +94,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
93
94
 
94
95
  expect(
95
96
  typeof chc.hostId === 'string' && (chc.hostId as string).length >= 1,
96
- driver.describe(
97
+ req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
97
98
  'RFCS/0040-multi-agent-cross-host-causation.md §D',
98
99
  'when crossHostCausation.supported: true, hostId MUST be present + non-empty',
99
100
  ),
@@ -103,7 +104,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
103
104
  if (chc.ancestryEndpointSupported !== undefined) {
104
105
  expect(
105
106
  typeof chc.ancestryEndpointSupported,
106
- driver.describe(
107
+ req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
107
108
  'RFCS/0040-multi-agent-cross-host-causation.md §D',
108
109
  'ancestryEndpointSupported MUST be boolean when present',
109
110
  ),
@@ -23,6 +23,7 @@
23
23
  import { describe, it, expect } from 'vitest';
24
24
  import { softSkip } from '../lib/soft-skip.js';
25
25
  import { driver } from '../lib/driver.js';
26
+ import { req } from '../lib/requirement-ids.js';
26
27
 
27
28
  const ISOLATION_CODES: ReadonlySet<string> = new Set(['run_forbidden', 'not_found']);
28
29
 
@@ -41,7 +42,7 @@ describe('cross-workspace-isolation: run-ownership echo shape (RFC 0048 §C)', (
41
42
  if (owner === undefined) return softSkip('blocked', 'single-tenant host — owner omitted (owner === undefined)');
42
43
  expect(
43
44
  typeof owner.tenant === 'string' && owner.tenant.length > 0,
44
- driver.describe('RFC 0048 §C', 'RunSnapshot.owner MUST carry a non-empty tenant when present'),
45
+ req('openwop.it.cross-workspace-isolation.owner-when-present-on-a-run-snapshot-carries-a-non-empty-tenant', 'RFC 0048 §C', 'RunSnapshot.owner MUST carry a non-empty tenant when present'),
45
46
  ).toBe(true);
46
47
  });
47
48
  });
@@ -55,7 +56,7 @@ describe('cross-workspace-isolation: a principal MUST NOT read another workspace
55
56
 
56
57
  expect(
57
58
  res.status,
58
- driver.describe(
59
+ req('openwop.it.cross-workspace-isolation.cross-workspace-read-fails-closed-with-run-forbidden',
59
60
  'spec/v1/auth.md §Identity claims',
60
61
  'a cross-workspace read MUST fail closed (4xx), never return the other workspace\'s run',
61
62
  ),
@@ -64,7 +65,7 @@ describe('cross-workspace-isolation: a principal MUST NOT read another workspace
64
65
  const code = (res.json as { error?: string } | undefined)?.error;
65
66
  expect(
66
67
  code !== undefined && ISOLATION_CODES.has(code),
67
- driver.describe(
68
+ req('openwop.it.cross-workspace-isolation.cross-workspace-read-fails-closed-with-run-forbidden',
68
69
  'spec/v1/rest-endpoints.md run_forbidden',
69
70
  `error MUST be one of {${[...ISOLATION_CODES].join(', ')}} (fail-closed, no existence leak), got: ${code ?? '(absent)'}`,
70
71
  ),
@@ -45,6 +45,7 @@ import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
45
45
  import { driver } from '../lib/driver.js';
46
46
  import { behaviorGate } from '../lib/behavior-gate.js';
47
47
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
48
+ import { req } from '../lib/requirement-ids.js';
48
49
 
49
50
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
50
51
 
@@ -52,31 +53,31 @@ describe('data-residency: schema + error registration (always-on, server-free)',
52
53
  it('capabilities.dataResidency requires `supported` (const true) + `regions`, closed', () => {
53
54
  const caps = JSON.parse(readFileSync(join(SCHEMAS_DIR, 'capabilities.schema.json'), 'utf8'));
54
55
  const fam = caps.properties?.dataResidency;
55
- expect(fam, 'capabilities.schema.json MUST define the dataResidency family (RFC 0129 §1)').toBeDefined();
56
- expect(fam.additionalProperties, 'dataResidency MUST close its shape').toBe(false);
56
+ expect(fam, req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'capabilities.schema.json MUST define the dataResidency family (RFC 0129 §1)')).toBeDefined();
57
+ expect(fam.additionalProperties, req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'dataResidency MUST close its shape')).toBe(false);
57
58
  expect(fam.required?.sort()).toEqual(['regions', 'supported']);
58
59
  const ajv = new Ajv2020({ allErrors: true, strict: false });
59
60
  const vf = ajv.compile(fam);
60
- expect(vf({ supported: true, regions: ['eu', 'us'] }), 'the canonical advert MUST validate').toBe(true);
61
- expect(vf({ supported: true }), 'an advert without `regions` MUST fail').toBe(false);
62
- expect(vf({ regions: ['eu'] }), 'an advert without `supported` MUST fail').toBe(false);
63
- expect(vf({ supported: false, regions: ['eu'] }), 'dataResidency.supported is const true — false MUST fail').toBe(false);
61
+ expect(vf({ supported: true, regions: ['eu', 'us'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'the canonical advert MUST validate')).toBe(true);
62
+ expect(vf({ supported: true }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'an advert without `regions` MUST fail')).toBe(false);
63
+ expect(vf({ regions: ['eu'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'an advert without `supported` MUST fail')).toBe(false);
64
+ expect(vf({ supported: false, regions: ['eu'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'dataResidency.supported is const true — false MUST fail')).toBe(false);
64
65
  });
65
66
 
66
67
  it('residency.schema.json requires `region` and closes its shape', () => {
67
68
  const ajv = new Ajv2020({ allErrors: true, strict: false });
68
69
  addFormats(ajv);
69
70
  const validate = ajv.compile(JSON.parse(readFileSync(join(SCHEMAS_DIR, 'residency.schema.json'), 'utf8')));
70
- expect(validate({ region: 'eu' }), 'RFC 0129 §2 — a `{region}` residency constraint MUST validate').toBe(true);
71
- expect(validate({}), 'RFC 0129 §2 — `region` is REQUIRED').toBe(false);
72
- expect(validate({ region: 'eu', extra: 1 }), 'residency MUST be closed (additionalProperties:false)').toBe(false);
71
+ expect(validate({ region: 'eu' }), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'RFC 0129 §2 — a `{region}` residency constraint MUST validate')).toBe(true);
72
+ expect(validate({}), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'RFC 0129 §2 — `region` is REQUIRED')).toBe(false);
73
+ expect(validate({ region: 'eu', extra: 1 }), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'residency MUST be closed (additionalProperties:false)')).toBe(false);
73
74
  });
74
75
 
75
76
  it.skipIf(V1_DIR === null)('residency_unavailable is registered in the rest-endpoints error prose', () => {
76
77
  const rest = readFileSync(join(V1_DIR as string, 'rest-endpoints.md'), 'utf8');
77
78
  expect(
78
79
  rest.includes('`residency_unavailable`'),
79
- 'rest-endpoints.md §"Common error codes" MUST register `residency_unavailable` (RFC 0129 §3)',
80
+ req('openwop.it.data-residency-admission.residency-unavailable-is-registered-in-the-rest-endpoints-error-prose', 'RFC 0129', 'rest-endpoints.md §"Common error codes" MUST register `residency_unavailable` (RFC 0129 §3)'),
80
81
  ).toBe(true);
81
82
  });
82
83
  });
@@ -99,7 +100,7 @@ describe.skipIf(HTTP_SKIP)('data-residency: admission control (capability-gated,
99
100
  // region with residency_unavailable. That specific pairing is the violation.
100
101
  expect(
101
102
  readErrorCode(ok.json) !== 'residency_unavailable',
102
- driver.describe(
103
+ req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
103
104
  'capabilities.md §dataResidency / RFC 0129 §3',
104
105
  `an ADVERTISED region ("${advertised}") MUST NOT be rejected with residency_unavailable (accept iff advertised) — got ${ok.status} ${JSON.stringify(ok.json).slice(0, 200)}`,
105
106
  ),
@@ -118,21 +119,21 @@ describe.skipIf(HTTP_SKIP)('data-residency: admission control (capability-gated,
118
119
 
119
120
  expect(
120
121
  rej.status === 400 || rej.status === 404 || rej.status === 422,
121
- driver.describe(
122
+ req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
122
123
  'rest-endpoints.md §residency_unavailable',
123
124
  `an unadvertised region MUST be rejected at HTTP one-of 400/404/422 (envelope-not-status, #815) — got ${rej.status}`,
124
125
  ),
125
126
  ).toBe(true);
126
127
  expect(
127
128
  readErrorCode(rej.json) === 'residency_unavailable',
128
- driver.describe(
129
+ req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
129
130
  'RFC 0129 §3',
130
131
  `an unadvertised region MUST be rejected with error code "residency_unavailable" (MUST NOT silently accept-and-ignore) — got ${JSON.stringify(rej.json).slice(0, 200)}`,
131
132
  ),
132
133
  ).toBe(true);
133
134
  expect(
134
135
  rejBody?.runId === undefined,
135
- driver.describe('RFC 0129 §3', 'a rejected residency request MUST create NO run (no runId in the response)'),
136
+ req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav', 'RFC 0129 §3', 'a rejected residency request MUST create NO run (no runId in the response)'),
136
137
  ).toBe(true);
137
138
  });
138
139
  });