@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
@@ -31,8 +31,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
31
31
  import { driver } from '../lib/driver.js';
32
32
  import { behaviorGate } from '../lib/behavior-gate.js';
33
33
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
34
-
35
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
34
+ import { req } from '../lib/requirement-ids.js';
35
+ import { softSkip } from '../lib/soft-skip.js';
36
36
  function loadSchema(name: string): Record<string, unknown> {
37
37
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
38
38
  }
@@ -42,11 +42,11 @@ describe('goal-standing-continuation: capability advertisement (RFC 0097 §A, se
42
42
  const caps = loadSchema('capabilities.schema.json');
43
43
  const agents = (caps.properties as Record<string, { properties?: Record<string, { properties?: Record<string, unknown>; required?: string[] }> }>).agents;
44
44
  const goals = agents?.properties?.goals;
45
- expect(goals, why('capabilities.md §agents', 'agents.goals MUST be declared')).toBeDefined();
45
+ expect(goals, req('openwop.it.goal-standing-continuation.capabilities-schema-declares-agents-goals-with-its-required-sub-flags', 'capabilities.md §agents', 'agents.goals MUST be declared')).toBeDefined();
46
46
  for (const flag of ['judge', 'continuation', 'requiresBounds']) {
47
- expect(goals?.properties?.[flag], why('RFC 0097 §A', `agents.goals.${flag} MUST be declared`)).toBeDefined();
47
+ expect(goals?.properties?.[flag], req('openwop.it.goal-standing-continuation.capabilities-schema-declares-agents-goals-with-its-required-sub-flags', 'RFC 0097 §A', `agents.goals.${flag} MUST be declared`)).toBeDefined();
48
48
  }
49
- expect(goals?.required, why('RFC 0097 §A', 'judge + continuation MUST be required')).toEqual(
49
+ expect(goals?.required, req('openwop.it.goal-standing-continuation.capabilities-schema-declares-agents-goals-with-its-required-sub-flags', 'RFC 0097 §A', 'judge + continuation MUST be required')).toEqual(
50
50
  expect.arrayContaining(['judge', 'continuation']),
51
51
  );
52
52
  });
@@ -69,13 +69,13 @@ describe('goal-standing-continuation: Goal shape (RFC 0097 §B, server-free)', (
69
69
  };
70
70
 
71
71
  it('validates a conforming active goal', () => {
72
- expect(validate(good), why('RFC 0097 §B', `a conforming goal MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
72
+ expect(validate(good), req('openwop.it.goal-standing-continuation.validates-a-conforming-active-goal', 'RFC 0097 §B', `a conforming goal MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
73
73
  });
74
74
 
75
75
  it('rejects an unknown state, an unknown judge, and a bad continuation mode', () => {
76
- expect(validate({ ...good, state: 'done' }), why('RFC 0097 §B', 'a state outside the lifecycle enum MUST be rejected')).toBe(false);
77
- expect(validate({ ...good, completion: { check: 'vibes' } }), why('RFC 0097 §B', 'judge check outside {verifier,host} MUST be rejected')).toBe(false);
78
- expect(validate({ ...good, continuation: { mode: 'whenever' } }), why('RFC 0097 §B', 'continuation mode outside the enum MUST be rejected')).toBe(false);
76
+ expect(validate({ ...good, state: 'done' }), req('openwop.it.goal-standing-continuation.rejects-an-unknown-state-an-unknown-judge-and-a-bad-continuation-mode', 'RFC 0097 §B', 'a state outside the lifecycle enum MUST be rejected')).toBe(false);
77
+ expect(validate({ ...good, completion: { check: 'vibes' } }), req('openwop.it.goal-standing-continuation.rejects-an-unknown-state-an-unknown-judge-and-a-bad-continuation-mode', 'RFC 0097 §B', 'judge check outside {verifier,host} MUST be rejected')).toBe(false);
78
+ expect(validate({ ...good, continuation: { mode: 'whenever' } }), req('openwop.it.goal-standing-continuation.rejects-an-unknown-state-an-unknown-judge-and-a-bad-continuation-mode', 'RFC 0097 §B', 'continuation mode outside the enum MUST be rejected')).toBe(false);
79
79
  });
80
80
  });
81
81
 
@@ -88,17 +88,17 @@ describe('goal-standing-continuation: content-free events (RFC 0097 §D, server-
88
88
 
89
89
  it('goal.evaluated and goal.closed are in the RunEventType enum', () => {
90
90
  const en = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
91
- expect(en).toContain('goal.evaluated');
91
+ expect(en, req('openwop.it.goal-standing-continuation.goal-evaluated-and-goal-closed-are-in-the-runeventtype-enum', 'RFC 0097', 'goal.evaluated and goal.closed are in the RunEventType enum')).toContain('goal.evaluated');
92
92
  expect(en).toContain('goal.closed');
93
93
  });
94
94
 
95
95
  it('goal.evaluated is content-free — an objective text field is rejected; goal.closed requires a terminal finalState', () => {
96
96
  const evaluated = ajv.getSchema('payloads#/$defs/goalEvaluated')!;
97
- expect(evaluated({ goalId: 'g1', satisfied: false, confidence: 0.4, runId: 'r1', iterations: 2 }), why('RFC 0097 §D', 'a content-free goal.evaluated MUST validate')).toBe(true);
98
- expect(evaluated({ goalId: 'g1', satisfied: false, runId: 'r1', iterations: 2, objective: 'ship it' }), why('RFC 0097 §D', 'goal.evaluated MUST NOT carry objective text')).toBe(false);
97
+ expect(evaluated({ goalId: 'g1', satisfied: false, confidence: 0.4, runId: 'r1', iterations: 2 }), req('openwop.it.goal-standing-continuation.goal-evaluated-is-content-free-an-objective-text-field-is-rejected-goal-closed-r', 'RFC 0097 §D', 'a content-free goal.evaluated MUST validate')).toBe(true);
98
+ expect(evaluated({ goalId: 'g1', satisfied: false, runId: 'r1', iterations: 2, objective: 'ship it' }), req('openwop.it.goal-standing-continuation.goal-evaluated-is-content-free-an-objective-text-field-is-rejected-goal-closed-r', 'RFC 0097 §D', 'goal.evaluated MUST NOT carry objective text')).toBe(false);
99
99
  const closed = ajv.getSchema('payloads#/$defs/goalClosed')!;
100
- expect(closed({ goalId: 'g1', finalState: 'bound-exceeded' }), why('RFC 0097 §D', 'goal.closed with a terminal finalState MUST validate')).toBe(true);
101
- expect(closed({ goalId: 'g1', finalState: 'active' }), why('RFC 0097 §D', 'goal.closed MUST NOT use the non-terminal `active` state')).toBe(false);
100
+ expect(closed({ goalId: 'g1', finalState: 'bound-exceeded' }), req('openwop.it.goal-standing-continuation.goal-evaluated-is-content-free-an-objective-text-field-is-rejected-goal-closed-r', 'RFC 0097 §D', 'goal.closed with a terminal finalState MUST validate')).toBe(true);
101
+ expect(closed({ goalId: 'g1', finalState: 'active' }), req('openwop.it.goal-standing-continuation.goal-evaluated-is-content-free-an-objective-text-field-is-rejected-goal-closed-r', 'RFC 0097 §D', 'goal.closed MUST NOT use the non-terminal `active` state')).toBe(false);
102
102
  });
103
103
  });
