@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
@@ -11,6 +11,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
11
11
  import addFormats from 'ajv-formats';
12
12
  import type { ErrorObject } from 'ajv';
13
13
  import { FIXTURES_DIR, SCHEMAS_DIR } from '../lib/paths.js';
14
+ import { req } from '../lib/requirement-ids.js';
14
15
 
15
16
  // Layout-aware paths — `lib/paths.ts` resolves these for both repo
16
17
  // checkouts (schemas one level above the conformance package) and the
@@ -46,7 +47,7 @@ describe('fixtures: workflow-definition schema validity', () => {
46
47
  .sort();
47
48
 
48
49
  it('finds at least one fixture file', () => {
49
- expect(files.length).toBeGreaterThan(0);
50
+ expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-fixture-file', 'fixtures-valid.test.ts (no spec citation in file)', 'finds at least one fixture file')).toBeGreaterThan(0);
50
51
  });
51
52
 
52
53
  for (const file of files) {
@@ -56,7 +57,7 @@ describe('fixtures: workflow-definition schema validity', () => {
56
57
  const errors = (validate.errors ?? [])
57
58
  .map((e: ErrorObject) => `${e.instancePath || '/'}: ${e.message}`)
58
59
  .join('\n');
59
- expect(ok, `Fixture ${file} fails workflow-definition schema:\n${errors}`).toBe(true);
60
+ expect(ok, req('openwop.it.fixtures-valid.validates-against-workflow-definition-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture ${file} fails workflow-definition schema:\n${errors}`)).toBe(true);
60
61
  });
61
62
  }
62
63
 
@@ -66,7 +67,7 @@ describe('fixtures: workflow-definition schema validity', () => {
66
67
  const expected = file.replace(/\.json$/, '');
67
68
  expect(
68
69
  data.id,
69
- `Fixture file ${file} declares id "${data.id}" — MUST match filename`,
70
+ req('openwop.it.fixtures-valid.every-fixture-id-matches-its-filename', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture file ${file} declares id "${data.id}" — MUST match filename`),
70
71
  ).toBe(expected);
71
72
  }
72
73
  });
@@ -80,7 +81,7 @@ describe('fixtures: workflow-definition schema validity', () => {
80
81
  const hasManual = data.triggers.some((t) => t.type === 'manual');
81
82
  expect(
82
83
  hasManual,
83
- `Fixture ${data.id} MUST include a manual trigger per fixtures.md §Seeding contract`,
84
+ req('openwop.it.fixtures-valid.every-fixture-has-a-manual-trigger-so-the-conformance-driver-can-start-it', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture ${data.id} MUST include a manual trigger per fixtures.md §Seeding contract`),
84
85
  ).toBe(true);
85
86
  }
86
87
  });
@@ -120,7 +121,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
120
121
  .sort();
121
122
 
122
123
  it('finds at least one pack-manifest fixture (private-scope coverage)', () => {
123
- expect(files.length).toBeGreaterThan(0);
124
+ expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-pack-manifest-fixture-private-scope-coverage', 'fixtures-valid.test.ts (no spec citation in file)', 'finds at least one pack-manifest fixture (private-scope coverage)')).toBeGreaterThan(0);
124
125
  });
125
126
 
126
127
  for (const file of files) {
@@ -139,7 +140,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
139
140
  .join('\n');
140
141
  expect(
141
142
  ok,
142
- `Fixture pack-manifests/${file} fails ${schemaName}:\n${errors}`,
143
+ req('openwop.it.fixtures-valid.pack-manifests-validates-against-its-kind-s-manifest-schema', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture pack-manifests/${file} fails ${schemaName}:\n${errors}`),
143
144
  ).toBe(true);
144
145
  });
145
146
  }
@@ -158,7 +159,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
158
159
  });
159
160
  expect(
160
161
  privateFixtures.length,
161
- 'Expected at least one pack-manifest fixture under the `private.<host>.*` scope to assert v1.0 private-scope pattern coverage',
162
+ req('openwop.it.fixtures-valid.the-private-scope-fixture-exercises-the-v1-0-private-pack-pattern', 'fixtures-valid.test.ts (no spec citation in file)', 'Expected at least one pack-manifest fixture under the `private.<host>.*` scope to assert v1.0 private-scope pattern coverage'),
162
163
  ).toBeGreaterThan(0);
163
164
  });
164
165
  });
@@ -179,7 +180,7 @@ describe('fixtures: connection-pack-manifest schema validity', () => {
179
180
  .sort();
180
181
 
181
182
  it('finds at least one connection-pack fixture (RFC 0095 coverage)', () => {
182
- expect(files.length).toBeGreaterThan(0);
183
+ expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-connection-pack-fixture-rfc-0095-coverage', 'RFC 0095', 'finds at least one connection-pack fixture (RFC 0095 coverage)')).toBeGreaterThan(0);
183
184
  });
184
185
 
185
186
  for (const file of files) {
@@ -191,7 +192,7 @@ describe('fixtures: connection-pack-manifest schema validity', () => {
191
192
  .join('\n');
192
193
  expect(
193
194
  ok,
194
- `Fixture connection-packs/${file} fails connection-pack-manifest schema:\n${errors}`,
195
+ req('openwop.it.fixtures-valid.connection-packs-validates-against-connection-pack-manifest-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture connection-packs/${file} fails connection-pack-manifest schema:\n${errors}`),
195
196
  ).toBe(true);
196
197
  });
197
198
  }
@@ -219,7 +220,7 @@ describe('fixtures: trigger-event + registration schema validity', () => {
219
220
  .sort();
220
221
 
221
222
  it('finds at least one trigger-event fixture (RFC 0099 coverage)', () => {
222
- expect(files.length).toBeGreaterThan(0);
223
+ expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-trigger-event-fixture-rfc-0099-coverage', 'RFC 0099', 'finds at least one trigger-event fixture (RFC 0099 coverage)')).toBeGreaterThan(0);
223
224
  });
224
225
 
225
226
  for (const file of files) {
@@ -230,7 +231,7 @@ describe('fixtures: trigger-event + registration schema validity', () => {
230
231
  const errors = (validate.errors ?? [])
231
232
  .map((e: ErrorObject) => `${e.instancePath || '/'}: ${e.message}`)
232
233
  .join('\n');
233
- expect(ok, `Fixture trigger-events/${file} fails its schema:\n${errors}`).toBe(true);
234
+ expect(ok, req('openwop.it.fixtures-valid.trigger-events-validates-against-its-schema', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture trigger-events/${file} fails its schema:\n${errors}`)).toBe(true);
234
235
  });
235
236
  }
236
237
  });
@@ -264,7 +265,7 @@ describe('fixtures: prompt-template schema validity', () => {
264
265
  it('finds at least one prompt-template fixture', () => {
265
266
  expect(
266
267
  files.length,
267
- 'Expected at least one PromptTemplate fixture under fixtures/prompt-templates/',
268
+ req('openwop.it.fixtures-valid.finds-at-least-one-prompt-template-fixture', 'fixtures-valid.test.ts (no spec citation in file)', 'Expected at least one PromptTemplate fixture under fixtures/prompt-templates/'),
268
269
  ).toBeGreaterThan(0);
269
270
  });
270
271
 
@@ -279,7 +280,7 @@ describe('fixtures: prompt-template schema validity', () => {
279
280
  .join('\n');
280
281
  expect(
281
282
  ok,
282
- `Fixture prompt-templates/${file} fails prompt-template schema:\n${errors}`,
283
+ req('openwop.it.fixtures-valid.prompt-templates-validates-against-prompt-template-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} fails prompt-template schema:\n${errors}`),
283
284
  ).toBe(true);
284
285
  });
285
286
  }
@@ -297,7 +298,7 @@ describe('fixtures: prompt-template schema validity', () => {
297
298
  ) as { templateId: string };
298
299
  expect(
299
300
  typeof data.templateId,
300
- `Fixture prompt-templates/${file} MUST declare a templateId`,
301
+ req('openwop.it.fixtures-valid.every-fixture-templateid-matches-its-filename', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} MUST declare a templateId`),
301
302
  ).toBe('string');
302
303
  expect(data.templateId.length).toBeGreaterThan(0);
303
304
  }
@@ -321,7 +322,7 @@ describe('fixtures: prompt-template schema validity', () => {
321
322
  if (hasSecretSource) {
322
323
  expect(
323
324
  (data.tags ?? []).includes('secret-redaction'),
324
- `Fixture prompt-templates/${file} declares a secret-source variable but lacks the 'secret-redaction' tag`,
325
+ req('openwop.it.fixtures-valid.every-secret-source-variable-lives-in-a-fixture-tagged-for-the-secret-redaction', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} declares a secret-source variable but lacks the 'secret-redaction' tag`),
325
326
  ).toBe(true);
326
327
  }
327
328
  }
@@ -55,7 +55,6 @@
55
55
  */
56
56
 
57
57
  import { describe, it, expect } from 'vitest';
58
- import { driver } from '../lib/driver.js';
59
58
  import { behaviorGate } from '../lib/behavior-gate.js';
60
59
  import {
61
60
  readFormContentCap,
@@ -65,6 +64,8 @@ import {
65
64
  isEditable,
66
65
  PLAIN_TEXT_CONTROLS,
67
66
  } from '../lib/formContentPacks.js';
67
+ import { req } from '../lib/requirement-ids.js';
68
+ import { softSkip } from '../lib/soft-skip.js';
68
69
 
69
70
  /**
70
71
  * Conformance fixture templates a host wires the seam against.
@@ -82,17 +83,17 @@ describe('form-content-instantiation: a host instantiates a registered template
82
83
  it('#1 instantiation goes through the host NORMAL create path', async () => {
83
84
  if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
84
85
  const res = await instantiateTemplate(BASIC_TEMPLATE);
85
- if (res === null) return; // seam absent — soft-skip
86
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
86
87
 
87
88
  expect(
88
89
  res.status >= 200 && res.status < 300,
89
- driver.describe('form-content-packs.md §Instantiation', 'a registered template MUST instantiate'),
90
+ req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path', 'form-content-packs.md §Instantiation', 'a registered template MUST instantiate'),
90
91
  ).toBe(true);
91
92
 
92
93
  if (res.json['viaCreatePath'] !== undefined) {
93
94
  expect(
94
95
  res.json['viaCreatePath'],
95
- driver.describe(
96
+ req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path',
96
97
  'form-content-packs.md §Instantiation #1',
97
98
  'the host MUST create the form through the SAME path that serves a hand-authored form',
98
99
  ),
@@ -101,14 +102,14 @@ describe('form-content-instantiation: a host instantiates a registered template
101
102
 
102
103
  expect(
103
104
  res.fields.length,
104
- driver.describe('form-content-packs.md §Instantiation', 'the instantiated form MUST carry the template fields'),
105
+ req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path', 'form-content-packs.md §Instantiation', 'the instantiated form MUST carry the template fields'),
105
106
  ).toBeGreaterThan(0);
106
107
  });
107
108
 
108
109
  it('#1/F2 the instantiated form carries NO pack-bound submission destination', async () => {
109
110
  if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
110
111
  const res = await instantiateTemplate(BASIC_TEMPLATE);
111
- if (res === null) return;
112
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
112
113
 
113
114
  const routing = res.json['routing'];
114
115
  const bound =
@@ -118,7 +119,7 @@ describe('form-content-instantiation: a host instantiates a registered template
118
119
 
119
120
  expect(
120
121
  bound,
121
- driver.describe(
122
+ req('openwop.it.form-content-instantiation.1-f2-the-instantiated-form-carries-no-pack-bound-submission-destination',
122
123
  'form-content-packs.md §No submission routing (F2)',
123
124
  'a template MUST NOT bind a submission destination — the operator configures routing afterward, as for any hand-authored form',
124
125
  ),
@@ -128,21 +129,21 @@ describe('form-content-instantiation: a host instantiates a registered template
128
129
  it('#2 an unrecognized vendor.* field type DEGRADES to plain text, and does NOT fail the instantiation', async () => {
129
130
  if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
130
131
  const res = await instantiateTemplate(EXTENDED_TEMPLATE);
131
- if (res === null) return;
132
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
132
133
 
133
134
  expect(
134
135
  res.status >= 200 && res.status < 300 && res.json['refused'] !== true,
135
- driver.describe(
136
+ req('openwop.it.form-content-instantiation.2-an-unrecognized-vendor-field-type-degrades-to-plain-text-and-does-not-fail-the',
136
137
  'form-content-packs.md §Instantiation #2',
137
138
  'a well-formed but unrecognized vendor.*/x- type MUST degrade, NOT fail the instantiation — refusing a valid extension breaks forward compatibility',
138
139
  ),
139
140
  ).toBe(true);
