@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
@@ -34,6 +34,7 @@
34
34
 
35
35
  import { describe, it, expect, beforeAll, afterAll } from 'vitest';
36
36
  import { A2AFakePeer } from '../lib/a2a-fake-peer.js';
37
+ import { req } from '../lib/requirement-ids.js';
37
38
 
38
39
  export const HOST_CALLBACK_NOT_REQUIRED = 'the suite drives both ends itself: it boots the dual-era A2AFakePeer in-process and reads its agent card directly; no host connection is originated';
39
40
 
@@ -57,24 +58,24 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
57
58
  expect(res.status).toBe(200);
58
59
  const card = (await res.json()) as Record<string, unknown>;
59
60
  const ifaces = card['supportedInterfaces'] as Array<{ url: string; protocolBinding: string; protocolVersion: string }>;
60
- expect(Array.isArray(ifaces) && ifaces.length > 0, '1.0 REQUIRES supportedInterfaces[]').toBe(true);
61
+ expect(Array.isArray(ifaces) && ifaces.length > 0, req('openwop.it.a2a-1-0-agent-card.the-agent-card-is-1-0-shaped-supportedinterfaces-no-top-level-url-protocolversio', 'RFC 0152 §A/§B/§C/§D', '1.0 REQUIRES supportedInterfaces[]')).toBe(true);
61
62
  expect(ifaces.map((i) => i.protocolVersion)).toEqual(['1.0', '0.3']);
62
63
  for (const i of ifaces) {
63
64
  expect(i.protocolBinding).toBe('JSONRPC');
64
65
  expect(i.url.startsWith(peer.endpoint())).toBe(true);
65
66
  }
66
- expect(card['url'], '1.0 removed top-level url').toBeUndefined();
67
- expect(card['protocolVersion'], '1.0 removed top-level protocolVersion (it is per interface)').toBeUndefined();
67
+ expect(card['url'], req('openwop.it.a2a-1-0-agent-card.the-agent-card-is-1-0-shaped-supportedinterfaces-no-top-level-url-protocolversio', 'RFC 0152 §A/§B/§C/§D', '1.0 removed top-level url')).toBeUndefined();
68
+ expect(card['protocolVersion'], req('openwop.it.a2a-1-0-agent-card.the-agent-card-is-1-0-shaped-supportedinterfaces-no-top-level-url-protocolversio', 'RFC 0152 §A/§B/§C/§D', '1.0 removed top-level protocolVersion (it is per interface)')).toBeUndefined();
68
69
  const caps = card['capabilities'] as Record<string, unknown>;
69
70
  expect(caps['extendedAgentCard']).toBe(false);
70
- expect(Array.isArray(card['skills']) && (card['skills'] as unknown[]).length > 0, 'skills[] REQUIRED').toBe(true);
71
- for (const k of ['name', 'description', 'version', 'defaultInputModes', 'defaultOutputModes']) expect(card[k], `${k} REQUIRED`).toBeDefined();
71
+ expect(Array.isArray(card['skills']) && (card['skills'] as unknown[]).length > 0, req('openwop.it.a2a-1-0-agent-card.the-agent-card-is-1-0-shaped-supportedinterfaces-no-top-level-url-protocolversio', 'RFC 0152 §A/§B/§C/§D', 'skills[] REQUIRED')).toBe(true);
72
+ for (const k of ['name', 'description', 'version', 'defaultInputModes', 'defaultOutputModes']) expect(card[k], req('openwop.it.a2a-1-0-agent-card.the-agent-card-is-1-0-shaped-supportedinterfaces-no-top-level-url-protocolversio', 'RFC 0152 §A/§B/§C/§D', `${k} REQUIRED`)).toBeDefined();
72
73
  });
73
74
 
