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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (611) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +262 -14
  3. package/dist/lib/certification-bundle-v3.js +142 -0
  4. package/dist/lib/paths.js +25 -3
  5. package/dist/lib/requirement-ids.js +57 -4
  6. package/dist/lib/requirement-ledger.js +1 -0
  7. package/dist/lib/scenario-disposition.js +6 -1
  8. package/dist/lib/spec-coherence.js +13 -32
  9. package/dist/spec-artifacts.lock.json +5 -0
  10. package/package.json +11 -33
  11. package/requirements.json +22892 -11701
  12. package/scenario-majors.json +1493 -0
  13. package/schemas/CORPUS-STAMP.json +137 -5
  14. package/src/cli.ts +236 -19
  15. package/src/global-setup.ts +3 -2
  16. package/src/lib/certification-bundle-v3.ts +175 -0
  17. package/src/lib/corpus-stamp.ts +29 -1
  18. package/src/lib/driver.ts +9 -1
  19. package/src/lib/era2-seed.ts +197 -0
  20. package/src/lib/paths.ts +25 -3
  21. package/src/lib/requirement-ids.ts +54 -4
  22. package/src/lib/requirement-ledger.ts +7 -1
  23. package/src/lib/scenario-disposition.ts +6 -1
  24. package/src/lib/seams.ts +45 -0
  25. package/src/lib/spec-coherence.ts +15 -32
  26. package/src/lib/v2.ts +62 -0
  27. package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
  28. package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
  29. package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
  30. package/src/scenarios/a2a-peer-authority.test.ts +7 -6
  31. package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
  32. package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
  33. package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
  34. package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
  35. package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
  36. package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
  37. package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
  38. package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
  39. package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
  40. package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
  41. package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
  42. package/src/scenarios/agent-deployment-shape.test.ts +22 -24
  43. package/src/scenarios/agent-eval-run.test.ts +19 -18
  44. package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
  45. package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
  46. package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
  47. package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
  48. package/src/scenarios/agent-live-structured-output.test.ts +7 -6
  49. package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
  50. package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
  51. package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
  52. package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
  53. package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
  54. package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
  55. package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
  56. package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
  57. package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
  58. package/src/scenarios/agent-platform-profile.test.ts +18 -19
  59. package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
  60. package/src/scenarios/agent-roster-attribution.test.ts +18 -17
  61. package/src/scenarios/agent-roster-shape.test.ts +17 -19
  62. package/src/scenarios/agent-verifier-shape.test.ts +11 -11
  63. package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
  64. package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
  65. package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
  66. package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
  67. package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
  68. package/src/scenarios/agentMessageReducer.test.ts +2 -1
  69. package/src/scenarios/agentMetadata.test.ts +2 -1
  70. package/src/scenarios/agentPackCatalog.test.ts +23 -21
  71. package/src/scenarios/agentPackExport.test.ts +4 -2
  72. package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
  73. package/src/scenarios/agentPackInstall.test.ts +4 -2
  74. package/src/scenarios/agentPackProvenance.test.ts +2 -1
  75. package/src/scenarios/agentReasoningEvents.test.ts +3 -2
  76. package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
  77. package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
  78. package/src/scenarios/ai-envelope-shape.test.ts +31 -29
  79. package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
  80. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
  81. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
  82. package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
  83. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
  84. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
  85. package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
  86. package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
  87. package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
  88. package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
  89. package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
  90. package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
  91. package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
  92. package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
  93. package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
  94. package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
  95. package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
  96. package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
  97. package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
  98. package/src/scenarios/append-ordering.test.ts +7 -5
  99. package/src/scenarios/approval-gate-events.test.ts +4 -3
  100. package/src/scenarios/approval-gate-flow.test.ts +4 -3
  101. package/src/scenarios/approval-payload.test.ts +5 -4
  102. package/src/scenarios/artifact-auth.test.ts +7 -6
  103. package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
  104. package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
  105. package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
  106. package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
  107. package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
  108. package/src/scenarios/audit-log-integrity.test.ts +8 -6
  109. package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
  110. package/src/scenarios/auth-mtls.test.ts +22 -20
  111. package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
  112. package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
  113. package/src/scenarios/auth-saml-profile.test.ts +14 -12
  114. package/src/scenarios/auth-scim-profile.test.ts +3 -2
  115. package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
  116. package/src/scenarios/auth-subject-link.test.ts +11 -10
  117. package/src/scenarios/auth.test.ts +5 -4
  118. package/src/scenarios/authorization-fail-closed.test.ts +3 -2
  119. package/src/scenarios/authorization-roles-shape.test.ts +9 -7
  120. package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
  121. package/src/scenarios/blob-presign-expiry.test.ts +12 -10
  122. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  123. package/src/scenarios/budget-enforcement.test.ts +15 -14
  124. package/src/scenarios/budget-policy-shape.test.ts +18 -19
  125. package/src/scenarios/bulk-cancel.test.ts +9 -8
  126. package/src/scenarios/byok-auth-modes.test.ts +13 -14
  127. package/src/scenarios/byok-roundtrip.test.ts +12 -10
  128. package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
  129. package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
  130. package/src/scenarios/callai-multimodal.test.ts +5 -3
  131. package/src/scenarios/cancellation.test.ts +6 -5
  132. package/src/scenarios/cap-breach.test.ts +15 -14
  133. package/src/scenarios/capability-arm-witness.test.ts +5 -3
  134. package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
  135. package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
  136. package/src/scenarios/certification-bundle-v2.test.ts +11 -10
  137. package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
  138. package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
  139. package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
  140. package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
  141. package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
  142. package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
  143. package/src/scenarios/channel-presence-shape.test.ts +11 -12
  144. package/src/scenarios/channel-ttl.test.ts +6 -5
  145. package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
  146. package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
  147. package/src/scenarios/commitment-fired.test.ts +6 -5
  148. package/src/scenarios/compensation-behavior.test.ts +24 -23
  149. package/src/scenarios/compensation-recovery.test.ts +28 -27
  150. package/src/scenarios/configurable-schema.test.ts +8 -6
  151. package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
  152. package/src/scenarios/conformance-execution-witness.test.ts +9 -8
  153. package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
  154. package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
  155. package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
  156. package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
  157. package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
  158. package/src/scenarios/connection-provider-resolution.test.ts +18 -16
  159. package/src/scenarios/connector-manifest-validity.test.ts +8 -7
  160. package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
  161. package/src/scenarios/context-summarization-replay.test.ts +14 -12
  162. package/src/scenarios/contract-provenance.test.ts +18 -18
  163. package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
  164. package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
  165. package/src/scenarios/conversationLifecycle.test.ts +2 -1
  166. package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
  167. package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
  168. package/src/scenarios/core-standard-profile.test.ts +8 -9
  169. package/src/scenarios/cost-attribution.test.ts +23 -21
  170. package/src/scenarios/credential-payload-redaction.test.ts +4 -3
  171. package/src/scenarios/credentials-capability-shape.test.ts +5 -4
  172. package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
  173. package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
  174. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
  175. package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
  176. package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
  177. package/src/scenarios/data-residency-admission.test.ts +15 -14
  178. package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
  179. package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
  180. package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
  181. package/src/scenarios/debugBundle.test.ts +25 -23
  182. package/src/scenarios/discovery-families-view.test.ts +5 -4
  183. package/src/scenarios/discovery.test.ts +30 -29
  184. package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
  185. package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
  186. package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
  187. package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
  188. package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
  189. package/src/scenarios/dispatchLoop.test.ts +3 -2
  190. package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
  191. package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
  192. package/src/scenarios/distillation-shape.test.ts +4 -4
  193. package/src/scenarios/distillation-stable-archive.test.ts +6 -6
  194. package/src/scenarios/distillation-token-budget.test.ts +5 -5
  195. package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
  196. package/src/scenarios/egress-audience-binding.test.ts +11 -10
  197. package/src/scenarios/egress-decision-content-free.test.ts +6 -5
  198. package/src/scenarios/egress-provenance-shape.test.ts +17 -18
  199. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
  200. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
  201. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
  202. package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
  203. package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
  204. package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
  205. package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
  206. package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
  207. package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
  208. package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
  209. package/src/scenarios/envelope-truncated.test.ts +19 -17
  210. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
  211. package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
  212. package/src/scenarios/errors.test.ts +20 -19
  213. package/src/scenarios/eventOrdering.test.ts +16 -14
  214. package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
  215. package/src/scenarios/experimental-tier-shape.test.ts +17 -15
  216. package/src/scenarios/export-bundle-portability.test.ts +17 -17
  217. package/src/scenarios/failure-path.test.ts +7 -6
  218. package/src/scenarios/feedback-capability-shape.test.ts +4 -3
  219. package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
  220. package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
  221. package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
  222. package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
  223. package/src/scenarios/feedback-record-and-list.test.ts +2 -1
  224. package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
  225. package/src/scenarios/fixtures-gating.test.ts +29 -28
  226. package/src/scenarios/fixtures-valid.test.ts +16 -15
  227. package/src/scenarios/form-content-instantiation.test.ts +15 -14
  228. package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
  229. package/src/scenarios/fs-path-traversal.test.ts +14 -12
  230. package/src/scenarios/goal-standing-continuation.test.ts +21 -21
  231. package/src/scenarios/grpc-transport.test.ts +9 -7
  232. package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
  233. package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
  234. package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
  235. package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
  236. package/src/scenarios/highConcurrency.test.ts +14 -13
  237. package/src/scenarios/host-callback-declaration.test.ts +8 -7
  238. package/src/scenarios/http-client-ssrf.test.ts +7 -5
  239. package/src/scenarios/i18n-negotiation.test.ts +14 -12
  240. package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
  241. package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
  242. package/src/scenarios/idempotency.test.ts +8 -7
  243. package/src/scenarios/idempotencyRetry.test.ts +13 -11
  244. package/src/scenarios/identity-owner-shape.test.ts +6 -5
  245. package/src/scenarios/identity-passthrough.test.ts +4 -3
  246. package/src/scenarios/interrupt-approval.test.ts +6 -5
  247. package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
  248. package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
  249. package/src/scenarios/interrupt-clarification.test.ts +4 -3
  250. package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
  251. package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
  252. package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
  253. package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
  254. package/src/scenarios/interruptRace.test.ts +12 -10
  255. package/src/scenarios/kv-atomic-increment.test.ts +11 -9
  256. package/src/scenarios/kv-cas.test.ts +14 -12
  257. package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
  258. package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
  259. package/src/scenarios/localized-content-delivery.test.ts +24 -26
  260. package/src/scenarios/maliciousManifest.test.ts +10 -8
  261. package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
  262. package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
  263. package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
  264. package/src/scenarios/mcp-discoverability.test.ts +9 -7
  265. package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
  266. package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
  267. package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
  268. package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
  269. package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
  270. package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
  271. package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
  272. package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
  273. package/src/scenarios/mcp-stateless-request.test.ts +11 -10
  274. package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
  275. package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
  276. package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
  277. package/src/scenarios/media-url-inline-cap.test.ts +21 -19
  278. package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
  279. package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
  280. package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
  281. package/src/scenarios/memory-attribution-shape.test.ts +4 -3
  282. package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
  283. package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
  284. package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
  285. package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
  286. package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
  287. package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
  288. package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
  289. package/src/scenarios/memory-degraded-projection.test.ts +10 -9
  290. package/src/scenarios/memory-injection-budget.test.ts +15 -14
  291. package/src/scenarios/metric-emission.test.ts +4 -3
  292. package/src/scenarios/model-capability-insufficient.test.ts +19 -17
  293. package/src/scenarios/model-capability-substituted.test.ts +20 -18
  294. package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
  295. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
  296. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
  297. package/src/scenarios/multi-node-ordering.test.ts +4 -3
  298. package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
  299. package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
  300. package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
  301. package/src/scenarios/multi-region-idempotency.test.ts +6 -5
  302. package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
  303. package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
  304. package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
  305. package/src/scenarios/oauth-capability-shape.test.ts +5 -4
  306. package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
  307. package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
  308. package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
  309. package/src/scenarios/orchestratorDispatch.test.ts +2 -1
  310. package/src/scenarios/orchestratorTermination.test.ts +2 -1
  311. package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
  312. package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
  313. package/src/scenarios/otel-emission-grpc.test.ts +3 -2
  314. package/src/scenarios/otel-emission.test.ts +6 -5
  315. package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
  316. package/src/scenarios/otel-trace-propagation.test.ts +2 -1
  317. package/src/scenarios/owner-subject-echo.test.ts +13 -12
  318. package/src/scenarios/owner-subject-shape.test.ts +11 -10
  319. package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
  320. package/src/scenarios/pack-registry-isolation.test.ts +4 -3
  321. package/src/scenarios/pack-registry-publish.test.ts +65 -63
  322. package/src/scenarios/pack-registry.test.ts +38 -36
  323. package/src/scenarios/pause-resume.test.ts +18 -16
  324. package/src/scenarios/policies.test.ts +20 -18
  325. package/src/scenarios/production-backpressure.test.ts +18 -16
  326. package/src/scenarios/production-retention-expiry.test.ts +8 -6
  327. package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
  328. package/src/scenarios/profileDerivation.test.ts +34 -33
  329. package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
  330. package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
  331. package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
  332. package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
  333. package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
  334. package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
  335. package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
  336. package/src/scenarios/prompt-pack-install.test.ts +14 -12
  337. package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
  338. package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
  339. package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
  340. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
  341. package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
  342. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
  343. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
  344. package/src/scenarios/prompt-template-shape.test.ts +30 -28
  345. package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
  346. package/src/scenarios/protocol-versions-array.test.ts +10 -9
  347. package/src/scenarios/provider-usage.test.ts +17 -15
  348. package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
  349. package/src/scenarios/purpose-propagation.test.ts +23 -21
  350. package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
  351. package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
  352. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
  353. package/src/scenarios/rate-limit-envelope.test.ts +6 -5
  354. package/src/scenarios/redaction.test.ts +13 -11
  355. package/src/scenarios/redactionAdversarial.test.ts +11 -9
  356. package/src/scenarios/registry-public.test.ts +12 -11
  357. package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
  358. package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
  359. package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
  360. package/src/scenarios/replay-fork.test.ts +20 -19
  361. package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
  362. package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
  363. package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
  364. package/src/scenarios/replay-retention-expiry.test.ts +11 -9
  365. package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
  366. package/src/scenarios/replayDeterminism.test.ts +13 -12
  367. package/src/scenarios/requirement-ledger.test.ts +15 -14
  368. package/src/scenarios/restart-during-run.test.ts +3 -2
  369. package/src/scenarios/route-coverage.test.ts +20 -19
  370. package/src/scenarios/run-diff.test.ts +22 -20
  371. package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
  372. package/src/scenarios/run-transport-economy.test.ts +13 -11
  373. package/src/scenarios/runner-ledger.test.ts +17 -16
  374. package/src/scenarios/runs-lifecycle.test.ts +7 -6
  375. package/src/scenarios/runtime-capabilities.test.ts +12 -10
  376. package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
  377. package/src/scenarios/runtime-requires-shape.test.ts +7 -6
  378. package/src/scenarios/safefetch-behavior.test.ts +22 -21
  379. package/src/scenarios/safefetch-live-audit.test.ts +14 -13
  380. package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
  381. package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
  382. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
  383. package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
  384. package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
  385. package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
  386. package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
  387. package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
  388. package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
  389. package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
  390. package/src/scenarios/self-hosted-runner.test.ts +26 -24
  391. package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
  392. package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
  393. package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
  394. package/src/scenarios/sql-injection-rejection.test.ts +8 -6
  395. package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
  396. package/src/scenarios/staleClaim.test.ts +5 -4
  397. package/src/scenarios/stream-modes-buffer.test.ts +8 -7
  398. package/src/scenarios/stream-modes-mixed.test.ts +10 -9
  399. package/src/scenarios/stream-modes.test.ts +12 -11
  400. package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
  401. package/src/scenarios/stream-text-fixture.test.ts +14 -13
  402. package/src/scenarios/streamReconnect.test.ts +13 -11
  403. package/src/scenarios/strict-behavior-gate.test.ts +9 -8
  404. package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
  405. package/src/scenarios/subrun-approval-gate.test.ts +3 -3
  406. package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
  407. package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
  408. package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
  409. package/src/scenarios/subworkflow.test.ts +10 -9
  410. package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
  411. package/src/scenarios/table-cursor-pagination.test.ts +8 -6
  412. package/src/scenarios/table-schema-enforcement.test.ts +7 -5
  413. package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
  414. package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
  415. package/src/scenarios/tool-catalog-projection.test.ts +11 -9
  416. package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
  417. package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
  418. package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
  419. package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
  420. package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
  421. package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
  422. package/src/scenarios/tool-hooks-shape.test.ts +3 -3
  423. package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
  424. package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
  425. package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
  426. package/src/scenarios/trigger-ingestion.test.ts +19 -17
  427. package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
  428. package/src/scenarios/v2-approver-enforced.test.ts +97 -0
  429. package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
  430. package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
  431. package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
  432. package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
  433. package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
  434. package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
  435. package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
  436. package/src/scenarios/v2-configurable-closed.test.ts +67 -0
  437. package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
  438. package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
  439. package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
  440. package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
  441. package/src/scenarios/v2-era-key.test.ts +86 -0
  442. package/src/scenarios/v2-error-registry.test.ts +89 -0
  443. package/src/scenarios/v2-event-type-closed.test.ts +97 -0
  444. package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
  445. package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
  446. package/src/scenarios/v2-header-scheme.test.ts +67 -0
  447. package/src/scenarios/v2-id-grammar.test.ts +77 -0
  448. package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
  449. package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
  450. package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
  451. package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
  452. package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
  453. package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
  454. package/src/scenarios/v2-min-client-version.test.ts +48 -0
  455. package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
  456. package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
  457. package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
  458. package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
  459. package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
  460. package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
  461. package/src/scenarios/v2-pack-isolation.test.ts +147 -0
  462. package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
  463. package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
  464. package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
  465. package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
  466. package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
  467. package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
  468. package/src/scenarios/v2-provider-conflict.test.ts +115 -0
  469. package/src/scenarios/v2-refresh-sla.test.ts +78 -0
  470. package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
  471. package/src/scenarios/v2-revocation-honored.test.ts +66 -0
  472. package/src/scenarios/v2-subject-link-record.test.ts +102 -0
  473. package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
  474. package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
  475. package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
  476. package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
  477. package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
  478. package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
  479. package/src/scenarios/verifier-gating.test.ts +8 -6
  480. package/src/scenarios/version-fold.test.ts +9 -8
  481. package/src/scenarios/version-negotiation.test.ts +12 -11
  482. package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
  483. package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
  484. package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
  485. package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
  486. package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
  487. package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
  488. package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
  489. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
  490. package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
  491. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
  492. package/src/scenarios/wasm-pack-load.test.ts +4 -3
  493. package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
  494. package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
  495. package/src/scenarios/webhook-negative.test.ts +11 -9
  496. package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
  497. package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
  498. package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
  499. package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
  500. package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
  501. package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
  502. package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
  503. package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
  504. package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
  505. package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
  506. package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
  507. package/src/scenarios/workflow-variable-format.test.ts +24 -24
  508. package/src/scenarios/workload-identity-behavior.test.ts +15 -13
  509. package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
  510. package/src/scenarios/workspace-behavior.test.ts +19 -18
  511. package/src/scenarios/workspace-capability-shape.test.ts +3 -2
  512. package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
  513. package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
  514. package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
  515. package/src/setup.ts +44 -6
  516. package/vitest.config.ts +5 -1
  517. package/api/.redocly.lint-ignore.yaml +0 -22
  518. package/api/asyncapi.yaml +0 -834
  519. package/api/grpc/openwop.proto +0 -251
  520. package/api/openapi.yaml +0 -2693
  521. package/api/redocly.yaml +0 -23
  522. package/schemas/README.md +0 -144
  523. package/schemas/a2a-task-state.schema.json +0 -78
  524. package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
  525. package/schemas/agent-deployment-transition.schema.json +0 -49
  526. package/schemas/agent-deployment.schema.json +0 -54
  527. package/schemas/agent-eval-suite.schema.json +0 -140
  528. package/schemas/agent-inventory-response.schema.json +0 -115
  529. package/schemas/agent-manifest.schema.json +0 -156
  530. package/schemas/agent-org-chart.schema.json +0 -82
  531. package/schemas/agent-ref.schema.json +0 -63
  532. package/schemas/agent-roster-entry.schema.json +0 -81
  533. package/schemas/agent-roster-response.schema.json +0 -21
  534. package/schemas/ai-envelope.schema.json +0 -134
  535. package/schemas/annotation-create.schema.json +0 -37
  536. package/schemas/annotation.schema.json +0 -56
  537. package/schemas/artifact-type-pack-manifest.schema.json +0 -244
  538. package/schemas/audit-verify-result.schema.json +0 -90
  539. package/schemas/budget-policy.schema.json +0 -18
  540. package/schemas/capabilities.schema.json +0 -4160
  541. package/schemas/certification-bundle-v2.schema.json +0 -118
  542. package/schemas/channel-presence-payload.schema.json +0 -41
  543. package/schemas/channel-written-payload.schema.json +0 -55
  544. package/schemas/chat-card-pack-manifest.schema.json +0 -253
  545. package/schemas/compact-tool-descriptor.schema.json +0 -51
  546. package/schemas/compensation-policy.schema.json +0 -64
  547. package/schemas/conformance-certification-bundle.schema.json +0 -86
  548. package/schemas/connection-pack-manifest.schema.json +0 -353
  549. package/schemas/conversation-event.schema.json +0 -168
  550. package/schemas/conversation-turn.schema.json +0 -117
  551. package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
  552. package/schemas/credential-provenance.schema.json +0 -18
  553. package/schemas/credential-reference.schema.json +0 -21
  554. package/schemas/debug-bundle.schema.json +0 -196
  555. package/schemas/dispatch-config.schema.json +0 -112
  556. package/schemas/envelopes/clarification.request.schema.json +0 -52
  557. package/schemas/envelopes/error.schema.json +0 -30
  558. package/schemas/envelopes/media.audio.schema.json +0 -38
  559. package/schemas/envelopes/media.file.schema.json +0 -37
  560. package/schemas/envelopes/media.image.schema.json +0 -33
  561. package/schemas/envelopes/schema.request.schema.json +0 -26
  562. package/schemas/envelopes/schema.response.schema.json +0 -22
  563. package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
  564. package/schemas/error-envelope.schema.json +0 -25
  565. package/schemas/eval-summary.schema.json +0 -92
  566. package/schemas/export-bundle.schema.json +0 -66
  567. package/schemas/form-content-pack-manifest.schema.json +0 -243
  568. package/schemas/frontend-plugin-manifest.schema.json +0 -109
  569. package/schemas/goal.schema.json +0 -104
  570. package/schemas/heartbeat-evaluated.schema.json +0 -14
  571. package/schemas/heartbeat-state-changed.schema.json +0 -14
  572. package/schemas/localized-content-language-settings.schema.json +0 -26
  573. package/schemas/localized-content-page-response.schema.json +0 -60
  574. package/schemas/localized-content-page.schema.json +0 -62
  575. package/schemas/localized-content-section.schema.json +0 -51
  576. package/schemas/memory-entry.schema.json +0 -36
  577. package/schemas/memory-list-options.schema.json +0 -37
  578. package/schemas/node-pack-manifest.schema.json +0 -654
  579. package/schemas/orchestrator-decision.schema.json +0 -90
  580. package/schemas/org-chart-responsibility-view.schema.json +0 -26
  581. package/schemas/pack-lockfile.schema.json +0 -108
  582. package/schemas/prompt-kind.schema.json +0 -8
  583. package/schemas/prompt-pack-manifest.schema.json +0 -117
  584. package/schemas/prompt-ref.schema.json +0 -40
  585. package/schemas/prompt-template.schema.json +0 -149
  586. package/schemas/proposal.schema.json +0 -84
  587. package/schemas/registry-version-manifest.schema.json +0 -208
  588. package/schemas/residency.schema.json +0 -16
  589. package/schemas/run-ancestry-response.schema.json +0 -54
  590. package/schemas/run-diff-response.schema.json +0 -64
  591. package/schemas/run-event-payloads.schema.json +0 -4452
  592. package/schemas/run-event.schema.json +0 -211
  593. package/schemas/run-options.schema.json +0 -80
  594. package/schemas/run-orchestrator-decided-event.schema.json +0 -20
  595. package/schemas/run-snapshot.schema.json +0 -148
  596. package/schemas/security-advisory.schema.json +0 -109
  597. package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
  598. package/schemas/self-hosted-runner-registration.schema.json +0 -53
  599. package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
  600. package/schemas/subject.schema.json +0 -56
  601. package/schemas/suspend-request.schema.json +0 -207
  602. package/schemas/tool-descriptor.schema.json +0 -63
  603. package/schemas/trigger-event.schema.json +0 -222
  604. package/schemas/trigger-subscription-registration.schema.json +0 -67
  605. package/schemas/trigger-subscription.schema.json +0 -26
  606. package/schemas/ui-plugin-message.schema.json +0 -90
  607. package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
  608. package/schemas/workflow-definition.schema.json +0 -850
  609. package/schemas/workload-identity.schema.json +0 -79
  610. package/schemas/workspace-file-create.schema.json +0 -20
  611. package/schemas/workspace-file.schema.json +0 -39