140
141
 
141
142
  const field = fieldById(res.fields, VENDOR_FIELD_ID);
142
- if (field === undefined) return; // host doesn't report per-field controls on the seam — soft-skip
143
+ if (field === undefined) return softSkip('blocked', 'precondition not met — `field === undefined` returned early (host doesn\'t report per-field controls on the seam — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't report per-field controls on the seam — soft-skip
143
144
  expect(
144
145
  field.control !== undefined && PLAIN_TEXT_CONTROLS.has(field.control),
145
- driver.describe(
146
+ req('openwop.it.form-content-instantiation.2-an-unrecognized-vendor-field-type-degrades-to-plain-text-and-does-not-fail-the',
146
147
  'form-content-packs.md §Instantiation #2',
147
148
  `an unrecognized field type MUST render as a plain text input (got control ${JSON.stringify(field.control)})`,
148
149
  ),
@@ -152,14 +153,14 @@ describe('form-content-instantiation: a host instantiates a registered template
152
153
  it('#3 pack-authored fields are FULLY EDITABLE — no privilege over a hand-added field', async () => {
153
154
  if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
154
155
  const res = await instantiateTemplate(BASIC_TEMPLATE);
155
- if (res === null) return;
156
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
156
157
 
157
158
  const reporting = res.fields.filter((f) => f.editable !== undefined || f.locked !== undefined);
158
- if (reporting.length === 0) return; // host doesn't report editability — soft-skip
159
+ if (reporting.length === 0) return softSkip('blocked', 'precondition not met — `reporting.length === 0` returned early (host doesn\'t report editability — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't report editability — soft-skip
159
160
 
160
161
  expect(
161
162
  reporting.every((f) => isEditable(f)),
162
- driver.describe(
163
+ req('openwop.it.form-content-instantiation.3-pack-authored-fields-are-fully-editable-no-privilege-over-a-hand-added-field',
163
164
  'form-content-packs.md §Instantiation #3',
164
165
  'the host MUST NOT treat a pack-authored field as immutable or privileged relative to a hand-added one',
165
166
  ),
@@ -39,6 +39,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
39
39
  import { driver } from '../lib/driver.js';
40
40
  import { behaviorGate } from '../lib/behavior-gate.js';
41
41
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
42
+ import { req } from '../lib/requirement-ids.js';
43
+ import { softSkip } from '../lib/soft-skip.js';
42
44
 
43
45
  const MANIFEST_SCHEMA = join(SCHEMAS_DIR, 'frontend-plugin-manifest.schema.json');
44
46
  const MESSAGE_SCHEMA = join(SCHEMAS_DIR, 'ui-plugin-message.schema.json');
@@ -68,7 +70,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
68
70
  it('a well-formed frontend-plugin manifest validates', () => {
69
71
  expect(
70
72
  validate(validManifest()),
71
- `frontend-plugin-packs.md §The pack — a valid manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`,
73
+ req('openwop.it.frontend-plugin-packs.a-well-formed-frontend-plugin-manifest-validates', 'frontend-plugin-packs.md', `frontend-plugin-packs.md §The pack — a valid manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
72
74
  ).toBe(true);
73
75
  });
74
76
 
@@ -76,20 +78,20 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
76
78
  const m = { ...validManifest(), runtime: { language: 'javascript', entry: 'index.mjs' } };
77
79
  expect(
78
80
  validate(m),
79
- 'node-packs.md §Pack kinds — a kind:"frontend-plugin" manifest carrying `runtime` MUST be rejected (pack_kind_invalid)',
81
+ req('openwop.it.frontend-plugin-packs.a-backend-runtime-member-is-rejected-a-plugin-is-sandboxed-ui-not-a-node-entry', 'frontend-plugin-packs.md', 'node-packs.md §Pack kinds — a kind:"frontend-plugin" manifest carrying `runtime` MUST be rejected (pack_kind_invalid)'),
80
82
  ).toBe(false);
81
83
  });
82
84
 
83
85
  it('a uiPlugins[] entry missing `entry` is rejected', () => {
84
86
  const m = validManifest();
85
87
  delete (m.uiPlugins as Array<Record<string, unknown>>)[0].entry;
86
- expect(validate(m), 'a uiPlugins[] entry missing `entry` MUST NOT validate').toBe(false);
88
+ expect(validate(m), req('openwop.it.frontend-plugin-packs.a-uiplugins-entry-missing-entry-is-rejected', 'frontend-plugin-packs.md', 'a uiPlugins[] entry missing `entry` MUST NOT validate')).toBe(false);
87
89
  });
88
90
 
89
91
  it('an `entry` path with `..` traversal is rejected', () => {
90
92
  const m = validManifest();
91
93
  (m.uiPlugins as Array<Record<string, unknown>>)[0].entry = '../escape.mjs';
92
- expect(validate(m), 'an `entry` path MUST NOT contain `..` (path-traversal)').toBe(false);
94
+ expect(validate(m), req('openwop.it.frontend-plugin-packs.an-entry-path-with-traversal-is-rejected', 'frontend-plugin-packs.md', 'an `entry` path MUST NOT contain `..` (path-traversal)')).toBe(false);
93
95
  });
94
96
 
95
97
  it('a hostApi method outside the closed allowlist is rejected (frontend-plugin-rpc-allowlist)', () => {
@@ -97,13 +99,13 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
97
99
  (m.uiPlugins as Array<Record<string, unknown>>)[0].hostApi = ['artifact.read', 'host.exec'];
98
100
  expect(
99
101
  validate(m),
100
- 'frontend-plugin-packs.md §Host-RPC — only the closed allowlist methods are permitted; `host.exec` MUST NOT validate',
102
+ req('openwop.it.frontend-plugin-packs.a-hostapi-method-outside-the-closed-allowlist-is-rejected-frontend-plugin-rpc-al', 'frontend-plugin-packs.md', 'frontend-plugin-packs.md §Host-RPC — only the closed allowlist methods are permitted; `host.exec` MUST NOT validate'),
101
103
  ).toBe(false);
102
104
  });
103
105
 
104
106
  it('an empty uiPlugins[] is rejected (a pack MUST declare at least one plugin)', () => {
105
107
  const m = { ...validManifest(), uiPlugins: [] };
106
- expect(validate(m), 'a frontend-plugin pack MUST declare at least one uiPlugins[] entry').toBe(false);
108
+ expect(validate(m), req('openwop.it.frontend-plugin-packs.an-empty-uiplugins-is-rejected-a-pack-must-declare-at-least-one-plugin', 'frontend-plugin-packs.md', 'a frontend-plugin pack MUST declare at least one uiPlugins[] entry')).toBe(false);
107
109
  });
108
110
 
109
111
  it('a canvas-preview entry with canvasTypes + host.announce validates (RFC 0130)', () => {
@@ -117,7 +119,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
117
119
  };
118
120
  expect(
119
121
  validate(m),
120
- `frontend-plugin-packs.md §The pack (RFC 0130) — a canvas-preview entry MUST validate. Errors: ${JSON.stringify(validate.errors)}`,
122
+ req('openwop.it.frontend-plugin-packs.a-canvas-preview-entry-with-canvastypes-host-announce-validates-rfc-0130', 'RFC 0130', `frontend-plugin-packs.md §The pack (RFC 0130) — a canvas-preview entry MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
121
123
  ).toBe(true);
122
124
  });
123
125
 
@@ -126,7 +128,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
126
128
  (m.uiPlugins as Array<Record<string, unknown>>)[0].surface = 'omni-panel';
127
129
  expect(
128
130
  validate(m),
129
- 'frontend-plugin-packs.md §The pack — the surface enum stays closed; an unknown surface MUST NOT validate',
131
+ req('openwop.it.frontend-plugin-packs.a-surface-outside-the-closed-set-is-still-rejected-rfc-0130-keeps-the-enum-close', 'RFC 0130', 'frontend-plugin-packs.md §The pack — the surface enum stays closed; an unknown surface MUST NOT validate'),
130
132
  ).toBe(false);
131
133
  });
132
134
  });
@@ -137,14 +139,14 @@ describe('ui-plugin/1 message: schema layer (always-on, server-free)', () => {
137
139
  const validate = ajv.compile(JSON.parse(readFileSync(MESSAGE_SCHEMA, 'utf8')));
138
140
 
139
141
  it('a valid artifact.write request carrying a version token validates', () => {
140
- const req = {
142
+ const reqBody = {
141
143
  openwop: 'ui-plugin/1',
142
144
  type: 'request',
143
145
  id: 7,
144
146
  method: 'artifact.write',
145
147
  params: { artifactId: 'a-1', version: 'opaque-v1', payload: {} },
146
148
  };
147
- expect(validate(req), `a valid artifact.write request MUST validate. Errors: ${JSON.stringify(validate.errors)}`).toBe(true);
149
+ expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-valid-artifact-write-request-carrying-a-version-token-validates', 'frontend-plugin-packs.md', `a valid artifact.write request MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
148
150
  });
149
151
 
150
152
  it('an artifact_conflict response carries currentVersion (version-token concurrency)', () => {
@@ -157,28 +159,28 @@ describe('ui-plugin/1 message: schema layer (always-on, server-free)', () => {
157
159
  };
158
160
  expect(
159
161
  validate(res),
160
- `frontend-plugin-packs.md §Concurrency — a stale write surfaces artifact_conflict + currentVersion. Errors: ${JSON.stringify(validate.errors)}`,
162
+ req('openwop.it.frontend-plugin-packs.an-artifact-conflict-response-carries-currentversion-version-token-concurrency', 'frontend-plugin-packs.md', `frontend-plugin-packs.md §Concurrency — a stale write surfaces artifact_conflict + currentVersion. Errors: ${JSON.stringify(validate.errors)}`),
161
163
  ).toBe(true);
162
164
  });
163
165
 
164
166
  it('a request with a method outside the allowlist is schema-rejected', () => {
165
- const req = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'host.exec' };
166
- expect(validate(req), 'a method outside the ui-plugin/1 allowlist MUST NOT validate').toBe(false);
167
+ const reqBody = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'host.exec' };
168
+ expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-request-with-a-method-outside-the-allowlist-is-schema-rejected', 'frontend-plugin-packs.md', 'a method outside the ui-plugin/1 allowlist MUST NOT validate')).toBe(false);
167
169
  });
168
170
 
169
171
  it('a message without the ui-plugin/1 protocol tag is rejected', () => {
170
- const req = { openwop: 'ui-plugin/2', type: 'request', id: 1, method: 'artifact.read' };
171
- expect(validate(req), 'a host MUST ignore messages whose ui-plugin tag it does not recognize').toBe(false);
172
+ const reqBody = { openwop: 'ui-plugin/2', type: 'request', id: 1, method: 'artifact.read' };
173
+ expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-message-without-the-ui-plugin-1-protocol-tag-is-rejected', 'frontend-plugin-packs.md', 'a host MUST ignore messages whose ui-plugin tag it does not recognize')).toBe(false);
172
174
  });
173
175
 
174
176
  it('no credential-bearing field is admitted on the envelope (frontend-plugin-no-byok)', () => {
175
177
  // additionalProperties:false on every envelope variant — a stray apiKey/token at the
176
178
  // envelope root cannot ride the boundary.
177
179
  for (const leak of ['apiKey', 'token', 'clientSecret', 'authorization']) {
178
- const req = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'artifact.read', [leak]: 'xxx' };
180
+ const reqBody = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'artifact.read', [leak]: 'xxx' };
179
181
  expect(
180
- validate(req),
181
- `frontend-plugin-no-byok — a credential-named envelope field ("${leak}") MUST NOT validate (additionalProperties:false)`,
182
+ validate(reqBody),
183
+ req('openwop.it.frontend-plugin-packs.no-credential-bearing-field-is-admitted-on-the-envelope-frontend-plugin-no-byok', 'frontend-plugin-packs.md', `frontend-plugin-no-byok — a credential-named envelope field ("${leak}") MUST NOT validate (additionalProperties:false)`),
182
184
  ).toBe(false);
183
185
  }
184
186
  });
@@ -194,11 +196,11 @@ describe('frontend-plugin: isolation advertisement (always-on, capability shape)
194
196
  const X_HOST = /^x-host-[a-z0-9-]+-[a-z0-9-]+$/;
195
197
  it('a host advertising uiPlugins MUST advertise a conformant isolation model', async () => {
196
198
  const uiPlugins = await readCapabilityFamily<{ supported?: boolean; isolation?: string }>('uiPlugins');
197
- if (!uiPlugins?.supported) return; // unadvertised → out of scope (graceful degradation)
199
+ if (!uiPlugins?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!uiPlugins?.supported` returned early (unadvertised → out of scope (graceful degradation))'); // unadvertised → out of scope (graceful degradation)
198
200
  const iso = uiPlugins.isolation;
199
201
  expect(
200
202
  iso !== undefined && (CONFORMANT_ISOLATION.includes(iso) || X_HOST.test(iso)),
201
- driver.describe(
203
+ req('openwop.it.frontend-plugin-packs.a-host-advertising-uiplugins-must-advertise-a-conformant-isolation-model',
202
204
  'frontend-plugin-packs.md §Isolation (RFC 0119)',
203
205
  'frontend-plugin-isolation — isolation MUST be a conformant model (cross-origin-iframe default | wasm | process | container | vm | x-host-*); every value denotes the same property, in-process loading is a protocol-tier MUST NOT regardless of mechanism',
204
206
  ),
@@ -214,16 +216,16 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
214
216
  const res = await driver.post('/v1/host/sample/ui-plugin/rpc', {
215
217
  message: { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'host.exec' },
216
218
  });
217
- if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
219
+ if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
218
220
 
219
221
  const body = res.json as { ok?: boolean; error?: { code?: string } } | undefined;
220
222
  expect(
221
223
  body?.ok,
222
- driver.describe('frontend-plugin-packs.md §Host-RPC', 'an undeclared method MUST NOT execute'),
224
+ req('openwop.it.frontend-plugin-packs.an-undeclared-host-rpc-method-is-refused-with-method-not-allowed', 'frontend-plugin-packs.md §Host-RPC', 'an undeclared method MUST NOT execute'),
223
225
  ).toBe(false);
224
226
  expect(
225
227
  body?.error?.code,
226
- driver.describe(
228
+ req('openwop.it.frontend-plugin-packs.an-undeclared-host-rpc-method-is-refused-with-method-not-allowed',
227
229
  'frontend-plugin-packs.md §Host-RPC',
228
230
  'frontend-plugin-rpc-allowlist — an undeclared method surfaces method_not_allowed',
229
231
  ),
@@ -233,7 +235,7 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
233
235
  it('a stale artifact.write is refused with artifact_conflict + currentVersion (no persist)', async () => {
234
236
  const uiPlugins = await readCapabilityFamily<{ supported?: boolean; hostApi?: string[] }>('uiPlugins');
235
237
  if (!behaviorGate('uiPlugins.supported', uiPlugins?.supported === true)) return;
236
- if (!(uiPlugins?.hostApi ?? []).includes('artifact.write')) return; // write unsupported → out of scope
238
+ if (!(uiPlugins?.hostApi ?? []).includes('artifact.write')) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(uiPlugins?.hostApi ?? []).includes(\'artifact.write\')` returned early (write unsupported → out of scope)'); // write unsupported → out of scope
237
239
 
238
240
  const res = await driver.post('/v1/host/sample/ui-plugin/rpc', {
239
241
  message: {
@@ -244,19 +246,19 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
244
246
  params: { artifactId: 'conformance-canary', version: 'stale-token', payload: {} },
245
247
  },
246
248
  });
247
- if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
249
+ if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
248
250
 
249
251
  const body = res.json as { ok?: boolean; error?: { code?: string; currentVersion?: string } } | undefined;
250
252
  expect(
251
253
  body?.error?.code,
252
- driver.describe(
254
+ req('openwop.it.frontend-plugin-packs.a-stale-artifact-write-is-refused-with-artifact-conflict-currentversion-no-persi',
253
255
  'frontend-plugin-packs.md §Concurrency',
254
256
  'a stale artifact.write version surfaces artifact_conflict (host MUST NOT persist)',
255
257
  ),
256
258
  ).toBe('artifact_conflict');
257
259
  expect(
258
260
  typeof body?.error?.currentVersion,
259
- driver.describe('frontend-plugin-packs.md §Concurrency', 'artifact_conflict carries the host currentVersion for re-read/merge'),
261
+ req('openwop.it.frontend-plugin-packs.a-stale-artifact-write-is-refused-with-artifact-conflict-currentversion-no-persi', 'frontend-plugin-packs.md §Concurrency', 'artifact_conflict carries the host currentVersion for re-read/merge'),
260
262
  ).toBe('string');
261
263
  });
262
264
  });
@@ -29,6 +29,8 @@ import { describe, it, expect } from 'vitest';
29
29
  import { readErrorCode } from '../lib/error-envelope.js';
30
30
  import { driver } from '../lib/driver.js';
31
31
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
32
+ import { req } from '../lib/requirement-ids.js';
33
+ import { softSkip } from '../lib/soft-skip.js';
32
34
 
33
35
  interface DiscoveryFs {
34
36
  supported?: boolean;
@@ -57,10 +59,10 @@ const PATH_REJECTION_CODES: ReadonlySet<string> = new Set([
57
59
  describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
58
60
  it('capabilities.fs is either absent or well-formed', async () => {
59
61
  const fs = await readFs();
60
- if (fs === null) return; // host doesn't advertise fs at all
62
+ if (fs === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `fs === null` returned early (host doesn\'t advertise fs at all)'); // host doesn't advertise fs at all
61
63
  expect(
62
64
  typeof fs.supported,
63
- driver.describe(
65
+ req('openwop.it.fs-path-traversal.capabilities-fs-is-either-absent-or-well-formed',
64
66
  'capabilities.schema.json §fs',
65
67
  'capabilities.fs.supported MUST be a boolean when fs is advertised',
66
68
  ),
@@ -69,17 +71,17 @@ describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
69
71
 
70
72
  it('fs.sandboxRoot is set + non-empty when fs.supported=true', async () => {
71
73
  const fs = await readFs();
72
- if (!fs?.supported) return;
74
+ if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
73
75
  expect(
74
76
  typeof fs.sandboxRoot,
75
- driver.describe(
77
+ req('openwop.it.fs-path-traversal.fs-sandboxroot-is-set-non-empty-when-fs-supported-true',
76
78
  'RFC 0014 §A',
77
79
  'capabilities.fs.sandboxRoot MUST be present when fs.supported=true',
78
80
  ),
79
81
  ).toBe('string');
80
82
  expect(
81
83
  (fs.sandboxRoot ?? '').length,
82
- driver.describe('RFC 0014 §A', 'capabilities.fs.sandboxRoot MUST NOT be empty'),
84
+ req('openwop.it.fs-path-traversal.fs-sandboxroot-is-set-non-empty-when-fs-supported-true', 'RFC 0014 §A', 'capabilities.fs.sandboxRoot MUST NOT be empty'),
83
85
  ).toBeGreaterThan(0);
84
86
  });
85
87
  });
@@ -87,13 +89,13 @@ describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
87
89
  describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () => {
88
90
  it('absolute path outside sandbox is rejected', async () => {
89
91
  const fs = await readFs();
90
- if (!fs?.supported) return;
92
+ if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
91
93
  const res = await driver.post('/v1/host/sample/fs/read', { path: '/etc/passwd' });
92
94
  // 404 from a host that hasn't wired the test seam is a soft-skip.
93
- if (res.status === 404) return;
95
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (404 from a host that hasn\'t wired the test seam is a soft-skip.) (seam, prior step, or fixture unavailable)');
94
96
  expect(
95
97
  res.status,
96
- driver.describe(
98
+ req('openwop.it.fs-path-traversal.absolute-path-outside-sandbox-is-rejected',
97
99
  'SECURITY/invariants.yaml fs-path-traversal',
98
100
  'absolute paths outside sandboxRoot MUST be rejected with a 4xx envelope',
99
101
  ),
@@ -101,7 +103,7 @@ describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () =>
101
103
  const code = readErrorCode(res.json);
102
104
  expect(
103
105
  code !== undefined && PATH_REJECTION_CODES.has(code),
104
- driver.describe(
106
+ req('openwop.it.fs-path-traversal.absolute-path-outside-sandbox-is-rejected',
105
107
  'SECURITY/invariants.yaml fs-path-traversal',
106
108
  `error.code MUST be one of {${[...PATH_REJECTION_CODES].join(', ')}}, got: ${code ?? '(absent)'}`,
107
109
  ),
@@ -110,14 +112,14 @@ describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () =>
110
112
 
111
113
  it('relative ../ path escape is rejected', async () => {
112
114
  const fs = await readFs();
113
- if (!fs?.supported) return;
115
+ if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
114
116
  const res = await driver.post('/v1/host/sample/fs/read', { path: '../../etc/passwd' });
115
- if (res.status === 404) return;
117
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
116
118
  expect(res.status).toBeGreaterThanOrEqual(400);
117
119
  const code = readErrorCode(res.json);
118
120
  expect(
119
121
  code !== undefined && PATH_REJECTION_CODES.has(code),
120
- driver.describe(
122
+ req('openwop.it.fs-path-traversal.relative-path-escape-is-rejected',
121
123
  'SECURITY/invariants.yaml fs-path-traversal',
122
124
  `error.code MUST be one of {${[...PATH_REJECTION_CODES].join(', ')}}, got: ${code ?? '(absent)'}`,
123
125
  ),