104
104
 
@@ -106,17 +106,17 @@ describe('goal-standing-continuation: behavioral (RFC 0097 §E, capability-gated
106
106
  it('a goal cannot be created without bounds when requiresBounds is advertised (422)', async () => {
107
107
  const agents = await readCapabilityFamily<{ goals?: { requiresBounds?: boolean } }>('agents');
108
108
  if (!behaviorGate('agents.goals', agents?.goals !== undefined)) return;
109
- if (agents?.goals?.requiresBounds === false) return; // host opted out of mandatory bounds
109
+ if (agents?.goals?.requiresBounds === false) return softSkip('blocked', 'precondition not met — `agents?.goals?.requiresBounds === false` returned early (host opted out of mandatory bounds) (seam, prior step, or fixture unavailable)'); // host opted out of mandatory bounds
110
110
 
111
111
  const res = await driver.post('/v1/host/sample/goals', {
112
112
  objective: 'unbounded work',
113
113
  completion: { check: 'host' },
114
114
  continuation: { mode: 'manual' },
115
115
  });
116
- if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
116
+ 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
117
117
  expect(
118
118
  res.status,
119
- driver.describe('agent-runtime.md §"Standing goals" clause 2', 'POST /goals without RFC 0058 bounds MUST be rejected (422) when requiresBounds is advertised'),
119
+ req('openwop.it.goal-standing-continuation.a-goal-cannot-be-created-without-bounds-when-requiresbounds-is-advertised-422', 'agent-runtime.md §"Standing goals" clause 2', 'POST /goals without RFC 0058 bounds MUST be rejected (422) when requiresBounds is advertised'),
120
120
  ).toBe(422);
121
121
  });
122
122
 
@@ -125,15 +125,15 @@ describe('goal-standing-continuation: behavioral (RFC 0097 §E, capability-gated
125
125
  if (!behaviorGate('agents.goals', agents?.goals !== undefined)) return;
126
126
 
127
127
  const list = await driver.get('/v1/host/sample/goals?state=active');
128
- if (list.status === 404 || list.status === 403) return;
128
+ if (list.status === 404 || list.status === 403) return softSkip('blocked', 'precondition not met — `list.status === 404 || list.status === 403` returned early (seam, prior step, or fixture unavailable)');
129
129
  const goals = (list.json as { goals?: Array<{ id: string }> })?.goals ?? [];
130
- if (goals.length === 0) return;
130
+ if (goals.length === 0) return softSkip('blocked', 'precondition not met — `goals.length === 0` returned early (seam, prior step, or fixture unavailable)');
131
131
 
132
132
  const res = await driver.post(`/v1/host/sample/goals/${goals[0]!.id}`, { state: 'satisfied' });
133
- if (res.status === 404) return;
133
+ if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
134
134
  expect(
135
135
  res.status >= 400,
136
- driver.describe('agent-runtime.md §"Standing goals" clause 1', 'a client-supplied state: satisfied MUST be refused — completion is the judge\'s verdict'),
136
+ req('openwop.it.goal-standing-continuation.a-client-must-not-set-state-satisfied-directly', 'agent-runtime.md §"Standing goals" clause 1', 'a client-supplied state: satisfied MUST be refused — completion is the judge\'s verdict'),
137
137
  ).toBe(true);
138
138
  });
139
139
  });
@@ -34,6 +34,8 @@ import { describe, it, expect } from 'vitest';
34
34
  import { driver } from '../lib/driver.js';
35
35
  import { behaviorGate } from '../lib/behavior-gate.js';
36
36
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
37
+ import { req } from '../lib/requirement-ids.js';
38
+ import { softSkip } from '../lib/soft-skip.js';
37
39
 
