@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
@@ -29,6 +29,8 @@ import { behaviorGate } from '../lib/behavior-gate.js';
29
29
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
30
30
  import { getA2AFakePeer } from '../lib/a2a-fake-peer.js';
31
31
  import { readErrorCode } from '../lib/error-envelope.js';
32
+ import { req } from '../lib/requirement-ids.js';
33
+ import { softSkip } from '../lib/soft-skip.js';
32
34
 
33
35
  /**
34
36
  * Callback-shaped: the host issues A2A calls to the suite's fake peer, which records the negotiated version header.
@@ -63,7 +65,7 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
63
65
  const caps = await a2a();
64
66
  expect(
65
67
  caps?.protocolVersions ?? [],
66
- driver.describe(
68
+ req('openwop.it.a2a-version-negotiation.the-advertised-preferred-version-is-one-the-host-actually-claims',
67
69
  'RFCS/0152-a2a-1-0-versioned-composition.md §A',
68
70
  '`preferredVersion` MUST be present in `protocolVersions`. Preferring a version you do ' +
69
71
  'not list is a claim no peer can act on.',
@@ -74,28 +76,28 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
74
76
  it('outbound calls carry an explicit A2A-Version header', async () => {
75
77
  if (!behaviorGate(PROFILE, await negotiationAdvertised())) return;
76
78
  const peer = getA2AFakePeer();
77
- if (peer === null) return; // no fake peer wired in this run
79
+ if (peer === null) return softSkip('blocked', 'precondition not met — `peer === null` returned early (no fake peer wired in this run) (seam, prior step, or fixture unavailable)'); // no fake peer wired in this run
78
80
  peer.reset();
79
81
  const drive = await driver.post('/v1/host/sample/a2a/invoke', { peerUrl: peer.endpoint() });
80
82
  if (drive.status === 404 || drive.status === 403) {
81
83
  // Seam absent. RFC 0148 §A: unobservable resolves to `blocked`, not a pass.
82
84
  expect(
83
85
  drive.status,
84
- driver.describe(
86
+ req('openwop.it.a2a-version-negotiation.outbound-calls-carry-an-explicit-a2a-version-header',
85
87
  'RFCS/0152 §B',
86
88
  'a host advertising A2A version negotiation MUST expose an invoke seam so the negotiated ' +
87
89
  'version is observable. Without it the requirement cannot be witnessed and resolves to ' +
88
90
  '`blocked` per RFC 0148 §A.',
89
91
  ),
90
92
  ).not.toBe(404);
91
- return;
93
+ return softSkip('blocked', 'precondition not met — `drive.status === 404 || drive.status === 403` returned early (seam, prior step, or fixture unavailable)');
92
94
  }
93
95
  const calls = peer.invocations().filter((i: { method: string }) => i.method !== 'GET');
94
- expect(calls.length, 'the host MUST have called the peer').toBeGreaterThan(0);
96
+ expect(calls.length, req('openwop.it.a2a-version-negotiation.outbound-calls-carry-an-explicit-a2a-version-header', 'RFCS/0152 §B', 'the host MUST have called the peer')).toBeGreaterThan(0);
95
97
  for (const c of calls) {
96
98
  expect(
97
99
  c.headers['a2a-version'],
98
- driver.describe(
100
+ req('openwop.it.a2a-version-negotiation.outbound-calls-carry-an-explicit-a2a-version-header',
99
101
  'RFCS/0152 §B',
100
102
  'the sender MUST send `A2A-Version`. An absent header leaves the receiver guessing, and ' +
101
103
  'a guess that happens to be right is not a negotiation.',
@@ -107,7 +109,7 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
107
109
  it('an authenticated request is not silently downgraded', async () => {
108
110
  if (!behaviorGate(PROFILE, await negotiationAdvertised())) return;
109
111
  const peer = getA2AFakePeer();
110
- if (peer === null) return;
112
+ if (peer === null) return softSkip('blocked', 'precondition not met — `peer === null` returned early (seam, prior step, or fixture unavailable)');
111
113
  const caps = await a2a();
112
114
  const preferred = caps?.preferredVersion;
113
115
  peer.reset();
@@ -116,7 +118,7 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
116
118
  authenticated: true,
117
119
  peerOffersOnly: '0.3',
118
120
  });
119
- if (drive.status === 404 || drive.status === 403) return; // covered above
121
+ if (drive.status === 404 || drive.status === 403) return softSkip('blocked', 'precondition not met — `drive.status === 404 || drive.status === 403` returned early (covered above) (seam, prior step, or fixture unavailable)'); // covered above
120
122
 
121
123
  // THE load-bearing leg. A silent downgrade is dangerous precisely because it
122
124
  // SUCCEEDS: the caller believes it negotiated `preferred`, the peer answered
@@ -127,7 +129,7 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
127
129
  const negotiated = (drive.json as { negotiatedVersion?: string }).negotiatedVersion;
128
130
  expect(
129
131
  negotiated,
130
- driver.describe(
132
+ req('openwop.it.a2a-version-negotiation.an-authenticated-request-is-not-silently-downgraded',
131
133
  'RFCS/0152 §B',
132
134
  'a host that proceeds after a downgrade MUST report the version it actually negotiated. ' +
133
135
  'Reporting the preferred version while having used a lower one is the silent downgrade ' +
@@ -138,7 +140,7 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
138
140
  for (const c of calls) {
139
141
  expect(
140
142
  c.headers['a2a-version'],
141
- driver.describe('RFCS/0152 §B', 'the wire header MUST match the reported negotiated version'),
143
+ req('openwop.it.a2a-version-negotiation.an-authenticated-request-is-not-silently-downgraded', 'RFCS/0152 §B', 'the wire header MUST match the reported negotiated version'),
142
144
  ).toBe(negotiated);
143
145
  }
144
146
  }
@@ -147,18 +149,18 @@ describe('RFC 0152 §B — A2A version negotiation', () => {
147
149
  it('an unsupported version fails through the canonical interop error envelope', async () => {
148
150
  if (!behaviorGate(PROFILE, await negotiationAdvertised())) return;
149
151
  const peer = getA2AFakePeer();
150
- if (peer === null) return;
152
+ if (peer === null) return softSkip('blocked', 'precondition not met — `peer === null` returned early (seam, prior step, or fixture unavailable)');
151
153
  const drive = await driver.post('/v1/host/sample/a2a/invoke', {
152
154
  peerUrl: peer.endpoint(),
153
155
  requestVersion: '99.0',
154
156
  });
155
- if (drive.status === 404 || drive.status === 403) return;
156
- expect(drive.status >= 400, driver.describe('RFCS/0152 §B', 'an unsupported version MUST fail')).toBe(true);
157
+ if (drive.status === 404 || drive.status === 403) return softSkip('blocked', 'precondition not met — `drive.status === 404 || drive.status === 403` returned early (seam, prior step, or fixture unavailable)');
158
+ expect(drive.status >= 400, req('openwop.it.a2a-version-negotiation.an-unsupported-version-fails-through-the-canonical-interop-error-envelope', 'RFCS/0152 §B', 'an unsupported version MUST fail')).toBe(true);
157
159
  // S28: canonical envelope is FLAT (`error: "<code>"`, error-envelope.schema.json);
158
160
  // the nested `error.code` is tolerated by the lib only through the deprecation window.
159
161
  expect(
160
162
  readErrorCode(drive.json),
161
- driver.describe(
163
+ req('openwop.it.a2a-version-negotiation.an-unsupported-version-fails-through-the-canonical-interop-error-envelope',
162
164
  'RFCS/0152 §B',
163
165
  'the upstream version error MUST be projected through the canonical OpenWOP interop error ' +
164
166
  'envelope when the failure crosses an OpenWOP boundary — a raw upstream body leaves the ' +
@@ -17,6 +17,8 @@
17
17
 
18
18
  import { describe, it, expect } from 'vitest';
19
19
  import { driver } from '../lib/driver.js';
20
+ import { req } from '../lib/requirement-ids.js';
21
+ import { softSkip } from '../lib/soft-skip.js';
20
22
 
21
23
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
22
24
  const UNIVERSAL_KINDS = ['clarification.request', 'schema.request', 'schema.response', 'error'];
@@ -25,7 +27,7 @@ describe('a2ui-surface-degrades: optional-advertised, not universal (RFC 0102 §
25
27
  it('ui.a2ui-surface is NOT a MUST-recognize universal kind', () => {
26
28
  expect(
27
29
  UNIVERSAL_KINDS.includes('ui.a2ui-surface'),
28
- 'ai-envelope.md §"A2UI surfaces": ui.a2ui-surface MUST be optional/advertised so an unrecognizing consumer may store-without-render',
30
+ req('openwop.it.a2ui-surface-degrades.ui-a2ui-surface-is-not-a-must-recognize-universal-kind', 'RFC 0102 §A', 'ai-envelope.md §"A2UI surfaces": ui.a2ui-surface MUST be optional/advertised so an unrecognizing consumer may store-without-render'),
29
31
  ).toBe(false);
30
32
  });
31
33
  });
@@ -43,12 +45,12 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-degrades: unadvertised kind is gated, r
43
45
  },
44
46
  hostSupportedEnvelopes: ['clarification.request'], // does not advertise ui.a2ui-surface
45
47
  });
46
- if (res.status === 404) return; // seam absent — soft-skip
48
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
47
49
  expect(res.status).toBe(200);
48
50
  const body = res.json as { status?: string };
49
51
  expect(
50
52
  body.status,
51
- driver.describe('RFC 0102 §A (N6)', 'an unadvertised ui.a2ui-surface MUST be gated, never crash the run'),
53
+ req('openwop.it.a2ui-surface-degrades.posting-ui-a2ui-surface-to-a-host-that-does-not-advertise-it-gated-not-failed', 'RFC 0102 §A (N6)', 'an unadvertised ui.a2ui-surface MUST be gated, never crash the run'),
52
54
  ).toBe('gated');
53
55
  });
54
56
  });
@@ -47,6 +47,8 @@ import { join } from 'node:path';
47
47
  import { SCHEMAS_DIR } from '../lib/paths.js';
48
48
  import { driver } from '../lib/driver.js';
49
49
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
50
+ import { req } from '../lib/requirement-ids.js';
51
+ import { softSkip } from '../lib/soft-skip.js';
50
52
 
51
53
  const ajv = new Ajv2020({ strict: false, allErrors: true });
52
54
 
@@ -270,7 +272,7 @@ function fullSurfaceMaterializedAfterUpdates(): { [key: string]: JsonValue } {
270
272
 
271
273
  describe('a2ui-surface-delta-transport: frame schema + op set (RFC 0114)', () => {
272
274
  it('a2ui-surface-delta-frame.schema.json compiles under Ajv2020', () => {
273
- expect(validateFrame, 'RFC 0114: the delta-frame schema MUST compile').toBeTypeOf('function');
275
+ expect(validateFrame, req('openwop.it.a2ui-surface-delta-transport.a2ui-surface-delta-frame-schema-json-compiles-under-ajv2020', 'RFC 0114 §"Delta transport', 'RFC 0114: the delta-frame schema MUST compile')).toBeTypeOf('function');
274
276
  });
275
277
 
276
278
  it('accepts a positive delta frame', () => {
@@ -281,18 +283,18 @@ describe('a2ui-surface-delta-transport: frame schema + op set (RFC 0114)', () =>
281
283
  };
282
284
  expect(
283
285
  validateFrame(frame),
284
- `RFC 0114: a positive delta frame MUST validate; errors: ${JSON.stringify(validateFrame.errors)}`,
286
+ req('openwop.it.a2ui-surface-delta-transport.accepts-a-positive-delta-frame', 'RFC 0114 §"Delta transport', `RFC 0114: a positive delta frame MUST validate; errors: ${JSON.stringify(validateFrame.errors)}`),
285
287
  ).toBe(true);
286
288
  });
287
289
 
288
290
  it('rejects a frame missing the required `surfaceRef`/`catalogVersion`/`patch`', () => {
289
- expect(validateFrame({ catalogVersion: CATALOG_VERSION, patch: [{ op: 'replace', path: '/x' }] })).toBe(false);
291
+ expect(validateFrame({ catalogVersion: CATALOG_VERSION, patch: [{ op: 'replace', path: '/x' }] }), req('openwop.it.a2ui-surface-delta-transport.rejects-a-frame-missing-the-required-surfaceref-catalogversion-patch', 'RFC 0114 §"Delta transport', 'rejects a frame missing the required `surfaceRef`/`catalogVersion`/`patch`')).toBe(false);
290
292
  expect(validateFrame({ surfaceRef: 'e', patch: [{ op: 'replace', path: '/x' }] })).toBe(false);
291
293
  expect(validateFrame({ surfaceRef: 'e', catalogVersion: CATALOG_VERSION })).toBe(false);
292
294
  });
293
295
 
294
296
  it('rejects an empty patch (minItems: 1)', () => {
295
- expect(validateFrame({ surfaceRef: 'e', catalogVersion: CATALOG_VERSION, patch: [] })).toBe(false);
297
+ expect(validateFrame({ surfaceRef: 'e', catalogVersion: CATALOG_VERSION, patch: [] }), req('openwop.it.a2ui-surface-delta-transport.rejects-an-empty-patch-minitems-1', 'RFC 0114 §"Delta transport', 'rejects an empty patch (minItems: 1)')).toBe(false);
296
298
  });
297
299
 
298
300
  it('EXCLUDES the `test` op from the op enum', () => {
@@ -303,7 +305,7 @@ describe('a2ui-surface-delta-transport: frame schema + op set (RFC 0114)', () =>
303
305
  };
304
306
  expect(
305
307
  validateFrame(frame),
306
- 'RFC 0114: a fire-and-forget transport frame cannot act on a failed conditional; `test` is excluded',
308
+ req('openwop.it.a2ui-surface-delta-transport.excludes-the-test-op-from-the-op-enum', 'RFC 0114 §"Delta transport', 'RFC 0114: a fire-and-forget transport frame cannot act on a failed conditional; `test` is excluded'),
307
309
  ).toBe(false);
308
310
  });
309
311
 
@@ -313,7 +315,7 @@ describe('a2ui-surface-delta-transport: frame schema + op set (RFC 0114)', () =>
313
315
  catalogVersion: CATALOG_VERSION,
314
316
  patch: [{ op: 'replace', path: '/x', value: 1, onApply: "fetch('https://evil')" }],
315
317
  };
316
- expect(validateFrame(frame)).toBe(false);
318
+ expect(validateFrame(frame), req('openwop.it.a2ui-surface-delta-transport.rejects-a-patch-item-carrying-an-out-of-set-property-additionalproperties-false', 'RFC 0114 §"Delta transport', 'rejects a patch item carrying an out-of-set property (additionalProperties:false)')).toBe(false);
317
319
  });
318
320
  });
319
321
 
@@ -337,11 +339,11 @@ describe('a2ui-surface-delta-transport: full + deltas reconstruct the materializ
337
339
  ];
338
340
 
339
341
  for (const frame of frames) {
340
- expect(validateFrame(frame), `RFC 0114: each delta frame MUST validate; ${JSON.stringify(validateFrame.errors)}`).toBe(true);
342
+ expect(validateFrame(frame), req('openwop.it.a2ui-surface-delta-transport.a-full-surface-delta-frames-reconstruct-the-tree-and-equal-the-non-negotiating-f', 'RFC 0114 §"Delta transport', `RFC 0114: each delta frame MUST validate; ${JSON.stringify(validateFrame.errors)}`)).toBe(true);
341
343
  // catalogVersion on a delta MUST equal the referenced full surface's.
342
344
  expect(
343
345
  frame.catalogVersion,
344
- 'RFC 0114: a delta frame\'s catalogVersion MUST equal the referenced full surface\'s',
346
+ req('openwop.it.a2ui-surface-delta-transport.a-full-surface-delta-frames-reconstruct-the-tree-and-equal-the-non-negotiating-f', 'RFC 0114 §"Delta transport', 'RFC 0114: a delta frame\'s catalogVersion MUST equal the referenced full surface\'s'),
345
347
  ).toBe(full.catalogVersion);
346
348
  }
347
349
 
@@ -354,13 +356,13 @@ describe('a2ui-surface-delta-transport: full + deltas reconstruct the materializ
354
356
  // (a) the reconstruction equals the full surface a non-negotiating subscriber materializes.
355
357
  expect(
356
358
  reconstructed,
357
- 'RFC 0114: the delta reconstruction MUST equal the full surface the host materializes for a non-negotiating subscriber',
359
+ req('openwop.it.a2ui-surface-delta-transport.a-full-surface-delta-frames-reconstruct-the-tree-and-equal-the-non-negotiating-f', 'RFC 0114 §"Delta transport', 'RFC 0114: the delta reconstruction MUST equal the full surface the host materializes for a non-negotiating subscriber'),
358
360
  ).toEqual(fullSurfaceMaterializedAfterUpdates());
359
361
 
360
362
  // (b) the reconstruction re-validates against the closed catalog before render.
361
363
  expect(
362
364
  validateRecorded(reconstructed),
363
- `RFC 0114: the post-patch surface MUST re-validate against the closed catalog; ${JSON.stringify(validateRecorded.errors)}`,
365
+ req('openwop.it.a2ui-surface-delta-transport.a-full-surface-delta-frames-reconstruct-the-tree-and-equal-the-non-negotiating-f', 'RFC 0114 §"Delta transport', `RFC 0114: the post-patch surface MUST re-validate against the closed catalog; ${JSON.stringify(validateRecorded.errors)}`),
364
366
  ).toBe(true);
365
367
  });
366
368
  });
@@ -390,7 +392,7 @@ describe('a2ui-surface-delta-transport: out-of-catalog delta fails closed (RFC 0
390
392
  // The `a2ui-surface-no-code-exec` boundary holds on the post-patch surface.
391
393
  expect(
392
394
  validateRecorded(postPatch),
393
- 'RFC 0114 / a2ui-surface-no-code-exec: an out-of-catalog component reached by a delta MUST fail closed-catalog validation post-patch',
395
+ req('openwop.it.a2ui-surface-delta-transport.a-delta-that-add-s-an-out-of-catalog-component-yields-a-post-patch-surface-that', 'RFC 0114 §"Delta transport', 'RFC 0114 / a2ui-surface-no-code-exec: an out-of-catalog component reached by a delta MUST fail closed-catalog validation post-patch'),
394
396
  ).toBe(false);
395
397
  });
396
398
 
@@ -411,7 +413,7 @@ describe('a2ui-surface-delta-transport: out-of-catalog delta fails closed (RFC 0
411
413
  const postPatch = applyPatch(full, frame.patch);
412
414
  expect(
413
415
  validateRecorded(postPatch),
414
- 'RFC 0114: a delta MUST NOT be a path by which a smuggled code field reaches render',
416
+ req('openwop.it.a2ui-surface-delta-transport.a-delta-replace-smuggling-a-script-bearing-property-also-fails-closed-catalog-va', 'RFC 0114 §"Delta transport', 'RFC 0114: a delta MUST NOT be a path by which a smuggled code field reaches render'),
415
417
  ).toBe(false);
416
418
  });
417
419
  });
@@ -425,14 +427,14 @@ describe('a2ui-surface-delta-transport: the recorded envelope is always full (RF
425
427
  };
426
428
  expect(
427
429
  validateRecorded(frame),
428
- 'RFC 0114: the recorded envelope is NEVER a delta — a delta frame MUST NOT validate as a recorded ui.a2ui-surface payload',
430
+ req('openwop.it.a2ui-surface-delta-transport.a-delta-frame-does-not-validate-against-the-recorded-ui-a2ui-surface-envelope-sc', 'RFC 0114 §"Delta transport', 'RFC 0114: the recorded envelope is NEVER a delta — a delta frame MUST NOT validate as a recorded ui.a2ui-surface payload'),
429
431
  ).toBe(false);
430
432
  });
431
433
 
432
434
  it('the full surface validates as the recorded ui.a2ui-surface payload (event-log read / replay shape)', () => {
433
435
  expect(
434
436
  validateRecorded(fullSurfaceV0()),
435
- 'RFC 0114: the event-log read / replay always sees the FULL surface, which MUST validate as the recorded payload',
437
+ req('openwop.it.a2ui-surface-delta-transport.the-full-surface-validates-as-the-recorded-ui-a2ui-surface-payload-event-log-rea', 'RFC 0114 §"Delta transport', 'RFC 0114: the event-log read / replay always sees the FULL surface, which MUST validate as the recorded payload'),
436
438
  ).toBe(true);
437
439
  });
438
440
  });
@@ -507,9 +509,9 @@ async function getEvents(runId: string, deltaOptIn: boolean): Promise<unknown> {
507
509
  describe.skipIf(HTTP_SKIP)('a2ui-surface-delta-transport: live host delta transport (RFC 0114, gated)', () => {
508
510
  it('drives the emit-surface seam: a ?a2uiDelta=1 subscriber reconstruction equals the non-negotiating full', async () => {
509
511
  const disco = await driver.get('/.well-known/openwop');
510
- if (disco.status !== 200) return; // no discovery — soft-skip
512
+ if (disco.status !== 200) return softSkip('blocked', 'precondition not met — `disco.status !== 200` returned early (no discovery — soft-skip) (seam, prior step, or fixture unavailable)'); // no discovery — soft-skip
511
513
  const cap = capabilityFamily<A2uiSurfaceCap>(disco.json, 'a2uiSurface');
512
- if (cap?.deltaTransport !== true) return; // capability not advertised — soft-skip
514
+ if (cap?.deltaTransport !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.deltaTransport !== true` returned early (capability not advertised — soft-skip)'); // capability not advertised — soft-skip
513
515
 
514
516
  const runId = `conf-a2ui-delta-${Date.now()}`;
515
517
  const surfaceA = fullSurfaceV0();
@@ -517,53 +519,53 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-delta-transport: live host delta transp
517
519
 
518
520
  // Baseline (surface A) through the host's REAL surface-emit path.
519
521
  const emitA = await driver.post('/v1/host/sample/a2ui/emit-surface', { runId, surface: surfaceA });
520
- if (emitA.status === 404 || emitA.status === 405) return; // seam absent — soft-skip the live leg
522
+ if (emitA.status === 404 || emitA.status === 405) return softSkip('blocked', 'precondition not met — `emitA.status === 404 || emitA.status === 405` returned early (seam absent — soft-skip the live leg) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip the live leg
521
523
  expect(
522
524
  emitA.status,
523
- driver.describe('RFC 0114 §15', 'the emit-surface seam MUST record the baseline full surface'),
525
+ req('openwop.it.a2ui-surface-delta-transport.drives-the-emit-surface-seam-a-a2uidelta-1-subscriber-reconstruction-equals-the', 'RFC 0114 §15', 'the emit-surface seam MUST record the baseline full surface'),
524
526
  ).toBeLessThan(300);
525
527
 
526
528
  // Second full surface (surface B) — recorded full AND transported as a delta
527
529
  // to any ?a2uiDelta=1 subscriber.
528
530
  const emitB = await driver.post('/v1/host/sample/a2ui/emit-surface', { runId, surface: surfaceB });
529
- if (emitB.status === 404 || emitB.status === 405) return;
530
- expect(emitB.status, driver.describe('RFC 0114 §15', 'the second emit MUST succeed')).toBeLessThan(300);
531
+ if (emitB.status === 404 || emitB.status === 405) return softSkip('blocked', 'precondition not met — `emitB.status === 404 || emitB.status === 405` returned early (seam, prior step, or fixture unavailable)');
532
+ expect(emitB.status, req('openwop.it.a2ui-surface-delta-transport.drives-the-emit-surface-seam-a-a2uidelta-1-subscriber-reconstruction-equals-the', 'RFC 0114 §15', 'the second emit MUST succeed')).toBeLessThan(300);
531
533
  const refB = (emitB.json as EmitSurfaceResponse)?.surfaceRef;
532
534
 
533
535
  // ?a2uiDelta=1 subscriber: locate the delta frame the host transported.
534
536
  const deltaEvents = await getEvents(runId, true);
535
- if (deltaEvents === null) return; // events stream unavailable in JSON — soft-skip
537
+ if (deltaEvents === null) return softSkip('blocked', 'precondition not met — `deltaEvents === null` returned early (events stream unavailable in JSON — soft-skip) (seam, prior step, or fixture unavailable)'); // events stream unavailable in JSON — soft-skip
536
538
  const frames = collectMatching(deltaEvents, validateFrame)
537
539
  .map(readFrame)
538
540
  .filter((f): f is { surfaceRef: string; catalogVersion: string; patch: PatchOp[] } => f !== null)
539
541
  .filter((f) => refB === undefined || f.surfaceRef === refB);
540
- if (frames.length === 0) return; // host streams SSE-only or buffered the frame — soft-skip
542
+ if (frames.length === 0) return softSkip('blocked', 'precondition not met — `frames.length === 0` returned early (host streams SSE-only or buffered the frame — soft-skip) (seam, prior step, or fixture unavailable)'); // host streams SSE-only or buffered the frame — soft-skip
541
543
  const frame = frames[frames.length - 1];
542
544
 
543
545
  // catalogVersion on the delta MUST equal the baseline full surface's.
544
546
  expect(
545
547
  frame.catalogVersion,
546
- driver.describe('RFC 0114', 'a delta frame catalogVersion MUST equal the referenced full surface'),
548
+ req('openwop.it.a2ui-surface-delta-transport.drives-the-emit-surface-seam-a-a2uidelta-1-subscriber-reconstruction-equals-the', 'RFC 0114', 'a delta frame catalogVersion MUST equal the referenced full surface'),
547
549
  ).toBe(surfaceA.catalogVersion);
548
550
 
549
551
  // Reconstruct: apply the host's real delta to the baseline, re-validate against the closed catalog.
550
552
  const reconstructed = applyPatch(surfaceA, frame.patch);
551
553
  expect(
552
554
  validateRecorded(reconstructed),
553
- driver.describe('RFC 0114 §"Delta transport"', 'the post-patch surface MUST re-validate against the closed catalog'),
555
+ req('openwop.it.a2ui-surface-delta-transport.drives-the-emit-surface-seam-a-a2uidelta-1-subscriber-reconstruction-equals-the', 'RFC 0114 §"Delta transport"', 'the post-patch surface MUST re-validate against the closed catalog'),
554
556
  ).toBe(true);
555
557
 
556
558
  // Non-negotiating subscriber: the host materializes the FULL surface for the same update.
557
559
  const fullEvents = await getEvents(runId, false);
558
- if (fullEvents === null) return;
560
+ if (fullEvents === null) return softSkip('blocked', 'precondition not met — `fullEvents === null` returned early (seam, prior step, or fixture unavailable)');
559
561
  const fulls = collectMatching(fullEvents, validateRecorded);
560
- if (fulls.length === 0) return; // soft-skip — no full surface observed on the non-delta stream
562
+ if (fulls.length === 0) return softSkip('blocked', 'precondition not met — `fulls.length === 0` returned early (soft-skip — no full surface observed on the non-delta stream) (seam, prior step, or fixture unavailable)'); // soft-skip — no full surface observed on the non-delta stream
561
563
  const materializedFull = fulls[fulls.length - 1];
562
564
 
563
565
  // delta and full agree — the core RFC 0114 transport guarantee, witnessed live.
564
566
  expect(
565
567
  reconstructed,
566
- driver.describe(
568
+ req('openwop.it.a2ui-surface-delta-transport.drives-the-emit-surface-seam-a-a2uidelta-1-subscriber-reconstruction-equals-the',
567
569
  'RFC 0114 §"Delta transport"',
568
570
  'a ?a2uiDelta=1 reconstruction MUST equal the full surface a non-negotiating subscriber materializes',
569
571
  ),
@@ -572,14 +574,14 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-delta-transport: live host delta transp
572
574
 
573
575
  it('the emit-surface seam rejects an out-of-catalog surface fail-closed (real catalog gate)', async () => {
574
576
  const disco = await driver.get('/.well-known/openwop');
575
- if (disco.status !== 200) return;
577
+ if (disco.status !== 200) return softSkip('blocked', 'precondition not met — `disco.status !== 200` returned early (seam, prior step, or fixture unavailable)');
576
578
  const cap = capabilityFamily<A2uiSurfaceCap>(disco.json, 'a2uiSurface');
577
- if (cap?.deltaTransport !== true) return;
579
+ if (cap?.deltaTransport !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.deltaTransport !== true` returned early');
578
580
 
579
581
  const runId = `conf-a2ui-delta-oob-${Date.now()}`;
580
582
  const baseline = await driver.post('/v1/host/sample/a2ui/emit-surface', { runId, surface: fullSurfaceV0() });
581
- if (baseline.status === 404 || baseline.status === 405) return; // seam absent — soft-skip
582
- expect(baseline.status, driver.describe('RFC 0114 §15', 'baseline emit MUST succeed')).toBeLessThan(300);
583
+ if (baseline.status === 404 || baseline.status === 405) return softSkip('blocked', 'precondition not met — `baseline.status === 404 || baseline.status === 405` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
584
+ expect(baseline.status, req('openwop.it.a2ui-surface-delta-transport.the-emit-surface-seam-rejects-an-out-of-catalog-surface-fail-closed-real-catalog', 'RFC 0114 §15', 'baseline emit MUST succeed')).toBeLessThan(300);
583
585
 
584
586
  // An out-of-catalog surface MUST be rejected by the host's REAL closed-catalog
585
587
  // validator — no delta transported, the a2ui-surface-no-code-exec boundary holds.
@@ -588,10 +590,10 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-delta-transport: live host delta transp
588
590
  surface: { components: [{ component: 'iframe', src: 'https://evil.example/x' }] },
589
591
  };
590
592
  const rejected = await driver.post('/v1/host/sample/a2ui/emit-surface', { runId, surface: outOfCatalog });
591
- if (rejected.status === 404 || rejected.status === 405) return;
593
+ if (rejected.status === 404 || rejected.status === 405) return softSkip('blocked', 'precondition not met — `rejected.status === 404 || rejected.status === 405` returned early (seam, prior step, or fixture unavailable)');
592
594
  expect(
593
595
  rejected.status,
594
- driver.describe(
596
+ req('openwop.it.a2ui-surface-delta-transport.the-emit-surface-seam-rejects-an-out-of-catalog-surface-fail-closed-real-catalog',
595
597
  'RFC 0114 §15 / a2ui-surface-no-code-exec',
596
598
  'an out-of-catalog surface MUST be rejected fail-closed by the host real catalog validator',
597
599
  ),
@@ -21,6 +21,8 @@ import { readFileSync } from 'node:fs';
21
21
  import { join } from 'node:path';
22
22
  import { driver } from '../lib/driver.js';
23
23
  import { SCHEMAS_DIR } from '../lib/paths.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
24
26
 
25
27
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
26
28
  const schema = JSON.parse(
@@ -45,7 +47,7 @@ describe('a2ui-surface-replay: self-contained surface (RFC 0102 §A.6)', () => {
45
47
  const external = refs.filter((r) => !r.startsWith('#'));
46
48
  expect(
47
49
  external,
48
- 'RFC 0102 §A.6: a stored surface MUST be self-contained for deterministic :fork/replay (no live external-catalog ref)',
50
+ req('openwop.it.a2ui-surface-replay.all-refs-are-internal-surface-renders-from-the-payload-alone-on-replay', 'RFC 0102 §A.6', 'RFC 0102 §A.6: a stored surface MUST be self-contained for deterministic :fork/replay (no live external-catalog ref)'),
49
51
  ).toEqual([]);
50
52
  });
51
53
  });
@@ -63,7 +65,7 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-replay: correlationId conflict on type
63
65
  envelope: { ...base, type: 'ui.a2ui-surface', envelopeId: 'env-a2ui-rep-1' },
64
66
  hostSupportedEnvelopes: ['ui.a2ui-surface', 'clarification.request'],
65
67
  });
66
- if (first.status === 404) return; // seam absent — soft-skip
68
+ if (first.status === 404) return softSkip('blocked', 'precondition not met — `first.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
67
69
 
68
70
  const conflict = await driver.post('/v1/host/sample/envelope/accept', {
69
71
  envelope: {
@@ -74,11 +76,11 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-replay: correlationId conflict on type
74
76
  },
75
77
  hostSupportedEnvelopes: ['ui.a2ui-surface', 'clarification.request'],
76
78
  });
77
- if (conflict.status === 404) return;
79
+ if (conflict.status === 404) return softSkip('blocked', 'precondition not met — `conflict.status === 404` returned early (seam, prior step, or fixture unavailable)');
78
80
  const body = conflict.json as { status?: string; reason?: string };
79
81
  expect(
80
82
  body.reason ?? '',
81
- driver.describe('ai-envelope.md §"Replay determinism"', 'same correlationId + divergent type MUST conflict'),
83
+ req('openwop.it.a2ui-surface-replay.re-emission-with-same-correlationid-different-type-envelope-correlation-conflict', 'ai-envelope.md §"Replay determinism"', 'same correlationId + divergent type MUST conflict'),
82
84
  ).toContain('envelope_correlation_conflict');
83
85
  });
84
86
  });
@@ -31,6 +31,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
31
31
  import { readFileSync } from 'node:fs';
32
32
  import { join } from 'node:path';
33
33
  import { SCHEMAS_DIR } from '../lib/paths.js';
34
+ import { req } from '../lib/requirement-ids.js';
34
35
 
35
36
  const ajv = new Ajv2020({ strict: false, allErrors: true });
36
37
  const schema = JSON.parse(
@@ -70,7 +71,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
70
71
  it('ui.a2ui-surface.schema.json compiles under Ajv2020', () => {
71
72
  expect(
72
73
  validate,
73
- 'RFC 0102 §A: the core ui.a2ui-surface payload schema MUST compile',
74
+ req('openwop.it.a2ui-surface-shape.ui-a2ui-surface-schema-json-compiles-under-ajv2020', 'RFC 0102 §A', 'RFC 0102 §A: the core ui.a2ui-surface payload schema MUST compile'),
74
75
  ).toBeTypeOf('function');
75
76
  });
76
77
 
@@ -78,7 +79,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
78
79
  const ok = validate(positivePayload());
79
80
  expect(
80
81
  ok,
81
- `RFC 0102 §A: positive surface MUST validate; errors: ${JSON.stringify(validate.errors)}`,
82
+ req('openwop.it.a2ui-surface-shape.accepts-a-positive-surface-payload-closed-catalog-confined-action', 'RFC 0102 §A', `RFC 0102 §A: positive surface MUST validate; errors: ${JSON.stringify(validate.errors)}`),
82
83
  ).toBe(true);
83
84
  });
84
85
 
@@ -87,19 +88,19 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
87
88
  (p.surface as { components: Array<Record<string, unknown>> }).components = [
88
89
  { component: 'action.button', id: 'send', label: 'Send', action: { target: 'exchange' } },
89
90
  ];
90
- expect(validate(p)).toBe(true);
91
+ expect(validate(p), req('openwop.it.a2ui-surface-shape.accepts-an-exchange-targeted-action-the-other-confined-target', 'RFC 0102 §A', 'accepts an exchange-targeted action (the other confined target)')).toBe(true);
91
92
  });
92
93
 
93
94
  it('rejects a payload missing required `catalogVersion`', () => {
94
95
  const p = positivePayload();
95
96
  delete p.catalogVersion;
96
- expect(validate(p), 'RFC 0102 §A: `catalogVersion` is REQUIRED').toBe(false);
97
+ expect(validate(p), req('openwop.it.a2ui-surface-shape.rejects-a-payload-missing-required-catalogversion', 'RFC 0102 §A', 'RFC 0102 §A: `catalogVersion` is REQUIRED')).toBe(false);
97
98
  });
98
99
 
99
100
  it('rejects a payload missing required `surface`', () => {
100
101
  const p = positivePayload();
101
102
  delete p.surface;
102
- expect(validate(p), 'RFC 0102 §A: `surface` is REQUIRED').toBe(false);
103
+ expect(validate(p), req('openwop.it.a2ui-surface-shape.rejects-a-payload-missing-required-surface', 'RFC 0102 §A', 'RFC 0102 §A: `surface` is REQUIRED')).toBe(false);
103
104
  });
104
105
 
105
106
  it('rejects a `catalogVersion` the schema does not enumerate (unknown version)', () => {
@@ -107,7 +108,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
107
108
  p.catalogVersion = '9.9.9';
108
109
  expect(
109
110
  validate(p),
110
- 'RFC 0102 §A.3: an unadvertised catalogVersion MUST fail the enumerated set',
111
+ req('openwop.it.a2ui-surface-shape.rejects-a-catalogversion-the-schema-does-not-enumerate-unknown-version', 'RFC 0102 §A', 'RFC 0102 §A.3: an unadvertised catalogVersion MUST fail the enumerated set'),
111
112
  ).toBe(false);
112
113
  });
113
114
 
@@ -118,7 +119,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
118
119
  ];
119
120
  expect(
120
121
  validate(p),
121
- 'RFC 0102 §A.1: an out-of-catalog component MUST fail the closed anyOf',
122
+ req('openwop.it.a2ui-surface-shape.rejects-an-out-of-catalog-component-object-additionalproperties-false', 'RFC 0102 §A', 'RFC 0102 §A.1: an out-of-catalog component MUST fail the closed anyOf'),
122
123
  ).toBe(false);
123
124
  });
124
125
 
@@ -129,7 +130,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
129
130
  ];
130
131
  expect(
131
132
  validate(p),
132
- 'RFC 0102 §A.1: additionalProperties:false MUST reject a smuggled code field',
133
+ req('openwop.it.a2ui-surface-shape.rejects-a-known-component-carrying-an-extra-script-bearing-property', 'RFC 0102 §A', 'RFC 0102 §A.1: additionalProperties:false MUST reject a smuggled code field'),
133
134
  ).toBe(false);
134
135
  });
135
136
 
@@ -140,7 +141,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
140
141
  ];
141
142
  expect(
142
143
  validate(p),
143
- 'RFC 0102 §A.4 / SECURITY a2ui-action-confinement: an action target outside resume/exchange MUST be rejected',
144
+ req('openwop.it.a2ui-surface-shape.rejects-an-action-whose-target-is-outside-enum-resume-exchange-action-confinemen', 'RFC 0102 §A', 'RFC 0102 §A.4 / SECURITY a2ui-action-confinement: an action target outside resume/exchange MUST be rejected'),
144
145
  ).toBe(false);
145
146
  });
146
147
 
@@ -156,7 +157,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
156
157
  ];
157
158
  expect(
158
159
  validate(p),
159
- 'RFC 0102 §A.4: action additionalProperties:false MUST reject an arbitrary URL target',
160
+ req('openwop.it.a2ui-surface-shape.rejects-an-action-carrying-an-arbitrary-url-field-no-unconfined-egress-target', 'RFC 0102 §A', 'RFC 0102 §A.4: action additionalProperties:false MUST reject an arbitrary URL target'),
160
161
  ).toBe(false);
161
162
  });
162
163
  });
@@ -20,6 +20,8 @@ import { readFileSync } from 'node:fs';
20
20
  import { join } from 'node:path';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { SCHEMAS_DIR } from '../lib/paths.js';
23
+ import { req } from '../lib/requirement-ids.js';
24
+ import { softSkip } from '../lib/soft-skip.js';
23
25
 
24
26
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
25
27
  const schema = JSON.parse(
@@ -42,14 +44,14 @@ describe('a2ui-surface-version-refusal: enumerated catalogVersion (RFC 0102 §A.
42
44
  const ok = validate({ catalogVersion: '9.9.9', surface: { components: [] } });
43
45
  expect(
44
46
  ok,
45
- 'RFC 0102 §A.3: a catalogVersion outside the host-enumerated set MUST fail (→ unknown_schema_version at runtime)',
47
+ req('openwop.it.a2ui-surface-version-refusal.catalogversion-is-a-closed-enum-an-unadvertised-version-fails-validation', 'RFC 0102 §A.3', 'RFC 0102 §A.3: a catalogVersion outside the host-enumerated set MUST fail (→ unknown_schema_version at runtime)'),
46
48
  ).toBe(false);
47
49
  });
48
50
 
49
51
  it('surface payload is self-contained — no external $ref (replay determinism)', () => {
50
52
  expect(
51
53
  hasAbsoluteRef(schema),
52
- 'RFC 0102 §A.3: the surface MUST be self-contained, never a live external-catalog reference',
54
+ req('openwop.it.a2ui-surface-version-refusal.surface-payload-is-self-contained-no-external-ref-replay-determinism', 'RFC 0102 §A.3', 'RFC 0102 §A.3: the surface MUST be self-contained, never a live external-catalog reference'),
53
55
  ).toBe(false);
54
56
  });
55
57
  });
@@ -67,11 +69,11 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-version-refusal: live host refuses unad
67
69
  },
68
70
  hostSupportedEnvelopes: ['ui.a2ui-surface'],
69
71
  });
70
- if (res.status === 404) return; // seam absent — soft-skip
72
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
71
73
  const body = res.json as { status?: string; reason?: string };
72
74
  expect(
73
75
  body.status === 'invalid' || body.status === 'refused',
74
- driver.describe('RFC 0102 §A.3', 'an unadvertised catalogVersion MUST be refused'),
76
+ req('openwop.it.a2ui-surface-version-refusal.ui-a2ui-surface-with-an-unadvertised-catalogversion-refused', 'RFC 0102 §A.3', 'an unadvertised catalogVersion MUST be refused'),
75
77
  ).toBe(true);
76
78
  });
77
79
  });
@@ -21,6 +21,8 @@
21
21
 
22
22
  import { describe, it, expect } from 'vitest';
23
23
  import { driver } from '../lib/driver.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
24
26
 
25
27
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
26
28
  const UNIVERSAL_KINDS = ['clarification.request', 'schema.request', 'schema.response', 'error'];
@@ -29,7 +31,7 @@ describe('a2ui-untrusted-blocks-approval: trust machinery applies (RFC 0102 §A.
29
31
  it('ui.a2ui-surface is an advertised kind subject to meta.contentTrust gating (not universal/always-allowed)', () => {
30
32
  expect(
31
33
  UNIVERSAL_KINDS.includes('ui.a2ui-surface'),
32
- 'ai-envelope.md §"A2UI surfaces" / §"Trust boundary": a ui.a2ui-surface is trust-gated like any advertised envelope, so an untrusted surface is subject to untrusted_content_blocks_approval',
34
+ req('openwop.it.a2ui-untrusted-blocks-approval.ui-a2ui-surface-is-an-advertised-kind-subject-to-meta-contenttrust-gating-not-un', 'RFC 0102 §A.5', 'ai-envelope.md §"A2UI surfaces" / §"Trust boundary": a ui.a2ui-surface is trust-gated like any advertised envelope, so an untrusted surface is subject to untrusted_content_blocks_approval'),
33
35
  ).toBe(false);
34
36
  });
35
37
  });
@@ -55,11 +57,11 @@ describe.skipIf(HTTP_SKIP)('a2ui-untrusted-blocks-approval: untrusted surface ca
55
57
  hostSupportedEnvelopes: ['ui.a2ui-surface'],
56
58
  boundInterruptKind: 'approval',
57
59
  });
58
- if (res.status === 404) return; // seam absent — soft-skip
60
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
59
61
  const body = res.json as { status?: string; reason?: string };
60
62
  expect(
61
63
  body.status === 'blocked' || (body.reason ?? '').includes('untrusted'),
62
- driver.describe(
64
+ req('openwop.it.a2ui-untrusted-blocks-approval.an-untrusted-marked-ui-a2ui-surface-bound-to-an-approval-interrupt-is-refused',
63
65
  'RFC 0102 §A.5',
64
66
  'an untrusted ui.a2ui-surface MUST NOT advance an approval interrupt (untrusted_content_blocks_approval)',
65
67
  ),