74
75
  it('the card shape follows the era asked for: A2A-Version: 0.3 on the GET returns the 0.3 card from the same peer', async () => {
75
76
  const res = await fetch(`${peer.endpoint()}/.well-known/agent-card.json`, { headers: { 'A2A-Version': '0.3' } });
76
77
  const card = (await res.json()) as Record<string, unknown>;
77
- expect(card['protocolVersion']).toBe('0.3.0');
78
+ expect(card['protocolVersion'], req('openwop.it.a2a-1-0-agent-card.the-card-shape-follows-the-era-asked-for-a2a-version-0-3-on-the-get-returns-the', 'RFC 0152 §A/§B/§C/§D', 'the card shape follows the era asked for: A2A-Version: 0.3 on the GET returns the 0.3 card from the same peer')).toBe('0.3.0');
78
79
  expect(typeof card['url']).toBe('string');
79
80
  expect(card['supportedInterfaces']).toBeUndefined();
80
81
  // and the default-constructed peer (0.3-first) serves the 0.3 card to a header-less GET
@@ -95,7 +96,7 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
95
96
  await legacy.start(0);
96
97
  try {
97
98
  const card = (await (await fetch(`${legacy.endpoint()}/.well-known/agent-card.json`)).json()) as Record<string, unknown>;
98
- expect(card['protocolVersion']).toBe('0.3.0');
99
+ expect(card['protocolVersion'], req('openwop.it.a2a-1-0-agent-card.a-legacy-only-peer-serves-the-0-3-card-shape-follows-revision-not-calendar', 'RFC 0152 §A/§B/§C/§D', 'a legacy-only peer serves the 0.3 card — shape follows revision, not calendar')).toBe('0.3.0');
99
100
  expect(typeof card['url']).toBe('string');
100
101
  expect(card['supportedInterfaces']).toBeUndefined();
101
102
  } finally {
@@ -105,14 +106,14 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
105
106
 
106
107
  it('A2A-Version absent ⇒ 0.3 semantics; message/send returns a 0.3 task', async () => {
107
108
  const r = await rpc(peer.endpoint(), 'message/send', { message: { kind: 'message', messageId: 'm1', role: 'user', parts: [{ kind: 'text', text: 'hi' }] } });
108
- expect(r.error).toBeUndefined();
109
+ expect(r.error, req('openwop.it.a2a-1-0-agent-card.a2a-version-absent-0-3-semantics-message-send-returns-a-0-3-task', 'RFC 0152 §A/§B/§C/§D', 'A2A-Version absent ⇒ 0.3 semantics; message/send returns a 0.3 task')).toBeUndefined();
109
110
  expect(r.result?.['kind']).toBe('task');
110
111
  expect((r.result?.['status'] as { state: string }).state).toBe('submitted');
111
112
  });
112
113
 
113
114
  it('an unsupported version fails -32009 VERSION_NOT_SUPPORTED with supportedVersions[] (HTTP 400)', async () => {
114
115
  const r = await rpc(peer.endpoint(), 'SendMessage', { message: { messageId: 'm2', role: 'ROLE_USER', parts: [{ text: 'hi' }] } }, '99.0');
115
- expect(r.status).toBe(400);
116
+ expect(r.status, req('openwop.it.a2a-1-0-agent-card.an-unsupported-version-fails-32009-version-not-supported-with-supportedversions', 'RFC 0152 §A/§B/§C/§D', 'an unsupported version fails -32009 VERSION_NOT_SUPPORTED with supportedVersions[] (HTTP 400)')).toBe(400);
116
117
  expect(r.error?.code).toBe(-32009);
117
118
  expect(r.error?.data?.['reason']).toBe('VERSION_NOT_SUPPORTED');
118
119
  expect(r.error?.data?.['supportedVersions']).toEqual(['1.0', '0.3']); // constructor order
@@ -123,7 +124,7 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
123
124
  await only10.start(0);
124
125
  try {
125
126
  const r = await rpc(only10.endpoint(), 'message/send', { message: { parts: [] } });
126
- expect(r.error?.code).toBe(-32009);
127
+ expect(r.error?.code, req('openwop.it.a2a-1-0-agent-card.a-1-0-only-peer-rejects-a-header-less-request-which-is-0-3-by-rule', 'RFC 0152 §A/§B/§C/§D', 'a 1.0-only peer rejects a header-less request (which is 0.3 by rule)')).toBe(-32009);
127
128
  expect(r.error?.data?.['requested']).toBe('0.3');
128
129
  } finally {
129
130
  await only10.stop();
@@ -135,8 +136,8 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
135
136
  const r = await rpc(peer.endpoint(), 'SendMessage', { message: { messageId: 'm3', role: 'ROLE_USER', parts: [{ text: 'hello 1.0' }] } }, '1.0');
136
137
  expect(r.error).toBeUndefined();
137
138
  const task = r.result?.['task'] as Record<string, unknown>;
138
- expect(task, 'SendMessageResponse is a oneof payload: { task } | { message }').toBeDefined();
139
- expect(task['kind'], '1.0 removed the kind discriminator').toBeUndefined();
139
+ expect(task, req('openwop.it.a2a-1-0-agent-card.sendmessage-1-0-returns-task-with-task-state-role-part-oneof-no-kind-status-time', 'RFC 0152 §A/§B/§C/§D', 'SendMessageResponse is a oneof payload: { task } | { message }')).toBeDefined();
140
+ expect(task['kind'], req('openwop.it.a2a-1-0-agent-card.sendmessage-1-0-returns-task-with-task-state-role-part-oneof-no-kind-status-time', 'RFC 0152 §A/§B/§C/§D', '1.0 removed the kind discriminator')).toBeUndefined();
140
141
  const status = task['status'] as { state: string; timestamp?: string };
141
142
  expect(status.state).toBe('TASK_STATE_SUBMITTED');
142
143
  expect(typeof status.timestamp).toBe('string');
@@ -144,7 +145,7 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
144
145
  expect(history[0]?.['role']).toBe('ROLE_USER');
145
146
  const part = (history[0]?.['parts'] as Array<Record<string, unknown>>)[0]!;
146
147
  expect(part['text']).toBe('hello 1.0');
147
- expect(part['kind'], 'Part is a oneof — discriminate by member presence').toBeUndefined();
148
+ expect(part['kind'], req('openwop.it.a2a-1-0-agent-card.sendmessage-1-0-returns-task-with-task-state-role-part-oneof-no-kind-status-time', 'RFC 0152 §A/§B/§C/§D', 'Part is a oneof — discriminate by member presence')).toBeUndefined();
148
149
  expect(Array.isArray(task['artifacts'])).toBe(true);
149
150
  });
150
151
 
@@ -153,7 +154,7 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
153
154
  const sent = await rpc(peer.endpoint(), 'SendMessage', { message: { messageId: 'm4', role: 'ROLE_USER', parts: [{ text: 'x' }] } }, '1.0');
154
155
  const id = (sent.result?.['task'] as { id: string }).id;
155
156
  const got = await rpc(peer.endpoint(), 'GetTask', { id }, '1.0');
156
- expect((got.result as { status: { state: string } }).status.state).toBe('TASK_STATE_SUBMITTED');
157
+ expect((got.result as { status: { state: string } }).status.state, req('openwop.it.a2a-1-0-agent-card.gettask-canceltask-listtasks-per-d-1-incl-task-not-cancelable-on-a-terminal-task', 'RFC 0152 §A/§B/§C/§D', 'GetTask / CancelTask / ListTasks per §D.1, incl. TASK_NOT_CANCELABLE on a terminal task')).toBe('TASK_STATE_SUBMITTED');
157
158
  const listed = await rpc(peer.endpoint(), 'ListTasks', { status: 'TASK_STATE_SUBMITTED' }, '1.0');
158
159
  expect((listed.result as { totalSize: number }).totalSize).toBe(1);
159
160
  const cancelled = await rpc(peer.endpoint(), 'CancelTask', { id }, '1.0');
@@ -168,12 +169,12 @@ describe('RFC 0152 — the suite peer speaks A2A 1.0 (dual-era A2AFakePeer)', ()
168
169
 
169
170
  it('a 0.3 method name under a 1.0 header is method-not-found — loudly', async () => {
170
171
  const r = await rpc(peer.endpoint(), 'message/send', { message: { parts: [] } }, '1.0');
171
- expect(r.status).toBe(404);
172
+ expect(r.status, req('openwop.it.a2a-1-0-agent-card.a-0-3-method-name-under-a-1-0-header-is-method-not-found-loudly', 'RFC 0152 §A/§B/§C/§D', 'a 0.3 method name under a 1.0 header is method-not-found — loudly')).toBe(404);
172
173
  expect(r.error?.code).toBe(-32601);
173
174
  });
174
175
 
175
176
  it('streaming is honestly unsupported: SubscribeToTask ⇒ UNSUPPORTED_OPERATION, matching capabilities.streaming=false', async () => {
176
177
  const r = await rpc(peer.endpoint(), 'SubscribeToTask', { id: 'task-1' }, '1.0');
177
- expect(r.error?.code).toBe(-32004);
178
+ expect(r.error?.code, req('openwop.it.a2a-1-0-agent-card.streaming-is-honestly-unsupported-subscribetotask-unsupported-operation-matching', 'RFC 0152 §A/§B/§C/§D', 'streaming is honestly unsupported: SubscribeToTask ⇒ UNSUPPORTED_OPERATION, matching capabilities.streaming=false')).toBe(-32004);
178
179
  });
179
180
  });
@@ -27,6 +27,7 @@ import { describe, it, expect } from 'vitest';
27
27
  import { driver } from '../lib/driver.js';
28
28
  import { behaviorGate } from '../lib/behavior-gate.js';
29
29
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
30
+ import { req } from '../lib/requirement-ids.js';
30
31
 
31
32
  const PROFILE = 'a2a-1.0';
32
33
  const STATES_10 = [
@@ -75,27 +76,27 @@ describe('RFC 0152 §D — a2a-1.0-task-roundtrip (host as A2A 1.0 server, gated
75
76
  it('SendMessage @1.0 creates a task whose id is the runId, in 1.0 spelling; GetTask reads it back; unknown id is TASK_NOT_FOUND', async () => {
76
77
  if (!behaviorGate(PROFILE, await claims10())) return;
77
78
  const url = await jsonrpc10Url();
78
- expect(url, driver.describe('a2a-integration.md §C', 'a `a2a-1.0` host MUST publish a JSONRPC/1.0 interface in its card')).not.toBeNull();
79
+ expect(url, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §C', 'a `a2a-1.0` host MUST publish a JSONRPC/1.0 interface in its card')).not.toBeNull();
79
80
  const sent = await rpc10(url!, 'SendMessage', {
80
81
  message: { messageId: `conf-${Date.now()}`, role: 'ROLE_USER', parts: [{ text: 'openwop conformance a2a-1.0 roundtrip' }] },
81
82
  configuration: { returnImmediately: true },
82
83
  }, 1);
83
- expect(sent.status, driver.describe('a2a-integration.md §D.1', 'SendMessage MUST be accepted on the 1.0 interface')).toBe(200);
84
- expect(sent.error, driver.describe('a2a-integration.md §D.1', `SendMessage MUST NOT error: ${JSON.stringify(sent.error)}`)).toBeUndefined();
84
+ expect(sent.status, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.1', 'SendMessage MUST be accepted on the 1.0 interface')).toBe(200);
85
+ expect(sent.error, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.1', `SendMessage MUST NOT error: ${JSON.stringify(sent.error)}`)).toBeUndefined();
85
86
  const result = sent.result ?? {};
86
87
  // SendMessageResponse is a oneof: { task } | { message }. A run-creating host answers with a task.
87
88
  const task = (result['task'] ?? (result['id'] !== undefined ? result : undefined)) as { id?: string; contextId?: string; status?: { state?: string; timestamp?: string }; history?: Array<{ role?: string; parts?: Array<Record<string, unknown>> }>; kind?: unknown } | undefined;
88
- expect(task, driver.describe('a2a-integration.md §D.1', 'SendMessage without taskId MUST create a run and return `{ task }`')).toBeDefined();
89
- expect(task!.kind, driver.describe('a2a-integration.md §D.5', '1.0 has no `kind` discriminator')).toBeUndefined();
89
+ expect(task, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.1', 'SendMessage without taskId MUST create a run and return `{ task }`')).toBeDefined();
90
+ expect(task!.kind, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.5', '1.0 has no `kind` discriminator')).toBeUndefined();
90
91
  expect(typeof task!.id).toBe('string');
91
- expect(STATES_10, driver.describe('a2a-integration.md §D.4', 'status.state MUST use the 1.0 TASK_STATE_* spelling')).toContain(task!.status?.state);
92
+ expect(STATES_10, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.4', 'status.state MUST use the 1.0 TASK_STATE_* spelling')).toContain(task!.status?.state);
92
93
  for (const m of task!.history ?? []) {
93
- expect(['ROLE_USER', 'ROLE_AGENT'], driver.describe('a2a-integration.md §D.2', 'history roles are ROLE_*')).toContain(m.role);
94
- for (const p of m.parts ?? []) expect(p['kind'], driver.describe('a2a-integration.md §D.3', 'Part is a oneof — no `kind`')).toBeUndefined();
94
+ expect(['ROLE_USER', 'ROLE_AGENT'], req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.2', 'history roles are ROLE_*')).toContain(m.role);
95
+ for (const p of m.parts ?? []) expect(p['kind'], req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.3', 'Part is a oneof — no `kind`')).toBeUndefined();
95
96
  }
96
97
  // Task.id IS the runId (RFC 0100): the OpenWOP snapshot for it MUST exist for the same caller.
97
98
  const snap = await driver.get(`/v1/runs/${encodeURIComponent(task!.id!)}`);
98
- expect(snap.status, driver.describe('a2a-integration.md §D.4', '`Task.id` MUST be the backing runId — GET /v1/runs/{id} resolves it for the same principal')).toBe(200);
99
+ expect(snap.status, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.4', '`Task.id` MUST be the backing runId — GET /v1/runs/{id} resolves it for the same principal')).toBe(200);
99
100
  // GetTask reads it back with the same id and a valid 1.0 state.
100
101
  const got = await rpc10(url!, 'GetTask', { id: task!.id }, 2);
101
102
  expect(got.error).toBeUndefined();
@@ -104,7 +105,7 @@ describe('RFC 0152 §D — a2a-1.0-task-roundtrip (host as A2A 1.0 server, gated
104
105
  expect(STATES_10).toContain(gotTask.status?.state);
105
106
  // Unknown id — and, per §E, a cross-tenant id — MUST be TASK_NOT_FOUND, never forbidden.
106
107
  const missing = await rpc10(url!, 'GetTask', { id: `run_does_not_exist_${Date.now()}` }, 3);
107
- expect(missing.error?.code, driver.describe('a2a-integration.md §D.7/§E', 'an unknown or unreadable task MUST be TASK_NOT_FOUND (-32001) — no enumeration')).toBe(-32001);
108
+ expect(missing.error?.code, req('openwop.it.a2a-1-0-task-roundtrip.sendmessage-1-0-creates-a-task-whose-id-is-the-runid-in-1-0-spelling-gettask-rea', 'a2a-integration.md §D.7/§E', 'an unknown or unreadable task MUST be TASK_NOT_FOUND (-32001) — no enumeration')).toBe(-32001);
108
109
  // Tidy: cancel the run we created (best effort; terminal runs answer TASK_NOT_CANCELABLE which is fine).
109
110
  await rpc10(url!, 'CancelTask', { id: task!.id }, 4);
110
111
  });
@@ -29,6 +29,7 @@ import { softSkip } from '../lib/soft-skip.js';
29
29
  import { driver } from '../lib/driver.js';
30
30
  import { behaviorGate } from '../lib/behavior-gate.js';
31
31
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
32
+ import { req } from '../lib/requirement-ids.js';
32
33
 
33
34
  const PROFILE = 'a2a-1.0';
34
35
 
@@ -81,14 +82,14 @@ describe('RFC 0152 §C — a2a-card-runtime-consistent (gated on a2a.profiles
81
82
  if (!behaviorGate(PROFILE, await claims10())) return;
82
83
  const caps = (await a2a())!;
83
84
  const card = await fetchCard(caps);
84
- expect(card, driver.describe('a2a-integration.md §C', '`agentCardUrl` MUST resolve to the Agent Card (200)')).not.toBeNull();
85
+ expect(card, req('openwop.it.a2a-card-runtime-consistency.the-card-is-1-0-shaped-and-reachable-at-agentcardurl', 'a2a-integration.md §C', '`agentCardUrl` MUST resolve to the Agent Card (200)')).not.toBeNull();
85
86
  expect(
86
87
  Array.isArray(card!.supportedInterfaces) && card!.supportedInterfaces!.length > 0,
87
- driver.describe('a2a-integration.md §C', 'a host claiming `a2a-1.0` MUST publish a 1.0 card: `supportedInterfaces[]` REQUIRED (≥1)'),
88
+ req('openwop.it.a2a-card-runtime-consistency.the-card-is-1-0-shaped-and-reachable-at-agentcardurl', 'a2a-integration.md §C', 'a host claiming `a2a-1.0` MUST publish a 1.0 card: `supportedInterfaces[]` REQUIRED (≥1)'),
88
89
  ).toBe(true);
89
- expect(card!.url, driver.describe('a2a-integration.md §C', '1.0 removed the top-level `url` — a card with both shapes is neither')).toBeUndefined();
90
- expect(card!.protocolVersion, driver.describe('a2a-integration.md §C', '1.0 removed the top-level `protocolVersion` (per interface now)')).toBeUndefined();
91
- expect(Array.isArray(card!.skills) && card!.skills!.length > 0, driver.describe('a2a-integration.md §C', '`skills[]` MUST be non-empty — one per invocable workflow')).toBe(true);
90
+ expect(card!.url, req('openwop.it.a2a-card-runtime-consistency.the-card-is-1-0-shaped-and-reachable-at-agentcardurl', 'a2a-integration.md §C', '1.0 removed the top-level `url` — a card with both shapes is neither')).toBeUndefined();
91
+ expect(card!.protocolVersion, req('openwop.it.a2a-card-runtime-consistency.the-card-is-1-0-shaped-and-reachable-at-agentcardurl', 'a2a-integration.md §C', '1.0 removed the top-level `protocolVersion` (per interface now)')).toBeUndefined();
92
+ expect(Array.isArray(card!.skills) && card!.skills!.length > 0, req('openwop.it.a2a-card-runtime-consistency.the-card-is-1-0-shaped-and-reachable-at-agentcardurl', 'a2a-integration.md §C', '`skills[]` MUST be non-empty — one per invocable workflow')).toBe(true);
92
93
  });
93
94
 
94
95
  it('a header-less card GET returns the 0.3-shaped card while a2a-0.3-legacy is advertised (§B receiver rule applied to discovery — S18 Q1)', async () => {
@@ -97,17 +98,17 @@ describe('RFC 0152 §C — a2a-card-runtime-consistent (gated on a2a.profiles
97
98
  if (typeof caps.agentCardUrl !== 'string') return softSkip('blocked', 'no agentCardUrl advertised');
98
99
  const legacy = (caps.protocolVersions ?? []).includes('0.3');
99
100
  const res = await fetch(caps.agentCardUrl, { headers: { accept: 'application/json' } });
100
- expect(res.status, driver.describe('a2a-integration.md §C', 'a header-less card GET MUST succeed — discovery must not fail')).toBe(200);
101
+ expect(res.status, req('openwop.it.a2a-card-runtime-consistency.a-header-less-card-get-returns-the-0-3-shaped-card-while-a2a-0-3-legacy-is-adver', 'a2a-integration.md §C', 'a header-less card GET MUST succeed — discovery must not fail')).toBe(200);
101
102
  const card = (await res.json()) as Card10 & { url?: string; protocolVersion?: string };
102
103
  if (legacy) {
103
104
  // While 0.3 is advertised the header-less card is the 0.3 shape: an
104
105
  // external 0.3 client reading `card.url` keeps working through the
105
106
  // legacy window — the point of advertising `a2a-0.3-legacy` at all.
106
- expect(typeof card.url, driver.describe('a2a-integration.md §C', 'header-less = 0.3 (§B receiver rule): the card MUST carry the 0.3 top-level `url` while `protocolVersions ∋ 0.3`')).toBe('string');
107
- expect(card.supportedInterfaces, driver.describe('a2a-integration.md §C', 'the header-less card MUST NOT be the 1.0 shape while 0.3 is advertised (a card with both shapes is neither)')).toBeUndefined();
107
+ expect(typeof card.url, req('openwop.it.a2a-card-runtime-consistency.a-header-less-card-get-returns-the-0-3-shaped-card-while-a2a-0-3-legacy-is-adver', 'a2a-integration.md §C', 'header-less = 0.3 (§B receiver rule): the card MUST carry the 0.3 top-level `url` while `protocolVersions ∋ 0.3`')).toBe('string');
108
+ expect(card.supportedInterfaces, req('openwop.it.a2a-card-runtime-consistency.a-header-less-card-get-returns-the-0-3-shaped-card-while-a2a-0-3-legacy-is-adver', 'a2a-integration.md §C', 'the header-less card MUST NOT be the 1.0 shape while 0.3 is advertised (a card with both shapes is neither)')).toBeUndefined();
108
109
  } else {
109
110
  // 0.3 dropped: the preferred-version (1.0) card is served header-less.
110
- expect(Array.isArray(card.supportedInterfaces) && card.supportedInterfaces!.length > 0, driver.describe('a2a-integration.md §C', 'with 0.3 dropped, the header-less card is the preferredVersion (1.0) card')).toBe(true);
111
+ expect(Array.isArray(card.supportedInterfaces) && card.supportedInterfaces!.length > 0, req('openwop.it.a2a-card-runtime-consistency.a-header-less-card-get-returns-the-0-3-shaped-card-while-a2a-0-3-legacy-is-adver', 'a2a-integration.md §C', 'with 0.3 dropped, the header-less card is the preferredVersion (1.0) card')).toBe(true);
111
112
  }
112
113
  });
113
114
 
@@ -115,12 +116,12 @@ describe('RFC 0152 §C — a2a-card-runtime-consistent (gated on a2a.profiles
115
116
  if (!behaviorGate(PROFILE, await claims10())) return;
116
117
  const caps = (await a2a())!;
117
118
  const card = await fetchCard(caps);
118
- if (card === null) return; // asserted above
119
+ if (card === null) return softSkip('blocked', 'precondition not met — `card === null` returned early (asserted above) (seam, prior step, or fixture unavailable)'); // asserted above
119
120
  const fromCard = [...new Set((card.supportedInterfaces ?? []).map((i) => i.protocolVersion).filter((v): v is string => typeof v === 'string'))].sort();
120
121
  const fromDiscovery = [...new Set(caps.protocolVersions ?? [])].sort();
121
122
  expect(
122
123
  fromCard,
123
- driver.describe(
124
+ req('openwop.it.a2a-card-runtime-consistency.the-set-of-supportedinterfaces-protocolversion-equals-capabilities-a2a-protocolv',
124
125
  'a2a-integration.md §C',
125
126
  'the SET of `supportedInterfaces[].protocolVersion` MUST equal `capabilities.a2a.protocolVersions` — two documents, one fact; ' +
126
127
  'a version advertised in one and not the other is card/runtime drift (`a2a-card-runtime-consistent`)',
@@ -132,14 +133,14 @@ describe('RFC 0152 §C — a2a-card-runtime-consistent (gated on a2a.profiles
132
133
  if (!behaviorGate(PROFILE, await claims10())) return;
133
134
  const caps = (await a2a())!;
134
135
  const card = await fetchCard(caps);
135
- if (card === null) return;
136
+ if (card === null) return softSkip('blocked', 'precondition not met — `card === null` returned early (seam, prior step, or fixture unavailable)');
136
137
  const ifaces = card.supportedInterfaces ?? [];
137
138
  expect(
138
139
  ifaces.some((i) => i.protocolBinding === 'JSONRPC' && i.protocolVersion === '1.0' && typeof i.url === 'string'),
139
- driver.describe('a2a-integration.md §C', 'the `a2a-1.0` profile floor is the JSON-RPC binding at 1.0; HTTP+JSON / gRPC are optional additions'),
140
+ req('openwop.it.a2a-card-runtime-consistency.a2a-1-0-must-serve-the-json-rpc-binding-at-1-0-the-mandatory-floor-and-should-li', 'a2a-integration.md §C', 'the `a2a-1.0` profile floor is the JSON-RPC binding at 1.0; HTTP+JSON / gRPC are optional additions'),
140
141
  ).toBe(true);
141
142
  for (const i of ifaces) {
142
- expect(['JSONRPC', 'GRPC', 'HTTP+JSON'], driver.describe('a2a-integration.md §C', 'protocolBinding uses the upstream binding names')).toContain(i.protocolBinding);
143
+ expect(['JSONRPC', 'GRPC', 'HTTP+JSON'], req('openwop.it.a2a-card-runtime-consistency.a2a-1-0-must-serve-the-json-rpc-binding-at-1-0-the-mandatory-floor-and-should-li', 'a2a-integration.md §C', 'protocolBinding uses the upstream binding names')).toContain(i.protocolBinding);
143
144
  }
144
145
  if (typeof caps.preferredVersion === 'string' && ifaces.length > 0) {
145
146
  // SHOULD, so a soft expectation: report, do not fail.
@@ -154,14 +155,14 @@ describe('RFC 0152 §C — a2a-card-runtime-consistent (gated on a2a.profiles
154
155
  if (!behaviorGate(PROFILE, await claims10())) return;
155
156
  const caps = (await a2a())!;
156
157
  const card = await fetchCard(caps);
157
- if (card === null) return;
158
+ if (card === null) return softSkip('blocked', 'precondition not met — `card === null` returned early (seam, prior step, or fixture unavailable)');
158
159
  expect(
159
160
  card.capabilities?.streaming === true,
160
- driver.describe('a2a-integration.md §C', '`capabilities.streaming` on the card MUST equal `capabilities.a2a.streaming` on discovery'),
161
+ req('openwop.it.a2a-card-runtime-consistency.card-capabilities-streaming-pushnotifications-equal-the-discovery-flags', 'a2a-integration.md §C', '`capabilities.streaming` on the card MUST equal `capabilities.a2a.streaming` on discovery'),
161
162
  ).toBe(caps.streaming === true);
162
163
  expect(
163
164
  card.capabilities?.pushNotifications === true,
164
- driver.describe('a2a-integration.md §C', '`capabilities.pushNotifications` on the card MUST equal `capabilities.a2a.pushNotifications`'),
165
+ req('openwop.it.a2a-card-runtime-consistency.card-capabilities-streaming-pushnotifications-equal-the-discovery-flags', 'a2a-integration.md §C', '`capabilities.pushNotifications` on the card MUST equal `capabilities.a2a.pushNotifications`'),
165
166
  ).toBe(caps.pushNotifications === true);
166
167
  });
167
168
  });
@@ -33,6 +33,7 @@ import { driver } from '../lib/driver.js';
33
33
  import { behaviorGate } from '../lib/behavior-gate.js';
34
34
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
35
35
  import { getA2AFakePeer } from '../lib/a2a-fake-peer.js';
36
+ import { req } from '../lib/requirement-ids.js';
36
37
 
37
38
  export const REQUIRES_HOST_CALLBACK = "the host issues A2A JSON-RPC calls to the suite's fake peer via /v1/host/sample/a2a/invoke (peerUrl), which the peer records";
38
39
 
@@ -75,25 +76,25 @@ describe('RFC 0152 §E — a2a-peer-no-authority-escalation (host as A2A client,
75
76
  // The peer must actually have answered with the authority-asserting message,
76
77
  // or this leg is vacuous.
77
78
  const created = peer.taskCount();
78
- expect(created, driver.describe('RFCS/0152 §E', 'the host MUST have created a task on the peer for this leg to mean anything')).toBeGreaterThan(0);
79
+ expect(created, req('openwop.it.a2a-peer-authority.a-peer-reply-that-asserts-approval-scopes-and-a-foreign-task-reference-changes-n', 'RFCS/0152 §E', 'the host MUST have created a task on the peer for this leg to mean anything')).toBeGreaterThan(0);
79
80
  const report = (drive.json as { peerAuthority?: PeerAuthorityReport }).peerAuthority;
80
81
  if (report === undefined) {
81
82
  // Additive seam field not yet implemented: blocked, not passed.
82
83
  expect(
83
84
  report,
84
- driver.describe(
85
+ req('openwop.it.a2a-peer-authority.a-peer-reply-that-asserts-approval-scopes-and-a-foreign-task-reference-changes-n',
85
86
  'host-sample-test-seams.md §22',
86
87
  'the invoke seam SHOULD report `peerAuthority: { approvalAdvanced, scopesWidened, referencedTaskDereferenced }` for ' +
87
88
  'scenario "peer-asserts-authority"; until it does this requirement is unobservable and resolves to `blocked`, not passed',
88
89
  ),
89
90
  ).toBeDefined();
90
- return;
91
+ return softSkip('blocked', 'precondition not met — `report === undefined` returned early (seam, prior step, or fixture unavailable)');
91
92
  }
92
- expect(report.approvalAdvanced, driver.describe('RFCS/0152 §E', 'peer content MUST NOT advance an approval gate (a2a-peer-no-authority-escalation)')).toBe(false);
93
- expect(report.scopesWidened, driver.describe('RFCS/0152 §E', 'peer content MUST NOT widen the run’s scopes or tool allowlist')).toBe(false);
93
+ expect(report.approvalAdvanced, req('openwop.it.a2a-peer-authority.a-peer-reply-that-asserts-approval-scopes-and-a-foreign-task-reference-changes-n', 'RFCS/0152 §E', 'peer content MUST NOT advance an approval gate (a2a-peer-no-authority-escalation)')).toBe(false);
94
+ expect(report.scopesWidened, req('openwop.it.a2a-peer-authority.a-peer-reply-that-asserts-approval-scopes-and-a-foreign-task-reference-changes-n', 'RFCS/0152 §E', 'peer content MUST NOT widen the run’s scopes or tool allowlist')).toBe(false);
94
95
  expect(
95
96
  report.referencedTaskDereferenced,
96
- driver.describe('a2a-integration.md §D.2', '`referenceTaskIds[]` are opaque hints — MUST NOT be dereferenced on the peer’s say-so'),
97
+ req('openwop.it.a2a-peer-authority.a-peer-reply-that-asserts-approval-scopes-and-a-foreign-task-reference-changes-n', 'a2a-integration.md §D.2', '`referenceTaskIds[]` are opaque hints — MUST NOT be dereferenced on the peer’s say-so'),
97
98
  ).toBe(false);
98
99
  });
99
100
  });
@@ -47,7 +47,8 @@ import { pollUntilTerminal, pollUntilStatus } from '../lib/polling.js';
47
47
  import { SCHEMAS_DIR } from '../lib/paths.js';
48
48
  import { behaviorGate } from '../lib/behavior-gate.js';
49
49
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
50
- import { seamAbsent } from '../lib/soft-skip.js';
50
+ import { seamAbsent, softSkip } from '../lib/soft-skip.js';
51
+ import { req } from '../lib/requirement-ids.js';
51
52
 
52
53
  /**
53
54
  * Callback-shaped: the host issues A2A JSON-RPC calls to the suite's fake peer.
@@ -113,7 +114,7 @@ describe('a2a-task-roundtrip: AgentCard + task lifecycle', () => {
113
114
  '[a2a-task-roundtrip] no A2A endpoint configured; set OPENWOP_A2A_FAKE_PEER=true ' +
114
115
  'or OPENWOP_A2A_REAL_PEER_URL=<base-url>',
115
116
  );
116
- return;
117
+ return softSkip('blocked', 'precondition not met — `!probe` returned early (seam, prior step, or fixture unavailable)');
117
118
  }
118
119
  if (!probe.isReal) getA2AFakePeer()!.reset();
119
120
 
@@ -137,7 +138,7 @@ describe('a2a-task-roundtrip: AgentCard + task lifecycle', () => {
137
138
  cardJson.supportedInterfaces?.find((i) => typeof i.protocolVersion === 'string')?.protocolVersion;
138
139
  expect(
139
140
  typeof advertisedVersion,
140
- 'the card MUST advertise a protocol version — top-level (0.3) or per interface (1.0)',
141
+ req('openwop.it.a2a-task-roundtrip.agentcard-exposes-a-protocol-version-0-3-top-level-or-1-0-per-interface-skills-m', 'spec/v1/a2a-integration.md', 'the card MUST advertise a protocol version — top-level (0.3) or per interface (1.0)'),
141
142
  ).toBe('string');
142
143
  expect(Array.isArray(cardJson.skills)).toBe(true);
143
144
  expect((cardJson.skills ?? []).length).toBeGreaterThan(0);
@@ -181,7 +182,7 @@ describe('a2a-task-roundtrip: AgentCard + task lifecycle', () => {
181
182
  `[a2a-task-roundtrip] real-peer interop OK against ${probe.url} ` +
182
183
  `(skill=${firstSkill?.id ?? firstSkill?.name}, kind=${kind})`,
183
184
  );
184
- return;
185
+ return softSkip('blocked', 'precondition not met — `probe.isReal` returned early (seam, prior step, or fixture unavailable)');
185
186
  }
186
187
 
187
188
  // Fake-peer path: deterministic state forcing, assert verbatim.
@@ -224,14 +225,14 @@ describe('a2a-task-roundtrip: drift point #3 — AUTH_REQUIRED projects to waiti
224
225
  if (!peer) {
225
226
  // eslint-disable-next-line no-console
226
227
  console.warn('[a2a-task-roundtrip] peer not started; skipping drift-point #3 subtest');
227
- return;
228
+ return softSkip('blocked', 'precondition not met — `!peer` returned early ([a2a-task-roundtrip] peer not started; skipping drift-point #3 subtest) (seam, prior step, or fixture unavailable)');
228
229
  }
229
230
  if (!isFixtureAdvertised(ROUNDTRIP_FIXTURE)) {
230
231
  // eslint-disable-next-line no-console
231
232
  console.warn(
232
233
  `[a2a-task-roundtrip] fixture ${ROUNDTRIP_FIXTURE} not advertised; skipping drift-point #3 subtest`,
233
234
  );
234
- return;
235
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(ROUNDTRIP_FIXTURE)` returned early ([a2a-task-roundtrip] fixture … not advertised; skipping drift-point #3 subtest)');
235
236
  }
236
237
  peer.reset();
237
238
  peer.setNextState('AUTH_REQUIRED');
@@ -246,7 +247,7 @@ describe('a2a-task-roundtrip: drift point #3 — AUTH_REQUIRED projects to waiti
246
247
  // Host should project AUTH_REQUIRED into `waiting-input` per
247
248
  // a2a-integration.md §"State projection (reverse)".
248
249
  const snapshot = await pollUntilStatus(runId, 'waiting-input', { timeoutMs: 15_000 });
249
- expect(snapshot.status, driver.describe(
250
+ expect(snapshot.status, req('openwop.it.a2a-task-roundtrip.host-consuming-an-a2a-peer-that-returns-auth-required-projects-to-waiting-input',
250
251
  'a2a-integration.md §"State projection" drift point #3',
251
252
  "A2A AUTH_REQUIRED MUST project to openwop 'waiting-input' (no native auth-required kind in v1)",
252
253
  )).toBe('waiting-input');
@@ -264,10 +265,10 @@ describe('a2a-task-roundtrip: drift point #4 — REJECTED projects to failed', (
264
265
  if (!peer) {
265
266
  // eslint-disable-next-line no-console
266
267
  console.warn('[a2a-task-roundtrip] peer not started; skipping drift-point #4 subtest');
267
- return;
268
+ return softSkip('blocked', 'precondition not met — `!peer` returned early ([a2a-task-roundtrip] peer not started; skipping drift-point #4 subtest) (seam, prior step, or fixture unavailable)');
268
269
  }
269
270
  if (!isFixtureAdvertised(ROUNDTRIP_FIXTURE)) {
270
- return;
271
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(ROUNDTRIP_FIXTURE)` returned early');
271
272
  }
272
273
  peer.reset();
273
274
  peer.setNextState('REJECTED');
@@ -280,7 +281,7 @@ describe('a2a-task-roundtrip: drift point #4 — REJECTED projects to failed', (
280
281
  const runId = (create.json as { runId: string }).runId;
281
282
 
282
283
  const terminal = await pollUntilTerminal(runId, { timeoutMs: 15_000 });
283
- expect(terminal.status, driver.describe(
284
+ expect(terminal.status, req('openwop.it.a2a-task-roundtrip.host-consuming-an-a2a-peer-that-returns-rejected-projects-to-failed-with-rejecte',
284
285
  'a2a-integration.md §"State projection" drift point #4',
285
286
  'A2A REJECTED MUST project to openwop terminal status `failed`',
286
287
  )).toBe('failed');
@@ -289,7 +290,7 @@ describe('a2a-task-roundtrip: drift point #4 — REJECTED projects to failed', (
289
290
  // snapshot, the final node payload, or the run-level error envelope.
290
291
  // We accept any of those: stringify the snapshot and search.
291
292
  const haystack = JSON.stringify(terminal).toLowerCase();
292
- expect(haystack.includes('rejected'), driver.describe(
293
+ expect(haystack.includes('rejected'), req('openwop.it.a2a-task-roundtrip.host-consuming-an-a2a-peer-that-returns-rejected-projects-to-failed-with-rejecte',
293
294
  'a2a-integration.md §"State projection" drift point #4',
294
295
  "host SHOULD surface 'rejected_by_remote' (or equivalent) so observers can attribute the failure to the remote A2A peer",
295
296
  )).toBe(true);
@@ -322,14 +323,14 @@ describe('a2a-task-roundtrip: A2ATaskState + a2a capability shape (always-on, se
322
323
  };
323
324
  expect(
324
325
  validateTaskState(ok),
325
- `a2a-task-state.schema.json MUST accept a conforming record. Errors: ${JSON.stringify(validateTaskState.errors)}`,
326
+ req('openwop.it.a2a-task-roundtrip.a-conforming-a2ataskstate-validates-with-the-lowercase-hyphen-state-enum-and-tas', 'spec/v1/a2a-integration.md', `a2a-task-state.schema.json MUST accept a conforming record. Errors: ${JSON.stringify(validateTaskState.errors)}`),
326
327
  ).toBe(true);
327
328
  });
328
329
 
329
330
  it('an UPPERCASE state fails (the persisted/wire form is the A2A v0.3 lowercase-hyphen variant)', () => {
330
331
  expect(
331
332
  validateTaskState({ taskId: 'r', runId: 'r', state: 'WORKING', updatedAt: '2026-06-13T19:00:00Z' }),
332
- 'a2a-integration.md spelling-drift note — the persisted A2ATaskState.state MUST be the lowercase-hyphen form',
333
+ req('openwop.it.a2a-task-roundtrip.an-uppercase-state-fails-the-persisted-wire-form-is-the-a2a-v0-3-lowercase-hyphe', 'spec/v1/a2a-integration.md', 'a2a-integration.md spelling-drift note — the persisted A2ATaskState.state MUST be the lowercase-hyphen form'),
333
334
  ).toBe(false);
334
335
  });
335
336
 
@@ -342,7 +343,7 @@ describe('a2a-task-roundtrip: A2ATaskState + a2a capability shape (always-on, se
342
343
  updatedAt: '2026-06-13T19:00:00Z',
343
344
  inputs: { secret: 'x' },
344
345
  }),
345
- 'SECURITY a2a-push-egress-ssrf / SR-1 — the persisted record MUST NOT carry run inputs/outputs/artifacts inline',
346
+ req('openwop.it.a2a-task-roundtrip.an-a2ataskstate-carrying-run-inputs-artifacts-inline-fails-additionalproperties', 'spec/v1/a2a-integration.md', 'SECURITY a2a-push-egress-ssrf / SR-1 — the persisted record MUST NOT carry run inputs/outputs/artifacts inline'),
346
347
  ).toBe(false);
347
348
  });
348
349
 
@@ -351,27 +352,27 @@ describe('a2a-task-roundtrip: A2ATaskState + a2a capability shape (always-on, se
351
352
  $ref: 'https://openwop.dev/spec/v1/a2a-task-state.schema.json#/$defs/PushConfig',
352
353
  $defs: taskStateSchema.$defs,
353
354
  });
354
- expect(validatePush({ tokenFingerprint: 'a1b2' }), 'PushConfig MUST require `url`').toBe(false);
355
+ expect(validatePush({ tokenFingerprint: 'a1b2' }), req('openwop.it.a2a-task-roundtrip.a-pushconfig-requires-url-and-structurally-rejects-a-raw-non-truncated-push-toke', 'spec/v1/a2a-integration.md', 'PushConfig MUST require `url`')).toBe(false);
355
356
  expect(
356
357
  validatePush({ url: 'https://caller.example.com/push', tokenFingerprint: 'a'.repeat(33) }),
357
- 'SECURITY a2a-push-egress-ssrf — tokenFingerprint maxLength:32 structurally rejects a full-length raw token (SR-1)',
358
+ req('openwop.it.a2a-task-roundtrip.a-pushconfig-requires-url-and-structurally-rejects-a-raw-non-truncated-push-toke', 'spec/v1/a2a-integration.md', 'SECURITY a2a-push-egress-ssrf — tokenFingerprint maxLength:32 structurally rejects a full-length raw token (SR-1)'),
358
359
  ).toBe(false);
359
360
  expect(
360
361
  validatePush({ url: 'https://caller.example.com/push', tokenFingerprint: 'a1b2c3d4' }),
361
- 'a truncated fingerprint + uri url MUST validate',
362
+ req('openwop.it.a2a-task-roundtrip.a-pushconfig-requires-url-and-structurally-rejects-a-raw-non-truncated-push-toke', 'spec/v1/a2a-integration.md', 'a truncated fingerprint + uri url MUST validate'),
362
363
  ).toBe(true);
363
364
  });
364
365
 
365
366
  it('the capabilities.a2a block shape is declared (supported + agentCardUrl required; three optional booleans)', () => {
366
- expect(a2aBlockSchema, 'capabilities.schema.json MUST declare the a2a block').toBeDefined();
367
+ expect(a2aBlockSchema, req('openwop.it.a2a-task-roundtrip.the-capabilities-a2a-block-shape-is-declared-supported-agentcardurl-required-thr', 'spec/v1/a2a-integration.md', 'capabilities.schema.json MUST declare the a2a block')).toBeDefined();
367
368
  expect(a2aBlockSchema.required).toEqual(expect.arrayContaining(['supported', 'agentCardUrl']));
368
369
  expect(a2aBlockSchema.additionalProperties).toBe(false);
369
370
  const validateA2A = ajv.compile({ ...a2aBlockSchema, $id: 'urn:test:a2a-block' });
370
371
  expect(
371
372
  validateA2A({ supported: true, agentCardUrl: 'https://example.com/.well-known/agent-card.json', durableTasks: true }),
372
- `a conforming a2a block MUST validate. Errors: ${JSON.stringify(validateA2A.errors)}`,
373
+ req('openwop.it.a2a-task-roundtrip.the-capabilities-a2a-block-shape-is-declared-supported-agentcardurl-required-thr', 'spec/v1/a2a-integration.md', `a conforming a2a block MUST validate. Errors: ${JSON.stringify(validateA2A.errors)}`),
373
374
  ).toBe(true);
374
- expect(validateA2A({ supported: true }), 'agentCardUrl is required').toBe(false);
375
+ expect(validateA2A({ supported: true }), req('openwop.it.a2a-task-roundtrip.the-capabilities-a2a-block-shape-is-declared-supported-agentcardurl-required-thr', 'spec/v1/a2a-integration.md', 'agentCardUrl is required')).toBe(false);
375
376
  });
376
377
  });
377
378
 
@@ -386,20 +387,20 @@ describe.skipIf(HTTP_SKIP)('a2a-task-roundtrip: durable tasks/get after disconne
386
387
  const start = await driver.post('/v1/host/sample/a2a/tasks/start', {
387
388
  scenario: 'paused-at-approval',
388
389
  });
389
- if (start.status === 404 || start.status === 403) return; // seam unwired — soft-skip
390
+ if (start.status === 404 || start.status === 403) return softSkip('blocked', 'precondition not met — `start.status === 404 || start.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
390
391
  const taskId = (start.json as { taskId?: string })?.taskId;
391
- if (!taskId) return;
392
+ if (!taskId) return softSkip('blocked', 'precondition not met — `!taskId` returned early (seam, prior step, or fixture unavailable)');
392
393
 
393
394
  const read = await driver.get(`/v1/host/sample/a2a/tasks/${encodeURIComponent(taskId)}`);
394
- if (read.status === 404 || read.status === 403) return;
395
+ if (read.status === 404 || read.status === 403) return softSkip('blocked', 'precondition not met — `read.status === 404 || read.status === 403` returned early (seam, prior step, or fixture unavailable)');
395
396
  const state = read.json as { state?: string; runId?: string; metadata?: { openwop?: { interrupt?: { kind?: string } } } };
396
397
  expect(
397
398
  state.state,
398
- driver.describe('a2a-integration.md §"Async / durable Tasks"', 'tasks/get after disconnect MUST return the live input-required projection (not a stale working)'),
399
+ req('openwop.it.a2a-task-roundtrip.a-paused-at-hitl-run-projects-a-live-input-required-task-on-a-later-tasks-get-re', 'a2a-integration.md §"Async / durable Tasks"', 'tasks/get after disconnect MUST return the live input-required projection (not a stale working)'),
399
400
  ).toBe('input-required');
400
401
  expect(
401
402
  state.runId,
402
- driver.describe('a2a-task-state.schema.json', 'taskId MUST equal the backing runId'),
403
+ req('openwop.it.a2a-task-roundtrip.a-paused-at-hitl-run-projects-a-live-input-required-task-on-a-later-tasks-get-re', 'a2a-task-state.schema.json', 'taskId MUST equal the backing runId'),
403
404
  ).toBe(taskId);
404
405
  });
405
406
  });
@@ -451,10 +452,10 @@ describe.skipIf(HTTP_SKIP)('a2a-task-roundtrip: push-config SSRF, two-sided (gat
451
452
  // `https` on purpose: this probe is refusable ONLY by the address arm, so a
452
453
  // host that implements the scheme arm alone cannot pass it by accident.
453
454
  const res = await registerPush('https://10.0.0.5/push');
454
- if (res === null) return;
455
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
455
456
  expect(
456
457
  res.status >= 400,
457
- driver.describe(
458
+ req('openwop.it.a2a-task-roundtrip.address-arm-an-https-pushconfig-url-at-a-private-address-is-refused',
458
459
  'a2a-integration.md §D.6 (address arm)',
459
460
  'a2a-push-egress-ssrf — a pushConfig.url at a private/loopback address MUST be refused before any push, even over https',
460
461
  ),
@@ -464,10 +465,10 @@ describe.skipIf(HTTP_SKIP)('a2a-task-roundtrip: push-config SSRF, two-sided (gat
464
465
  it('SCHEME arm: an http pushConfig.url at a public host is refused', async () => {
465
466
  // Public hostname on purpose: refusable ONLY by the scheme arm.
466
467
  const res = await registerPush('http://push.example.com/push');
467
- if (res === null) return;
468
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
468
469
  expect(
469
470
  res.status >= 400,
470
- driver.describe(
471
+ req('openwop.it.a2a-task-roundtrip.scheme-arm-an-http-pushconfig-url-at-a-public-host-is-refused',
471
472
  'a2a-integration.md §D.6 (scheme arm)',
472
473
  'a2a-push-egress-ssrf — a plaintext `http://` pushConfig.url MUST be refused before any push. '
473
474
  + 'The RFC 0093 webhook-egress guard is the `webhooks.md` §"SSRF protection" list IN FULL, whose first entry is '