@@ -47,10 +47,10 @@ async function readSupportedEnvelopes(): Promise<string[] | null> {
47
47
  describe('aiEnvelope.universalKinds: advertisement shape (FINAL v1.1)', () => {
48
48
  it('capabilities.envelopeContracts is either absent or a well-formed object', async () => {
49
49
  const block = await readEnvelopeContracts();
50
- if (block === null) return; // host doesn't opt in — skip
50
+ if (block === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `block === null` returned early (host doesn\'t opt in — skip)'); // host doesn't opt in — skip
51
51
  expect(
52
52
  typeof block.advertised,
53
- driver.describe(
53
+ req('openwop.it.aiEnvelope.universalKinds.capabilities-envelopecontracts-is-either-absent-or-a-well-formed-object',
54
54
  'ai-envelope.md §"Capability handshake integration"',
55
55
  'capabilities.envelopeContracts.advertised MUST be a boolean when present',
56
56
  ),
@@ -59,11 +59,11 @@ describe('aiEnvelope.universalKinds: advertisement shape (FINAL v1.1)', () => {
59
59
 
60
60
  it('opted-in hosts advertise every universal kind in supportedEnvelopes', async () => {
61
61
  const block = await readEnvelopeContracts();
62
- if (block === null || !block.advertised) return; // not opted in — skip
62
+ if (block === null || !block.advertised) return softSkip('blocked', 'precondition not met — `block === null || !block.advertised` returned early (not opted in — skip) (seam, prior step, or fixture unavailable)'); // not opted in — skip
63
63
  const advertised = await readSupportedEnvelopes();
64
64
  expect(
65
65
  Array.isArray(advertised),
66
- driver.describe(
66
+ req('openwop.it.aiEnvelope.universalKinds.opted-in-hosts-advertise-every-universal-kind-in-supportedenvelopes',
67
67
  'capabilities.schema.json §supportedEnvelopes',
68
68
  'supportedEnvelopes MUST be present as an array on hosts that advertise envelopeContracts',
69
69
  ),
@@ -71,7 +71,7 @@ describe('aiEnvelope.universalKinds: advertisement shape (FINAL v1.1)', () => {
71
71
  for (const kind of UNIVERSALS) {
72
72
  expect(
73
73
  advertised!.includes(kind),
74
- driver.describe(
74
+ req('openwop.it.aiEnvelope.universalKinds.opted-in-hosts-advertise-every-universal-kind-in-supportedenvelopes',
75
75
  'ai-envelope.md §"Universal kinds"',
76
76
  `supportedEnvelopes MUST include "${kind}" — universals are always-allowed`,
77
77
  ),
@@ -103,8 +103,8 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
103
103
  payload: { questions: [{ id: 'q1', question: 'Which provider?' }] },
104
104
  meta: baseMeta,
105
105
  });
106
- if (r.status === 404) return;
107
- expect(r.body.status, driver.describe('ai-envelope.md §"Universal kinds"', 'valid clarification.request MUST be accepted')).toBe('accepted');
106
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
107
+ expect(r.body.status, req('openwop.it.aiEnvelope.universalKinds.accept-clarification-request-with-valid-payload-status-accepted', 'ai-envelope.md §"Universal kinds"', 'valid clarification.request MUST be accepted')).toBe('accepted');
108
108
  });
109
109
 
110
110
  it('accept schema.request → status: accepted', async () => {
@@ -116,8 +116,8 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
116
116
  payload: { envelopeType: 'vendor.acme.prd.create' },
117
117
  meta: baseMeta,
118
118
  });
119
- if (r.status === 404) return;
120
- expect(r.body.status).toBe('accepted');
119
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
120
+ expect(r.body.status, req('openwop.it.aiEnvelope.universalKinds.accept-schema-request-status-accepted', 'spec/v1/ai-envelope.md', 'accept schema.request → status: accepted')).toBe('accepted');
121
121
  });
122
122
 
123
123
  it('accept schema.response (ack:true) → status: accepted', async () => {
@@ -129,8 +129,8 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
129
129
  payload: { envelopeType: 'vendor.acme.prd.create', ack: true },
130
130
  meta: baseMeta,
131
131
  });
132
- if (r.status === 404) return;
133
- expect(r.body.status).toBe('accepted');
132
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
133
+ expect(r.body.status, req('openwop.it.aiEnvelope.universalKinds.accept-schema-response-ack-true-status-accepted', 'spec/v1/ai-envelope.md', 'accept schema.response (ack:true) → status: accepted')).toBe('accepted');
134
134
  });
135
135
 
136
136
  it('accept error envelope (LLM-emitted) → status: accepted (distinct from host-level ErrorEnvelope)', async () => {
@@ -142,8 +142,8 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
142
142
  payload: { code: 'validation_failed', message: 'I cannot produce JSON matching that schema' },
143
143
  meta: baseMeta,
144
144
  });
145
- if (r.status === 404) return;
146
- expect(r.body.status, driver.describe('ai-envelope.md §error', 'LLM-emitted error envelope MUST be accepted (NOT the host HTTP ErrorEnvelope)')).toBe('accepted');
145
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
146
+ expect(r.body.status, req('openwop.it.aiEnvelope.universalKinds.accept-error-envelope-llm-emitted-status-accepted-distinct-from-host-level-error', 'ai-envelope.md §error', 'LLM-emitted error envelope MUST be accepted (NOT the host HTTP ErrorEnvelope)')).toBe('accepted');
147
147
  });
148
148
 
149
149
  it('refuse invalid clarification.request (missing questions[]) → status: invalid', async () => {
@@ -155,22 +155,24 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
155
155
  payload: { contextType: 'form-field' }, // missing required `questions`
156
156
  meta: baseMeta,
157
157
  });
158
- if (r.status === 404) return;
158
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
159
159
  expect(
160
160
  r.body.status,
161
- driver.describe('ai-envelope.md §"Schema discipline"', 'malformed payload MUST be rejected with invalid'),
161
+ req('openwop.it.aiEnvelope.universalKinds.refuse-invalid-clarification-request-missing-questions-status-invalid', 'ai-envelope.md §"Schema discipline"', 'malformed payload MUST be rejected with invalid'),
162
162
  ).toBe('invalid');
163
- expect(Array.isArray(r.body.details), 'invalid outcome MUST carry validation details').toBe(true);
163
+ expect(Array.isArray(r.body.details), req('openwop.it.aiEnvelope.universalKinds.refuse-invalid-clarification-request-missing-questions-status-invalid', 'ai-envelope.md §"Schema discipline"', 'invalid outcome MUST carry validation details')).toBe(true);
164
164
  });
165
165
  });
166
166
 
167
167
  // E.1 engine-projection via the test-only event-log seam.
168
168
  import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
169
169
  import { capabilityFamily, discoveryFamilies } from '../lib/discovery-capabilities.js';
170
+ import { req } from '../lib/requirement-ids.js';
171
+ import { softSkip } from '../lib/soft-skip.js';
170
172
 
171
173
  describe('aiEnvelope.universalKinds: engine projection via event-log seam', () => {
172
174
  it('clarification.request MUST be lifted to interrupt.requested { kind: "clarification" } per interrupt.md', async () => {
173
- if (!(await isEventLogSeamAvailable())) return;
175
+ if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
174
176
  const runId = `r-uk-clar-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
175
177
  const r = await accept(
176
178
  {
@@ -183,20 +185,20 @@ describe('aiEnvelope.universalKinds: engine projection via event-log seam', () =
183
185
  },
184
186
  { projectTo: { runId, nodeId: 'n' } },
185
187
  );
186
- if (r.status === 404) return;
188
+ if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
187
189
  expect(r.body.status).toBe('accepted');
188
190
  const events = await queryTestEvents(runId, { type: 'interrupt.requested' });
189
- if (!events.ok) return;
191
+ if (!events.ok) return softSkip('blocked', 'precondition not met — `!events.ok` returned early (seam, prior step, or fixture unavailable)');
190
192
  expect(
191
193
  events.events.length,
192
- driver.describe('ai-envelope.md §"Universal kinds"', 'accepted clarification.request MUST project to interrupt.requested per interrupt.md'),
194
+ req('openwop.it.aiEnvelope.universalKinds.clarification-request-must-be-lifted-to-interrupt-requested-kind-clarification-p', 'ai-envelope.md §"Universal kinds"', 'accepted clarification.request MUST project to interrupt.requested per interrupt.md'),
193
195
  ).toBe(1);
194
196
  expect((events.events[0]!.payload as { kind?: string }).kind).toBe('clarification');
195
197
  await resetTestSeam();
196
198
  });
197
199
 
198
200
  it('error envelope MUST project to log.appended { level: "error" } — NOT node.failed', async () => {
199
- if (!(await isEventLogSeamAvailable())) return;
201
+ if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
200
202
  const runId = `r-uk-err-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
201
203
  await accept(
202
204
  {
@@ -211,20 +213,20 @@ describe('aiEnvelope.universalKinds: engine projection via event-log seam', () =
211
213
  );
212
214
  const logs = await queryTestEvents(runId, { type: 'log.appended' });
213
215
  const fails = await queryTestEvents(runId, { type: 'node.failed' });
214
- if (!logs.ok || !fails.ok) return;
216
+ if (!logs.ok || !fails.ok) return softSkip('blocked', 'precondition not met — `!logs.ok || !fails.ok` returned early (seam, prior step, or fixture unavailable)');
215
217
  expect(
216
218
  logs.events.some((e) => (e.payload as { level?: string }).level === 'error'),
217
- driver.describe('ai-envelope.md §"Universal kinds"', 'LLM-emitted error envelope MUST project to log.appended at error level'),
219
+ req('openwop.it.aiEnvelope.universalKinds.error-envelope-must-project-to-log-appended-level-error-not-node-failed', 'ai-envelope.md §"Universal kinds"', 'LLM-emitted error envelope MUST project to log.appended at error level'),
218
220
  ).toBe(true);
219
221
  expect(
220
222
  fails.events.length,
221
- driver.describe('ai-envelope.md §"Universal kinds"', 'LLM-emitted error envelope MUST NOT project to node.failed (distinct from terminal node failure)'),
223
+ req('openwop.it.aiEnvelope.universalKinds.error-envelope-must-project-to-log-appended-level-error-not-node-failed', 'ai-envelope.md §"Universal kinds"', 'LLM-emitted error envelope MUST NOT project to node.failed (distinct from terminal node failure)'),
222
224
  ).toBe(0);
223
225
  await resetTestSeam();
224
226
  });
225
227
 
226
228
  it('schema.request projects to log.appended (host implements next-turn injection out-of-band)', async () => {
227
- if (!(await isEventLogSeamAvailable())) return;
229
+ if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
228
230
  const runId = `r-uk-sr-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
229
231
  await accept(
230
232
  {
@@ -238,10 +240,10 @@ describe('aiEnvelope.universalKinds: engine projection via event-log seam', () =
238
240
  { projectTo: { runId, nodeId: 'n' } },
239
241
  );
240
242
  const events = await queryTestEvents(runId, { type: 'log.appended' });
241
- if (!events.ok) return;
243
+ if (!events.ok) return softSkip('blocked', 'precondition not met — `!events.ok` returned early (seam, prior step, or fixture unavailable)');
242
244
  expect(
243
245
  events.events.length,
244
- driver.describe('ai-envelope.md §"Universal kinds"', 'schema.request MUST project to log.appended (the schema delivery itself happens out-of-band via the host\'s next-turn system prompt)'),
246
+ req('openwop.it.aiEnvelope.universalKinds.schema-request-projects-to-log-appended-host-implements-next-turn-injection-out', 'ai-envelope.md §"Universal kinds"', 'schema.request MUST project to log.appended (the schema delivery itself happens out-of-band via the host\'s next-turn system prompt)'),
245
247
  ).toBeGreaterThan(0);
246
248
  await resetTestSeam();
247
249
  });
@@ -256,10 +258,10 @@ describe('aiEnvelope.universalKinds: schema.response counter-policy advertisemen
256
258
  const res = await driver.get('/.well-known/openwop');
257
259
  const body = res.json as { capabilities?: { aiEnvelope?: { schemaResponseCounterPolicy?: string } } } | undefined;
258
260
  const policy = capabilityFamily<{ schemaResponseCounterPolicy?: string }>(body, 'aiEnvelope')?.schemaResponseCounterPolicy;
259
- if (policy === undefined) return; // no policy advertised — host MAY omit
261
+ if (policy === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `policy === undefined` returned early (no policy advertised — host MAY omit)'); // no policy advertised — host MAY omit
260
262
  expect(
261
263
  ['counted', 'exempt'].includes(policy),
262
- driver.describe(
264
+ req('openwop.it.aiEnvelope.universalKinds.host-may-count-or-exempt-schema-response-against-envelopesperturn-when-advertise',
263
265
  'ai-envelope.md §"Universal kinds"',
264
266
  'when advertised, schemaResponseCounterPolicy MUST be either "counted" or "exempt"',
265
267
  ),
@@ -21,9 +21,9 @@ import { join } from 'node:path';
21
21
  import Ajv2020 from 'ajv/dist/2020.js';
22
22
  import addFormats from 'ajv-formats';
23
23
  import { SCHEMAS_DIR } from '../lib/paths.js';
24
+ import { req } from '../lib/requirement-ids.js';
24
25
 
25
26
  const BASE = 'https://openwop.dev/spec/v1/';
26
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
27
27
  function loadSchema(name: string): Record<string, unknown> {
28
28
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
29
29
  }
@@ -43,27 +43,27 @@ describe('aiproviders-input-shape: callAI perception input (RFC 0091 §B, server
43
43
  const input = ajv.getSchema(`${BASE}capabilities.schema.json#/properties/aiProviders/properties/input`);
44
44
 
45
45
  it('the aiProviders.input sub-schema exists', () => {
46
- expect(input, 'capabilities.aiProviders.input MUST be declared').toBeTruthy();
46
+ expect(input, req('openwop.it.aiproviders-input-shape.the-aiproviders-input-sub-schema-exists', 'RFC 0091', 'capabilities.aiProviders.input MUST be declared')).toBeTruthy();
47
47
  });
48
48
 
49
49
  it('accepts a conforming modalities advertisement', () => {
50
50
  expect(
51
51
  input!({ modalities: ['text', 'image', 'document'], maxBytesPerPart: 1048576 }),
52
- why('RFC 0091 §B', 'a conforming input advertisement MUST validate'),
52
+ req('openwop.it.aiproviders-input-shape.accepts-a-conforming-modalities-advertisement', 'RFC 0091 §B', 'a conforming input advertisement MUST validate'),
53
53
  ).toBe(true);
54
54
  });
55
55
 
56
56
  it('rejects an out-of-enum modality', () => {
57
57
  expect(
58
58
  input!({ modalities: ['text', 'video'] }),
59
- why('RFC 0091 §B', 'modalities is a closed enum (text/image/audio/document)'),
59
+ req('openwop.it.aiproviders-input-shape.rejects-an-out-of-enum-modality', 'RFC 0091 §B', 'modalities is a closed enum (text/image/audio/document)'),
60
60
  ).toBe(false);
61
61
  });
62
62
 
63
63
  it('rejects a non-positive maxBytesPerPart', () => {
64
64
  expect(
65
65
  input!({ modalities: ['text'], maxBytesPerPart: 0 }),
66
- why('RFC 0091 §B', 'maxBytesPerPart MUST be a positive integer'),
66
+ req('openwop.it.aiproviders-input-shape.rejects-a-non-positive-maxbytesperpart', 'RFC 0091 §B', 'maxBytesPerPart MUST be a positive integer'),
67
67
  ).toBe(false);
68
68
  });
69
69
  });
@@ -30,9 +30,7 @@ import { join } from 'node:path';
30
30
  import Ajv2020 from 'ajv/dist/2020.js';
31
31
  import addFormats from 'ajv-formats';
32
32
  import { SCHEMAS_DIR } from '../lib/paths.js';
33
-
34
- /** Server-free assertion-message helper. */
35
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
33
+ import { req } from '../lib/requirement-ids.js';
36
34
 
37
35
  function loadSchema(name: string): Record<string, unknown> {
38
36
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
@@ -49,14 +47,14 @@ describe('aiproviders-realtimevoice-shape: capability advertisement (RFC 0106 §
49
47
  .realtimeVoice;
50
48
  expect(
51
49
  realtimeVoice,
52
- why('host-capabilities.md §host.aiProviders', 'aiProviders.realtimeVoice MUST be declared'),
50
+ req('openwop.it.aiproviders-realtimevoice-shape.aiproviders-realtimevoice-is-an-object-with-the-four-sub-flags', 'host-capabilities.md §host.aiProviders', 'aiProviders.realtimeVoice MUST be declared'),
53
51
  ).toBeDefined();
54
- expect(realtimeVoice?.type, why('RFC 0106 §A', 'realtimeVoice MUST be an object')).toBe('object');
52
+ expect(realtimeVoice?.type, req('openwop.it.aiproviders-realtimevoice-shape.aiproviders-realtimevoice-is-an-object-with-the-four-sub-flags', 'RFC 0106 §A', 'realtimeVoice MUST be an object')).toBe('object');
55
53
  const props = realtimeVoice?.properties ?? {};
56
54
  for (const flag of ['transcription', 'synthesis', 'turnDetection', 'bargeIn']) {
57
55
  expect(
58
56
  Object.prototype.hasOwnProperty.call(props, flag),
59
- why('RFC 0106 §A', `realtimeVoice.${flag} MUST be declared`),
57
+ req('openwop.it.aiproviders-realtimevoice-shape.aiproviders-realtimevoice-is-an-object-with-the-four-sub-flags', 'RFC 0106 §A', `realtimeVoice.${flag} MUST be declared`),
60
58
  ).toBe(true);
61
59
  }
62
60
  });
@@ -66,7 +64,7 @@ describe('aiproviders-realtimevoice-shape: capability advertisement (RFC 0106 §
66
64
  const required = Array.isArray(aiProviders.required) ? (aiProviders.required as string[]) : [];
67
65
  expect(
68
66
  required.includes('realtimeVoice'),
69
- why('RFC 0106 §A', 'aiProviders.realtimeVoice MUST be optional (a host without live voice is valid)'),
67
+ req('openwop.it.aiproviders-realtimevoice-shape.realtimevoice-is-not-in-aiproviders-required-absence-no-live-voice-is-a-valid-de', 'RFC 0106 §A', 'aiProviders.realtimeVoice MUST be optional (a host without live voice is valid)'),
70
68
  ).toBe(false);
71
69
  });
72
70
 
@@ -78,24 +76,24 @@ describe('aiproviders-realtimevoice-shape: capability advertisement (RFC 0106 §
78
76
 
79
77
  expect(
80
78
  validate({ transcription: 'streaming', turnDetection: 'semantic', bargeIn: 'supported' }),
81
- why('RFC 0106 §A', 'a full transcription advertisement MUST validate'),
79
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'a full transcription advertisement MUST validate'),
82
80
  ).toBe(true);
83
- expect(validate({}), why('RFC 0106 §A', 'an empty realtimeVoice object MUST validate')).toBe(true);
81
+ expect(validate({}), req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'an empty realtimeVoice object MUST validate')).toBe(true);
84
82
  expect(
85
83
  validate({ turnDetection: 'semantic' }),
86
- why('RFC 0106 §A', 'turnDetection without transcription MUST be rejected (dependentRequired)'),
84
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'turnDetection without transcription MUST be rejected (dependentRequired)'),
87
85
  ).toBe(false);
88
86
  expect(
89
87
  validate({ bargeIn: 'supported' }),
90
- why('RFC 0106 §A', 'bargeIn without transcription MUST be rejected (dependentRequired)'),
88
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'bargeIn without transcription MUST be rejected (dependentRequired)'),
91
89
  ).toBe(false);
92
90
  expect(
93
91
  validate({ transcription: 'streaming', turnDetection: 'aggressive' }),
94
- why('RFC 0106 §A', 'an out-of-enum turnDetection MUST be rejected'),
92
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'an out-of-enum turnDetection MUST be rejected'),
95
93
  ).toBe(false);
96
94
  expect(
97
95
  validate({ transcription: true }),
98
- why('RFC 0106 §A', 'transcription MUST be the string const "streaming", not a boolean'),
96
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-realtimevoice-subschema-accepts-the-floor-and-enforces-the-turndetection', 'RFC 0106 §A', 'transcription MUST be the string const "streaming", not a boolean'),
99
97
  ).toBe(false);
100
98
  });
101
99
 
@@ -106,15 +104,15 @@ describe('aiproviders-realtimevoice-shape: capability advertisement (RFC 0106 §
106
104
 
107
105
  expect(
108
106
  validate({ realtimeVoice: { transcription: 'streaming', synthesis: 'streaming' } }),
109
- why('RFC 0106 §A', 'streaming synthesis without speechSynthesis: "supported" MUST be rejected'),
107
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-aiproviders-subschema-enforces-realtimevoice-synthesis-speechsynthesis', 'RFC 0106 §A', 'streaming synthesis without speechSynthesis: "supported" MUST be rejected'),
110
108
  ).toBe(false);
111
109
  expect(
112
110
  validate({ speechSynthesis: 'supported', realtimeVoice: { transcription: 'streaming', synthesis: 'streaming' } }),
113
- why('RFC 0106 §A', 'streaming synthesis WITH speechSynthesis: "supported" MUST validate'),
111
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-aiproviders-subschema-enforces-realtimevoice-synthesis-speechsynthesis', 'RFC 0106 §A', 'streaming synthesis WITH speechSynthesis: "supported" MUST validate'),
114
112
  ).toBe(true);
115
113
  expect(
116
114
  validate({ realtimeVoice: { transcription: 'streaming' } }),
117
- why('RFC 0106 §A', 'transcription-only (no synthesis) MUST validate without speechSynthesis'),
115
+ req('openwop.it.aiproviders-realtimevoice-shape.ajv-the-aiproviders-subschema-enforces-realtimevoice-synthesis-speechsynthesis', 'RFC 0106 §A', 'transcription-only (no synthesis) MUST validate without speechSynthesis'),
118
116
  ).toBe(true);
119
117
  });
120
118
  });
