@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
@@ -18,6 +18,8 @@ import { describe, it, expect } from 'vitest';
18
18
  import { driver } from '../lib/driver.js';
19
19
  import { pollUntilTerminal } from '../lib/polling.js';
20
20
  import { isFixtureAdvertised } from '../lib/fixtures.js';
21
+ import { req } from '../lib/requirement-ids.js';
22
+ import { softSkip } from '../lib/soft-skip.js';
21
23
 
22
24
  const CANDIDATES = ['conformance-append-ordering', 'conformance-multi-node'] as const;
23
25
  const FIXTURE = CANDIDATES.find((id) => isFixtureAdvertised(id)) ?? null;
@@ -71,13 +73,13 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
71
73
  console.warn(
72
74
  '[append-ordering] fixture emitted no channel.written events; skipping ordering assertions',
73
75
  );
74
- return;
76
+ return softSkip('blocked', 'precondition not met — `byChannel.size === 0` returned early ([append-ordering] fixture emitted no channel.written events; skipping ordering assertions) (seam, prior step, or fixture unavailable)');
75
77
  }
76
78
 
77
79
  // For each channel, sequence MUST be strictly increasing within the run.
78
80
  for (const [channel, writes] of byChannel) {
79
81
  for (let i = 1; i < writes.length; i++) {
80
- expect(writes[i].sequence, driver.describe(
82
+ expect(writes[i].sequence, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
81
83
  'channels-and-reducers.md §"Append ordering"',
82
84
  `channel '${channel}': channel.written events MUST appear in sequence order in the event log`,
83
85
  )).toBeGreaterThan(writes[i - 1].sequence);
@@ -101,7 +103,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
101
103
  // Property: every cross-engine event carries BOTH sourceEngineId
102
104
  // AND sourceRunId (per channel-written-payload.schema.json).
103
105
  for (const e of crossEngineWrites) {
104
- expect(typeof e.payload?.sourceRunId, driver.describe(
106
+ expect(typeof e.payload?.sourceRunId, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
105
107
  'channel-written-payload.schema.json',
106
108
  'cross-engine writes MUST carry sourceRunId alongside sourceEngineId',
107
109
  )).toBe('string');
@@ -110,7 +112,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
110
112
  const seen = new Set<string>();
111
113
  for (const e of allWrites) {
112
114
  const key = `${e.sequence}::${e.eventId ?? ''}`;
113
- expect(seen.has(key), driver.describe(
115
+ expect(seen.has(key), req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
114
116
  'channels-and-reducers.md §"Tie-breaking when sequences collide"',
115
117
  `(sequence, eventId) MUST be unique across the run — duplicate found: ${key}`,
116
118
  )).toBe(false);
@@ -125,7 +127,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
125
127
  for (const [channel, writes] of byChannel) {
126
128
  const projected = (channels as Record<string, unknown>)[channel];
127
129
  if (Array.isArray(projected)) {
128
- expect(projected.length, driver.describe(
130
+ expect(projected.length, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
129
131
  'channels-and-reducers.md §"Append ordering"',
130
132
  `channel '${channel}': projected array length MUST equal #channel.written events`,
131
133
  )).toBe(writes.length);
@@ -22,6 +22,7 @@ import { readFileSync } from 'node:fs';
22
22
  import { join } from 'node:path';
23
23
  import Ajv2020 from 'ajv/dist/2020.js';
24
24
  import { SCHEMAS_DIR } from '../lib/paths.js';
25
+ import { req } from '../lib/requirement-ids.js';
25
26
 
26
27
  interface PayloadsSchema {
27
28
  $schema: string;
@@ -41,7 +42,7 @@ describe('category: approval-gate governance events (RFC 0051 §B)', () => {
41
42
  it('approval.granted requires gateId + principal; quorumProgress optional', () => {
42
43
  const v = compile('approvalGranted');
43
44
  expect(v({ gateId: 'g1', principal: 'user_1' }), JSON.stringify(v.errors)).toBe(true);
44
- expect(v({ gateId: 'g1', principal: 'user_1', quorumProgress: { granted: 1, required: 2 } })).toBe(true);
45
+ expect(v({ gateId: 'g1', principal: 'user_1', quorumProgress: { granted: 1, required: 2 } }), req('openwop.it.approval-gate-events.approval-granted-requires-gateid-principal-quorumprogress-optional', 'RFC 0051 §B', 'approval.granted requires gateId + principal; quorumProgress optional')).toBe(true);
45
46
  expect(v({ gateId: 'g1' })).toBe(false); // missing principal
46
47
  expect(v({ gateId: 'g1', principal: 'user_1', role: 'admin' })).toBe(false); // unknown prop
47
48
  });
@@ -49,13 +50,13 @@ describe('category: approval-gate governance events (RFC 0051 §B)', () => {
49
50
  it('approval.rejected requires gateId + principal; reason optional', () => {
50
51
  const v = compile('approvalRejected');
51
52
  expect(v({ gateId: 'g1', principal: 'user_1' }), JSON.stringify(v.errors)).toBe(true);
52
- expect(v({ gateId: 'g1', principal: 'user_1', reason: 'incomplete' })).toBe(true);
53
+ expect(v({ gateId: 'g1', principal: 'user_1', reason: 'incomplete' }), req('openwop.it.approval-gate-events.approval-rejected-requires-gateid-principal-reason-optional', 'RFC 0051 §B', 'approval.rejected requires gateId + principal; reason optional')).toBe(true);
53
54
  expect(v({ principal: 'user_1' })).toBe(false); // missing gateId
54
55
  });
55
56
 
56
57
  it('approval.overridden requires gateId + principal + reason (audit breadcrumb)', () => {
57
58
  const v = compile('approvalOverridden');
58
59
  expect(v({ gateId: 'g1', principal: 'owner_1', reason: 'emergency publish' }), JSON.stringify(v.errors)).toBe(true);
59
- expect(v({ gateId: 'g1', principal: 'owner_1' })).toBe(false); // reason MUST be present
60
+ expect(v({ gateId: 'g1', principal: 'owner_1' }), req('openwop.it.approval-gate-events.approval-overridden-requires-gateid-principal-reason-audit-breadcrumb', 'RFC 0051 §B', 'approval.overridden requires gateId + principal + reason (audit breadcrumb)')).toBe(false); // reason MUST be present
60
61
  });
61
62
  });
@@ -24,6 +24,7 @@ import { describe, it, expect } from 'vitest';
24
24
  import { softSkip } from '../lib/soft-skip.js';
25
25
  import { driver } from '../lib/driver.js';
26
26
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
27
+ import { req } from '../lib/requirement-ids.js';
27
28
 
28
29
  async function authorizationSupported(): Promise<boolean> {
29
30
  // Root-first per RFC 0073 (`capabilities.authorization` is the deprecated wrapper shape).
@@ -42,7 +43,7 @@ describe('approval-gate-flow: role-gated, audited approval (RFC 0051 §A)', () =
42
43
  const body = res.json as { released?: boolean } | undefined;
43
44
  expect(
44
45
  body?.released,
45
- driver.describe('RFC 0051 §A', 'an unauthorized principal MUST NOT release the gate (fail-closed)'),
46
+ req('openwop.it.approval-gate-flow.an-unauthorized-principal-does-not-release-the-gate-fail-closed', 'RFC 0051 §A', 'an unauthorized principal MUST NOT release the gate (fail-closed)'),
46
47
  ).toBe(false);
47
48
  });
48
49
 
@@ -57,11 +58,11 @@ describe('approval-gate-flow: role-gated, audited approval (RFC 0051 §A)', () =
57
58
  const body = res.json as { event?: { type?: string; payload?: { reason?: string } } } | undefined;
58
59
  expect(
59
60
  body?.event?.type,
60
- driver.describe('RFC 0051 §B', 'taking the override path MUST emit approval.overridden'),
61
+ req('openwop.it.approval-gate-flow.the-override-path-emits-an-audited-approval-overridden-with-a-reason', 'RFC 0051 §B', 'taking the override path MUST emit approval.overridden'),
61
62
  ).toBe('approval.overridden');
62
63
  expect(
63
64
  typeof body?.event?.payload?.reason === 'string' && body.event.payload.reason.length > 0,
64
- driver.describe('RFC 0051 §B', 'approval.overridden MUST carry a non-empty reason (the audit breadcrumb)'),
65
+ req('openwop.it.approval-gate-flow.the-override-path-emits-an-audited-approval-overridden-with-a-reason', 'RFC 0051 §B', 'approval.overridden MUST carry a non-empty reason (the audit breadcrumb)'),
65
66
  ).toBe(true);
66
67
  });
67
68
  });
@@ -43,6 +43,7 @@
43
43
 
44
44
  import { describe, it, expect } from 'vitest';
45
45
  import { driver } from '../lib/driver.js';
46
+ import { req } from '../lib/requirement-ids.js';
46
47
 
47
48
  const CANONICAL_ACTIONS = ['accept', 'reject', 'refine', 'edit-accept', 'ask'] as const;
48
49
  const CANONICAL_EVENT_ACTIONS = ['accept', 'reject', 'refine', 'edit-accept', 'timeout'] as const;
@@ -73,7 +74,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
73
74
  // is distinguishable from the canonical form.
74
75
  const legacyHits = text.match(/"edit"/g) ?? [];
75
76
 
76
- expect(legacyHits.length, driver.describe(
77
+ expect(legacyHits.length, req('openwop.it.approval-payload.host-capability-declaration-does-not-regress-on-the-legacy-edit-form-7-drift-pin',
77
78
  'interrupt.md §"`ApprovalResume`"',
78
79
  'capability declaration MUST NOT contain the legacy `"edit"` action token (use `"edit-accept"` per spec)',
79
80
  )).toBe(0);
@@ -84,7 +85,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
84
85
  // accept/reject/refine/edit-accept/ask. Per-host advertisement is
85
86
  // optional; this test pins the vocabulary itself for future
86
87
  // scenarios that gate on it.
87
- expect(CANONICAL_ACTIONS).toHaveLength(5);
88
+ expect(CANONICAL_ACTIONS, req('openwop.it.approval-payload.canonical-action-vocabulary-is-documented-in-spec-assertion-free-reference', 'capabilities.md', 'canonical action vocabulary is documented in spec (assertion-free reference)')).toHaveLength(5);
88
89
  expect(new Set(CANONICAL_ACTIONS)).toEqual(
89
90
  new Set(['accept', 'reject', 'refine', 'edit-accept', 'ask']),
90
91
  );
@@ -98,7 +99,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
98
99
  // but isn't a resume action (clients can't submit a timeout).
99
100
  //
100
101
  // Pin this asymmetry so it doesn't drift.
101
- expect(CANONICAL_EVENT_ACTIONS).toHaveLength(5);
102
+ expect(CANONICAL_EVENT_ACTIONS, req('openwop.it.approval-payload.canonical-event-action-vocabulary-differs-from-resume-timeout-instead-of-ask', 'capabilities.md', 'canonical event action vocabulary differs from resume (timeout instead of ask)')).toHaveLength(5);
102
103
  expect(new Set(CANONICAL_EVENT_ACTIONS)).toEqual(
103
104
  new Set(['accept', 'reject', 'refine', 'edit-accept', 'timeout']),
104
105
  );
@@ -112,7 +113,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
112
113
  // The 3 documented scopes `whole/section/items` MUST be a stable
113
114
  // set in v1.x. Adding a scope is additive (clients tolerating
114
115
  // unknown values) but semantic changes need a spec discussion.
115
- expect(CANONICAL_REFINE_SCOPES).toHaveLength(3);
116
+ expect(CANONICAL_REFINE_SCOPES, req('openwop.it.approval-payload.refinefeedback-scope-vocabulary-pin-7-audit-a-5-prereq', 'capabilities.md', 'refineFeedback scope vocabulary pin (§7 audit, A.5 prereq)')).toHaveLength(3);
116
117
  expect(new Set(CANONICAL_REFINE_SCOPES)).toEqual(
117
118
  new Set(['whole', 'section', 'items']),
118
119
  );
@@ -20,8 +20,9 @@
20
20
 
21
21
  import { describe, it, expect } from 'vitest';
22
22
 
23
- import { driver } from '../lib/driver.js';
24
23
  import { loadEnv } from '../lib/env.js';
24
+ import { req } from '../lib/requirement-ids.js';
25
+ import { softSkip } from '../lib/soft-skip.js';
25
26
 
26
27
  describe('artifact-auth: unauthenticated artifact requests are rejected', () => {
27
28
  it('GET /v1/runs/{runId}/artifacts/{artifactId} without Authorization returns 401', async () => {
@@ -31,12 +32,12 @@ describe('artifact-auth: unauthenticated artifact requests are rejected', () =>
31
32
  const res = await fetch(
32
33
  `${env.baseUrl}/v1/runs/openwop-conformance-noauth-run/artifacts/openwop-conformance-noauth-artifact`,
33
34
  );
34
- expect(res.status, driver.describe(
35
+ expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401',
35
36
  'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}',
36
37
  'artifact endpoint MUST reject unauthenticated requests with 401 (never 200, never redirect)',
37
38
  )).toBe(401);
38
- expect(res.status, 'redirect MUST NOT be used to handle missing auth on artifact endpoint').not.toBe(301);
39
- expect(res.status, 'redirect MUST NOT be used to handle missing auth on artifact endpoint').not.toBe(302);
39
+ expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401', 'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}', 'redirect MUST NOT be used to handle missing auth on artifact endpoint')).not.toBe(301);
40
+ expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401', 'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}', 'redirect MUST NOT be used to handle missing auth on artifact endpoint')).not.toBe(302);
40
41
  expect(res.status).not.toBe(200);
41
42
 
42
43
  // Canonical error envelope: error: 'unauthenticated', message: string.
@@ -46,10 +47,10 @@ describe('artifact-auth: unauthenticated artifact requests are rejected', () =>
46
47
  } catch {
47
48
  // Some hosts return a bare 401 with no body — acceptable. Skip the
48
49
  // envelope-shape assertion in that case.
49
- return;
50
+ return softSkip('blocked', 'precondition not met — an earlier step threw (Some hosts return a bare 401 with no body — acceptable. Skip the envelope-shape assertion in that case.) (seam, prior step, or fixture unavailable)');
50
51
  }
51
52
  if (typeof body.error === 'string') {
52
- expect(body.error, driver.describe(
53
+ expect(body.error, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401',
53
54
  'auth.md §"Error envelope"',
54
55
  '401 envelope SHOULD carry `error: "unauthenticated"` for missing-auth on artifact endpoint',
55
56
  )).toBe('unauthenticated');
@@ -26,7 +26,6 @@
26
26
  */
27
27
 
28
28
  import { describe, it, expect } from 'vitest';
29
- import { driver } from '../lib/driver.js';
30
29
  import { behaviorGate, behaviorGatePresent } from '../lib/behavior-gate.js';
31
30
 
32
31
  const PROFILE = 'openwop-artifact-type-packs';
@@ -37,6 +36,7 @@ import {
37
36
  produceArtifact,
38
37
  sampleArtifactTypePack,
39
38
  } from '../lib/artifactTypes.js';
39
+ import { req } from '../lib/requirement-ids.js';
40
40
 
41
41
  describe('artifact-type-pack-install: registered artifacts are schema-validated (RFC 0071)', () => {
42
42
  it('a conforming payload yields artifact.created { registered: true }', async () => {
@@ -47,24 +47,24 @@ describe('artifact-type-pack-install: registered artifacts are schema-validated
47
47
  if (!behaviorGatePresent(PROFILE, installed)) return; // seam absent: skip default, FAIL strict
48
48
  expect(
49
49
  installed.status >= 200 && installed.status < 300,
50
- driver.describe('artifact-type-packs.md §"Pack kind"', 'a valid artifact-type pack MUST install cleanly'),
50
+ req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md §"Pack kind"', 'a valid artifact-type pack MUST install cleanly'),
51
51
  ).toBe(true);
52
52
 
53
53
  const produced = await produceArtifact(artifactTypeId, { title: 'Hello', body: 'World' });
54
54
  if (!behaviorGatePresent(PROFILE, produced)) return; // seam absent: skip default, FAIL strict
55
55
  expect(
56
56
  produced.json['registered'],
57
- driver.describe('artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload matching a registered artifactTypeId MUST be marked registered'),
57
+ req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload matching a registered artifactTypeId MUST be marked registered'),
58
58
  ).toBe(true);
59
59
  expect(
60
60
  produced.json['validated'],
61
- driver.describe('artifact-type-packs.md', 'the host MUST validate the payload against the pack schema before emitting artifact.created'),
61
+ req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md', 'the host MUST validate the payload against the pack schema before emitting artifact.created'),
62
62
  ).toBe(true);
63
63
  const evt = produced.json['artifactCreated'] as { registered?: unknown } | undefined;
64
64
  if (evt && 'registered' in evt) {
65
65
  expect(
66
66
  evt.registered,
67
- driver.describe('run-event-payloads.schema.json §artifactCreated', 'artifact.created.registered MUST be true for a validated registered artifact'),
67
+ req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'run-event-payloads.schema.json §artifactCreated', 'artifact.created.registered MUST be true for a validated registered artifact'),
68
68
  ).toBe(true);
69
69
  }
70
70
  });
@@ -83,7 +83,7 @@ describe('artifact-type-pack-install: registered artifacts are schema-validated
83
83
  produced.json['stored'] === false;
84
84
  expect(
85
85
  rejected,
86
- driver.describe('artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload that fails the pack schema MUST NOT be emitted as a validated registered artifact'),
86
+ req('openwop.it.artifact-type-pack-install.a-schema-violating-payload-is-rejected-not-stored-as-a-validated-registered-arti', 'artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload that fails the pack schema MUST NOT be emitted as a validated registered artifact'),
87
87
  ).toBe(true);
88
88
  });
89
89
  });
@@ -47,6 +47,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
47
47
  import addFormats from 'ajv-formats';
48
48
  import type { ErrorObject } from 'ajv';
49
49
  import { SCHEMAS_DIR } from '../lib/paths.js';
50
+ import { req } from '../lib/requirement-ids.js';
50
51
 
51
52
  const SCHEMA_PATH = join(SCHEMAS_DIR, 'artifact-type-pack-manifest.schema.json');
52
53
 
@@ -87,7 +88,7 @@ describe('category: artifact-type-pack manifest validation', () => {
87
88
  const ok = validate(validManifest());
88
89
  expect(
89
90
  ok,
90
- `artifact-type-packs.md §"Manifest format": a well-formed kind:"artifact-type" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`,
91
+ req('openwop.it.artifact-type-pack-manifest-validation.positive-a-valid-artifact-type-pack-manifest-validates-cleanly', 'artifact-type-packs.md', `artifact-type-packs.md §"Manifest format": a well-formed kind:"artifact-type" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
91
92
  ).toBe(true);
92
93
  });
93
94
 
@@ -96,45 +97,45 @@ describe('category: artifact-type-pack manifest validation', () => {
96
97
  const errs = failsWith(manifest, 'additionalProperties');
97
98
  expect(
98
99
  errs.some((e) => (e.params as { additionalProperty?: string }).additionalProperty === 'nodes'),
99
- 'artifact-type-packs.md §"Pack kind": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)',
100
+ req('openwop.it.artifact-type-pack-manifest-validation.negative-a-manifest-mixing-artifacttypes-and-nodes-is-rejected-pack-kind-invalid', 'artifact-type-packs.md', 'artifact-type-packs.md §"Pack kind": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)'),
100
101
  ).toBe(true);
101
102
  });
102
103
 
103
104
  it('negative: an empty artifactTypes[] is rejected (a pack MUST declare ≥1 type)', () => {
104
105
  const manifest = { ...validManifest(), artifactTypes: [] };
105
106
  const errs = failsWith(manifest, 'minItems');
106
- expect(errs.length, 'artifact-type-pack-manifest.schema.json: artifactTypes minItems:1').toBeGreaterThan(0);
107
+ expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-empty-artifacttypes-is-rejected-a-pack-must-declare-1-type', 'artifact-type-packs.md', 'artifact-type-pack-manifest.schema.json: artifactTypes minItems:1')).toBeGreaterThan(0);
107
108
  });
108
109
 
109
110
  it('negative: an artifactTypeId that is not reverse-DNS scoped is rejected', () => {
110
111
  const manifest = validManifest();
111
112
  manifest.artifactTypes[0]!.artifactTypeId = 'Vendor.Acme.Model'; // uppercase scope
112
113
  const errs = failsWith(manifest, 'pattern');
113
- expect(errs.length, 'artifact-type-packs.md: artifactTypeId MUST match the reverse-DNS pattern').toBeGreaterThan(0);
114
+ expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-artifacttypeid-that-is-not-reverse-dns-scoped-is-rejected', 'artifact-type-packs.md', 'artifact-type-packs.md: artifactTypeId MUST match the reverse-DNS pattern')).toBeGreaterThan(0);
114
115
  });
115
116
 
116
117
  it('negative: an unknown rendering.display value is rejected (closed RFC 0055 enum, card excluded)', () => {
117
118
  const manifest = validManifest();
118
119
  (manifest.artifactTypes[0]!.rendering as { display: string }).display = '3d-viewport';
119
120
  const errs = failsWith(manifest, 'enum');
120
- expect(errs.length, 'artifact-type-packs.md: rendering.display reuses the closed ai-envelope §"Rendering hints" enum').toBeGreaterThan(0);
121
+ expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-unknown-rendering-display-value-is-rejected-closed-rfc-0055-enum-car', 'RFC 0055', 'artifact-type-packs.md: rendering.display reuses the closed ai-envelope §"Rendering hints" enum')).toBeGreaterThan(0);
121
122
  });
122
123
 
123
124
  it('negative: a non-conforming exportFormats identifier is rejected (reserved-core + vendor.*/x- only)', () => {
124
125
  const manifest = validManifest();
125
126
  manifest.artifactTypes[0]!.exportFormats = ['PPTX']; // uppercase, unprefixed
126
127
  const errs = failsWith(manifest, 'pattern');
127
- expect(errs.length, 'artifact-type-packs.md: exportFormats identifiers are lowercase core ids OR vendor.*/x- extensions').toBeGreaterThan(0);
128
+ expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-a-non-conforming-exportformats-identifier-is-rejected-reserved-core-ven', 'artifact-type-packs.md', 'artifact-type-packs.md: exportFormats identifiers are lowercase core ids OR vendor.*/x- extensions')).toBeGreaterThan(0);
128
129
  });
129
130
 
130
131
  it('positive: the validation field accepts "open"/"closed" and rejects other values (RFC 0075)', () => {
131
132
  for (const v of ['open', 'closed']) {
132
133
  const m = validManifest();
133
134
  (m.artifactTypes[0] as Record<string, unknown>).validation = v;
134
- expect(validate(m), `artifact-type-packs.md §validation: "${v}" MUST validate (RFC 0075)`).toBe(true);
135
+ expect(validate(m), req('openwop.it.artifact-type-pack-manifest-validation.positive-the-validation-field-accepts-open-closed-and-rejects-other-values-rfc-0', 'RFC 0075', `artifact-type-packs.md §validation: "${v}" MUST validate (RFC 0075)`)).toBe(true);
135
136
  }
136
137
  const bad = validManifest();
137
138
  (bad.artifactTypes[0] as Record<string, unknown>).validation = 'lenient';
138
- expect(failsWith(bad, 'enum').length, 'validation MUST be open|closed').toBeGreaterThan(0);
139
+ expect(failsWith(bad, 'enum').length, req('openwop.it.artifact-type-pack-manifest-validation.positive-the-validation-field-accepts-open-closed-and-rejects-other-values-rfc-0', 'RFC 0075', 'validation MUST be open|closed')).toBeGreaterThan(0);
139
140
  });
140
141
  });
@@ -36,8 +36,8 @@ import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
36
36
  import { driver } from '../lib/driver.js';
37
37
  import { behaviorGatePresent } from '../lib/behavior-gate.js';
38
38
  import { readArtifactTypesCap } from '../lib/artifactTypes.js';
39
-
40
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
39
+ import { req } from '../lib/requirement-ids.js';
40
+ import { softSkip } from '../lib/soft-skip.js';
41
41
  const CAPS = join(SCHEMAS_DIR, 'capabilities.schema.json');
42
42
  const EVENT_PAYLOADS = join(SCHEMAS_DIR, 'run-event-payloads.schema.json');
43
43
  const readDoc = (name: string): string => (V1_DIR ? readFileSync(join(V1_DIR, name), 'utf8') : '');
@@ -59,14 +59,14 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
59
59
  const entry = perTypeEntry();
60
60
  const props = entry.properties as Record<string, Record<string, unknown>>;
61
61
 
62
- expect(props.registrationSource, why('§artifactTypes.types', 'facet is declared')).toBeDefined();
62
+ expect(props.registrationSource, req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'facet is declared')).toBeDefined();
63
63
  expect(
64
64
  props.registrationSource.enum,
65
- why('§artifactTypes.types', 'enum is exactly [pack, host]'),
65
+ req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'enum is exactly [pack, host]'),
66
66
  ).toEqual(['pack', 'host']);
67
67
  expect(
68
68
  (entry.required as string[] | undefined)?.includes('registrationSource') ?? false,
69
- why('§artifactTypes.types', 'facet is OPTIONAL — absent ⇒ unspecified provenance, not a default'),
69
+ req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'facet is OPTIONAL — absent ⇒ unspecified provenance, not a default'),
70
70
  ).toBe(false);
71
71
  });
72
72
 
@@ -77,22 +77,22 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
77
77
 
78
78
  expect(
79
79
  validate({ validated: true, registrationSource: 'host', schemaVersion: 1 }),
80
- why('§artifactTypes.types', `"host" validates: ${JSON.stringify(validate.errors)}`),
80
+ req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `"host" validates: ${JSON.stringify(validate.errors)}`),
81
81
  ).toBe(true);
82
82
  expect(
83
83
  validate({ validated: true, registrationSource: 'pack' }),
84
- why('§artifactTypes.types', `"pack" validates: ${JSON.stringify(validate.errors)}`),
84
+ req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `"pack" validates: ${JSON.stringify(validate.errors)}`),
85
85
  ).toBe(true);
86
86
  // Absent stays legal — requirement 2.
87
87
  expect(
88
88
  validate({ validated: true }),
89
- why('§artifactTypes.types', `absent validates: ${JSON.stringify(validate.errors)}`),
89
+ req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `absent validates: ${JSON.stringify(validate.errors)}`),
90
90
  ).toBe(true);
91
91
  // A third provenance is a wire error, NOT a hint to ignore. This is where the facet
92
92
  // parts company with RFC 0136's `format`, and the reason is in the docblock.
93
93
  expect(
94
94
  validate({ validated: true, registrationSource: 'registry' }),
95
- why('§artifactTypes.types', 'an undefined provenance is REJECTED'),
95
+ req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', 'an undefined provenance is REJECTED'),
96
96
  ).toBe(false);
97
97
  });
98
98
 
@@ -107,7 +107,7 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
107
107
  // advertise a provenance it could never emit.
108
108
  expect(
109
109
  entryProps.registrationSource.enum,
110
- why('RFC 0145 req 3', 'discovery enum matches artifact.created enum'),
110
+ req('openwop.it.artifact-type-registration-source.a3-the-facet-mirrors-the-vocabulary-artifact-created-already-carries', 'RFC 0145 req 3', 'discovery enum matches artifact.created enum'),
111
111
  ).toEqual(eventProps.registrationSource.enum);
112
112
  });
113
113
 
@@ -118,10 +118,10 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
118
118
  const facetList = readDoc(name).match(
119
119
  /validated, validation, schemaVersion, store, render, export[^}]*}/,
120
120
  );
121
- expect(facetList, why(`${name} §"Per-type facets"`, 'per-type facet list present')).not.toBeNull();
121
+ expect(facetList, req('openwop.it.artifact-type-registration-source.a4-both-prose-sites-list-the-facet-so-schema-and-normative-surface-cannot-drift', `${name} §"Per-type facets"`, 'per-type facet list present')).not.toBeNull();
122
122
  expect(
123
123
  facetList?.[0].includes('registrationSource'),
124
- why(`${name} §"Per-type facets"`, 'facet list names registrationSource'),
124
+ req('openwop.it.artifact-type-registration-source.a4-both-prose-sites-list-the-facet-so-schema-and-normative-surface-cannot-drift', `${name} §"Per-type facets"`, 'facet list names registrationSource'),
125
125
  ).toBe(true);
126
126
  }
127
127
  });
@@ -130,11 +130,11 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
130
130
  const doc = readDoc('artifact-type-packs.md');
131
131
  expect(
132
132
  /Serving is a MUST for host-registered/.test(doc),
133
- why('§Schema distribution', 'serving is a MUST for no-pack types'),
133
+ req('openwop.it.artifact-type-registration-source.a5-the-spec-states-the-must-should-asymmetry-the-facet-exists-to-disclose', '§Schema distribution', 'serving is a MUST for no-pack types'),
134
134
  ).toBe(true);
135
135
  expect(
136
136
  /serving stays a SHOULD for them/.test(doc),
137
- why('§Schema distribution', 'serving stays a SHOULD for pack-backed types'),
137
+ req('openwop.it.artifact-type-registration-source.a5-the-spec-states-the-must-should-asymmetry-the-facet-exists-to-disclose', '§Schema distribution', 'serving stays a SHOULD for pack-backed types'),
138
138
  ).toBe(true);
139
139
  });
140
140
  });
@@ -179,7 +179,7 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
179
179
  const target = comparableType(cap);
180
180
  // INAPPLICABLE, not gated. `registrationSource` is OPTIONAL (requirement 2) and strict mode
181
181
  // must not coerce a host into advertising it — the same call RFC 0142 makes for `store`.
182
- if (target === null) return;
182
+ if (target === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `target === null` returned early (INAPPLICABLE, not gated. `registrationSource` is OPTIONAL (requirement 2) and strict mode must not coerce a host into advertis…');
183
183
 
184
184
  const started = await driver.post('/v1/host/sample/artifacttypes/runproduce', {
185
185
  artifactTypeId: target.id,
@@ -189,10 +189,10 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
189
189
  // scenario that owns that enforcement. Gating again here would double-report one defect,
190
190
  // and gating on the seam for a 0145 advert would coerce hosts into wiring 0142's host-sample
191
191
  // surface in order to advertise a facet that has nothing to do with it.
192
- if (started.status === 404 || started.status === 405) return; // seam absent — 0142 reports it
192
+ if (started.status === 404 || started.status === 405) return softSkip('blocked', 'precondition not met — `started.status === 404 || started.status === 405` returned early (seam absent — 0142 reports it) (seam, prior step, or fixture unavailable)'); // seam absent — 0142 reports it
193
193
  expect(
194
194
  started.status >= 200 && started.status < 300,
195
- driver.describe('coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
195
+ req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type', 'coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
196
196
  ).toBe(true);
197
197
  const runId = (started.json as Record<string, unknown> | undefined)?.['runId'];
198
198
  if (!behaviorGatePresent(PROFILE, typeof runId === 'string' ? runId : null)) return;
@@ -200,18 +200,18 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
200
200
  const events = await driver.get(`/v1/runs/${runId}/events/poll?timeout=5`);
201
201
  expect(
202
202
  events.status,
203
- driver.describe('run-events surface', 'the run event log is readable over the standard poll endpoint'),
203
+ req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type', 'run-events surface', 'the run event log is readable over the standard poll endpoint'),
204
204
  ).toBe(200);
205
205
  const list = ((events.json as Record<string, unknown>)?.['events'] ?? []) as Array<Record<string, unknown>>;
206
206
  const created = list.filter((e) => e['type'] === 'artifact.created');
207
207
  // Emission itself is RFC 0142's MUST, reported by its own leg. Reaching here without an
208
208
  // event means that leg is already red; don't restate its finding as a 0145 failure.
209
- if (created.length === 0) return;
209
+ if (created.length === 0) return softSkip('blocked', 'precondition not met — `created.length === 0` returned early (Emission itself is RFC 0142\'s MUST, reported by its own leg. Reaching here without an event means that leg is already red; don\'t restate its finding as a 0…');
210
210
 
211
211
  const payload = (created[0]?.['payload'] ?? created[0]?.['data'] ?? {}) as Record<string, unknown>;
212
212
  expect(
213
213
  payload['registrationSource'],
214
- driver.describe(
214
+ req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type',
215
215
  'RFC 0145 requirement 3',
216
216
  `the host advertises registrationSource: "${target.advertised}" for ${target.id}, so that is the value it MUST emit — an advert of one provenance against an event carrying another (or carrying none, which asserts UNSPECIFIED provenance and therefore disagrees) is a false advertisement, not a permitted divergence`,
217
217
  ),
@@ -43,31 +43,28 @@ import { driver } from '../lib/driver.js';
43
43
  import { behaviorGate, behaviorGatePresent } from '../lib/behavior-gate.js';
44
44
  import { readArtifactTypesCap } from '../lib/artifactTypes.js';
45
45
  import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
46
+ import { req } from '../lib/requirement-ids.js';
47
+ import { softSkip } from '../lib/soft-skip.js';
46
48
 
47
49
  const PROFILE = 'openwop-artifact-type-store';
48
50
 
49
- /** Server-free assertion message helper — leg A must not touch `driver`, whose
50
- * describe() loads env and would make a "server-free" leg fail on a missing
51
- * OPENWOP_BASE_URL instead of on its assertion (a vacuous red). */
52
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
53
-
54
51
  describe('artifact-type-store-emission: the payload fact is pinned always-on (RFC 0142 leg A)', () => {
55
52
  it('artifactCreated REQUIRES artifactType — the fact the RFC 0138 replay correction rests on', () => {
56
53
  const schema = JSON.parse(
57
54
  readFileSync(join(SCHEMAS_DIR, 'run-event-payloads.schema.json'), 'utf8'),
58
55
  ) as { $defs?: Record<string, { properties?: Record<string, unknown>; required?: string[] }> };
59
56
  const ac = schema.$defs?.['artifactCreated'];
60
- expect(ac !== undefined, 'run-event-payloads.schema.json — $defs/artifactCreated exists').toBe(true);
57
+ expect(ac !== undefined, req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re', 'RFC 0138', 'run-event-payloads.schema.json — $defs/artifactCreated exists')).toBe(true);
61
58
  expect(
62
59
  ac?.required?.includes('artifactType'),
63
- why(
60
+ req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re',
64
61
  'run-event-payloads.schema.json §artifactCreated',
65
62
  'artifactType is REQUIRED on the artifact.created payload — artifactTypeId values ride in the fixed event log, which is why identifier migrations MUST NOT rewrite history (RFC 0141) and why this fact must be pinned by an always-on leg rather than a gated one (RFC 0138 G8)',
66
63
  ),
67
64
  ).toBe(true);
68
65
  expect(
69
66
  Object.keys(ac?.properties ?? {}).includes('registered'),
70
- why('run-event-payloads.schema.json §artifactCreated', 'the registered flag the store-tier validation promise is reported through is present'),
67
+ req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re', 'run-event-payloads.schema.json §artifactCreated', 'the registered flag the store-tier validation promise is reported through is present'),
71
68
  ).toBe(true);
72
69
  });
73
70
  });
@@ -83,21 +80,21 @@ describe('artifact-type-store-emission: what `store: true` claims is stated norm
83
80
  it.skipIf(V1_DIR === null)('the claim is quantified over artifacts of the type, not over the host\'s paths', () => {
84
81
  expect(
85
82
  /\*\*every\*\* path by which the host persists an artifact carrying that registered `artifactTypeId` MUST emit `artifact\.created`/.test(doc),
86
- why(
83
+ req('openwop.it.artifact-type-store-emission.the-claim-is-quantified-over-artifacts-of-the-type-not-over-the-host-s-paths',
87
84
  'artifact-type-packs.md §"Sub-flags"',
88
85
  'EVERY production path emits, not at least one — the permissive reading lets a host wire the leg-B seam through its single emitting path and pass while most of its production stays silent',
89
86
  ),
90
87
  ).toBe(true);
91
88
  expect(
92
89
  /MUST NOT advertise `store: true` for that type/.test(doc),
93
- why('artifact-type-packs.md §"Sub-flags"', 'a host with a silent persistence path for the type is forbidden from advertising it, rather than merely discouraged'),
90
+ req('openwop.it.artifact-type-store-emission.the-claim-is-quantified-over-artifacts-of-the-type-not-over-the-host-s-paths', 'artifact-type-packs.md §"Sub-flags"', 'a host with a silent persistence path for the type is forbidden from advertising it, rather than merely discouraged'),
94
91
  ).toBe(true);
95
92
  });
96
93
 
97
94
  it.skipIf(V1_DIR === null)('the obligation is scoped to REGISTERED types, so the unregistered tier does not falsify an advert', () => {
98
95
  expect(
99
96
  /a path that persists only unregistered artifacts[^.]*is outside this facet and does not falsify the advert/.test(doc),
100
- why(
97
+ req('openwop.it.artifact-type-store-emission.the-obligation-is-scoped-to-registered-types-so-the-unregistered-tier-does-not-f',
101
98
  'artifact-type-packs.md §"Sub-flags"',
102
99
  'the narrowing is normative, not a courtesy — without it a host holds back an honest advert on account of a path the facet never bound',
103
100
  ),
@@ -107,7 +104,7 @@ describe('artifact-type-store-emission: what `store: true` claims is stated norm
107
104
  it.skipIf(V1_DIR === null)('per-type is named as the instrument, including the case it cannot rescue', () => {
108
105
  expect(
109
106
  /cannot be advertised `store: true` at all until one of those two facts changes/.test(doc),
110
- why(
107
+ req('openwop.it.artifact-type-store-emission.per-type-is-named-as-the-instrument-including-the-case-it-cannot-rescue',
111
108
  'artifact-type-packs.md §"Sub-flags"',
112
109
  'a single type produced through both an emitting and a non-emitting path is not advertisable — per-type resolves a heterogeneous fleet, not a heterogeneous type',
113
110
  ),
@@ -144,7 +141,7 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
144
141
  const cap = await readArtifactTypesCap();
145
142
  // `store` is OPTIONAL. A host that does not advertise it is INAPPLICABLE —
146
143
  // not gated: strict mode must not coerce hosts into an advertisement.
147
- if (!storeAdvertised(cap)) return; // scenario inapplicable
144
+ if (!storeAdvertised(cap)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!storeAdvertised(cap)` returned early (scenario inapplicable)'); // scenario inapplicable
148
145
 
149
146
  const requested = storeTypeId(cap) ?? 'vendor.conformance.note';
150
147
  const started = await driver.post('/v1/host/sample/artifacttypes/runproduce', {
@@ -155,7 +152,7 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
155
152
 
156
153
  expect(
157
154
  started.status >= 200 && started.status < 300,
158
- driver.describe('coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
155
+ req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist', 'coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
159
156
  ).toBe(true);
160
157
  const runId = (started.json as Record<string, unknown> | undefined)?.['runId'];
161
158
  if (!behaviorGatePresent(PROFILE, typeof runId === 'string' ? runId : null)) return;
@@ -163,14 +160,14 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
163
160
  const events = await driver.get(`/v1/runs/${runId}/events/poll?timeout=5`);
164
161
  expect(
165
162
  events.status,
166
- driver.describe('run-events surface', 'the run event log is readable over the standard poll endpoint — the same wire any consumer uses'),
163
+ req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist', 'run-events surface', 'the run event log is readable over the standard poll endpoint — the same wire any consumer uses'),
167
164
  ).toBe(200);
168
165
  const list = ((events.json as Record<string, unknown>)?.['events'] ?? []) as Array<Record<string, unknown>>;
169
166
  const created = list.filter((e) => e['type'] === 'artifact.created');
170
167
 
171
168
  expect(
172
169
  created.length > 0,
173
- driver.describe(
170
+ req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
174
171
  'artifact-type-packs.md §"Host capability", store row',
175
172
  'a host advertising store:true MUST emit artifact.created — persistence without emission is the exact posture the advertisement forbids',
176
173
  ),
@@ -179,14 +176,14 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
179
176
  const payload = (created[0]?.['payload'] ?? created[0]?.['data'] ?? {}) as Record<string, unknown>;
180
177
  expect(
181
178
  payload['artifactType'],
182
- driver.describe(
179
+ req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
183
180
  'run-event-payloads.schema.json §artifactCreated',
184
181
  'the emitted artifactType is the bound id — an event present but carrying the wrong type would let a mis-wired emitter pass a presence-only check',
185
182
  ),
186
183
  ).toBe(requested);
187
184
  expect(
188
185
  payload['registered'],
189
- driver.describe(
186
+ req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
190
187
  'artifact-type-packs.md §"Binding the existing artifact surfaces"',
191
188
  'a store-tier host validates before emitting and reports registered:true for a registered type',
192
189
  ),