@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,8 @@ import { join } from 'node:path';
34
34
  import { driver } from '../lib/driver.js';
35
35
  import { SCHEMAS_DIR } from '../lib/paths.js';
36
36
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
37
+ import { req } from '../lib/requirement-ids.js';
38
+ import { softSkip } from '../lib/soft-skip.js';
37
39
 
38
40
  const PROMPT_KIND_VALUES = ['system', 'user', 'few-shot', 'schema-hint'] as const;
39
41
 
@@ -92,11 +94,11 @@ describe('prompt-template-shape: schema compile (RFC 0027 §A)', () => {
92
94
  // Reuse the already-registered validator when present — Ajv refuses
93
95
  // to re-`compile` a schema whose `$id` it already knows.
94
96
  const validate = ajv.getSchema(schema['$id'] as string) ?? ajv.compile(schema);
95
- expect(validate, 'RFC 0027 §A: prompt-kind.schema.json MUST compile').toBeTypeOf('function');
96
- expect(schema.type, 'prompt-kind MUST be type: string').toBe('string');
97
+ expect(validate, req('openwop.it.prompt-template-shape.prompt-kind-schema-json-compiles-and-is-a-string-enum-of-the-four-canonical-kind', 'spec/v1/prompts.md §PromptTemplate', 'RFC 0027 §A: prompt-kind.schema.json MUST compile')).toBeTypeOf('function');
98
+ expect(schema.type, req('openwop.it.prompt-template-shape.prompt-kind-schema-json-compiles-and-is-a-string-enum-of-the-four-canonical-kind', 'spec/v1/prompts.md §PromptTemplate', 'prompt-kind MUST be type: string')).toBe('string');
97
99
  expect(
98
100
  schema.enum,
99
- driver.describe(
101
+ req('openwop.it.prompt-template-shape.prompt-kind-schema-json-compiles-and-is-a-string-enum-of-the-four-canonical-kind',
100
102
  'spec/v1/prompts.md §PromptTemplate',
101
103
  'prompt-kind enum MUST contain exactly the four canonical values',
102
104
  ),
@@ -106,13 +108,13 @@ describe('prompt-template-shape: schema compile (RFC 0027 §A)', () => {
106
108
  it('prompt-template.schema.json compiles with cross-ref to prompt-kind', () => {
107
109
  const schema = loadSchema('prompt-template.schema.json');
108
110
  const validate = ajv.compile(schema);
109
- expect(validate, 'RFC 0027 §A: prompt-template.schema.json MUST compile').toBeTypeOf('function');
111
+ expect(validate, req('openwop.it.prompt-template-shape.prompt-template-schema-json-compiles-with-cross-ref-to-prompt-kind', 'RFC 0027 §A', 'RFC 0027 §A: prompt-template.schema.json MUST compile')).toBeTypeOf('function');
110
112
  });
111
113
 
112
114
  it('prompt-ref.schema.json compiles', () => {
113
115
  const schema = loadSchema('prompt-ref.schema.json');
114
116
  const validate = ajv.compile(schema);
115
- expect(validate, 'RFC 0027 §B: prompt-ref.schema.json MUST compile').toBeTypeOf('function');
117
+ expect(validate, req('openwop.it.prompt-template-shape.prompt-ref-schema-json-compiles', 'RFC 0027 §A', 'RFC 0027 §B: prompt-ref.schema.json MUST compile')).toBeTypeOf('function');
116
118
  });
117
119
  });
118
120
 
@@ -130,7 +132,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
130
132
  const ok = validate(positive);
131
133
  expect(
132
134
  ok,
133
- `RFC 0027 §A: minimal PromptTemplate MUST validate; errors: ${JSON.stringify(validate.errors)}`,
135
+ req('openwop.it.prompt-template-shape.accepts-a-minimal-positive-prompttemplate-fixture', 'RFC 0027 §A', `RFC 0027 §A: minimal PromptTemplate MUST validate; errors: ${JSON.stringify(validate.errors)}`),
134
136
  ).toBe(true);
135
137
  });
136
138
 
@@ -157,7 +159,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
157
159
  const ok = validate(positive);
158
160
  expect(
159
161
  ok,
160
- `RFC 0027 §A: full PromptTemplate MUST validate; errors: ${JSON.stringify(validate.errors)}`,
162
+ req('openwop.it.prompt-template-shape.accepts-a-prompttemplate-with-typed-variables-modelhints-meta', 'RFC 0027 §A', `RFC 0027 §A: full PromptTemplate MUST validate; errors: ${JSON.stringify(validate.errors)}`),
161
163
  ).toBe(true);
162
164
  });
163
165
 
@@ -170,7 +172,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
170
172
  };