@@ -39,6 +39,8 @@ import { describe, it, expect } from 'vitest';
39
39
  import { driver } from '../lib/driver.js';
40
40
  import { behaviorGate } from '../lib/behavior-gate.js';
41
41
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
42
+ import { req } from '../lib/requirement-ids.js';
43
+ import { softSkip } from '../lib/soft-skip.js';
42
44
 
43
45
  const SEAM = '/v1/host/sample/ai/call';
44
46
 
@@ -91,7 +93,7 @@ describe('aiproviders-selfhosted-honesty (RFC 0108 §A.2/§D)', () => {
91
93
  provider: providerId,
92
94
  messages: [{ role: 'user', content: 'ping' }],
93
95
  });
94
- if (res.status === 404) return; // seam unwired — soft-skip the behavioral suite
96
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip the behavioral suite) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip the behavioral suite
95
97
 
96
98
  // §A.2 — the advertisement must be backed by a real endpoint. A success or a
97
99
  // transport-class failure both prove a real endpoint was reached; a
@@ -100,7 +102,7 @@ describe('aiproviders-selfhosted-honesty (RFC 0108 §A.2/§D)', () => {
100
102
  const code = errCode(res.json);
101
103
  expect(
102
104
  code === undefined || !NO_ENDPOINT_CODES.has(code),
103
- driver.describe(
105
+ req('openwop.it.aiproviders-selfhosted-honesty.a-selfhosted-dispatch-reaches-a-real-endpoint-a-2-and-never-discloses-the-endpoi',
104
106
  'RFC 0108 §A.2',
105
107
  `an advertised selfHosted id (${providerId}) MUST be backed by a configured, reachable endpoint ` +
106
108
  `(dispatch succeeds or fails with a transport error) — MUST NOT refuse "${code}" (no endpoint configured)`,
@@ -116,14 +118,14 @@ describe('aiproviders-selfhosted-honesty (RFC 0108 §A.2/§D)', () => {
116
118
  '[openwop-selfhosted-providers] §D disclosure check skipped — set OPENWOP_TEST_COMPAT_ENDPOINT ' +
117
119
  "to the host's configured compat endpoint to assert non-disclosure on the wire.",
118
120
  );
119
- return;
121
+ return softSkip('blocked', 'precondition not met — `!endpoint` returned early (seam, prior step, or fixture unavailable)');
120
122
  }
121
123
 
122
124
  const serialized = JSON.stringify(res.json ?? {});
123
125
  for (const needle of endpointNeedles(endpoint)) {
124
126
  expect(
125
127
  !serialized.includes(needle),
126
- driver.describe(
128
+ req('openwop.it.aiproviders-selfhosted-honesty.a-selfhosted-dispatch-reaches-a-real-endpoint-a-2-and-never-discloses-the-endpoi',
127
129
  'RFC 0108 §D (self-hosted-endpoint-no-disclosure)',
128
130
  `the endpoint location ("${needle}") MUST NOT appear in any selfHosted dispatch response or error payload`,
129
131
  ),
@@ -32,9 +32,7 @@ import { join } from 'node:path';
32
32
  import Ajv2020 from 'ajv/dist/2020.js';
33
33
  import addFormats from 'ajv-formats';
34
34
  import { SCHEMAS_DIR } from '../lib/paths.js';
35
-
36
- /** Server-free assertion-message helper. */
37
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
35
+ import { req } from '../lib/requirement-ids.js';
38
36
 
39
37
  function loadSchema(name: string): Record<string, unknown> {
40
38
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
@@ -87,19 +85,19 @@ describe('aiproviders-selfhosted-shape: self-hosted provider-class advertisement
87
85
  | undefined;
88
86
  expect(
89
87
  selfHosted,
90
- why('capabilities.md §aiProviders.selfHosted', 'aiProviders.selfHosted MUST be declared'),
88
+ req('openwop.it.aiproviders-selfhosted-shape.aiproviders-selfhosted-is-declared-as-a-string-with-uniqueitems', 'capabilities.md §aiProviders.selfHosted', 'aiProviders.selfHosted MUST be declared'),
91
89
  ).toBeDefined();
92
- expect(selfHosted?.type, why('RFC 0108 §A', 'selfHosted MUST be an array')).toBe('array');
90
+ expect(selfHosted?.type, req('openwop.it.aiproviders-selfhosted-shape.aiproviders-selfhosted-is-declared-as-a-string-with-uniqueitems', 'RFC 0108 §A', 'selfHosted MUST be an array')).toBe('array');
93
91
  expect(
94
92
  selfHosted?.uniqueItems,
95
- why('RFC 0108 §A', 'selfHosted entries MUST be unique'),
93
+ req('openwop.it.aiproviders-selfhosted-shape.aiproviders-selfhosted-is-declared-as-a-string-with-uniqueitems', 'RFC 0108 §A', 'selfHosted entries MUST be unique'),
96
94
  ).toBe(true);
97
- expect(selfHosted?.items?.type, why('RFC 0108 §A', 'selfHosted entries MUST be strings')).toBe(
95
+ expect(selfHosted?.items?.type, req('openwop.it.aiproviders-selfhosted-shape.aiproviders-selfhosted-is-declared-as-a-string-with-uniqueitems', 'RFC 0108 §A', 'selfHosted entries MUST be strings')).toBe(
98
96
  'string',
99
97
  );
100
98
  expect(
101
99
  selfHosted?.items?.minLength,
102
- why('RFC 0108 §A', 'a selfHosted id MUST be non-empty'),
100
+ req('openwop.it.aiproviders-selfhosted-shape.aiproviders-selfhosted-is-declared-as-a-string-with-uniqueitems', 'RFC 0108 §A', 'a selfHosted id MUST be non-empty'),
103
101
  ).toBe(1);
104
102
  });
105
103
 
@@ -109,7 +107,7 @@ describe('aiproviders-selfhosted-shape: self-hosted provider-class advertisement
109
107
  const required = Array.isArray(aiProviders?.required) ? (aiProviders!.required as string[]) : [];
110
108
  expect(
111
109
  required.includes('selfHosted'),
112
- why('RFC 0108 §A.1', 'aiProviders.selfHosted MUST be optional'),
110
+ req('openwop.it.aiproviders-selfhosted-shape.selfhosted-is-not-in-aiproviders-required-absence-no-self-hosted-endpoint-is-a-v', 'RFC 0108 §A.1', 'aiProviders.selfHosted MUST be optional'),
113
111
  ).toBe(false);
114
112
  });
115
113
 
@@ -125,19 +123,19 @@ describe('aiproviders-selfhosted-shape: self-hosted provider-class advertisement
125
123
 
126
124
  expect(
127
125
  validate(['ollama', 'compat']),
128
- why('RFC 0108 §A', 'a conforming selfHosted array MUST validate'),
126
+ req('openwop.it.aiproviders-selfhosted-shape.ajv-accepts-a-conforming-selfhosted-array-and-rejects-non-array-duplicate-empty', 'RFC 0108 §A', 'a conforming selfHosted array MUST validate'),
129
127
  ).toBe(true);
130
128
  expect(
131
129
  validate('ollama'),
132
- why('RFC 0108 §A', 'a non-array selfHosted MUST be rejected'),
130
+ req('openwop.it.aiproviders-selfhosted-shape.ajv-accepts-a-conforming-selfhosted-array-and-rejects-non-array-duplicate-empty', 'RFC 0108 §A', 'a non-array selfHosted MUST be rejected'),
133
131
  ).toBe(false);
134
132
  expect(
135
133
  validate(['ollama', 'ollama']),
136
- why('RFC 0108 §A', 'duplicate selfHosted entries MUST be rejected (uniqueItems)'),
134
+ req('openwop.it.aiproviders-selfhosted-shape.ajv-accepts-a-conforming-selfhosted-array-and-rejects-non-array-duplicate-empty', 'RFC 0108 §A', 'duplicate selfHosted entries MUST be rejected (uniqueItems)'),
137
135
  ).toBe(false);
138
136
  expect(
139
137
  validate(['']),
140
- why('RFC 0108 §A', 'an empty-string selfHosted id MUST be rejected (minLength 1)'),
138
+ req('openwop.it.aiproviders-selfhosted-shape.ajv-accepts-a-conforming-selfhosted-array-and-rejects-non-array-duplicate-empty', 'RFC 0108 §A', 'an empty-string selfHosted id MUST be rejected (minLength 1)'),
141
139
  ).toBe(false);
142
140
  });
143
141
 
@@ -149,13 +147,13 @@ describe('aiproviders-selfhosted-shape: self-hosted provider-class advertisement
149
147
  byok: ['anthropic', 'openai', 'compat'],
150
148
  selfHosted: ['ollama', 'compat'],
151
149
  }),
152
- why('RFC 0108 §A.1/§A.3', 'a conforming advertisement MUST have no violations'),
150
+ req('openwop.it.aiproviders-selfhosted-shape.a-1-subset-a-3-non-disclosure-a-conforming-doc-has-no-violations-an-out-of-subse', 'RFC 0108 §A.1/§A.3', 'a conforming advertisement MUST have no violations'),
153
151
  ).toEqual([]);
154
152
 
155
153
  // §A.1 violation: `vllm` not in supported.
156
154
  expect(
157
155
  validateSelfHosted({ supported: ['anthropic', 'ollama'], selfHosted: ['ollama', 'vllm'] }),
158
- why('RFC 0108 §A.1', 'a selfHosted id absent from supported MUST be flagged'),
156
+ req('openwop.it.aiproviders-selfhosted-shape.a-1-subset-a-3-non-disclosure-a-conforming-doc-has-no-violations-an-out-of-subse', 'RFC 0108 §A.1', 'a selfHosted id absent from supported MUST be flagged'),
159
157
  ).not.toEqual([]);
160
158
 
161
159
  // §A.3 violations: URL-shaped ids leak the endpoint location.
@@ -166,14 +164,14 @@ describe('aiproviders-selfhosted-shape: self-hosted provider-class advertisement
166
164
  ]) {
167
165
  expect(
168
166
  isUrlShaped(leaky),
169
- why('RFC 0108 §A.3', `the URL-shaped id "${leaky}" MUST be detected as non-conformant`),
167
+ req('openwop.it.aiproviders-selfhosted-shape.a-1-subset-a-3-non-disclosure-a-conforming-doc-has-no-violations-an-out-of-subse', 'RFC 0108 §A.3', `the URL-shaped id "${leaky}" MUST be detected as non-conformant`),
170
168
  ).toBe(true);
171
169
  }
172
170
 
173
171
  // A label with a non-numeric suffix (`compat:label`) is NOT URL-shaped — it is a permitted opaque id.
174
172
  expect(
175
173
  isUrlShaped('compat:local-ollama'),
176
- why('RFC 0108 §A.3', 'an opaque `compat:<label>` id (no host:port) MUST be permitted'),
174
+ req('openwop.it.aiproviders-selfhosted-shape.a-1-subset-a-3-non-disclosure-a-conforming-doc-has-no-violations-an-out-of-subse', 'RFC 0108 §A.3', 'an opaque `compat:<label>` id (no host:port) MUST be permitted'),
177
175
  ).toBe(false);
178
176
  });
179
177
  });