38
40
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
39
41
 
@@ -50,23 +52,23 @@ interface GrpcCap {
50
52
  describe.skipIf(HTTP_SKIP)('grpc-transport: advertisement shape (grpc-transport.md §Field semantics)', () => {
51
53
  it('an advertised capabilities.grpc block satisfies every doc MUST', async () => {
52
54
  const res = await driver.get('/.well-known/openwop');
53
- if (res.status !== 200) return;
55
+ if (res.status !== 200) return softSkip('blocked', 'precondition not met — `res.status !== 200` returned early (seam, prior step, or fixture unavailable)');
54
56
  const grpc = capabilityFamily<GrpcCap>(res.json, 'grpc');
55
57
  if (!behaviorGate('openwop-grpc-transport', grpc !== undefined)) return;
56
58
 
57
59
  expect(
58
60
  typeof grpc!.supported,
59
- driver.describe('grpc-transport.md §Field semantics', 'capabilities.grpc.supported MUST be a boolean'),
61
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must', 'grpc-transport.md §Field semantics', 'capabilities.grpc.supported MUST be a boolean'),
60
62
  ).toBe('boolean');
61
63
 
62
64
  expect(
63
65
  grpc!.service,
64
- driver.describe('grpc-transport.md §Field semantics', 'v1 hosts MUST use the canonical service name openwop.v1.Engine'),
66
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must', 'grpc-transport.md §Field semantics', 'v1 hosts MUST use the canonical service name openwop.v1.Engine'),
65
67
  ).toBe(V1_SERVICE);
66
68
 
67
69
  expect(
68
70
  TLS_VALUES,
69
- driver.describe(
71
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must',
70
72
  'grpc-transport.md §Field semantics',
71
73
  `capabilities.grpc.tls MUST be one of ${TLS_VALUES.join(' / ')} (got ${String(grpc!.tls)})`,
72
74
  ),
@@ -75,7 +77,7 @@ describe.skipIf(HTTP_SKIP)('grpc-transport: advertisement shape (grpc-transport.
75
77
  if (grpc!.endpoint !== undefined) {
76
78
  expect(
77
79
  typeof grpc!.endpoint === 'string' && /^grpcs?:\/\/.+/.test(grpc!.endpoint),
78
- driver.describe(
80
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must',
79
81
  'grpc-transport.md §Field semantics',
80
82
  `capabilities.grpc.endpoint MUST be a grpc:// (cleartext) or grpcs:// (TLS) URI (got ${String(grpc!.endpoint)})`,
81
83
  ),
@@ -86,7 +88,7 @@ describe.skipIf(HTTP_SKIP)('grpc-transport: advertisement shape (grpc-transport.
86
88
  const transports = capabilityFamily<unknown>(res.json, 'supportedTransports');
87
89
  expect(
88
90
  Array.isArray(transports) && transports.includes('grpc'),
89
- driver.describe(
91
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must',
90
92
  'grpc-transport.md §Field semantics',
91
93
  'supportedTransports MUST include "grpc" when the gRPC surface is exposed',
92
94
  ),
@@ -98,7 +100,7 @@ describe.skipIf(HTTP_SKIP)('grpc-transport: advertisement shape (grpc-transport.
98
100
  if (production !== undefined && grpc!.supported === true) {
99
101
  expect(
100
102
  grpc!.tls,
101
- driver.describe(
103
+ req('openwop.it.grpc-transport.an-advertised-capabilities-grpc-block-satisfies-every-doc-must',
102
104
  'grpc-transport.md §Field semantics',
103
105
  'production hosts MUST set capabilities.grpc.tls: "required"',
104
106
  ),
@@ -12,8 +12,8 @@
12
12
 
13
13
  import { describe, it, expect } from 'vitest';
14
14
  import { softSkip } from '../lib/soft-skip.js';
15
- import { driver } from '../lib/driver.js';
16
15
  import { readHeartbeatCap } from '../lib/heartbeat.js';
16
+ import { req } from '../lib/requirement-ids.js';
17
17
 
18
18
  describe('heartbeat-capability-shape: advertisement (RFC 0060 §A)', () => {
19
19
  it('capabilities.heartbeat is absent or a well-formed object', async () => {
@@ -21,14 +21,14 @@ describe('heartbeat-capability-shape: advertisement (RFC 0060 §A)', () => {
21
21
  if (cap === null) return softSkip('inapplicable', 'not advertised — valid');
22
22
  expect(
23
23
  typeof cap.supported,
24
- driver.describe('capabilities.schema.json §heartbeat', 'heartbeat.supported MUST be a boolean when the block is present'),
24
+ req('openwop.it.heartbeat-capability-shape.capabilities-heartbeat-is-absent-or-a-well-formed-object', 'capabilities.schema.json §heartbeat', 'heartbeat.supported MUST be a boolean when the block is present'),
25
25
  ).toBe('boolean');
26
26
  for (const k of ['minIntervalSec', 'maxRuntimeMs'] as const) {
27
27
  if (cap[k] !== undefined) {
28
28
  const v = cap[k];
29
29
  expect(
30
30
  typeof v === 'number' && Number.isInteger(v) && v >= 1,
31
- driver.describe('capabilities.schema.json §heartbeat', `heartbeat.${k} MUST be a positive integer when present`),
31
+ req('openwop.it.heartbeat-capability-shape.capabilities-heartbeat-is-absent-or-a-well-formed-object', 'capabilities.schema.json §heartbeat', `heartbeat.${k} MUST be a positive integer when present`),
32
32
  ).toBe(true);
33
33
  }
34
34
  }
@@ -11,8 +11,8 @@
11
11
 
12
12
  import { describe, it, expect } from 'vitest';
13
13
  import { softSkip } from '../lib/soft-skip.js';
14
- import { driver } from '../lib/driver.js';
15
14
  import { readHeartbeatCap, heartbeatSupported, tickHeartbeat } from '../lib/heartbeat.js';
15
+ import { req } from '../lib/requirement-ids.js';
16
16
 
17
17
  describe('heartbeat-fires-once-per-tick (RFC 0060 §B.1)', () => {
18
18
  it('one tick emits exactly one heartbeat.evaluated', async () => {
@@ -23,7 +23,7 @@ describe('heartbeat-fires-once-per-tick (RFC 0060 §B.1)', () => {
23
23
  if (!Array.isArray(evaluated)) return softSkip('blocked', 'host doesn\'t surface per-tick events on the seam');
24
24
  expect(
25
25
  evaluated.length,
26
- driver.describe('RFC 0060 §B.1', 'a single tick MUST emit exactly one heartbeat.evaluated'),
26
+ req('openwop.it.heartbeat-fires-once-per-tick.one-tick-emits-exactly-one-heartbeat-evaluated', 'RFC 0060 §B.1', 'a single tick MUST emit exactly one heartbeat.evaluated'),
27
27
  ).toBe(1);
28
28
  });
29
29
  });
@@ -12,8 +12,8 @@
12
12
 
13
13
  import { describe, it, expect } from 'vitest';
14
14
  import { softSkip } from '../lib/soft-skip.js';
15
- import { driver } from '../lib/driver.js';
16
15
  import { readHeartbeatCap, heartbeatSupported, tickHeartbeat } from '../lib/heartbeat.js';
16
+ import { req } from '../lib/requirement-ids.js';
17
17
 
18
18
  function changedCount(json: unknown): number | null {
19
19
  const sc = (json as { stateChanged?: unknown[] } | undefined)?.stateChanged;
@@ -32,13 +32,13 @@ describe('heartbeat-idempotent-no-spam (RFC 0060 §B.5)', () => {
32
32
  if (unchanged === null) return softSkip('blocked', 'host doesn\'t surface stateChanged on the seam');
33
33
  expect(
34
34
  unchanged,
35
- driver.describe('RFC 0060 §B.5', 'an unchanged tick MUST NOT emit heartbeat.stateChanged'),
35
+ req('openwop.it.heartbeat-idempotent-no-spam.an-unchanged-tick-enqueues-nothing-only-a-transition-does', 'RFC 0060 §B.5', 'an unchanged tick MUST NOT emit heartbeat.stateChanged'),
36
36
  ).toBe(0);
37
37
  const transition = await tickHeartbeat({ heartbeatId: hb, observedState: { unread: 3 } });
38
38
  if (transition === null) return softSkip('blocked', 'precondition not met — `transition === null` returned early (seam, prior step, or fixture unavailable)');
39
39
  expect(
40
40
  changedCount(transition.json),
41
- driver.describe('RFC 0060 §B.5', 'a transitioning tick MUST emit exactly one heartbeat.stateChanged'),
41
+ req('openwop.it.heartbeat-idempotent-no-spam.an-unchanged-tick-enqueues-nothing-only-a-transition-does', 'RFC 0060 §B.5', 'a transitioning tick MUST emit exactly one heartbeat.stateChanged'),
42
42
  ).toBe(1);
43
43
  });
44
44
  });
@@ -11,8 +11,8 @@
11
11
 
12
12
  import { describe, it, expect } from 'vitest';
13
13
  import { softSkip } from '../lib/soft-skip.js';
14
- import { driver } from '../lib/driver.js';
15
14
  import { readHeartbeatCap, heartbeatSupported, tickHeartbeat } from '../lib/heartbeat.js';
15
+ import { req } from '../lib/requirement-ids.js';
16
16
 
17
17
  describe('heartbeat-runtime-bound (RFC 0060 §B.2)', () => {
18
18
  it('an over-budget predicate is reported as timeout', async () => {
@@ -25,7 +25,7 @@ describe('heartbeat-runtime-bound (RFC 0060 §B.2)', () => {
25
25
  if (!Array.isArray(evaluated) || evaluated.length === 0) return softSkip('blocked', 'host doesn\'t surface per-tick events (!Array.isArray(evaluated) || evaluated.length === 0)');
26
26
  expect(
27
27
  evaluated.every((e) => e.status === 'timeout'),
28
- driver.describe('RFC 0060 §B.2', 'an over-budget predicate MUST be terminated and reported status:"timeout"'),
28
+ req('openwop.it.heartbeat-runtime-bound.an-over-budget-predicate-is-reported-as-timeout', 'RFC 0060 §B.2', 'an over-budget predicate MUST be terminated and reported status:"timeout"'),
29
29
  ).toBe(true);
30
30
  });
31
31
  });
@@ -25,6 +25,7 @@
25
25
  import { describe, it, expect } from 'vitest';
26
26
  import { driver } from '../lib/driver.js';
27
27
  import { isFixtureAdvertised } from '../lib/fixtures.js';
28
+ import { req } from '../lib/requirement-ids.js';
28
29
 
29
30
  const WORKFLOW_ID = 'conformance-idempotent';
30
31
  const SKIP_SCALE = process.env.OPENWOP_SKIP_SCALE_PRODUCTION === '1';
@@ -81,7 +82,7 @@ describe.skipIf(SKIP)(
81
82
 
82
83
  expect(
83
84
  succeeded.length + conflicted.length,
84
- driver.describe(
85
+ req('openwop.it.highConcurrency.10-parallel-requests-with-same-key-yield-one-runid-and-9-replays',
85
86
  'idempotency.md §Concurrent duplicates',
86
87
  'every concurrent request MUST resolve to either the cached response or a deterministic 409',
87
88
  ),
@@ -90,7 +91,7 @@ describe.skipIf(SKIP)(
90
91
  const runIds = new Set(succeeded.map((r) => r.runId).filter((id): id is string => !!id));
91
92
  expect(
92
93
  runIds.size,
93
- driver.describe(
94
+ req('openwop.it.highConcurrency.10-parallel-requests-with-same-key-yield-one-runid-and-9-replays',
94
95
  'idempotency.md §Layer 1',
95
96
  'same idempotency key MUST yield exactly ONE runId across all successful responses',
96
97
  ),
@@ -101,7 +102,7 @@ describe.skipIf(SKIP)(
101
102
  for (const c of conflicted) {
102
103
  expect(
103
104
  c.errorCode === 'idempotency_in_flight' || c.errorCode === undefined,
104
- driver.describe(
105
+ req('openwop.it.highConcurrency.10-parallel-requests-with-same-key-yield-one-runid-and-9-replays',
105
106
  'idempotency.md',
106
107
  '409 on parallel idempotency-keyed retry MUST carry error="idempotency_in_flight"',
107
108
  ),
@@ -109,7 +110,7 @@ describe.skipIf(SKIP)(
109
110
  if (c.retryAfter !== undefined) {
110
111
  expect(
111
112
  c.retryAfter,
112
- driver.describe(
113
+ req('openwop.it.highConcurrency.10-parallel-requests-with-same-key-yield-one-runid-and-9-replays',
113
114
  'idempotency.md',
114
115
  '409 idempotency_in_flight MUST include a numeric retryAfter',
115
116
  ),
@@ -136,7 +137,7 @@ describe.skipIf(SKIP)(
136
137
  // A `minimal`-tier host MAY rate-limit; documented in scale-profiles.md.
137
138
  expect(
138
139
  succeeded.length + rateLimited.length,
139
- driver.describe(
140
+ req('openwop.it.highConcurrency.10-parallel-requests-with-distinct-keys-yield-10-distinct-runids',
140
141
  'rest-endpoints.md',
141
142
  'concurrent POST /v1/runs requests MUST resolve to either success or rate-limited',
142
143
  ),
@@ -148,7 +149,7 @@ describe.skipIf(SKIP)(
148
149
  const uniqueRunIds = new Set(succeededRunIds);
149
150
  expect(
150
151
  uniqueRunIds.size,
151
- driver.describe(
152
+ req('openwop.it.highConcurrency.10-parallel-requests-with-distinct-keys-yield-10-distinct-runids',
152
153
  'idempotency.md §Layer 1',
153
154
  'distinct idempotency keys MUST yield distinct runIds (Layer 1 dedup is keyed)',
154
155
  ),
@@ -159,7 +160,7 @@ describe.skipIf(SKIP)(
159
160
  for (const r of rateLimited) {
160
161
  expect(
161
162
  r.retryAfter,
162
- driver.describe(
163
+ req('openwop.it.highConcurrency.10-parallel-requests-with-distinct-keys-yield-10-distinct-runids',
163
164
  'scale-profiles.md §Backpressure',
164
165
  '429/503 response MUST include numeric Retry-After',
165
166
  ),
@@ -184,7 +185,7 @@ describe.skipIf(SKIP)(
184
185
  const succeeded = results.filter((r) => r.status === 200 || r.status === 201);
185
186
  expect(
186
187
  succeeded.length,
187
- driver.describe(
188
+ req('openwop.it.highConcurrency.5-sequential-retries-with-same-key-100ms-apart-all-succeed-idempotency-cache-sur',
188
189
  'scale-profiles.md §Retry semantics',
189
190
  'host MUST handle ≥5 retries with same key 100ms apart without losing the cached response',
190
191
  ),
@@ -193,7 +194,7 @@ describe.skipIf(SKIP)(
193
194
  const runIds = new Set(succeeded.map((r) => r.runId));
194
195
  expect(
195
196
  runIds.size,
196
- driver.describe(
197
+ req('openwop.it.highConcurrency.5-sequential-retries-with-same-key-100ms-apart-all-succeed-idempotency-cache-sur',
197
198
  'idempotency.md §Layer 1',
198
199
  'all 5 retries with same key MUST resolve to the same runId',
199
200
  ),
@@ -202,7 +203,7 @@ describe.skipIf(SKIP)(
202
203
  // First request is fresh; subsequent are replays.
203
204
  expect(
204
205
  results[0]!.replay,
205
- driver.describe(
206
+ req('openwop.it.highConcurrency.5-sequential-retries-with-same-key-100ms-apart-all-succeed-idempotency-cache-sur',
206
207
  'idempotency.md §Server responsibilities',
207
208
  'first request with new key MUST NOT be marked as replay',
208
209
  ),
@@ -214,7 +215,7 @@ describe.skipIf(SKIP)(
214
215
  const someReplay = results.slice(1).some((r) => r.replay);
215
216
  expect(
216
217
  someReplay,
217
- driver.describe(
218
+ req('openwop.it.highConcurrency.5-sequential-retries-with-same-key-100ms-apart-all-succeed-idempotency-cache-sur',
218
219
  'idempotency.md §Server responsibilities #2',
219
220
  'replay responses SHOULD set openwop-Idempotent-Replay: true',
220
221
  ),
@@ -236,7 +237,7 @@ describe.skipIf(SKIP)(
236
237
  const limits = (discovery.json as { limits?: Record<string, unknown> })?.limits;
237
238
  expect(
238
239
  limits,
239
- driver.describe(
240
+ req('openwop.it.highConcurrency.concurrent-distinct-key-requests-respect-advertised-idempotency-cache-retention',
240
241
  'capabilities.md §3',
241
242
  'limits MUST be advertised in discovery',
242
243
  ),
@@ -250,7 +251,7 @@ describe.skipIf(SKIP)(
250
251
  if (ackTimeout !== undefined) {
251
252
  expect(
252
253
  typeof ackTimeout === 'number' && Number.isInteger(ackTimeout) && ackTimeout >= 5,
253
- driver.describe(
254
+ req('openwop.it.highConcurrency.concurrent-distinct-key-requests-respect-advertised-idempotency-cache-retention',
254
255
  'idempotency.md',
255
256
  'limits.idempotencyAckTimeoutSec MUST be integer ≥5 when advertised',
256
257
  ),
@@ -19,6 +19,7 @@ import { readFileSync, readdirSync } from 'node:fs';
19
19
  import { join } from 'node:path';
20
20
  import { SCENARIOS_DIR } from '../lib/paths.js';
21
21
  import { HARNESS_DOUBLE_MODULES } from '../lib/host-callback.js';
22
+ import { req } from '../lib/requirement-ids.js';
22
23
 
23
24
  const DECLARATION = /export\s+const\s+REQUIRES_HOST_CALLBACK\s*[:=]/;
24
25
  /**
@@ -63,7 +64,7 @@ describe.skipIf(SCENARIOS_DIR === null)('host-callback declaration (conformance/
63
64
  // Guard: an empty scan makes every leg below vacuously true, which is the
64
65
  // shape RFC 0148 §C found in the floor verifier. A gate that passes by
65
66
  // having looked at nothing is worse than no gate, because it reports clean.
66
- expect(all.length, 'the scenario directory MUST be readable and populated').toBeGreaterThan(100);
67
+ expect(all.length, req('openwop.it.host-callback-declaration.the-scan-reaches-the-scenario-corpus', 'host-callback-declaration.test.ts (no spec citation in file)', 'the scenario directory MUST be readable and populated')).toBeGreaterThan(100);
67
68
  expect(
68
69
  all.filter((s) => s.doubles.length > 0).length,
69
70
  'the suite MUST contain scenarios that drive harness doubles — if this hits zero the ' +
@@ -78,14 +79,14 @@ describe.skipIf(SCENARIOS_DIR === null)('host-callback declaration (conformance/
78
79
  .map((s) => `${s.file} (imports ${s.doubles.join(', ')})`);
79
80
  expect(
80
81
  undeclared,
81
- 'A scenario that hands the host a harness-hosted endpoint MUST export ' +
82
+ req('openwop.it.host-callback-declaration.every-scenario-driving-a-harness-double-declares-the-callback', 'host-callback-declaration.test.ts (no spec citation in file)', 'A scenario that hands the host a harness-hosted endpoint MUST export ' +
82
83
  '`REQUIRES_HOST_CALLBACK` naming the connection the host has to originate — or ' +
83
84
  '`HOST_CALLBACK_NOT_REQUIRED` explaining why it drives both ends itself.\n\n' +
84
85
  'Without it, a consumer running the suite off-process — against a container, VM, or ' +
85
86
  'remote origin — discovers the scenario is unwitnessable by watching it fail, and reads ' +
86
87
  'a routing problem as host non-conformance. RFC 0148 §A resolves an unwitnessed ' +
87
88
  'requirement to `blocked` rather than to a pass, and a consumer can only honour that ' +
88
- 'for scenarios they can identify in advance.\n ' + undeclared.join('\n '),
89
+ 'for scenarios they can identify in advance.\n ' + undeclared.join('\n ')),
89
90
  ).toEqual([]);
90
91
  });
91
92
 
@@ -102,9 +103,9 @@ describe.skipIf(SCENARIOS_DIR === null)('host-callback declaration (conformance/
102
103
  }
103
104
  expect(
104
105
  bare,
105
- '`REQUIRES_HOST_CALLBACK` MUST be a string naming which connection the host originates — ' +
106
+ req('openwop.it.host-callback-declaration.the-declaration-states-a-reason-rather-than-a-bare-flag', 'host-callback-declaration.test.ts (no spec citation in file)', '`REQUIRES_HOST_CALLBACK` MUST be a string naming which connection the host originates — ' +
106
107
  'a bare boolean says a box was ticked, not what a consumer has to route.\n ' +
107
- bare.join('\n '),
108
+ bare.join('\n ')),
108
109
  ).toEqual([]);
109
110
  });
110
111
 
@@ -119,9 +120,9 @@ describe.skipIf(SCENARIOS_DIR === null)('host-callback declaration (conformance/
119
120
  .map((s) => s.file);
120
121
  expect(
121
122
  orphaned,
122
- 'a scenario declaring `REQUIRES_HOST_CALLBACK` MUST actually drive a harness-hosted ' +
123
+ req('openwop.it.host-callback-declaration.nothing-declares-a-callback-it-does-not-make', 'host-callback-declaration.test.ts (no spec citation in file)', 'a scenario declaring `REQUIRES_HOST_CALLBACK` MUST actually drive a harness-hosted ' +
123
124
  'endpoint. A declaration that outlived its double is a routing instruction for a ' +
124
- 'connection nobody makes.\n ' + orphaned.join('\n '),
125
+ 'connection nobody makes.\n ' + orphaned.join('\n ')),
125
126
  ).toEqual([]);
126
127
  });
127
128
  });
@@ -21,6 +21,8 @@
21
21
  import { describe, it, expect } from 'vitest';
22
22
  import { driver } from '../lib/driver.js';
23
23
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
24
26
 
25
27
  async function isHttpClientSupported(): Promise<boolean> {
26
28
  const disco = await driver.get('/.well-known/openwop');
@@ -34,7 +36,7 @@ describe('http-client-ssrf: capability advertisement contract', () => {
34
36
  if (!(await isHttpClientSupported())) {
35
37
  // eslint-disable-next-line no-console
36
38
  console.warn('[http-client-ssrf] host does not advertise httpClient; skipping');
37
- return;
39
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isHttpClientSupported())` returned early ([http-client-ssrf] host does not advertise httpClient; skipping)');
38
40
  }
39
41
  const disco = await driver.get('/.well-known/openwop');
40
42
  const cap = capabilityFamily<{
@@ -44,23 +46,23 @@ describe('http-client-ssrf: capability advertisement contract', () => {
44
46
  methods?: unknown;
45
47
  }>(disco.json, 'httpClient');
46
48
 
47
- expect(cap?.supported, driver.describe(
49
+ expect(cap?.supported, req('openwop.it.http-client-ssrf.host-advertising-httpclient-must-declare-ssrfguard-true-maxresponsebodybytes',
48
50
  'capabilities.md §httpClient',
49
51
  'httpClient.supported MUST be a boolean',
50
52
  )).toBe(true);
51
53
 
52
- expect(cap?.ssrfGuard, driver.describe(
54
+ expect(cap?.ssrfGuard, req('openwop.it.http-client-ssrf.host-advertising-httpclient-must-declare-ssrfguard-true-maxresponsebodybytes',
53
55
  'SECURITY/threat-model-secret-leakage.md (SSRF probing analog)',
54
56
  'httpClient.ssrfGuard MUST be true — a host that lets any tenant POST a workflow with arbitrary URLs without SSRF protection enables blind probing of deployer-internal services',
55
57
  )).toBe(true);
56
58
 
57
- expect(typeof cap?.maxResponseBodyBytes, driver.describe(
59
+ expect(typeof cap?.maxResponseBodyBytes, req('openwop.it.http-client-ssrf.host-advertising-httpclient-must-declare-ssrfguard-true-maxresponsebodybytes',
58
60
  'capabilities.md §httpClient',
59
61
  'httpClient.maxResponseBodyBytes MUST be a number — a host that streams unbounded response bodies into variables is a DoS vector',
60
62
  )).toBe('number');
61
63
  expect((cap?.maxResponseBodyBytes ?? 0) > 0).toBe(true);
62
64
 
63
- expect(Array.isArray(cap?.methods), driver.describe(
65
+ expect(Array.isArray(cap?.methods), req('openwop.it.http-client-ssrf.host-advertising-httpclient-must-declare-ssrfguard-true-maxresponsebodybytes',
64
66
  'capabilities.md §httpClient',
65
67
  'httpClient.methods MUST be an array of supported HTTP methods',
66
68
  )).toBe(true);
@@ -36,6 +36,8 @@ import { describe, it, expect } from 'vitest';
36
36
  import { driver } from '../lib/driver.js';
37
37
  import { behaviorGate } from '../lib/behavior-gate.js';
38
38
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
39
+ import { req } from '../lib/requirement-ids.js';
40
+ import { softSkip } from '../lib/soft-skip.js';
39
41
 
40
42
  const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
41
43
 
@@ -65,36 +67,36 @@ function errCode(json: unknown): string | undefined {
65
67
  describe.skipIf(HTTP_SKIP)('i18n-negotiation: advertisement shape (i18n.md §Capability advertisement)', () => {
66
68
  it('the i18n block is either absent or well-formed', async () => {
67
69
  const cap = await readCapabilityFamily<I18nCap>('i18n');
68
- if (cap === undefined) return; // absent ⇒ single-locale host — conformant
70
+ if (cap === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === undefined` returned early (absent ⇒ single-locale host — conformant)'); // absent ⇒ single-locale host — conformant
69
71
 
70
72
  expect(
71
73
  typeof cap.supported,
72
- driver.describe('capabilities.schema.json §i18n', 'i18n.supported MUST be a boolean when the block is present'),
74
+ req('openwop.it.i18n-negotiation.the-i18n-block-is-either-absent-or-well-formed', 'capabilities.schema.json §i18n', 'i18n.supported MUST be a boolean when the block is present'),
73
75
  ).toBe('boolean');
74
76
 
75
77
  if (cap.defaultLocale !== undefined) {
76
78
  expect(
77
79
  typeof cap.defaultLocale === 'string' && BCP47.test(cap.defaultLocale),
78
- driver.describe('i18n.md §Capability advertisement', `i18n.defaultLocale MUST be a BCP 47 tag (got ${String(cap.defaultLocale)})`),
80
+ req('openwop.it.i18n-negotiation.the-i18n-block-is-either-absent-or-well-formed', 'i18n.md §Capability advertisement', `i18n.defaultLocale MUST be a BCP 47 tag (got ${String(cap.defaultLocale)})`),
79
81
  ).toBe(true);
80
82
  }
81
83
 
82
84
  if (cap.supportedLocales !== undefined) {
83
85
  expect(
84
86
  Array.isArray(cap.supportedLocales),
85
- driver.describe('i18n.md §Capability advertisement', 'i18n.supportedLocales MUST be an array when present'),
87
+ req('openwop.it.i18n-negotiation.the-i18n-block-is-either-absent-or-well-formed', 'i18n.md §Capability advertisement', 'i18n.supportedLocales MUST be an array when present'),
86
88
  ).toBe(true);
87
89
  const locales = (cap.supportedLocales as unknown[]) ?? [];
88
90
  for (const tag of locales) {
89
91
  expect(
90
92
  typeof tag === 'string' && BCP47.test(tag),
91
- driver.describe('i18n.md §Capability advertisement', `every supportedLocales entry MUST be a BCP 47 tag (got ${String(tag)})`),
93
+ req('openwop.it.i18n-negotiation.the-i18n-block-is-either-absent-or-well-formed', 'i18n.md §Capability advertisement', `every supportedLocales entry MUST be a BCP 47 tag (got ${String(tag)})`),
92
94
  ).toBe(true);
93
95
  }
94
96
  if (typeof cap.defaultLocale === 'string') {
95
97
  expect(
96
98
  locales,
97
- driver.describe('i18n.md §Capability advertisement', 'supportedLocales MUST contain defaultLocale'),
99
+ req('openwop.it.i18n-negotiation.the-i18n-block-is-either-absent-or-well-formed', 'i18n.md §Capability advertisement', 'supportedLocales MUST contain defaultLocale'),
98
100
  ).toContain(cap.defaultLocale);
99
101
  }
100
102
  }
@@ -116,7 +118,7 @@ describe.skipIf(HTTP_SKIP)('i18n-negotiation: behavioral (i18n.md §Accept-Langu
116
118
  });
117
119
  expect(
118
120
  res.status,
119
- driver.describe(
121
+ req('openwop.it.i18n-negotiation.an-unsupported-accept-language-falls-back-never-400-and-content-language-reflect',
120
122
  'i18n.md §Accept-Language ("Host MUST NOT") + §Fallback rules',
121
123
  'an unsupported Accept-Language MUST NOT fail the request — the route still answers 404 not_found, not 400/406',
122
124
  ),
@@ -126,12 +128,12 @@ describe.skipIf(HTTP_SKIP)('i18n-negotiation: behavioral (i18n.md §Accept-Langu
126
128
  if (contentLanguage !== null) {
127
129
  expect(
128
130
  BCP47.test(contentLanguage),
129
- driver.describe('i18n.md §Accept-Language rule 4', `Content-Language MUST be a BCP 47 tag (got ${contentLanguage})`),
131
+ req('openwop.it.i18n-negotiation.an-unsupported-accept-language-falls-back-never-400-and-content-language-reflect', 'i18n.md §Accept-Language rule 4', `Content-Language MUST be a BCP 47 tag (got ${contentLanguage})`),
130
132
  ).toBe(true);
131
133
  const primary = (tag: string): string => (tag.split('-')[0] ?? tag).toLowerCase();
132
134
  expect(
133
135
  primary(contentLanguage),
134
- driver.describe(
136
+ req('openwop.it.i18n-negotiation.an-unsupported-accept-language-falls-back-never-400-and-content-language-reflect',
135
137
  'i18n.md §Fallback rules 3–4 + §Conformance',
136
138
  'for an unsupported Accept-Language, Content-Language MUST reflect the host default locale (never lie)',
137
139
  ),
@@ -148,7 +150,7 @@ describe.skipIf(HTTP_SKIP)('i18n-negotiation: behavioral (i18n.md §Accept-Langu
148
150
  });
149
151
  expect(
150
152
  res.status,
151
- driver.describe(
153
+ req('openwop.it.i18n-negotiation.a-malformed-accept-language-must-not-cause-400',
152
154
  'i18n.md §Accept-Language Host-MUST rule 1',
153
155
  'a malformed Accept-Language MUST NOT cause 400 — the host parses best-effort and proceeds (404 not_found here)',
154
156
  ),
@@ -190,7 +192,7 @@ describe.skipIf(HTTP_SKIP)('i18n-negotiation: behavioral (i18n.md §Accept-Langu
190
192
  // (a) the code is an English snake_case identifier (not localized prose)
191
193
  expect(
192
194
  typeof negotiatedCode === 'string' && /^[a-z][a-z0-9_]*$/.test(negotiatedCode),
193
- driver.describe(
195
+ req('openwop.it.i18n-negotiation.the-error-code-stays-the-canonical-english-token-under-a-negotiated-locale',
194
196
  'i18n.md §"`locale` field on `ErrorEnvelope.details`"',
195
197
  `the machine-readable error code MUST be an English lowercase snake_case identifier, not localized text (got ${String(negotiatedCode)} under ${negotiated})`,
196
198
  ),
@@ -199,7 +201,7 @@ describe.skipIf(HTTP_SKIP)('i18n-negotiation: behavioral (i18n.md §Accept-Langu
199
201
  // (b) it is byte-identical to the default-locale code — the actual invariance MUST
200
202
  expect(
201
203
  negotiatedCode,
202
- driver.describe(
204
+ req('openwop.it.i18n-negotiation.the-error-code-stays-the-canonical-english-token-under-a-negotiated-locale',
203
205
  'i18n.md §"`locale` field on `ErrorEnvelope.details`"',
204
206
  `the machine-readable error code MUST remain identical regardless of the negotiated locale (default ${defaultLocale} → ${String(baseCode)}; negotiated ${negotiated})`,
205
207
  ),