171
173
  expect(
172
174
  validate(negative),
173
- driver.describe(
175
+ req('openwop.it.prompt-template-shape.rejects-a-prompttemplate-missing-required-text',
174
176
  'spec/v1/prompts.md §PromptTemplate',
175
177
  'PromptTemplate MUST require text field',
176
178
  ),
@@ -186,7 +188,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
186
188
  };
187
189
  expect(
188
190
  validate(negative),
189
- driver.describe(
191
+ req('openwop.it.prompt-template-shape.rejects-a-prompttemplate-with-non-semver-version',
190
192
  'spec/v1/prompts.md §PromptTemplate',
191
193
  'PromptTemplate.version MUST match SemVer 2.0.0 pattern',
192
194
  ),
@@ -202,7 +204,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
202
204
  };
203
205
  expect(
204
206
  validate(negative),
205
- driver.describe(
207
+ req('openwop.it.prompt-template-shape.rejects-a-prompttemplate-with-invalid-templateid-uppercase-letter',
206
208
  'spec/v1/prompts.md §PromptTemplate',
207
209
  'PromptTemplate.templateId MUST match ^[a-z0-9][a-z0-9._-]{0,127}$',
208
210
  ),
@@ -218,7 +220,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
218
220
  };
219
221
  expect(
220
222
  validate(negative),
221
- driver.describe(
223
+ req('openwop.it.prompt-template-shape.rejects-a-prompttemplate-with-kind-not-in-the-prompt-kind-enum',
222
224
  'spec/v1/prompts.md §PromptTemplate',
223
225
  'PromptTemplate.kind MUST be one of the four canonical values',
224
226
  ),
@@ -235,7 +237,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
235
237
  };
236
238
  expect(
237
239
  validate(negative),
238
- driver.describe(
240
+ req('openwop.it.prompt-template-shape.rejects-an-unknown-top-level-property-additionalproperties-false',
239
241
  'spec/v1/prompts.md §PromptTemplate',
240
242
  'PromptTemplate top-level additionalProperties:false MUST reject unknown fields',
241
243
  ),
@@ -252,7 +254,7 @@ describe('prompt-template-shape: PromptTemplate round-trip (RFC 0027 §A)', () =
252
254
  };
253
255
  expect(
254
256
  validate(negative),
255
- driver.describe(
257
+ req('openwop.it.prompt-template-shape.rejects-a-promptvariable-with-bad-name-pattern-dash',
256
258
  'spec/v1/prompts.md §PromptTemplate',
257
259
  'PromptVariable.name MUST match common-templating identifier pattern (no dashes)',
258
260
  ),
@@ -265,19 +267,19 @@ describe('prompt-template-shape: PromptRef round-trip (RFC 0027 §B)', () => {
265
267
  const validate = ajv.compile(loadSchema('prompt-ref.schema.json'));
266
268
 
267
269
  it('accepts stringy form without version', () => {
268
- expect(validate('prompt:writer-system')).toBe(true);
270
+ expect(validate('prompt:writer-system'), req('openwop.it.prompt-template-shape.accepts-stringy-form-without-version', 'RFC 0027 §A', 'accepts stringy form without version')).toBe(true);
269
271
  });
270
272
 
271
273
  it('accepts stringy form with version', () => {
272
- expect(validate('prompt:writer-system@1.2.3')).toBe(true);
274
+ expect(validate('prompt:writer-system@1.2.3'), req('openwop.it.prompt-template-shape.accepts-stringy-form-with-version', 'RFC 0027 §A', 'accepts stringy form with version')).toBe(true);
273
275
  });
274
276
 
275
277
  it('accepts stringy form with vendor-prefixed templateId', () => {
276
- expect(validate('prompt:vendor.acme.writer.v2@2.0.0')).toBe(true);
278
+ expect(validate('prompt:vendor.acme.writer.v2@2.0.0'), req('openwop.it.prompt-template-shape.accepts-stringy-form-with-vendor-prefixed-templateid', 'RFC 0027 §A', 'accepts stringy form with vendor-prefixed templateId')).toBe(true);
277
279
  });
278
280
 
279
281
  it('accepts object form with templateId only', () => {
280
- expect(validate({ templateId: 'writer-system' })).toBe(true);
282
+ expect(validate({ templateId: 'writer-system' }), req('openwop.it.prompt-template-shape.accepts-object-form-with-templateid-only', 'RFC 0027 §A', 'accepts object form with templateId only')).toBe(true);
281
283
  });
282
284
 
283
285
  it('accepts object form with libraryId, version, and variableOverrides', () => {
@@ -287,35 +289,35 @@ describe('prompt-template-shape: PromptRef round-trip (RFC 0027 §B)', () => {
287
289
  templateId: 'writer-system',
288
290
  version: '1.0.0',
289
291
  variableOverrides: { tone: 'formal' },
290
- }),
292
+ }), req('openwop.it.prompt-template-shape.accepts-object-form-with-libraryid-version-and-variableoverrides', 'RFC 0027 §A', 'accepts object form with libraryId, version, and variableOverrides'),
291
293
  ).toBe(true);
292
294
  });
293
295
 
294
296
  it('rejects stringy form without `prompt:` prefix', () => {
295
297
  expect(
296
298
  validate('writer-system'),
297
- driver.describe('spec/v1/prompts.md §PromptRef', 'stringy PromptRef MUST start with prompt:'),
299
+ req('openwop.it.prompt-template-shape.rejects-stringy-form-without-prompt-prefix', 'spec/v1/prompts.md §PromptRef', 'stringy PromptRef MUST start with prompt:'),
298
300
  ).toBe(false);
299
301
  });
300
302
 
301
303
  it('rejects stringy form with non-SemVer version', () => {
302
304
  expect(
303
305
  validate('prompt:writer-system@latest'),
304
- driver.describe('spec/v1/prompts.md §PromptRef', 'stringy PromptRef version MUST be SemVer'),
306
+ req('openwop.it.prompt-template-shape.rejects-stringy-form-with-non-semver-version', 'spec/v1/prompts.md §PromptRef', 'stringy PromptRef version MUST be SemVer'),
305
307
  ).toBe(false);
306
308
  });
307
309
 
308
310
  it('rejects object form missing required templateId', () => {
309
311
  expect(
310
312
  validate({ version: '1.0.0' }),
311
- driver.describe('spec/v1/prompts.md §PromptRef', 'object PromptRef MUST require templateId'),
313
+ req('openwop.it.prompt-template-shape.rejects-object-form-missing-required-templateid', 'spec/v1/prompts.md §PromptRef', 'object PromptRef MUST require templateId'),
312
314
  ).toBe(false);
313
315
  });
314
316
 
315
317
  it('rejects object form with unknown additional property', () => {
316
318
  expect(
317
319
  validate({ templateId: 'writer-system', unknownExtra: true }),
318
- driver.describe(
320
+ req('openwop.it.prompt-template-shape.rejects-object-form-with-unknown-additional-property',
319
321
  'spec/v1/prompts.md §PromptRef',
320
322
  'object PromptRef additionalProperties:false MUST reject unknown fields',
321
323
  ),
@@ -326,24 +328,24 @@ describe('prompt-template-shape: PromptRef round-trip (RFC 0027 §B)', () => {
326
328
  describe.skipIf(HTTP_SKIP)('prompt-template-shape: capabilities.prompts advertisement (RFC 0027 §D)', () => {
327
329
  it('capabilities.prompts (when present) carries the optional shape per RFC 0027 §D', async () => {
328
330
  const d = await readDiscovery();
329
- if (d === null) return;
331
+ if (d === null) return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
330
332
  const prompts = capabilityFamily(d, 'prompts');
331
- if (prompts === undefined) return; // optional block; host MAY omit
333
+ if (prompts === undefined) return softSkip('blocked', 'precondition not met — `prompts === undefined` returned early (optional block; host MAY omit) (seam, prior step, or fixture unavailable)'); // optional block; host MAY omit
332
334
  expect(
333
335
  typeof prompts.supported,
334
- driver.describe(
336
+ req('openwop.it.prompt-template-shape.capabilities-prompts-when-present-carries-the-optional-shape-per-rfc-0027-d',
335
337
  'spec/v1/prompts.md §Capability advertisement',
336
338
  'capabilities.prompts.supported MUST be boolean when block is advertised',
337
339
  ),
338
340
  ).toBe('boolean');
339
341
  if (prompts.templateKinds !== undefined) {
340
- expect(Array.isArray(prompts.templateKinds), 'templateKinds MUST be an array').toBe(true);
342
+ expect(Array.isArray(prompts.templateKinds), req('openwop.it.prompt-template-shape.capabilities-prompts-when-present-carries-the-optional-shape-per-rfc-0027-d', 'spec/v1/prompts.md §Capability advertisement', 'templateKinds MUST be an array')).toBe(true);
341
343
  for (const k of prompts.templateKinds as unknown[]) {
342
344
  expect((PROMPT_KIND_VALUES as readonly string[]).includes(String(k))).toBe(true);
343
345
  }
344
346
  }
345
347
  if (prompts.variableSources !== undefined) {
346
- expect(Array.isArray(prompts.variableSources), 'variableSources MUST be an array').toBe(true);
348
+ expect(Array.isArray(prompts.variableSources), req('openwop.it.prompt-template-shape.capabilities-prompts-when-present-carries-the-optional-shape-per-rfc-0027-d', 'spec/v1/prompts.md §Capability advertisement', 'variableSources MUST be an array')).toBe(true);
347
349
  for (const s of prompts.variableSources as unknown[]) {
348
350
  expect(['input', 'variable', 'secret', 'context']).toContain(String(s));
349
351
  }
@@ -352,7 +354,7 @@ describe.skipIf(HTTP_SKIP)('prompt-template-shape: capabilities.prompts advertis
352
354
  expect(['off', 'hashed', 'full']).toContain(String(prompts.observability));
353
355
  }
354
356
  if (prompts.maxTemplateBytes !== undefined) {
355
- expect(typeof prompts.maxTemplateBytes, 'maxTemplateBytes MUST be integer').toBe('number');
357
+ expect(typeof prompts.maxTemplateBytes, req('openwop.it.prompt-template-shape.capabilities-prompts-when-present-carries-the-optional-shape-per-rfc-0027-d', 'spec/v1/prompts.md §Capability advertisement', 'maxTemplateBytes MUST be integer')).toBe('number');
356
358
  expect((prompts.maxTemplateBytes as number) > 0).toBe(true);
357
359
  expect((prompts.maxTemplateBytes as number) <= 65536).toBe(true);
358
360
  }
@@ -31,8 +31,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
31
31
  import { driver } from '../lib/driver.js';
32
32
  import { behaviorGate } from '../lib/behavior-gate.js';
33
33
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
34
-
35
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
34
+ import { req } from '../lib/requirement-ids.js';
35
+ import { softSkip } from '../lib/soft-skip.js';
36
36
  function loadSchema(name: string): Record<string, unknown> {
37
37
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
38
38
  }
@@ -43,21 +43,21 @@ describe('proposal-reviewable-learning: capability advertisement (RFC 0096 §A,
43
43
 
44
44
  it('capabilities schema declares agents.proposals with its required sub-flags', () => {
45
45
  const proposals = agents?.properties?.proposals;
46
- expect(proposals, why('capabilities.md §agents', 'agents.proposals MUST be declared')).toBeDefined();
46
+ expect(proposals, req('openwop.it.proposal-reviewable-learning.capabilities-schema-declares-agents-proposals-with-its-required-sub-flags', 'capabilities.md §agents', 'agents.proposals MUST be declared')).toBeDefined();
47
47
  for (const flag of ['artifactKinds', 'duplicationDetection', 'activation']) {
48
- expect(proposals?.properties?.[flag], why('RFC 0096 §A', `agents.proposals.${flag} MUST be declared`)).toBeDefined();
48
+ expect(proposals?.properties?.[flag], req('openwop.it.proposal-reviewable-learning.capabilities-schema-declares-agents-proposals-with-its-required-sub-flags', 'RFC 0096 §A', `agents.proposals.${flag} MUST be declared`)).toBeDefined();
49
49
  }
50
- expect(proposals?.required, why('RFC 0096 §A', 'artifactKinds + activation MUST be required')).toEqual(
50
+ expect(proposals?.required, req('openwop.it.proposal-reviewable-learning.capabilities-schema-declares-agents-proposals-with-its-required-sub-flags', 'RFC 0096 §A', 'artifactKinds + activation MUST be required')).toEqual(
51
51
  expect.arrayContaining(['artifactKinds', 'activation']),
52
52
  );
53
53
  });
54
54
 
55
55
  it('the `rule` artifact kind is NOT in the enum (dropped — no defining RFC)', () => {
56
56
  const kinds = (agents?.properties?.proposals as { properties?: Record<string, { items?: { enum?: string[] } }> })?.properties?.artifactKinds?.items?.enum ?? [];
57
- expect(kinds, why('RFC 0096 §A', 'artifactKinds enumerates the four kinds with a defining RFC')).toEqual(
57
+ expect(kinds, req('openwop.it.proposal-reviewable-learning.the-rule-artifact-kind-is-not-in-the-enum-dropped-no-defining-rfc', 'RFC 0096 §A', 'artifactKinds enumerates the four kinds with a defining RFC')).toEqual(
58
58
  expect.arrayContaining(['agent-pack', 'workflow-chain-pack', 'prompt-template', 'automation']),
59
59
  );
60
- expect(kinds, why('RFC 0096 §A', '`rule` MUST NOT appear — it has no defining RFC, so its artifact is unvalidatable')).not.toContain('rule');
60
+ expect(kinds, req('openwop.it.proposal-reviewable-learning.the-rule-artifact-kind-is-not-in-the-enum-dropped-no-defining-rfc', 'RFC 0096 §A', '`rule` MUST NOT appear — it has no defining RFC, so its artifact is unvalidatable')).not.toContain('rule');
61
61
  });
62
62
  });
63
63
 
@@ -77,13 +77,13 @@ describe('proposal-reviewable-learning: Proposal shape (RFC 0096 §B, server-fre
77
77
  };
78
78
 
79
79
  it('validates a conforming draft proposal', () => {
80
- expect(validate(good), why('RFC 0096 §B', `a conforming proposal MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
80
+ expect(validate(good), req('openwop.it.proposal-reviewable-learning.validates-a-conforming-draft-proposal', 'RFC 0096 §B', `a conforming proposal MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
81
81
  });
82
82
 
83
83
  it('rejects an unknown state and the dropped `rule` kind', () => {
84
- expect(validate({ ...good, state: 'live' }), why('RFC 0096 §B', 'a state outside the lifecycle enum MUST be rejected')).toBe(false);
85
- expect(validate({ ...good, kind: 'rule' }), why('RFC 0096 §B', '`kind: "rule"` MUST be rejected (dropped from the enum)')).toBe(false);
86
- expect(validate({ ...good, owner: { workspace: 'x' } }), why('RFC 0048', 'owner without tenant MUST be rejected')).toBe(false);
84
+ expect(validate({ ...good, state: 'live' }), req('openwop.it.proposal-reviewable-learning.rejects-an-unknown-state-and-the-dropped-rule-kind', 'RFC 0096 §B', 'a state outside the lifecycle enum MUST be rejected')).toBe(false);
85
+ expect(validate({ ...good, kind: 'rule' }), req('openwop.it.proposal-reviewable-learning.rejects-an-unknown-state-and-the-dropped-rule-kind', 'RFC 0096 §B', '`kind: "rule"` MUST be rejected (dropped from the enum)')).toBe(false);
86
+ expect(validate({ ...good, owner: { workspace: 'x' } }), req('openwop.it.proposal-reviewable-learning.rejects-an-unknown-state-and-the-dropped-rule-kind', 'RFC 0048', 'owner without tenant MUST be rejected')).toBe(false);
87
87
  });
88
88
  });
89
89
 
@@ -96,15 +96,15 @@ describe('proposal-reviewable-learning: content-free events (RFC 0096 §D, serve
96
96
 
97
97
  it('proposal.created and proposal.activated are in the RunEventType enum', () => {
98
98
  const en = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
99
- expect(en).toContain('proposal.created');
99
+ expect(en, req('openwop.it.proposal-reviewable-learning.proposal-created-and-proposal-activated-are-in-the-runeventtype-enum', 'RFC 0096', 'proposal.created and proposal.activated are in the RunEventType enum')).toContain('proposal.created');
100
100
  expect(en).toContain('proposal.activated');
101
101
  });
102
102
 
103
103
  it('proposal.created is content-free — an artifact body and rationale text are rejected', () => {
104
104
  const created = ajv.getSchema('payloads#/$defs/proposalCreated')!;
105
- expect(created({ proposalId: 'p1', kind: 'agent-pack', sourceRunIds: ['r1'], duplicateOf: null }), why('RFC 0096 §D', 'a content-free proposal.created MUST validate')).toBe(true);
106
- expect(created({ proposalId: 'p1', kind: 'agent-pack', artifact: { x: 1 } }), why('SECURITY invariant proposal-inert-until-applied', 'proposal.created MUST NOT carry the artifact body')).toBe(false);
107
- expect(created({ proposalId: 'p1', kind: 'agent-pack', rationale: 'because…' }), why('RFC 0096 §D', 'proposal.created MUST NOT carry rationale text')).toBe(false);
105
+ expect(created({ proposalId: 'p1', kind: 'agent-pack', sourceRunIds: ['r1'], duplicateOf: null }), req('openwop.it.proposal-reviewable-learning.proposal-created-is-content-free-an-artifact-body-and-rationale-text-are-rejecte', 'RFC 0096 §D', 'a content-free proposal.created MUST validate')).toBe(true);
106
+ expect(created({ proposalId: 'p1', kind: 'agent-pack', artifact: { x: 1 } }), req('openwop.it.proposal-reviewable-learning.proposal-created-is-content-free-an-artifact-body-and-rationale-text-are-rejecte', 'SECURITY invariant proposal-inert-until-applied', 'proposal.created MUST NOT carry the artifact body')).toBe(false);
107
+ expect(created({ proposalId: 'p1', kind: 'agent-pack', rationale: 'because…' }), req('openwop.it.proposal-reviewable-learning.proposal-created-is-content-free-an-artifact-body-and-rationale-text-are-rejecte', 'RFC 0096 §D', 'proposal.created MUST NOT carry rationale text')).toBe(false);
108
108
  });
109
109
  });
110
110
 
@@ -114,16 +114,16 @@ describe('proposal-reviewable-learning: behavioral (RFC 0096 §E, capability-gat
114
114
  if (!behaviorGate('agents.proposals', agents?.proposals !== undefined)) return;
115
115
 
116
116
  const list = await driver.get('/v1/host/sample/proposals?state=draft');
117
- if (list.status === 404 || list.status === 403) return; // seam unwired — soft-skip
117
+ if (list.status === 404 || list.status === 403) return softSkip('blocked', 'precondition not met — `list.status === 404 || list.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
118
118
  const proposals = (list.json as { proposals?: Array<{ id: string }> })?.proposals ?? [];
119
- if (proposals.length === 0) return; // nothing to act on — soft-skip
119
+ if (proposals.length === 0) return softSkip('blocked', 'precondition not met — `proposals.length === 0` returned early (nothing to act on — soft-skip) (seam, prior step, or fixture unavailable)'); // nothing to act on — soft-skip
120
120
 
121
121
  // Apply with no auth/scope — MUST be refused.
122
122
  const res = await driver.post(`/v1/host/sample/proposals/${proposals[0]!.id}/apply`, {});
123
- if (res.status === 404) return;
123
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
124
124
  expect(
125
125
  res.status,
126
- driver.describe('agent-memory.md §"Reviewable learning" clause 2', 'apply without the activation scope MUST be denied (403)'),
126
+ req('openwop.it.proposal-reviewable-learning.apply-without-the-activation-scope-is-denied-403-and-installs-nothing', 'agent-memory.md §"Reviewable learning" clause 2', 'apply without the activation scope MUST be denied (403)'),
127
127
  ).toBe(403);
128
128
  });
129
129
  });
@@ -29,6 +29,7 @@ import { driver } from '../lib/driver.js';
29
29
  import { SCHEMAS_DIR } from '../lib/paths.js';
30
30
  import { isCore, type DiscoveryPayload } from '../lib/profiles.js';
31
31
  import { softSkip } from '../lib/soft-skip.js';
32
+ import { req } from '../lib/requirement-ids.js';
32
33
 
33
34
  interface CapsSchema {
34
35
  $schema: string;
@@ -43,7 +44,7 @@ const caps = JSON.parse(readFileSync(join(SCHEMAS_DIR, 'capabilities.schema.json
43
44
  describe('protocol-versions-array: schema shape (RFC 0165 §A.1, server-free)', () => {
44
45
  it('declares root `protocolVersions` as a unique, non-empty string array', () => {
45
46
  const p = caps.properties.protocolVersions;
46
- expect(p, 'RFC 0165 §A.1: capabilities.schema.json MUST declare root `protocolVersions`').toBeDefined();
47
+ expect(p, req('openwop.it.protocol-versions-array.declares-root-protocolversions-as-a-unique-non-empty-string-array', 'RFC 0165 §A', 'RFC 0165 §A.1: capabilities.schema.json MUST declare root `protocolVersions`')).toBeDefined();
47
48
  expect(p?.type).toBe('array');
48
49
  expect(p?.minItems).toBe(1);
49
50
  expect(p?.uniqueItems).toBe(true);
@@ -52,14 +53,14 @@ describe('protocol-versions-array: schema shape (RFC 0165 §A.1, server-free)',
52
53
  it('item grammar equals the scalar grammar (one axis, one grammar)', () => {
53
54
  expect(
54
55
  caps.properties.protocolVersions?.items?.pattern,
55
- 'RFC 0165 §A.1: protocolVersions items MUST use the RFC 0149 §C grammar, not the A2A item pattern',
56
+ req('openwop.it.protocol-versions-array.item-grammar-equals-the-scalar-grammar-one-axis-one-grammar', 'RFC 0165 §A', 'RFC 0165 §A.1: protocolVersions items MUST use the RFC 0149 §C grammar, not the A2A item pattern'),
56
57
  ).toBe(caps.properties.protocolVersion?.pattern);
57
58
  });
58
59
 
59
60
  it('accepts ["1.11", "2.0"], rejects "01.0", "1.0.0", duplicates, and empty', () => {
60
61
  const ajv = new Ajv2020({ allErrors: true, strict: false });
61
62
  const validate = ajv.compile({ $schema: caps.$schema, ...(caps.properties.protocolVersions as Record<string, unknown>) });
62
- expect(validate(['1.11', '2.0'])).toBe(true);
63
+ expect(validate(['1.11', '2.0']), req('openwop.it.protocol-versions-array.accepts-1-11-2-0-rejects-01-0-1-0-0-duplicates-and-empty', 'RFC 0165 §A', 'accepts ["1.11", "2.0"], rejects "01.0", "1.0.0", duplicates, and empty')).toBe(true);
63
64
  expect(validate(['01.0'])).toBe(false);
64
65
  expect(validate(['1.0.0'])).toBe(false);
65
66
  expect(validate(['1.0', '1.0'])).toBe(false);
@@ -77,14 +78,14 @@ describe('protocol-versions-array: advertisement (RFC 0165 §A.2 — presence-ga
77
78
  if (arr === undefined) {
78
79
  return softSkip('inapplicable', 'host does not advertise protocolVersions (RFC 0165 §A — optional in v1.x)');
79
80
  }
80
- expect(Array.isArray(arr), driver.describe('RFC 0165 §A.1', 'protocolVersions MUST be an array')).toBe(true);
81
+ expect(Array.isArray(arr), req('openwop.it.protocol-versions-array.when-advertised-every-item-matches-the-grammar-items-are-unique-and-the-array-co', 'RFC 0165 §A.1', 'protocolVersions MUST be an array')).toBe(true);
81
82
  const items = arr as unknown[];
82
- expect(items.length, driver.describe('RFC 0165 §A.1', 'protocolVersions MUST be non-empty')).toBeGreaterThan(0);
83
+ expect(items.length, req('openwop.it.protocol-versions-array.when-advertised-every-item-matches-the-grammar-items-are-unique-and-the-array-co', 'RFC 0165 §A.1', 'protocolVersions MUST be non-empty')).toBeGreaterThan(0);
83
84
  for (const v of items) {
84
- expect(typeof v === 'string' && GRAMMAR.test(v), driver.describe('RFC 0165 §A.1', `protocolVersions item ${JSON.stringify(v)} MUST match the RFC 0149 §C grammar`)).toBe(true);
85
+ expect(typeof v === 'string' && GRAMMAR.test(v), req('openwop.it.protocol-versions-array.when-advertised-every-item-matches-the-grammar-items-are-unique-and-the-array-co', 'RFC 0165 §A.1', `protocolVersions item ${JSON.stringify(v)} MUST match the RFC 0149 §C grammar`)).toBe(true);
85
86
  }
86
- expect(new Set(items).size, driver.describe('RFC 0165 §A.1', 'protocolVersions items MUST be unique')).toBe(items.length);
87
- expect(items, driver.describe('RFC 0165 §A.2', 'protocolVersions MUST contain the value of protocolVersion')).toContain(doc['protocolVersion']);
87
+ expect(new Set(items).size, req('openwop.it.protocol-versions-array.when-advertised-every-item-matches-the-grammar-items-are-unique-and-the-array-co', 'RFC 0165 §A.1', 'protocolVersions items MUST be unique')).toBe(items.length);
88
+ expect(items, req('openwop.it.protocol-versions-array.when-advertised-every-item-matches-the-grammar-items-are-unique-and-the-array-co', 'RFC 0165 §A.2', 'protocolVersions MUST contain the value of protocolVersion')).toContain(doc['protocolVersion']);
88
89
  });
89
90
 
90
91
  it('profile derivation is unchanged by the array (isCore reads the scalar only)', async () => {
@@ -97,7 +98,7 @@ describe('protocol-versions-array: advertisement (RFC 0165 §A.2 — presence-ga
97
98
  delete without['protocolVersions'];
98
99
  expect(
99
100
  isCore(doc),
100
- driver.describe('RFC 0165 §A.2', 'openwop-discovery-core derivation MUST NOT depend on protocolVersions in v1.x'),
101
+ req('openwop.it.protocol-versions-array.profile-derivation-is-unchanged-by-the-array-iscore-reads-the-scalar-only', 'RFC 0165 §A.2', 'openwop-discovery-core derivation MUST NOT depend on protocolVersions in v1.x'),
101
102
  ).toBe(isCore(without as DiscoveryPayload));
102
103
  });
103
104
  });
@@ -28,6 +28,8 @@ import { driver } from '../lib/driver.js';
28
28
  import { SCHEMAS_DIR } from '../lib/paths.js';
29
29
  import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
30
30
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
31
+ import { req } from '../lib/requirement-ids.js';
32
+ import { softSkip } from '../lib/soft-skip.js';
31
33
 
32
34
  interface DiscoveryDoc {
33
35
  capabilities?: {
@@ -45,21 +47,21 @@ async function readProviderUsageCap(): Promise<{ supported?: boolean; costEstima
45
47
  describe('provider-usage: capability advertisement (RFC 0026 §E)', () => {
46
48
  it('capabilities.providerUsage is either absent or a well-formed object', async () => {
47
49
  const cap = await readProviderUsageCap();
48
- if (cap === null) return; // host doesn't advertise — skip
50
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early (host doesn\'t advertise — skip)'); // host doesn't advertise — skip
49
51
  expect(
50
52
  typeof cap.supported,
51
- driver.describe('RFC 0026 §E', 'capabilities.providerUsage.supported MUST be a boolean when the block is present'),
53
+ req('openwop.it.provider-usage.capabilities-providerusage-is-either-absent-or-a-well-formed-object', 'RFC 0026 §E', 'capabilities.providerUsage.supported MUST be a boolean when the block is present'),
52
54
  ).toBe('boolean');
53
55
  if (cap.costEstimates !== undefined) {
54
56
  expect(
55
57
  typeof cap.costEstimates,
56
- driver.describe('RFC 0026 §E', 'capabilities.providerUsage.costEstimates MUST be a boolean when present'),
58
+ req('openwop.it.provider-usage.capabilities-providerusage-is-either-absent-or-a-well-formed-object', 'RFC 0026 §E', 'capabilities.providerUsage.costEstimates MUST be a boolean when present'),
57
59
  ).toBe('boolean');
58
60
  }
59
61
  if (cap.currency !== undefined) {
60
62
  expect(
61
63
  /^[A-Z]{3}$/.test(cap.currency),
62
- driver.describe('RFC 0026 §E', 'capabilities.providerUsage.currency MUST be a 3-letter uppercase ISO 4217 code when present'),
64
+ req('openwop.it.provider-usage.capabilities-providerusage-is-either-absent-or-a-well-formed-object', 'RFC 0026 §E', 'capabilities.providerUsage.currency MUST be a 3-letter uppercase ISO 4217 code when present'),
63
65
  ).toBe(true);
64
66
  }
65
67
  });
@@ -84,7 +86,7 @@ describe('provider-usage: schema round-trip (RFC 0026 §A)', () => {
84
86
  cacheHit: false,
85
87
  nodeId: 'chat-respond',
86
88
  });
87
- expect(ok, `positive fixture MUST validate; errors: ${JSON.stringify(validate.errors)}`).toBe(true);
89
+ expect(ok, req('openwop.it.provider-usage.positive-fixture-validates', 'RFC 0026', `positive fixture MUST validate; errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
88
90
  });
89
91
 
90
92
  it('negative fixture (missing required field) MUST be rejected', () => {
@@ -96,7 +98,7 @@ describe('provider-usage: schema round-trip (RFC 0026 §A)', () => {
96
98
  });
97
99
  expect(
98
100
  ok,
99
- driver.describe('RFC 0026 §A', 'payload missing required `outputTokens` MUST fail schema validation'),
101
+ req('openwop.it.provider-usage.negative-fixture-missing-required-field-must-be-rejected', 'RFC 0026 §A', 'payload missing required `outputTokens` MUST fail schema validation'),
100
102
  ).toBe(false);
101
103
  });
102
104
 
@@ -110,7 +112,7 @@ describe('provider-usage: schema round-trip (RFC 0026 §A)', () => {
110
112
  });
111
113
  expect(
112
114
  ok,
113
- driver.describe('RFC 0026 §D', 'additionalProperties:false MUST reject credentialRef-shaped fields per provider-usage-no-credential-leak'),
115
+ req('openwop.it.provider-usage.negative-fixture-additionalproperties-credentialref-leak-must-be-rejected', 'RFC 0026 §D', 'additionalProperties:false MUST reject credentialRef-shaped fields per provider-usage-no-credential-leak'),
114
116
  ).toBe(false);
115
117
  });
116
118
 
@@ -121,13 +123,13 @@ describe('provider-usage: schema round-trip (RFC 0026 §A)', () => {
121
123
  inputTokens: 100.5, // non-integer
122
124
  outputTokens: 50,
123
125
  });
124
- expect(ok, 'inputTokens MUST be integer per §A').toBe(false);
126
+ expect(ok, req('openwop.it.provider-usage.negative-fixture-non-integer-token-count-must-be-rejected', 'RFC 0026', 'inputTokens MUST be integer per §A')).toBe(false);
125
127
  });
126
128
  });
127
129
 
128
130
  describe('provider-usage: event presence via emit-seam + event-log query (RFC 0026 §B)', () => {
129
131
  it('emit-seam projects exactly one provider.usage event with required fields populated', async () => {
130
- if (!(await isEventLogSeamAvailable())) return; // E.1 seam not exposed — soft-skip
132
+ if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (E.1 seam not exposed — soft-skip) (seam, prior step, or fixture unavailable)'); // E.1 seam not exposed — soft-skip
131
133
  const runId = `r-pu-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
132
134
  const correlationId = `${runId}:node-1:turn-0:pu-1`;
133
135
  const payload = {
@@ -139,14 +141,14 @@ describe('provider-usage: event presence via emit-seam + event-log query (RFC 00
139
141
  nodeId: 'node-1',
140
142
  };
141
143
  const emit = await driver.post('/v1/host/sample/test/emit-provider-usage', { runId, payload, correlationId, nodeId: 'node-1' });
142
- if (emit.status === 404) return; // emit seam not exposed
144
+ if (emit.status === 404) return softSkip('blocked', 'precondition not met — `emit.status === 404` returned early (emit seam not exposed) (seam, prior step, or fixture unavailable)'); // emit seam not exposed
143
145
  expect(emit.status).toBe(200);
144
146
 
145
147
  const events = await queryTestEvents(runId, { type: 'provider.usage' });
146
- if (!events.ok) return;
148
+ if (!events.ok) return softSkip('blocked', 'precondition not met — `!events.ok` returned early (seam, prior step, or fixture unavailable)');
147
149
  expect(
148
150
  events.events.length,
149
- driver.describe('RFC 0026 §B', 'emit-seam MUST project exactly one provider.usage event'),
151
+ req('openwop.it.provider-usage.emit-seam-projects-exactly-one-provider-usage-event-with-required-fields-populat', 'RFC 0026 §B', 'emit-seam MUST project exactly one provider.usage event'),
150
152
  ).toBe(1);
151
153
  const e = events.events[0]!;
152
154
  expect(e.payload.provider).toBe('anthropic');
@@ -159,7 +161,7 @@ describe('provider-usage: event presence via emit-seam + event-log query (RFC 00
159
161
  });
160
162
 
161
163
  it('emit-seam refuses payloads containing credentialRef-shaped content (provider-usage-no-credential-leak invariant)', async () => {
162
- if (!(await isEventLogSeamAvailable())) return;
164
+ if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
163
165
  const runId = `r-pu-leak-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
164
166
  // Inject a credentialRef-shaped field via a synthetic payload that
165
167
  // contains 'secret:' in a string field. The seam's defense-in-depth
@@ -175,10 +177,10 @@ describe('provider-usage: event presence via emit-seam + event-log query (RFC 00
175
177
  nodeId: 'secret:tenant:byok-anthropic:v1', // banned content
176
178
  },
177
179
  });
178
- if (res.status === 404) return;
180
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
179
181
  expect(
180
182
  res.status,
181
- driver.describe('SECURITY/invariants.yaml provider-usage-no-credential-leak', 'payload with credentialRef-shaped content MUST be refused'),
183
+ req('openwop.it.provider-usage.emit-seam-refuses-payloads-containing-credentialref-shaped-content-provider-usag', 'SECURITY/invariants.yaml provider-usage-no-credential-leak', 'payload with credentialRef-shaped content MUST be refused'),
182
184
  ).toBe(400);
183
185
  expect(readErrorCode(res.json)).toBe('provider_usage_credential_leak');
184
186
  await resetTestSeam();
@@ -30,6 +30,8 @@
30
30
 
31
31
  import { describe, it, expect } from 'vitest';
32
32
  import { driver } from '../lib/driver.js';
33
+ import { req } from '../lib/requirement-ids.js';
34
+ import { softSkip } from '../lib/soft-skip.js';
33
35
 
34
36
  const CANONICAL_MODES = ['disabled', 'optional', 'required', 'restricted'] as const;
35
37
 
@@ -57,16 +59,16 @@ async function fetchPolicies(): Promise<PoliciesShape | null> {
57
59
  describe('provider-policy-enforcement: closed mode set per spec/v1/capabilities.md §`aiProviders.policies`', () => {
58
60
  it('every advertised mode is one of the four canonical values', async () => {
59
61
  const policies = await fetchPolicies();
60
- if (policies === null || !Array.isArray(policies.modes)) return;
62
+ if (policies === null || !Array.isArray(policies.modes)) return softSkip('blocked', 'precondition not met — `policies === null || !Array.isArray(policies.modes)` returned early (seam, prior step, or fixture unavailable)');
61
63
 
62
64
  for (const mode of policies.modes) {
63
- expect(typeof mode, driver.describe(
65
+ expect(typeof mode, req('openwop.it.providerPolicyEnforcement.every-advertised-mode-is-one-of-the-four-canonical-values',
64
66
  'capabilities.md §"`aiProviders.policies`"',
65
67
  'each entry in policies.modes MUST be a string',
66
68
  )).toBe('string');
67
69
  expect(
68
70
  (CANONICAL_MODES as readonly string[]).includes(mode as string),
69
- driver.describe(
71
+ req('openwop.it.providerPolicyEnforcement.every-advertised-mode-is-one-of-the-four-canonical-values',
70
72
  'capabilities.md §"`aiProviders.policies`"',
71
73
  `mode "${String(mode)}" is not in the closed canonical set [${CANONICAL_MODES.join(', ')}]`,
72
74
  ),
@@ -76,10 +78,10 @@ describe('provider-policy-enforcement: closed mode set per spec/v1/capabilities.
76
78
 
77
79
  it('hosts that support `restricted` MUST also support `optional` (default no-restriction case)', async () => {
78
80
  const policies = await fetchPolicies();
79
- if (policies === null || !Array.isArray(policies.modes)) return;
81
+ if (policies === null || !Array.isArray(policies.modes)) return softSkip('blocked', 'precondition not met — `policies === null || !Array.isArray(policies.modes)` returned early (seam, prior step, or fixture unavailable)');
80
82
  const modes = policies.modes as string[];
81
- if (!modes.includes('restricted')) return;
82
- expect(modes.includes('optional'), driver.describe(
83
+ if (!modes.includes('restricted')) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'restricted\')` returned early');
84
+ expect(modes.includes('optional'), req('openwop.it.providerPolicyEnforcement.hosts-that-support-restricted-must-also-support-optional-default-no-restriction',
83
85
  'spec/v1/profiles.md §`openwop-provider-policy`',
84
86
  'a host advertising `restricted` MUST also advertise `optional` so workflows without policy hit the default permissive case',
85
87
  )).toBe(true);
@@ -87,12 +89,12 @@ describe('provider-policy-enforcement: closed mode set per spec/v1/capabilities.
87
89
 
88
90
  it('errorCode is a non-empty string when present', async () => {
89
91
  const policies = await fetchPolicies();
90
- if (policies === null || policies.errorCode === undefined) return;
91
- expect(typeof policies.errorCode, driver.describe(
92
+ if (policies === null || policies.errorCode === undefined) return softSkip('blocked', 'precondition not met — `policies === null || policies.errorCode === undefined` returned early (seam, prior step, or fixture unavailable)');
93
+ expect(typeof policies.errorCode, req('openwop.it.providerPolicyEnforcement.errorcode-is-a-non-empty-string-when-present',
92
94
  'capabilities.md §"`aiProviders.policies`"',
93
95
  'aiProviders.policies.errorCode MUST be a string when present',
94
96
  )).toBe('string');
95
- expect((policies.errorCode as string).length, driver.describe(
97
+ expect((policies.errorCode as string).length, req('openwop.it.providerPolicyEnforcement.errorcode-is-a-non-empty-string-when-present',
96
98
  'capabilities.md §"`aiProviders.policies`"',
97
99
  'aiProviders.policies.errorCode MUST be non-empty when present',
98
100
  )).toBeGreaterThan(0);
@@ -102,11 +104,11 @@ describe('provider-policy-enforcement: closed mode set per spec/v1/capabilities.
102
104
  describe('provider-policy-enforcement: scope advertisement', () => {
103
105
  it('scopes contains only non-empty strings when present', async () => {
104
106
  const policies = await fetchPolicies();
105
- if (policies === null) return;
106
- if (!Array.isArray(policies.scopes)) return;
107
+ if (policies === null) return softSkip('blocked', 'precondition not met — `policies === null` returned early (seam, prior step, or fixture unavailable)');
108
+ if (!Array.isArray(policies.scopes)) return softSkip('blocked', 'precondition not met — `!Array.isArray(policies.scopes)` returned early (seam, prior step, or fixture unavailable)');
107
109
 
108
110
  for (const scope of policies.scopes) {
109
- expect(typeof scope === 'string' && scope.length > 0, driver.describe(
111
+ expect(typeof scope === 'string' && scope.length > 0, req('openwop.it.providerPolicyEnforcement.scopes-contains-only-non-empty-strings-when-present',
110
112
  'capabilities.md §"`aiProviders.policies`"',
111
113
  'each entry in policies.scopes MUST be a non-empty string',
112
114
  )).toBe(true);
@@ -120,11 +122,11 @@ describe('provider-policy-enforcement: documented denial reasons enumeration', (
120
122
  // file isn't updated, scenario authors will be surprised. This
121
123
  // assertion catches that — an empty CANONICAL_MODES or DOCUMENTED_
122
124
  // DENIAL_REASONS would indicate the test file got truncated.
123
- expect(CANONICAL_MODES.length, driver.describe(
125
+ expect(CANONICAL_MODES.length, req('openwop.it.providerPolicyEnforcement.lists-are-non-empty-sanity-check-on-documentation-drift',
124
126
  'spec/v1/capabilities.md §"`aiProviders.policies`"',
125
127
  'closed mode set MUST be the four canonical values',
126
128
  )).toBe(4);
127
- expect(DOCUMENTED_DENIAL_REASONS.length, driver.describe(
129
+ expect(DOCUMENTED_DENIAL_REASONS.length, req('openwop.it.providerPolicyEnforcement.lists-are-non-empty-sanity-check-on-documentation-drift',
128
130
  'openwop/openwop@0bebfb0 — denial-reason enum alignment',
129
131
  'documented denial-reason set is non-empty',
130
132
  )).toBeGreaterThan(0);