@@ -31,9 +31,7 @@ import { join } from 'node:path';
31
31
  import Ajv2020 from 'ajv/dist/2020.js';
32
32
  import addFormats from 'ajv-formats';
33
33
  import { SCHEMAS_DIR } from '../lib/paths.js';
34
-
35
- /** Server-free assertion-message helper. */
36
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
34
+ import { req } from '../lib/requirement-ids.js';
37
35
 
38
36
  function loadSchema(name: string): Record<string, unknown> {
39
37
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
@@ -49,11 +47,11 @@ describe('aiproviders-speechsynth-shape: capability advertisement (RFC 0105 §B,
49
47
  | undefined;
50
48
  expect(
51
49
  speechSynthesis,
52
- why('host-capabilities.md §host.aiProviders', 'aiProviders.speechSynthesis MUST be declared'),
50
+ req('openwop.it.aiproviders-speechsynth-shape.aiproviders-speechsynthesis-is-declared-as-the-string-const-supported', 'host-capabilities.md §host.aiProviders', 'aiProviders.speechSynthesis MUST be declared'),
53
51
  ).toBeDefined();
54
52
  expect(
55
53
  speechSynthesis?.const,
56
- why('RFC 0105 §B', 'aiProviders.speechSynthesis MUST be the string const "supported" (not an object)'),
54
+ req('openwop.it.aiproviders-speechsynth-shape.aiproviders-speechsynthesis-is-declared-as-the-string-const-supported', 'RFC 0105 §B', 'aiProviders.speechSynthesis MUST be the string const "supported" (not an object)'),
57
55
  ).toBe('supported');
58
56
  });
