@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
@@ -57,6 +57,8 @@ import { pollUntilTerminal } from '../lib/polling.js';
57
57
  import { isFixtureAdvertised } from '../lib/fixtures.js';
58
58
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
59
59
  import { getCollector, waitForRunSpans } from '../lib/otel-collector.js';
60
+ import { req } from '../lib/requirement-ids.js';
61
+ import { softSkip } from '../lib/soft-skip.js';
60
62
 
61
63
  /**
62
64
  * Callback-shaped: the host exports OTLP spans to the suite's collector, which scans them for the BYOK canary.
@@ -106,25 +108,25 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
106
108
  it('NO OTel span attribute MUST contain the BYOK canary plaintext for a run that resolved it', async (ctx) => {
107
109
  if (!CANARY_VALUE) {
108
110
  ctx.skip();
109
- return;
111
+ return softSkip('blocked', 'precondition not met — `!CANARY_VALUE` returned early (seam, prior step, or fixture unavailable)');
110
112
  }
111
113
  const d = await readDiscovery();
112
114
  const secretsOk = capabilityFamily<{ supported?: unknown }>(d, 'secrets')?.supported === true;
113
115
  const seamOk = capabilityFamily<{ testSeams?: Record<string, unknown> }>(d, 'observability')?.testSeams?.otelScrape === true;
114
116
  if (!secretsOk || !seamOk) {
115
117
  ctx.skip();
116
- return;
118
+ return softSkip('blocked', 'precondition not met — `!secretsOk || !seamOk` returned early (seam, prior step, or fixture unavailable)');
117
119
  }
118
120
 
119
121
  const runId = await startByokRun();
120
122
  if (runId === null) {
121
123
  ctx.skip();
122
- return;
124
+ return softSkip('blocked', 'precondition not met — `runId === null` returned early (seam, prior step, or fixture unavailable)');
123
125
  }
124
126
  const terminal = await pollUntilTerminal(runId);
125
127
  expect(
126
128
  terminal.status,
127
- driver.describe(
129
+ req('openwop.it.secret-leakage-otel-attribute.no-otel-span-attribute-must-contain-the-byok-canary-plaintext-for-a-run-that-res',
128
130
  'auth.md §"Secret resolution"',
129
131
  'BYOK fixture run MUST terminate `completed` when the canary is provisioned',
130
132
  ),
@@ -135,7 +137,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
135
137
  );
136
138
  expect(
137
139
  spansRes.status,
138
- driver.describe(
140
+ req('openwop.it.secret-leakage-otel-attribute.no-otel-span-attribute-must-contain-the-byok-canary-plaintext-for-a-run-that-res',
139
141
  'RFCS/0034-otel-collector-test-seam.md §B',
140
142
  'host advertising capabilities.observability.testSeams.otelScrape MUST serve GET /v1/host/sample/test/otel/spans (200) — 404 is non-conformant',
141
143
  ),
@@ -145,7 +147,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
145
147
  const spans = body.spans ?? [];
146
148
  expect(
147
149
  Array.isArray(spans),
148
- driver.describe(
150
+ req('openwop.it.secret-leakage-otel-attribute.no-otel-span-attribute-must-contain-the-byok-canary-plaintext-for-a-run-that-res',
149
151
  'RFCS/0034-otel-collector-test-seam.md §B',
150
152
  'response body MUST have a `spans` array',
151
153
  ),
@@ -160,7 +162,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
160
162
 
161
163
  expect(
162
164
  serialized.includes(CANARY_VALUE),
163
- driver.describe(
165
+ req('openwop.it.secret-leakage-otel-attribute.no-otel-span-attribute-must-contain-the-byok-canary-plaintext-for-a-run-that-res',
164
166
  'SECURITY/invariants.yaml secret-leakage-otel-attribute',
165
167
  'no OTel span attribute may contain the BYOK canary plaintext — host instrumentation MUST redact or omit secret material before any span emission. Per `agent-memory.md` §SR-1, the canonical redaction marker is `[REDACTED:<secretId>]`.',
166
168
  ),
@@ -175,20 +177,20 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
175
177
  it('NO debug-bundle field MUST contain the BYOK canary plaintext for a run that resolved it', async (ctx) => {
176
178
  if (!CANARY_VALUE) {
177
179
  ctx.skip();
178
- return;
180
+ return softSkip('blocked', 'precondition not met — `!CANARY_VALUE` returned early (seam, prior step, or fixture unavailable)');
179
181
  }
180
182
  const d = await readDiscovery();
181
183
  const secretsOk = capabilityFamily<{ supported?: unknown }>(d, 'secrets')?.supported === true;
182
184
  const seamOk = capabilityFamily<{ testSeams?: Record<string, unknown> }>(d, 'observability')?.testSeams?.debugBundleExport === true;
183
185
  if (!secretsOk || !seamOk) {
184
186
  ctx.skip();
185
- return;
187
+ return softSkip('blocked', 'precondition not met — `!secretsOk || !seamOk` returned early (seam, prior step, or fixture unavailable)');
186
188
  }
187
189
 
188
190
  const runId = await startByokRun();
189
191
  if (runId === null) {
190
192
  ctx.skip();
191
- return;
193
+ return softSkip('blocked', 'precondition not met — `runId === null` returned early (seam, prior step, or fixture unavailable)');
192
194
  }
193
195
  const terminal = await pollUntilTerminal(runId);
194
196
  expect(terminal.status).toBe('completed');
@@ -196,7 +198,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
196
198
  const bundleRes = await driver.post('/v1/host/sample/test/debug-bundle/export', { runId });
197
199
  expect(
198
200
  bundleRes.status,
199
- driver.describe(
201
+ req('openwop.it.secret-leakage-otel-attribute.no-debug-bundle-field-must-contain-the-byok-canary-plaintext-for-a-run-that-reso',
200
202
  'RFCS/0034-otel-collector-test-seam.md §B',
201
203
  'host advertising capabilities.observability.testSeams.debugBundleExport MUST serve POST /v1/host/sample/test/debug-bundle/export (200) — 404 is non-conformant',
202
204
  ),
@@ -205,7 +207,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
205
207
  const serialized = JSON.stringify(bundleRes.json ?? {});
206
208
  expect(
207
209
  serialized.includes(CANARY_VALUE),
208
- driver.describe(
210
+ req('openwop.it.secret-leakage-otel-attribute.no-debug-bundle-field-must-contain-the-byok-canary-plaintext-for-a-run-that-reso',
209
211
  'SECURITY/invariants.yaml secret-leakage-debug-bundle-otel',
210
212
  'no debug-bundle field may contain the BYOK canary plaintext — debug-bundle export MUST redact or omit secret material. Per `debug-bundle.md` §"Redaction", the canonical marker is `[REDACTED:<secretId>]`.',
211
213
  ),
@@ -229,21 +231,21 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
229
231
  const collector = getCollector();
230
232
  if (!collector || !CANARY_VALUE) {
231
233
  ctx.skip();
232
- return;
234
+ return softSkip('blocked', 'precondition not met — `!collector || !CANARY_VALUE` returned early (seam, prior step, or fixture unavailable)');
233
235
  }
234
236
  const d = await readDiscovery();
235
237
  const secretsOk = capabilityFamily<{ supported?: unknown }>(d, 'secrets')?.supported === true;
236
238
  const obsOk = capabilityFamily<unknown>(d, 'observability') !== undefined;
237
239
  if (!secretsOk || !obsOk) {
238
240
  ctx.skip();
239
- return;
241
+ return softSkip('blocked', 'precondition not met — `!secretsOk || !obsOk` returned early (seam, prior step, or fixture unavailable)');
240
242
  }
241
243
 
242
244
  collector.reset();
243
245
  const runId = await startByokRun();
244
246
  if (runId === null) {
245
247
  ctx.skip();
246
- return;
248
+ return softSkip('blocked', 'precondition not met — `runId === null` returned early (seam, prior step, or fixture unavailable)');
247
249
  }
248
250
  const terminal = await pollUntilTerminal(runId);
249
251
  expect(terminal.status).toBe('completed');
@@ -256,7 +258,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
256
258
  const leaks = collector.findCanaryLeakage(CANARY_VALUE);
257
259
  expect(
258
260
  leaks,
259
- driver.describe(
261
+ req('openwop.it.secret-leakage-otel-attribute.no-real-exported-otel-span-metric-attribute-must-contain-the-byok-canary-plainte',
260
262
  'SECURITY/invariants.yaml secret-leakage-otel-attribute',
261
263
  `no real-exported OTel span/metric attribute may contain the BYOK canary plaintext. Leaking surfaces: ${JSON.stringify(leaks)}`,
262
264
  ),
@@ -272,17 +274,17 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
272
274
  const d = await readDiscovery();
273
275
  if (capabilityFamily<{ supported?: unknown }>(d, 'secrets')?.supported !== true) {
274
276
  ctx.skip();
275
- return;
277
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `capabilityFamily<{ supported?: unknown }>(d, \'secrets\')?.supported !== true` returned early');
276
278
  }
277
279
  const seams = capabilityFamily<{ testSeams?: Record<string, unknown> }>(d, 'observability')?.testSeams;
278
280
  if (seams === undefined) {
279
281
  ctx.skip(); // host honest about not exposing the seams — Drift #17 path
280
- return;
282
+ return softSkip('blocked', 'precondition not met — `seams === undefined` returned early (seam, prior step, or fixture unavailable)');
281
283
  }
282
284
  if ('otelScrape' in seams && seams.otelScrape !== undefined) {
283
285
  expect(
284
286
  typeof seams.otelScrape,
285
- driver.describe(
287
+ req('openwop.it.secret-leakage-otel-attribute.when-secrets-supported-is-true-observability-testseams-advertisements-must-be-bo',
286
288
  'RFCS/0034-otel-collector-test-seam.md §A',
287
289
  'capabilities.observability.testSeams.otelScrape MUST be boolean when present',
288
290
  ),
@@ -291,7 +293,7 @@ describe.skipIf(HTTP_SKIP || FIXTURE_SKIP)(
291
293
  if ('debugBundleExport' in seams && seams.debugBundleExport !== undefined) {
292
294
  expect(
293
295
  typeof seams.debugBundleExport,
294
- driver.describe(
296
+ req('openwop.it.secret-leakage-otel-attribute.when-secrets-supported-is-true-observability-testseams-advertisements-must-be-bo',
295
297
  'RFCS/0034-otel-collector-test-seam.md §A',
296
298
  'capabilities.observability.testSeams.debugBundleExport MUST be boolean when present',
297
299
  ),
@@ -37,6 +37,8 @@ import { behaviorGate } from '../lib/behavior-gate.js';
37
37
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
38
38
  import { SCHEMAS_DIR } from '../lib/paths.js';
39
39
  import { readErrorCode, readRetriable } from '../lib/error-envelope.js';
40
+ import { req } from '../lib/requirement-ids.js';
41
+ import { softSkip } from '../lib/soft-skip.js';
40
42
 
41
43
  const GATE = 'openwop-self-hosted-runner';
42
44
 
@@ -85,32 +87,32 @@ describe('self-hosted-runner: schema shape (RFC 0122, server-free)', () => {
85
87
  it('capabilities.schema.json declares selfHostedRunner {supported} with required supported', () => {
86
88
  const caps = readSchema('capabilities.schema.json');
87
89
  const shr = caps.properties?.selfHostedRunner;
88
- expect(shr, 'capabilities.md §selfHostedRunner — the block MUST be declared').toBeDefined();
90
+ expect(shr, req('openwop.it.self-hosted-runner.capabilities-schema-json-declares-selfhostedrunner-supported-with-required-suppo', 'RFC 0122', 'capabilities.md §selfHostedRunner — the block MUST be declared')).toBeDefined();
89
91
  expect(
90
92
  shr?.required,
91
- 'RFC 0122 — selfHostedRunner.supported is REQUIRED when the block is present',
93
+ req('openwop.it.self-hosted-runner.capabilities-schema-json-declares-selfhostedrunner-supported-with-required-suppo', 'RFC 0122', 'RFC 0122 — selfHostedRunner.supported is REQUIRED when the block is present'),
92
94
  ).toContain('supported');
93
95
  expect(
94
96
  shr?.properties?.supported?.type,
95
- 'selfHostedRunner.supported MUST be a boolean',
97
+ req('openwop.it.self-hosted-runner.capabilities-schema-json-declares-selfhostedrunner-supported-with-required-suppo', 'RFC 0122', 'selfHostedRunner.supported MUST be a boolean'),
96
98
  ).toBe('boolean');
97
99
  expect(
98
100
  shr?.additionalProperties,
99
- 'selfHostedRunner MUST be a closed object',
101
+ req('openwop.it.self-hosted-runner.capabilities-schema-json-declares-selfhostedrunner-supported-with-required-suppo', 'RFC 0122', 'selfHostedRunner MUST be a closed object'),
100
102
  ).toBe(false);
101
103
  });
102
104
 
103
105
  it('the dispatch frame schema pins {runId, stepId, seq, kind, inputs} with an integer cursor', () => {
104
106
  const s = readSchema('self-hosted-runner-dispatch-frame.schema.json');
105
107
  for (const f of ['runId', 'stepId', 'seq', 'kind', 'inputs']) {
106
- expect(s.required, `dispatch frame MUST require '${f}'`).toContain(f);
108
+ expect(s.required, req('openwop.it.self-hosted-runner.the-dispatch-frame-schema-pins-runid-stepid-seq-kind-inputs-with-an-integer-curs', 'RFC 0122', `dispatch frame MUST require '${f}'`)).toContain(f);
107
109
  }
108
- expect(s.additionalProperties, 'dispatch frame MUST be a closed object').toBe(false);
110
+ expect(s.additionalProperties, req('openwop.it.self-hosted-runner.the-dispatch-frame-schema-pins-runid-stepid-seq-kind-inputs-with-an-integer-curs', 'RFC 0122', 'dispatch frame MUST be a closed object')).toBe(false);
109
111
  expect(
110
112
  s.properties?.seq?.type,
111
- 'RFC 0122 §Channel — the dispatch cursor `seq` MUST be an integer (distinct from the event-log sequence)',
113
+ req('openwop.it.self-hosted-runner.the-dispatch-frame-schema-pins-runid-stepid-seq-kind-inputs-with-an-integer-curs', 'RFC 0122', 'RFC 0122 §Channel — the dispatch cursor `seq` MUST be an integer (distinct from the event-log sequence)'),
112
114
  ).toBe('integer');
113
- expect(s.properties?.kind?.enum, "dispatch kind MUST be one of {model, tool}").toEqual(
115
+ expect(s.properties?.kind?.enum, req('openwop.it.self-hosted-runner.the-dispatch-frame-schema-pins-runid-stepid-seq-kind-inputs-with-an-integer-curs', 'RFC 0122', "dispatch kind MUST be one of {model, tool}")).toEqual(
114
116
  expect.arrayContaining(['model', 'tool']),
115
117
  );
116
118
  });
@@ -118,25 +120,25 @@ describe('self-hosted-runner: schema shape (RFC 0122, server-free)', () => {
118
120
  it('the result frame schema pins {runId, stepId, seq, output} and is closed', () => {
119
121
  const s = readSchema('self-hosted-runner-result-frame.schema.json');
120
122
  for (const f of ['runId', 'stepId', 'seq', 'output']) {
121
- expect(s.required, `result frame MUST require '${f}'`).toContain(f);
123
+ expect(s.required, req('openwop.it.self-hosted-runner.the-result-frame-schema-pins-runid-stepid-seq-output-and-is-closed', 'RFC 0122', `result frame MUST require '${f}'`)).toContain(f);
122
124
  }
123
125
  // additionalProperties:false is the schema-level runner-credential-non-transit rail —
124
126
  // a runner cannot smuggle a credential field onto a result frame.
125
127
  expect(
126
128
  s.additionalProperties,
127
- 'result frame MUST be a closed object (runner-credential-non-transit)',
129
+ req('openwop.it.self-hosted-runner.the-result-frame-schema-pins-runid-stepid-seq-output-and-is-closed', 'RFC 0122', 'result frame MUST be a closed object (runner-credential-non-transit)'),
128
130
  ).toBe(false);
129
131
  });
130
132
 
131
133
  it('the registration schema pins {runnerId, subject, capabilities} and is closed', () => {
132
134
  const s = readSchema('self-hosted-runner-registration.schema.json');
133
135
  for (const f of ['runnerId', 'subject', 'capabilities']) {
134
- expect(s.required, `registration MUST require '${f}'`).toContain(f);
136
+ expect(s.required, req('openwop.it.self-hosted-runner.the-registration-schema-pins-runnerid-subject-capabilities-and-is-closed', 'RFC 0122', `registration MUST require '${f}'`)).toContain(f);
135
137
  }
136
- expect(s.additionalProperties, 'registration MUST be a closed object').toBe(false);
138
+ expect(s.additionalProperties, req('openwop.it.self-hosted-runner.the-registration-schema-pins-runnerid-subject-capabilities-and-is-closed', 'RFC 0122', 'registration MUST be a closed object')).toBe(false);
137
139
  expect(
138
140
  s.properties?.capabilities?.additionalProperties,
139
- 'registration.capabilities MUST be a closed object',
141
+ req('openwop.it.self-hosted-runner.the-registration-schema-pins-runnerid-subject-capabilities-and-is-closed', 'RFC 0122', 'registration.capabilities MUST be a closed object'),
140
142
  ).toBe(false);
141
143
  });
142
144
  });
@@ -148,13 +150,13 @@ describe('self-hosted-runner: advertisement shape (gated)', () => {
148
150
 
149
151
  expect(
150
152
  typeof shr?.supported,
151
- driver.describe('capabilities.md §selfHostedRunner', 'supported MUST be a boolean'),
153
+ req('openwop.it.self-hosted-runner.an-advertised-selfhostedrunner-block-is-well-formed', 'capabilities.md §selfHostedRunner', 'supported MUST be a boolean'),
152
154
  ).toBe('boolean');
153
155
  if (shr?.dispatchKinds !== undefined) {
154
156
  for (const k of shr.dispatchKinds) {
155
157
  expect(
156
158
  ['model', 'tool'],
157
- driver.describe('capabilities.md §selfHostedRunner', `dispatchKinds entry '${k}' MUST be model|tool`),
159
+ req('openwop.it.self-hosted-runner.an-advertised-selfhostedrunner-block-is-well-formed', 'capabilities.md §selfHostedRunner', `dispatchKinds entry '${k}' MUST be model|tool`),
158
160
  ).toContain(k);
159
161
  }
160
162
  }
@@ -171,7 +173,7 @@ describe('self-hosted-runner: behavioral (seam-gated, soft-skip 404)', () => {
171
173
  subject: SUBJECT_B,
172
174
  capabilities: { providers: ['anthropic'] },
173
175
  });
174
- if (reg.status === 404) return; // seam unwired — soft-skip
176
+ if (reg.status === 404) return softSkip('blocked', 'precondition not met — `reg.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
175
177
 
176
178
  const res = await driver.post(DISPATCH, {
177
179
  subject: SUBJECT_A,
@@ -183,19 +185,19 @@ describe('self-hosted-runner: behavioral (seam-gated, soft-skip 404)', () => {
183
185
  model: 'claude-opus-4-8',
184
186
  inputs: { messages: [] },
185
187
  });
186
- if (res.status === 404) return;
188
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
187
189
 
188
190
  expect(
189
191
  res.status >= 400,
190
- driver.describe('self-hosted-runner.md §Behavior#1', 'a subject-A dispatch MUST NOT route to a subject-B runner'),
192
+ req('openwop.it.self-hosted-runner.a-dispatch-for-a-subject-with-no-runner-fails-retriably-with-runner-unavailable', 'self-hosted-runner.md §Behavior#1', 'a subject-A dispatch MUST NOT route to a subject-B runner'),
191
193
  ).toBe(true);
192
194
  expect(
193
195
  errCode(res.json),
194
- driver.describe('RFC 0122 §Behavior#5', 'a dispatch with no owning-subject runner MUST fail `runner_unavailable`'),
196
+ req('openwop.it.self-hosted-runner.a-dispatch-for-a-subject-with-no-runner-fails-retriably-with-runner-unavailable', 'RFC 0122 §Behavior#5', 'a dispatch with no owning-subject runner MUST fail `runner_unavailable`'),
195
197
  ).toBe('runner_unavailable');
196
198
  expect(
197
199
  retriable(res.json),
198
- driver.describe('RFC 0122 §Behavior#5', '`runner_unavailable` MUST be retriable'),
200
+ req('openwop.it.self-hosted-runner.a-dispatch-for-a-subject-with-no-runner-fails-retriably-with-runner-unavailable', 'RFC 0122 §Behavior#5', '`runner_unavailable` MUST be retriable'),
199
201
  ).toBe(true);
200
202
  });
201
203
 
@@ -205,7 +207,7 @@ describe('self-hosted-runner: behavioral (seam-gated, soft-skip 404)', () => {
205
207
  subject: SUBJECT_A,
206
208
  capabilities: { providers: ['anthropic'] },
207
209
  });
208
- if (reg.status === 404) return;
210
+ if (reg.status === 404) return softSkip('blocked', 'precondition not met — `reg.status === 404` returned early (seam, prior step, or fixture unavailable)');
209
211
 
210
212
  const frame = {
211
213
  subject: SUBJECT_A,
@@ -218,16 +220,16 @@ describe('self-hosted-runner: behavioral (seam-gated, soft-skip 404)', () => {
218
220
  inputs: { messages: [] },
219
221
  };
220
222
  const first = await driver.post(DISPATCH, frame);
221
- if (first.status === 404) return;
223
+ if (first.status === 404) return softSkip('blocked', 'precondition not met — `first.status === 404` returned early (seam, prior step, or fixture unavailable)');
222
224
  // A host without a live runner backing the seam MAY answer runner_unavailable;
223
225
  // the at-most-once property is only observable when the first dispatch resolved.
224
- if (errCode(first.json) === 'runner_unavailable') return;
226
+ if (errCode(first.json) === 'runner_unavailable') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(first.json) === \'runner_unavailable\'` returned early (A host without a live runner backing the seam MAY answer runner_unavailable; the at-most-once pro…');
225
227
 
226
228
  const second = await driver.post(DISPATCH, frame);
227
229
  const body = second.json as { deduped?: unknown };
228
230
  expect(
229
231
  body?.deduped,
230
- driver.describe(
232
+ req('openwop.it.self-hosted-runner.a-redelivered-runid-stepid-dispatch-is-dropped-not-re-executed-at-most-once',
231
233
  'self-hosted-runner.md §At-most-once dispatch',
232
234
  'a redelivered {runId, stepId} with a persisted result MUST be dropped (deduped:true), not re-dispatched',
233
235
  ),
@@ -35,6 +35,7 @@ import {
35
35
  canonicalize,
36
36
  SEMANTIC_REQUEST_RECIPE_V2,
37
37
  } from '../lib/llm-cache-key-recipe.js';
38
+ import { req } from '../lib/requirement-ids.js';
38
39
 
39
40
  interface Vector {
40
41
  readonly id: string;
@@ -87,10 +88,10 @@ describe('RFC 0150 §C — semantic request digest golden vectors', () => {
87
88
  // Guard: an empty or truncated file would make every leg below vacuous, and
88
89
  // this gate's whole value is that it fails when an implementation drifts.
89
90
  expect(doc.recipe).toBe(SEMANTIC_REQUEST_RECIPE_V2);
90
- expect(doc.vectors.length, 'the golden set MUST cover the recipe').toBeGreaterThanOrEqual(10);
91
+ expect(doc.vectors.length, req('openwop.it.semantic-digest-vectors.the-vector-set-is-present-and-non-trivial', 'RFC 0150 §C', 'the golden set MUST cover the recipe')).toBeGreaterThanOrEqual(10);
91
92
  expect(new Set(doc.vectors.map((v) => v.id)).size).toBe(doc.vectors.length);
92
93
  for (const v of doc.vectors) {
93
- expect(v.why.length, `vector '${v.id}' MUST say what it pins`).toBeGreaterThan(20);
94
+ expect(v.why.length, req('openwop.it.semantic-digest-vectors.the-vector-set-is-present-and-non-trivial', 'RFC 0150 §C', `vector '${v.id}' MUST say what it pins`)).toBeGreaterThan(20);
94
95
  }
95
96
  });
96
97
 
@@ -100,19 +101,19 @@ describe('RFC 0150 §C — semantic request digest golden vectors', () => {
100
101
  // The preimage is asserted as well as the hash: a mismatch on `canonical`
101
102
  // tells an implementer WHICH field they got wrong, where a hash mismatch
102
103
  // tells them only that something is.
103
- expect(canonicalize(projectSemanticRequestV2(v.input)), v.why).toBe(v.canonical);
104
+ expect(canonicalize(projectSemanticRequestV2(v.input)), req('openwop.it.semantic-digest-vectors.the-implementation-reproduces-s', 'RFC 0150 §C', v.why)).toBe(v.canonical);
104
105
  expect(semanticRequestDigestV2(v.input), v.why).toBe(v.digest);
105
106
  },
106
107
  );
107
108
 
108
109
  it('tool order is not semantic — sorted and reversed agree', () => {
109
- expect(digest('tools-sorted-by-name')).toBe(digest('tools-reversed-same-digest'));
110
+ expect(digest('tools-sorted-by-name'), req('openwop.it.semantic-digest-vectors.tool-order-is-not-semantic-sorted-and-reversed-agree', 'RFC 0150 §C', 'tool order is not semantic — sorted and reversed agree')).toBe(digest('tools-reversed-same-digest'));
110
111
  });
111
112
 
112
113
  it('message order IS semantic — reversing changes the digest', () => {
113
114
  expect(
114
115
  digest('message-order-is-semantic'),
115
- 'messages carry conversational sequence; sorting them would make two different conversations collide',
116
+ req('openwop.it.semantic-digest-vectors.message-order-is-semantic-reversing-changes-the-digest', 'RFC 0150 §C', 'messages carry conversational sequence; sorting them would make two different conversations collide'),
116
117
  ).not.toBe(digest('message-order-reversed'));
117
118
  });
118
119
 
@@ -120,7 +121,7 @@ describe('RFC 0150 §C — semantic request digest golden vectors', () => {
120
121
  // The pair that catches a well-meaning "add NFC to be safe" change — and it
121
122
  // catches it only because `digest()` RECOMPUTES from the input. Comparing
122
123
  // stored values here would be two constants from one file.
123
- expect(storedDigest('non-ascii-not-normalized')).not.toBe(storedDigest('non-ascii-composed'));
124
+ expect(storedDigest('non-ascii-not-normalized'), req('openwop.it.semantic-digest-vectors.the-two-unicode-forms-do-not-collide-because-jcs-does-not-apply-nfc', 'RFC 0150 §C', 'the two Unicode forms do not collide, because JCS does not apply NFC')).not.toBe(storedDigest('non-ascii-composed'));
124
125
  expect(
125
126
  digest('non-ascii-not-normalized'),
126
127
  'RFC 0150 §C: "Implementations MUST NOT add Unicode normalization outside JCS." An ' +
@@ -134,7 +135,7 @@ describe('RFC 0150 §C — semantic request digest golden vectors', () => {
134
135
  // these were equal to `minimal`, so requests producing different completions
135
136
  // shared a cache key — a wrong hit, not a miss.
136
137
  for (const id of ['stop-changes-digest', 'seed-changes-digest', 'max-output-changes-digest']) {
137
- expect(digest(id), `${id} MUST NOT equal the minimal request`).not.toBe(digest('minimal'));
138
+ expect(digest(id), req('openwop.it.semantic-digest-vectors.each-field-v1-excluded-now-changes-the-digest', 'RFC 0150 §C', `${id} MUST NOT equal the minimal request`)).not.toBe(digest('minimal'));
138
139
  }
139
140
  });
140
141
  });
@@ -24,6 +24,8 @@ import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
25
  import { behaviorGate } from '../lib/behavior-gate.js';
26
26
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
27
+ import { req } from '../lib/requirement-ids.js';
28
+ import { softSkip } from '../lib/soft-skip.js';
27
29
 
28
30
  const SEAM = '/v1/host/sample/ai/call-speech-synthesizer';
29
31
  const VOICE_ID = 'host:narrator-test';
@@ -44,35 +46,35 @@ describe('speech-synthesis-roundtrip (RFC 0105 §A)', () => {
44
46
  text: 'Welcome to the weekly digest.',
45
47
  voiceId: VOICE_ID,
46
48
  });
47
- if (res.status === 404) return; // seam unwired — soft-skip the behavioral suite
49
+ 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
48
50
 
49
51
  expect(
50
52
  res.status === 200,
51
- driver.describe('RFC 0105 §A', 'an advertised host MUST synthesize and return 200'),
53
+ req('openwop.it.speech-synthesis-roundtrip.synthesizes-an-audio-asset-with-exactly-one-of-url-base64-and-echoes-the-voiceid', 'RFC 0105 §A', 'an advertised host MUST synthesize and return 200'),
52
54
  ).toBe(true);
53
55
 
54
56
  const audio = audioOf(res.json);
55
57
  expect(
56
58
  audio !== undefined,
57
- driver.describe('RFC 0105 §A', 'the response MUST carry an `audio` object'),
59
+ req('openwop.it.speech-synthesis-roundtrip.synthesizes-an-audio-asset-with-exactly-one-of-url-base64-and-echoes-the-voiceid', 'RFC 0105 §A', 'the response MUST carry an `audio` object'),
58
60
  ).toBe(true);
59
- if (!audio) return;
61
+ if (!audio) return softSkip('blocked', 'precondition not met — `!audio` returned early (seam, prior step, or fixture unavailable)');
60
62
 
61
63
  const hasUrl = typeof audio.url === 'string' && (audio.url as string).length > 0;
62
64
  const hasBase64 = typeof audio.base64 === 'string' && (audio.base64 as string).length > 0;
63
65
  expect(
64
66
  hasUrl !== hasBase64,
65
- driver.describe('RFC 0105 §A', 'audio MUST carry EXACTLY ONE of `url` / `base64`'),
67
+ req('openwop.it.speech-synthesis-roundtrip.synthesizes-an-audio-asset-with-exactly-one-of-url-base64-and-echoes-the-voiceid', 'RFC 0105 §A', 'audio MUST carry EXACTLY ONE of `url` / `base64`'),
66
68
  ).toBe(true);
67
69
 
68
70
  expect(
69
71
  typeof audio.mimeType === 'string' && (audio.mimeType as string).length > 0,
70
- driver.describe('RFC 0105 §A', 'audio.mimeType MUST be a non-empty string'),
72
+ req('openwop.it.speech-synthesis-roundtrip.synthesizes-an-audio-asset-with-exactly-one-of-url-base64-and-echoes-the-voiceid', 'RFC 0105 §A', 'audio.mimeType MUST be a non-empty string'),
71
73
  ).toBe(true);
72
74
 
73
75
  expect(
74
76
  audio.voiceId === VOICE_ID,
75
- driver.describe('RFC 0105 §A', 'audio.voiceId MUST echo the input voiceId'),
77
+ req('openwop.it.speech-synthesis-roundtrip.synthesizes-an-audio-asset-with-exactly-one-of-url-base64-and-echoes-the-voiceid', 'RFC 0105 §A', 'audio.voiceId MUST echo the input voiceId'),
76
78
  ).toBe(true);
77
79
  });
78
80
  });
@@ -24,6 +24,8 @@ import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
25
  import { behaviorGate } from '../lib/behavior-gate.js';
26
26
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
27
+ import { req } from '../lib/requirement-ids.js';
28
+ import { softSkip } from '../lib/soft-skip.js';
27
29
 
28
30
  const SEAM = '/v1/host/sample/ai/call-speech-synthesizer';
29
31
 
@@ -50,16 +52,16 @@ describe('speech-synthesis-unadvertised (RFC 0105 §C)', () => {
50
52
  text: 'Welcome to the weekly digest.',
51
53
  voiceId: 'host:narrator-test',
52
54
  });
53
- if (res.status === 404) return; // seam unwired — soft-skip
55
+ 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
54
56
 
55
57
  // MUST reject — never a 200 success, never a silent no-op.
56
58
  expect(
57
59
  res.status !== 200,
58
- driver.describe('RFC 0105 §C', 'an unadvertising host MUST NOT return a 200 success (never a no-op)'),
60
+ req('openwop.it.speech-synthesis-unadvertised.a-host-not-advertising-speechsynthesis-must-reject-the-call-with-speech-synthesi', 'RFC 0105 §C', 'an unadvertising host MUST NOT return a 200 success (never a no-op)'),
59
61
  ).toBe(true);
60
62
  expect(
61
63
  errCode(res.json) === 'speech_synthesis_unsupported',
62
- driver.describe('RFC 0105 §C', 'the call MUST be rejected with `speech_synthesis_unsupported`'),
64
+ req('openwop.it.speech-synthesis-unadvertised.a-host-not-advertising-speechsynthesis-must-reject-the-call-with-speech-synthesi', 'RFC 0105 §C', 'the call MUST be rejected with `speech_synthesis_unsupported`'),
63
65
  ).toBe(true);
64
66
  });
65
67
  });
@@ -14,6 +14,8 @@
14
14
  import { describe, it, expect } from 'vitest';
15
15
  import { driver } from '../lib/driver.js';
16
16
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
17
+ import { req } from '../lib/requirement-ids.js';
18
+ import { softSkip } from '../lib/soft-skip.js';
17
19
 
18
20
  interface DiscoveryDoc {
19
21
  capabilities?: Record<string, unknown>;
@@ -34,10 +36,10 @@ async function call(op: string, args: Record<string, unknown>) {
34
36
  describe('sql-injection-rejection: advertisement shape (RFC 0018)', () => {
35
37
  it('capabilities.sql is either absent or a well-formed object', async () => {
36
38
  const cap = await readCap();
37
- if (cap === null) return;
39
+ if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
38
40
  expect(
39
41
  typeof cap.supported,
40
- driver.describe(
42
+ req('openwop.it.sql-injection-rejection.capabilities-sql-is-either-absent-or-a-well-formed-object',
41
43
  'capabilities.schema.json §sql',
42
44
  'capabilities.sql.supported MUST be a boolean when present',
43
45
  ),
@@ -48,13 +50,13 @@ describe('sql-injection-rejection: advertisement shape (RFC 0018)', () => {
48
50
  describe('sql-injection-rejection: behavioral (RFC 0018 §C)', () => {
49
51
  it('parametric SELECT with bound user input rejects injection-shape strings as data', async () => {
50
52
  const cap = await readCap();
51
- if (!cap || cap.supported !== true) return;
53
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
52
54
 
53
55
  const create = await call('execute', {
54
56
  sql: `CREATE TABLE IF NOT EXISTS sql_inj_t (id TEXT PRIMARY KEY, body TEXT)`,
55
57
  params: [],
56
58
  });
57
- if (create.status === 404) return;
59
+ if (create.status === 404) return softSkip('blocked', 'precondition not met — `create.status === 404` returned early (seam, prior step, or fixture unavailable)');
58
60
  await call('execute', { sql: `INSERT OR REPLACE INTO sql_inj_t VALUES (?, ?)`, params: ['k1', 'ok'] });
59
61
 
60
62
  // Parametric round-trip MUST succeed.
@@ -64,7 +66,7 @@ describe('sql-injection-rejection: behavioral (RFC 0018 §C)', () => {
64
66
  });
65
67
  expect(okRes.status).toBe(200);
66
68
  const okBody = okRes.json as { rows?: Array<Record<string, unknown>> };
67
- expect(okBody.rows?.[0]?.body, 'parametric round-trip MUST return stored value').toBe('ok');
69
+ expect(okBody.rows?.[0]?.body, req('openwop.it.sql-injection-rejection.parametric-select-with-bound-user-input-rejects-injection-shape-strings-as-data', 'SECURITY/invariants.yaml sql-parametric-only', 'parametric round-trip MUST return stored value')).toBe('ok');
68
70
 
69
71
  // Injection-shape input MUST be bound as a literal value, not SQL.
70
72
  const attack = `' OR '1'='1`;
@@ -76,7 +78,7 @@ describe('sql-injection-rejection: behavioral (RFC 0018 §C)', () => {
76
78
  const attackBody = attackRes.json as { rows?: Array<Record<string, unknown>> };
77
79
  expect(
78
80
  Array.isArray(attackBody.rows) ? attackBody.rows.length : -1,
79
- driver.describe(
81
+ req('openwop.it.sql-injection-rejection.parametric-select-with-bound-user-input-rejects-injection-shape-strings-as-data',
80
82
  'SECURITY/invariants.yaml sql-parametric-only',
81
83
  'parametric binding MUST treat injection-shape input as a literal value, not SQL',
82
84
  ),
@@ -16,6 +16,8 @@
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
18
  import { discoveryFamilies } from '../lib/discovery-capabilities.js';
19
+ import { req } from '../lib/requirement-ids.js';
20
+ import { softSkip } from '../lib/soft-skip.js';
19
21
 
20
22
  interface DiscoveryDoc {
21
23
  capabilities?: Record<string, unknown>;
@@ -32,10 +34,10 @@ async function readCap(): Promise<Record<string, unknown> | null> {
32
34
  describe('sql-transaction-atomicity: advertisement shape (RFC 0018)', () => {
33
35
  it('capabilities.sql is either absent or a well-formed object', async () => {
34
36
  const cap = await readCap();
35
- if (cap === null) return; // host doesn't advertise — skip
37
+ 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
36
38
  expect(
37
39
  typeof cap.supported,
38
- driver.describe(
40
+ req('openwop.it.sql-transaction-atomicity.capabilities-sql-is-either-absent-or-a-well-formed-object',
39
41
  'capabilities.schema.json §sql',
40
42
  'capabilities.sql.supported MUST be a boolean when present',
41
43
  ),
@@ -44,17 +46,17 @@ describe('sql-transaction-atomicity: advertisement shape (RFC 0018)', () => {
44
46
 
45
47
  it('transactions is a boolean when set', async () => {
46
48
  const cap = await readCap();
47
- if (!cap || cap.supported !== true) return;
49
+ if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
48
50
  const subParts = ["transactions"];
49
51
  let sub: unknown = cap;
50
52
  for (const p of subParts) {
51
53
  if (sub && typeof sub === 'object') sub = (sub as Record<string, unknown>)[p];
52
54
  else { sub = undefined; break; }
53
55
  }
54
- if (sub === undefined) return; // optional sub-field
56
+ if (sub === undefined) return softSkip('blocked', 'precondition not met — `sub === undefined` returned early (optional sub-field) (seam, prior step, or fixture unavailable)'); // optional sub-field
55
57
  expect(
56
58
  typeof sub,
57
- driver.describe(
59
+ req('openwop.it.sql-transaction-atomicity.transactions-is-a-boolean-when-set',
58
60
  'RFC 0018 §A',
59
61
  'sql.transactions MUST be boolean when present',
60
62
  ),
@@ -69,7 +71,7 @@ async function call(op: string, args: Record<string, unknown>) {
69
71
  describe('sql-transaction-atomicity: behavioral (RFC 0018 §B.sql — transaction atomicity)', () => {
70
72
  it('transaction with N statements where N-th fails → earlier writes MUST roll back', async () => {
71
73
  const probe = await call('execute', { sql: 'CREATE TABLE IF NOT EXISTS atomicity_probe (id TEXT PRIMARY KEY)', params: [] });
72
- if (probe.status === 404) return;
74
+ if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
73
75
  const table = `t_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
74
76
  await call('execute', { sql: `CREATE TABLE ${table} (id INTEGER PRIMARY KEY, val TEXT)`, params: [] });
75
77
 
@@ -82,7 +84,7 @@ describe('sql-transaction-atomicity: behavioral (RFC 0018 §B.sql — transactio
82
84
  });
83
85
  expect(
84
86
  txnRes.status >= 400 && txnRes.status < 500,
85
- driver.describe('RFC 0018 §B.sql', 'transaction with failing statement MUST surface as 4xx'),
87
+ req('openwop.it.sql-transaction-atomicity.transaction-with-n-statements-where-n-th-fails-earlier-writes-must-roll-back', 'RFC 0018 §B.sql', 'transaction with failing statement MUST surface as 4xx'),
86
88
  ).toBe(true);
87
89
 
88
90
  const queryRes = await call('query', { sql: `SELECT id, val FROM ${table}`, params: [] });
@@ -90,7 +92,7 @@ describe('sql-transaction-atomicity: behavioral (RFC 0018 §B.sql — transactio
90
92
  const body = queryRes.json as { rows?: unknown[] };
91
93
  expect(
92
94
  Array.isArray(body.rows) && body.rows.length === 0,
93
- driver.describe('RFC 0018 §B.sql', 'rows from earlier statements in a failed transaction MUST NOT be visible'),
95
+ req('openwop.it.sql-transaction-atomicity.transaction-with-n-statements-where-n-th-fails-earlier-writes-must-roll-back', 'RFC 0018 §B.sql', 'rows from earlier statements in a failed transaction MUST NOT be visible'),
94
96
  ).toBe(true);
95
97
  });
96
98
  });