59
57
 
@@ -63,7 +61,7 @@ describe('aiproviders-speechsynth-shape: capability advertisement (RFC 0105 §B,
63
61
  const required = Array.isArray(aiProviders?.required) ? (aiProviders!.required as string[]) : [];
64
62
  expect(
65
63
  required.includes('speechSynthesis'),
66
- why('RFC 0105 §B', 'aiProviders.speechSynthesis MUST be optional (a host without TTS is valid)'),
64
+ req('openwop.it.aiproviders-speechsynth-shape.speechsynthesis-is-not-in-aiproviders-required-absence-no-tts-is-a-valid-default', 'RFC 0105 §B', 'aiProviders.speechSynthesis MUST be optional (a host without TTS is valid)'),
67
65
  ).toBe(false);
68
66
  });
69
67
 
@@ -81,12 +79,12 @@ describe('aiproviders-speechsynth-shape: capability advertisement (RFC 0105 §B,
81
79
 
82
80
  expect(
83
81
  validate('supported'),
84
- why('RFC 0105 §B', 'aiProviders.speechSynthesis === "supported" MUST validate'),
82
+ req('openwop.it.aiproviders-speechsynth-shape.ajv-accepts-the-string-const-form-and-rejects-the-object-form', 'RFC 0105 §B', 'aiProviders.speechSynthesis === "supported" MUST validate'),
85
83
  ).toBe(true);
86
84
 
87
85
  expect(
88
86
  validate({ supported: true }),
89
- why('RFC 0105 §B', 'the object form { supported: true } MUST be rejected by the const'),
87
+ req('openwop.it.aiproviders-speechsynth-shape.ajv-accepts-the-string-const-form-and-rejects-the-object-form', 'RFC 0105 §B', 'the object form { supported: true } MUST be rejected by the const'),
90
88
  ).toBe(false);
91
89
  });
92
90
  });
@@ -38,9 +38,8 @@ import { driver } from '../lib/driver.js';
38
38
  import { behaviorGate } from '../lib/behavior-gate.js';
39
39
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
40
40
  import { SCHEMAS_DIR } from '../lib/paths.js';
41
-
42
- /** Server-free assertion-message helper. */
43
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
41
+ import { req } from '../lib/requirement-ids.js';
42
+ import { softSkip } from '../lib/soft-skip.js';
44
43
 
45
44
  /** Read the canonical error code from a response body (tolerant of
46
45
  * `{error}` / `{code}` / `{error:{code}}` shapes). */
@@ -73,7 +72,7 @@ describe('aiproviders-subscription-scope: schema shape (RFC 0121, server-free)',
73
72
  | undefined;
74
73
  expect(
75
74
  authModes?.additionalProperties?.items?.enum,
76
- why('capabilities.md §aiProviders.authModes', 'the authModes enum MUST include "subscription" (RFC 0121)'),
75
+ req('openwop.it.aiproviders-subscription-scope.the-aiproviders-authmodes-enum-includes-subscription', 'capabilities.md §aiProviders.authModes', 'the authModes enum MUST include "subscription" (RFC 0121)'),
77
76
  ).toContain('subscription');
78
77
  });
79
78
  });
@@ -94,7 +93,7 @@ describe('aiproviders-subscription-scope: §B.7 in-byok (advertisement-gated)',
94
93
  for (const provider of subProviders) {
95
94
  expect(
96
95
  byok.has(provider),
97
- driver.describe('RFC 0121 §B.7', `subscription provider '${provider}' MUST appear in aiProviders.byok`),
96
+ req('openwop.it.aiproviders-subscription-scope.every-advertised-subscription-provider-appears-in-aiproviders-byok', 'RFC 0121 §B.7', `subscription provider '${provider}' MUST appear in aiProviders.byok`),
98
97
  ).toBe(true);
99
98
  }
100
99
  });
@@ -110,18 +109,18 @@ describe('aiproviders-subscription-scope: §B.8 user-scope-only (bind-seam-gated
110
109
  // multi-instance deploy with no durable per-user login) can still prove the
111
110
  // safety rail here. Soft-skips on 404 when the seam is unwired.
112
111
  const res = await driver.post(SEAM, { provider: 'anthropic', mode: 'subscription', scope: 'tenant' });
113
- if (res.status === 404) return; // seam unwired — soft-skip
112
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
114
113
 
115
114
  expect(
116
115
  res.status >= 400,
117
- driver.describe(
116
+ req('openwop.it.aiproviders-subscription-scope.a-tenant-scope-subscription-binding-is-rejected-with-credential-scope-forbidden',
118
117
  'RFC 0121 §B.8',
119
118
  `binding a subscription credential at tenant scope MUST be rejected (got HTTP ${res.status})`,
120
119
  ),
121
120
  ).toBe(true);
122
121
  expect(
123
122
  errCode(res.json),
124
- driver.describe(
123
+ req('openwop.it.aiproviders-subscription-scope.a-tenant-scope-subscription-binding-is-rejected-with-credential-scope-forbidden',
125
124
  'RFC 0121 §B.8',
126
125
  'a rejected tenant-scope subscription binding MUST carry the canonical `credential_scope_forbidden` error code',
127
126
  ),
@@ -18,8 +18,9 @@
18
18
 
19
19
  import { describe, it, expect } from 'vitest';
20
20
  import { behaviorGate } from '../lib/behavior-gate.js';
21
- import { driver } from '../lib/driver.js';
22
21
  import { isAnonymousActorAdvertised, anonDispatch } from '../lib/anonymousActor.js';
22
+ import { req } from '../lib/requirement-ids.js';
23
+ import { softSkip } from '../lib/soft-skip.js';
23
24
 
24
25
  const PROFILE = 'openwop-anonymous-actor';
25
26
 
@@ -33,19 +34,19 @@ describe('anonymous-actor-audit-opaque (RFC 0132 §D)', () => {
33
34
  it('the authorization.decided principal is opaque, non-PII, and the record carries no credential', async () => {
34
35
  if (!behaviorGate(PROFILE, await isAnonymousActorAdvertised())) return;
35
36
  const res = await anonDispatch({ tool: 'catalog.read' });
36
- if (res.status === 404 || res.status === 405) return; // seam unwired — soft-skip
37
+ if (res.status === 404 || res.status === 405) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 405` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
37
38
 
38
39
  const decided = res.json?.authorizationDecided?.payload;
39
40
  expect(
40
41
  decided?.principal,
41
- driver.describe('RFC 0132 §D', 'an anon tool call MUST emit authorization.decided with a principal'),
42
+ req('openwop.it.anonymous-actor-audit-opaque.the-authorization-decided-principal-is-opaque-non-pii-and-the-record-carries-no', 'RFC 0132 §D', 'an anon tool call MUST emit authorization.decided with a principal'),
42
43
  ).toBeTruthy();
43
44
 
44
45
  const principal = decided?.principal ?? '';
45
46
  for (const [pattern, label] of PII_PATTERNS) {
46
47
  expect(
47
48
  pattern.test(principal),
48
- driver.describe('SECURITY anon-actor-audit-opaque', `the anon principal MUST NOT embed ${label}`),
49
+ req('openwop.it.anonymous-actor-audit-opaque.the-authorization-decided-principal-is-opaque-non-pii-and-the-record-carries-no', 'SECURITY anon-actor-audit-opaque', `the anon principal MUST NOT embed ${label}`),
49
50
  ).toBe(false);
50
51
  }
51
52
  // The record MUST NOT carry credential material (reason is redaction-safe).
@@ -53,7 +54,7 @@ describe('anonymous-actor-audit-opaque (RFC 0132 §D)', () => {
53
54
  for (const [pattern, label] of PII_PATTERNS) {
54
55
  expect(
55
56
  pattern.test(serialized),
56
- driver.describe('SECURITY anon-actor-audit-opaque', `the audit record MUST NOT carry ${label}`),
57
+ req('openwop.it.anonymous-actor-audit-opaque.the-authorization-decided-principal-is-opaque-non-pii-and-the-record-carries-no', 'SECURITY anon-actor-audit-opaque', `the audit record MUST NOT carry ${label}`),
57
58
  ).toBe(false);
58
59
  }
59
60
  });
@@ -61,11 +62,11 @@ describe('anonymous-actor-audit-opaque (RFC 0132 §D)', () => {
61
62
  it('the run snapshot echoes owner.principalKind "anonymous"', async () => {
62
63
  if (!behaviorGate(PROFILE, await isAnonymousActorAdvertised())) return;
63
64
  const res = await anonDispatch({ tool: 'catalog.read' });
64
- if (res.status === 404 || res.status === 405) return; // seam unwired — soft-skip
65
- if (!res.json?.owner) return; // seam does not echo an owner triple — nothing to assert
65
+ if (res.status === 404 || res.status === 405) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 405` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
66
+ if (!res.json?.owner) return softSkip('blocked', 'precondition not met — `!res.json?.owner` returned early (seam does not echo an owner triple — nothing to assert) (seam, prior step, or fixture unavailable)'); // seam does not echo an owner triple — nothing to assert
66
67
  expect(
67
68
  res.json.owner.principalKind,
68
- driver.describe('RFC 0132 §A', 'an anon-authorized run MUST set owner.principalKind "anonymous"'),
69
+ req('openwop.it.anonymous-actor-audit-opaque.the-run-snapshot-echoes-owner-principalkind-anonymous', 'RFC 0132 §A', 'an anon-authorized run MUST set owner.principalKind "anonymous"'),
69
70
  ).toBe('anonymous');
70
71
  });
71
72
  });