@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
@@ -37,6 +37,7 @@ import { fileDisposition, deriveRequirementDispositions, requirementIdForFile, f
37
37
  import { softSkip, softSkipDisposition, resetSoftSkips, UNCLASSIFIED_RETURN_DETAIL } from '../lib/soft-skip.js';
38
38
  import { PROFILE_FLOOR_SCENARIOS } from '../lib/profiles.js';
39
39
  import { requirementsFor, requirementIdForScenario, requirementIdForPrefix } from '../lib/requirement-registry.js';
40
+ import { req } from '../lib/requirement-ids.js';
40
41
 
41
42
  describe('RFC 0148 §A (S6) — ledger file sink and reader', () => {
42
43
  it('recordRequirement appends JSONL when OPENWOP_LEDGER_PATH is set; the reader merges and ranks conflicts least-certifiable-first', () => {
@@ -57,7 +58,7 @@ describe('RFC 0148 §A (S6) — ledger file sink and reader', () => {
57
58
  expect(lines.length).toBe(4);
58
59
  const merged = readLedgerFile(path);
59
60
  expect(merged.map((e) => e.requirementId)).toEqual(['t.a', 't.b']);
60
- expect(merged.find((e) => e.requirementId === 't.a')?.disposition, 'conflict resolves to the least certifiable (blocked over executed-pass)').toBe('blocked');
61
+ expect(merged.find((e) => e.requirementId === 't.a')?.disposition, req('openwop.it.runner-ledger.recordrequirement-appends-jsonl-when-openwop-ledger-path-is-set-the-reader-merge', 'RFC 0148 §A', 'conflict resolves to the least certifiable (blocked over executed-pass)')).toBe('blocked');
61
62
  expect(merged.find((e) => e.requirementId === 't.b')?.disposition).toBe('inapplicable');
62
63
  expect(readLedgerFile(join(dir, 'missing.jsonl'))).toEqual([]);
63
64
  } finally {
@@ -71,7 +72,7 @@ describe('RFC 0148 §A (S6) — ledger file sink and reader', () => {
71
72
 
72
73
  describe('RFC 0148 §A (S6) — fileDisposition folds a file honestly', () => {
73
74
  it('fail beats pass; pass beats a gate reason; a gate reason beats blocked; nothing is blocked (unclassified)', () => {
74
- expect(fileDisposition(['pass', 'fail', 'skip'], undefined).disposition).toBe('executed-fail');
75
+ expect(fileDisposition(['pass', 'fail', 'skip'], undefined).disposition, req('openwop.it.runner-ledger.fail-beats-pass-pass-beats-a-gate-reason-a-gate-reason-beats-blocked-nothing-is', 'RFC 0148 §A', 'fail beats pass; pass beats a gate reason; a gate reason beats blocked; nothing is blocked (unclassified)')).toBe('executed-fail');
75
76
  expect(fileDisposition(['pass', 'skip'], 'inapplicable').disposition).toBe('executed-pass');
76
77
  // real assertions + a gate reason → still an executed pass
77
78
  expect(fileDisposition(['pass', 'skip'], 'inapplicable', 4).disposition).toBe('executed-pass');
@@ -90,7 +91,7 @@ describe('RFC 0148 §A (S6) — fileDisposition folds a file honestly', () => {
90
91
 
91
92
  it('a floor file records under its §A floor id; any other file under openwop.scenario.*', () => {
92
93
  const floor = [...floorScenarioFiles()];
93
- expect(floor.length).toBeGreaterThan(0);
94
+ expect(floor.length, req('openwop.it.runner-ledger.a-floor-file-records-under-its-a-floor-id-any-other-file-under-openwop-scenario', 'RFC 0148 §A', 'a floor file records under its §A floor id; any other file under openwop.scenario.*')).toBeGreaterThan(0);
94
95
  expect(requirementIdForFile(floor[0]!)).toBe(requirementIdForScenario(floor[0]!));
95
96
  expect(requirementIdForFile('some-other.test.ts')).toBe('openwop.scenario.some-other');
96
97
  });
@@ -119,7 +120,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
119
120
 
120
121
  it('ledger rows win, prefix requirements derive from matching files, and a fully recorded floor certifies', () => {
121
122
  const d = deriveRequirementDispositions(reportAllPassed(), ledgerAllPassed(), [profile]);
122
- expect(d.ledgerPresent).toBe(true);
123
+ expect(d.ledgerPresent, req('openwop.it.runner-ledger.ledger-rows-win-prefix-requirements-derive-from-matching-files-and-a-fully-recor', 'RFC 0148 §A', 'ledger rows win, prefix requirements derive from matching files, and a fully recorded floor certifies')).toBe(true);
123
124
  expect(d.rejectUnclassified).toBe(false);
124
125
  const v = d.verdicts.find((x) => x.profile === profile)!;
125
126
  expect(v.certifiable, JSON.stringify(v)).toBe(true);
@@ -144,7 +145,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
144
145
  const row = d.requirements.find((r) => r.requirementId === requirementIdForScenario(files[0]!))!;
145
146
  expect(row.disposition).toBe('executed-pass'); // vitest did say passed — the row is honest about the source
146
147
  expect(row.detail).toMatch(/report-derived/);
147
- expect(v.unclassified, 'no ledger entry ⇒ unclassified for a claimed floor').toContain(requirementIdForScenario(files[0]!));
148
+ expect(v.unclassified, req('openwop.it.runner-ledger.a-floor-file-that-vitest-passed-but-that-recorded-nothing-is-unclassified-when-a', 'RFC 0148 §A', 'no ledger entry ⇒ unclassified for a claimed floor')).toContain(requirementIdForScenario(files[0]!));
148
149
  expect(v.certifiable).toBe(false);
149
150
  expect(d.rejectUnclassified).toBe(true);
150
151
  });
@@ -153,7 +154,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
153
154
  const l = ledgerAllPassed(5).map((e) => (e.requirementId === requirementIdForScenario(files[0]!) ? { ...e, assertionCount: 0 } : e));
154
155
  const d = deriveRequirementDispositions(reportAllPassed(), l, [profile]);
155
156
  const v = d.verdicts.find((x) => x.profile === profile)!;
156
- expect(v.unclassified).toContain(requirementIdForScenario(files[0]!));
157
+ expect(v.unclassified, req('openwop.it.runner-ledger.a-vacuous-pass-executed-pass-with-assertioncount-0-on-a-claimed-floor-is-unclass', 'RFC 0148 §A', 'a VACUOUS pass (executed-pass with assertionCount 0) on a claimed floor is unclassified and REJECTS certification')).toContain(requirementIdForScenario(files[0]!));
157
158
  expect(v.certifiable).toBe(false);
158
159
  expect(d.rejectUnclassified).toBe(true);
159
160
  });
@@ -163,7 +164,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
163
164
  const l = ledgerAllPassed().filter((e) => e.requirementId !== requirementIdForScenario(files[0]!));
164
165
  const d = deriveRequirementDispositions(rep, l, [profile]);
165
166
  const row = d.requirements.find((r) => r.requirementId === requirementIdForScenario(files[0]!))!;
166
- expect(row.disposition).toBe('blocked');
167
+ expect(row.disposition, req('openwop.it.runner-ledger.a-skipped-file-with-no-ledger-entry-is-blocked-unclassified-and-it-never-reads-a', 'RFC 0148 §A', 'a skipped file with no ledger entry is blocked (unclassified) — and it never reads as skipped/inapplicable')).toBe('blocked');
167
168
  expect(row.detail).toMatch(/unclassified/);
168
169
  expect(d.verdicts[0]!.unclassified).toContain(requirementIdForScenario(files[0]!));
169
170
  expect(d.rejectUnclassified).toBe(true);
@@ -173,7 +174,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
173
174
  it('a recorded inapplicable/skipped is certifiable and NOT unclassified; a recorded executed-fail blocks but is classified', () => {
174
175
  const l = ledgerAllPassed().map((e) => (e.requirementId === requirementIdForScenario(files[0]!) ? { requirementId: e.requirementId, disposition: 'inapplicable' as const, detail: 'not advertised' } : e));
175
176
  const d = deriveRequirementDispositions(reportAllPassed({ [files[0]!]: 'skipped' }), l, [profile]);
176
- expect(d.verdicts[0]!.unclassified).toEqual([]);
177
+ expect(d.verdicts[0]!.unclassified, req('openwop.it.runner-ledger.a-recorded-inapplicable-skipped-is-certifiable-and-not-unclassified-a-recorded-e', 'RFC 0148 §A', 'a recorded inapplicable/skipped is certifiable and NOT unclassified; a recorded executed-fail blocks but is classified')).toEqual([]);
177
178
  expect(d.verdicts[0]!.certifiable).toBe(true);
178
179
  const l2 = ledgerAllPassed().map((e) => (e.requirementId === requirementIdForScenario(files[0]!) ? { requirementId: e.requirementId, disposition: 'executed-fail' as const, detail: 'assertion failed', assertionCount: 2 } : e));
179
180
  const d2 = deriveRequirementDispositions(reportAllPassed({ [files[0]!]: 'failed' }), l2, [profile]);
@@ -185,7 +186,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
185
186
 
186
187
  it('a discoveryOnly profile certifies with an empty floor; an unknown profile does not', () => {
187
188
  const d = deriveRequirementDispositions(new Map(), [], ['openwop-discovery-core', 'openwop-nope']);
188
- expect(d.verdicts.find((v) => v.profile === 'openwop-discovery-core')?.certifiable).toBe(true);
189
+ expect(d.verdicts.find((v) => v.profile === 'openwop-discovery-core')?.certifiable, req('openwop.it.runner-ledger.a-discoveryonly-profile-certifies-with-an-empty-floor-an-unknown-profile-does-no', 'RFC 0148 §A', 'a discoveryOnly profile certifies with an empty floor; an unknown profile does not')).toBe(true);
189
190
  expect(d.verdicts.find((v) => v.profile === 'openwop-nope')?.certifiable).toBe(false);
190
191
  expect(requirementsFor('openwop-discovery-core')).toEqual([]);
191
192
  });
@@ -193,7 +194,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
193
194
  it('a RUNTIME-DERIVED profile (openwop-node-packs) is HELD only when every floor row is a witnessed pass; otherwise it is not held — not rejected, not blocked', () => {
194
195
  const np = 'openwop-node-packs';
195
196
  const f = PROFILE_FLOOR_SCENARIOS[np]!;
196
- expect(f.runtimeDerived, 'profiles.md: node-packs is "derivable from which scenarios pass"').toBe(true);
197
+ expect(f.runtimeDerived, req('openwop.it.runner-ledger.a-runtime-derived-profile-openwop-node-packs-is-held-only-when-every-floor-row-i', 'RFC 0148 §A', 'profiles.md: node-packs is "derivable from which scenarios pass"')).toBe(true);
197
198
  const ids = f.required.map((x) => requirementIdForScenario(x));
198
199
  const rep = new Map<string, 'passed' | 'failed' | 'skipped'>(f.required.map((x) => [x, 'passed' as const]));
199
200
  // (a) held: every row a witnessed pass
@@ -207,7 +208,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
207
208
  const vn = notHeld.verdicts.find((v) => v.profile === np)!;
208
209
  expect(vn.held).toBe(false);
209
210
  expect(vn.certifiable).toBe(false);
210
- expect(vn.unclassified, 'a profile the host does not hold is not a rejected claim').toEqual([]);
211
+ expect(vn.unclassified, req('openwop.it.runner-ledger.a-runtime-derived-profile-openwop-node-packs-is-held-only-when-every-floor-row-i', 'RFC 0148 §A', 'a profile the host does not hold is not a rejected claim')).toEqual([]);
211
212
  expect([...vn.blocking].sort()).toEqual([...ids].sort());
212
213
  expect(notHeld.rejectUnclassified).toBe(false);
213
214
  // (c) a vacuous pass on a runtime-derived floor is still not a rejection — the emitter drops the claim
@@ -229,7 +230,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
229
230
  const l = ledgerAllPassed().map((e) => (e.requirementId === requirementIdForScenario(files[0]!) ? { requirementId: e.requirementId, disposition: 'blocked' as const, detail: UNCLASSIFIED_RETURN_DETAIL, assertionCount: 0 } : e));
230
231
  const d = deriveRequirementDispositions(reportAllPassed(), l, [profile]);
231
232
  const v = d.verdicts.find((x) => x.profile === profile)!;
232
- expect(v.unclassified).toContain(requirementIdForScenario(files[0]!));
233
+ expect(v.unclassified, req('openwop.it.runner-ledger.the-runner-s-a-resolution-of-a-silent-zero-assertion-file-blocked-marker-is-stil', 'RFC 0148 §A', 'the runner\'s §A resolution of a silent zero-assertion file (blocked + marker) is STILL unclassified for a claimed floor')).toContain(requirementIdForScenario(files[0]!));
233
234
  expect(d.rejectUnclassified).toBe(true);
234
235
  // whereas a blocked row WITH a scenario-authored reason is classified (blocking, not unclassified)
235
236
  const l2 = ledgerAllPassed().map((e) => (e.requirementId === requirementIdForScenario(files[0]!) ? { requirementId: e.requirementId, disposition: 'blocked' as const, detail: 'seam /v1/host/sample/x not mounted', assertionCount: 0 } : e));
@@ -240,7 +241,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
240
241
 
241
242
  it('with no ledger at all, every skipped file is blocked and the runner says so (the pre-S6 honest reading)', () => {
242
243
  const d = deriveRequirementDispositions(reportAllPassed({ [files[0]!]: 'skipped' }), [], [profile]);
243
- expect(d.ledgerPresent).toBe(false);
244
+ expect(d.ledgerPresent, req('openwop.it.runner-ledger.with-no-ledger-at-all-every-skipped-file-is-blocked-and-the-runner-says-so-the-p', 'RFC 0148 §A', 'with no ledger at all, every skipped file is blocked and the runner says so (the pre-S6 honest reading)')).toBe(false);
244
245
  const row = d.requirements.find((r) => r.requirementId === requirementIdForScenario(files[0]!))!;
245
246
  expect(row.disposition).toBe('blocked');
246
247
  expect(row.detail).toMatch(/without a ledger/);
@@ -250,7 +251,7 @@ describe('RFC 0148 §A (S6) — the runner derivation', () => {
250
251
  describe('RFC 0148 §A — softSkip notes the reason for an early return, per file', () => {
251
252
  it('notes are keyed to the current test file, worst-first when mixed, and read back with joined reasons', () => {
252
253
  resetSoftSkips();
253
- expect(softSkip('inapplicable', 'host does not advertise X')).toBeUndefined();
254
+ expect(softSkip('inapplicable', 'host does not advertise X'), req('openwop.it.runner-ledger.notes-are-keyed-to-the-current-test-file-worst-first-when-mixed-and-read-back-wi', 'RFC 0148 §A', 'notes are keyed to the current test file, worst-first when mixed, and read back with joined reasons')).toBeUndefined();
254
255
  softSkip('inapplicable', 'host does not advertise X'); // de-duplicated
255
256
  let d = softSkipDisposition('runner-ledger.test.ts');
256
257
  expect(d).toEqual({ kind: 'inapplicable', reason: 'host does not advertise X' });
@@ -268,12 +269,12 @@ describe('RFC 0148 §A — softSkip notes the reason for an early return, per fi
268
269
  describe('RFC 0148 §A (S6) — the live sink, when this run was given one', () => {
269
270
  it('files that finished before this one appear in the ledger file with an assertion count', () => {
270
271
  const path = process.env['OPENWOP_LEDGER_PATH'];
271
- if (!path || !existsSync(path)) return; // not a --certify run; nothing to inspect
272
+ if (!path || !existsSync(path)) return softSkip('blocked', 'precondition not met — `!path || !existsSync(path)` returned early (not a --certify run; nothing to inspect) (seam, prior step, or fixture unavailable)'); // not a --certify run; nothing to inspect
272
273
  const entries = readLedgerFile(path);
273
274
  // At least the in-memory ledger of THIS worker has file-level entries for
274
275
  // earlier files (setup.ts afterAll), and each carries assertionCount.
275
276
  const fileEntries = snapshot().filter((e) => e.requirementId.startsWith('openwop.scenario.') || e.requirementId.startsWith('openwop.floor.'));
276
- for (const e of fileEntries) expect(typeof e.assertionCount).toBe('number');
277
+ for (const e of fileEntries) expect(typeof e.assertionCount, req('openwop.it.runner-ledger.files-that-finished-before-this-one-appear-in-the-ledger-file-with-an-assertion', 'RFC 0148 §A', 'files that finished before this one appear in the ledger file with an assertion count')).toBe('number');
277
278
  expect(entries.length).toBeGreaterThanOrEqual(0);
278
279
  });
279
280
  });
@@ -13,6 +13,7 @@ import { describe, it, expect } from 'vitest';
13
13
  import { driver } from '../lib/driver.js';
14
14
  import { pollUntilTerminal } from '../lib/polling.js';
15
15
  import { isFixtureAdvertised } from '../lib/fixtures.js';
16
+ import { req } from '../lib/requirement-ids.js';
16
17
 
17
18
  const NOOP_WORKFLOW_ID = 'conformance-noop';
18
19
  const SKIP_NO_NOOP = !isFixtureAdvertised(NOOP_WORKFLOW_ID);
@@ -21,17 +22,17 @@ describe.skipIf(SKIP_NO_NOOP)('run lifecycle: conformance-noop fixture', () => {
21
22
  it('POST /v1/runs returns 201 with runId per rest-endpoints.md', async () => {
22
23
  const res = await driver.post('/v1/runs', { workflowId: NOOP_WORKFLOW_ID });
23
24
 
24
- expect(res.status, driver.describe(
25
+ expect(res.status, req('openwop.it.runs-lifecycle.post-v1-runs-returns-201-with-runid-per-rest-endpoints-md',
25
26
  'rest-endpoints.md',
26
27
  'POST /v1/runs MUST return 201 on accepted run',
27
28
  )).toBe(201);
28
29
 
29
30
  const body = res.json as { runId?: unknown; status?: unknown } | undefined;
30
- expect(typeof body?.runId, driver.describe(
31
+ expect(typeof body?.runId, req('openwop.it.runs-lifecycle.post-v1-runs-returns-201-with-runid-per-rest-endpoints-md',
31
32
  'rest-endpoints.md',
32
33
  'POST /v1/runs response body MUST include `runId` string',
33
34
  )).toBe('string');
34
- expect(typeof body?.status, driver.describe(
35
+ expect(typeof body?.status, req('openwop.it.runs-lifecycle.post-v1-runs-returns-201-with-runid-per-rest-endpoints-md',
35
36
  'rest-endpoints.md',
36
37
  'POST /v1/runs response body MUST include `status` string',
37
38
  )).toBe('string');
@@ -44,12 +45,12 @@ describe.skipIf(SKIP_NO_NOOP)('run lifecycle: conformance-noop fixture', () => {
44
45
 
45
46
  const terminal = await pollUntilTerminal(runId);
46
47
 
47
- expect(terminal.status, driver.describe(
48
+ expect(terminal.status, req('openwop.it.runs-lifecycle.reaches-terminal-completed-within-bounded-time-per-fixtures-md-noop-spec',
48
49
  'fixtures.md conformance-noop §Terminal status',
49
50
  'fixture MUST reach terminal status `completed`',
50
51
  )).toBe('completed');
51
52
 
52
- expect(terminal.runId, driver.describe(
53
+ expect(terminal.runId, req('openwop.it.runs-lifecycle.reaches-terminal-completed-within-bounded-time-per-fixtures-md-noop-spec',
53
54
  'rest-endpoints.md RunSnapshot',
54
55
  'GET /v1/runs/{runId} MUST echo runId',
55
56
  )).toBe(runId);
@@ -59,7 +60,7 @@ describe.skipIf(SKIP_NO_NOOP)('run lifecycle: conformance-noop fixture', () => {
59
60
  const res = await driver.get('/v1/runs/openwop-conformance-this-run-id-does-not-exist');
60
61
  expect(
61
62
  [403, 404].includes(res.status),
62
- driver.describe('rest-endpoints.md', 'unknown run MUST return 404 or 403'),
63
+ req('openwop.it.runs-lifecycle.get-v1-runs-nonexistentid-returns-404-or-403-per-rest-endpoints-md', 'rest-endpoints.md', 'unknown run MUST return 404 or 403'),
63
64
  ).toBe(true);
64
65
  });
65
66
  });
@@ -29,6 +29,8 @@ import { describe, it, expect } from 'vitest';
29
29
  import { driver } from '../lib/driver.js';
30
30
  import { pollUntilTerminal } from '../lib/polling.js';
31
31
  import { isFixtureAdvertised } from '../lib/fixtures.js';
32
+ import { req } from '../lib/requirement-ids.js';
33
+ import { softSkip } from '../lib/soft-skip.js';
32
34
 
33
35
  const CAPABILITY_MISSING_WORKFLOW_ID = 'conformance-capability-missing';
34
36
  const SKIP_NO_FIXTURE = !isFixtureAdvertised(CAPABILITY_MISSING_WORKFLOW_ID);
@@ -37,7 +39,7 @@ describe('runtime-capabilities: /.well-known/openwop forward-compat shape', () =
37
39
  it('IF runtimeCapabilities is present, it MUST be a string[] of unique non-empty entries', async () => {
38
40
  const res = await driver.get('/.well-known/openwop', { authenticated: false });
39
41
 
40
- expect(res.status, driver.describe(
42
+ expect(res.status, req('openwop.it.runtime-capabilities.if-runtimecapabilities-is-present-it-must-be-a-string-of-unique-non-empty-entrie',
41
43
  'capabilities.md §2',
42
44
  'discovery endpoint MUST return 200',
43
45
  )).toBe(200);
@@ -50,28 +52,28 @@ describe('runtime-capabilities: /.well-known/openwop forward-compat shape', () =
50
52
  // of v1 hosts will omit it. Assertion passes trivially; don't
51
53
  // force a value on a host that doesn't advertise any.
52
54
  expect(caps).toBeUndefined();
53
- return;
55
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `caps === undefined` returned early');
54
56
  }
55
57
 
56
- expect(Array.isArray(caps), driver.describe(
58
+ expect(Array.isArray(caps), req('openwop.it.runtime-capabilities.if-runtimecapabilities-is-present-it-must-be-a-string-of-unique-non-empty-entrie',
57
59
  'capabilities.md §"Runtime capabilities"',
58
60
  'runtimeCapabilities MUST be an array when present',
59
61
  )).toBe(true);
60
62
 
61
63
  const arr = caps as unknown[];
62
64
  for (const entry of arr) {
63
- expect(typeof entry, driver.describe(
65
+ expect(typeof entry, req('openwop.it.runtime-capabilities.if-runtimecapabilities-is-present-it-must-be-a-string-of-unique-non-empty-entrie',
64
66
  'capabilities.md §"Runtime capabilities"',
65
67
  'every runtimeCapabilities entry MUST be a string',
66
68
  )).toBe('string');
67
- expect((entry as string).length, driver.describe(
69
+ expect((entry as string).length, req('openwop.it.runtime-capabilities.if-runtimecapabilities-is-present-it-must-be-a-string-of-unique-non-empty-entrie',
68
70
  'capabilities.md §"Runtime capabilities"',
69
71
  'every runtimeCapabilities entry MUST be non-empty',
70
72
  )).toBeGreaterThan(0);
71
73
  }
72
74
 
73
75
  const unique = new Set(arr as string[]);
74
- expect(unique.size, driver.describe(
76
+ expect(unique.size, req('openwop.it.runtime-capabilities.if-runtimecapabilities-is-present-it-must-be-a-string-of-unique-non-empty-entrie',
75
77
  'capabilities.md §"Runtime capabilities"',
76
78
  'runtimeCapabilities entries MUST be unique',
77
79
  )).toBe(arr.length);
@@ -91,7 +93,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('runtime-capabilities: dispatch refusal on unsa
91
93
  const create = await driver.post('/v1/runs', {
92
94
  workflowId: 'conformance-capability-missing',
93
95
  });
94
- expect(create.status, driver.describe(
96
+ expect(create.status, req('openwop.it.runtime-capabilities.terminates-the-run-with-error-code-capability-not-provided',
95
97
  'capabilities.md §"Runtime capabilities"',
96
98
  'POST /v1/runs MUST accept the run; refusal is engine-side at dispatch time, not request-validation',
97
99
  )).toBe(201);
@@ -99,18 +101,18 @@ describe.skipIf(SKIP_NO_FIXTURE)('runtime-capabilities: dispatch refusal on unsa
99
101
 
100
102
  const terminal = await pollUntilTerminal(runId);
101
103
 
102
- expect(terminal.status, driver.describe(
104
+ expect(terminal.status, req('openwop.it.runtime-capabilities.terminates-the-run-with-error-code-capability-not-provided',
103
105
  'capabilities.md §"Runtime capabilities"',
104
106
  'a node with unsatisfied requires MUST cause the run to terminate as failed',
105
107
  )).toBe('failed');
106
108
 
107
109
  const error = (terminal as { error?: { code?: string; message?: string } }).error;
108
- expect(error?.code, driver.describe(
110
+ expect(error?.code, req('openwop.it.runtime-capabilities.terminates-the-run-with-error-code-capability-not-provided',
109
111
  'rest-endpoints.md §"Common error codes"',
110
112
  'terminal RunSnapshot.error.code MUST be "capability_not_provided"',
111
113
  )).toBe('capability_not_provided');
112
114
 
113
- expect(error?.message, driver.describe(
115
+ expect(error?.message, req('openwop.it.runtime-capabilities.terminates-the-run-with-error-code-capability-not-provided',
114
116
  'capabilities.md §"Runtime capabilities"',
115
117
  'error.message MUST name the missing capability id verbatim so operators can act without grepping logs',
116
118
  )).toContain('conformance.never-provided');
@@ -29,8 +29,8 @@
29
29
 
30
30
  import { describe, it, expect } from 'vitest';
31
31
  import { softSkip } from '../lib/soft-skip.js';
32
- import { driver } from '../lib/driver.js';
33
32
  import { installGate } from '../lib/runtimeRequires.js';
33
+ import { req } from '../lib/requirement-ids.js';
34
34
 
35
35
  function manifest(requires: string[]) {
36
36
  return {
@@ -48,11 +48,11 @@ describe('runtime-requires install gate (RFC 0076 §A)', () => {
48
48
  if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
49
49
  expect(
50
50
  res.status,
51
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'a pack whose runtime.requires are all grantable MUST install (no refusal)'),
51
+ req('openwop.it.runtime-requires-install-gate.install-grant-requires-grant-set-install-succeeds', 'registry-operations.md §"Runtime-requirement install gate"', 'a pack whose runtime.requires are all grantable MUST install (no refusal)'),
52
52
  ).toBe(200);
53
53
  expect(
54
54
  res.body.outcome,
55
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'a granted install reports outcome:"installed"'),
55
+ req('openwop.it.runtime-requires-install-gate.install-grant-requires-grant-set-install-succeeds', 'registry-operations.md §"Runtime-requirement install gate"', 'a granted install reports outcome:"installed"'),
56
56
  ).toBe('installed');
57
57
  });
58
58
 
@@ -61,19 +61,19 @@ describe('runtime-requires install gate (RFC 0076 §A)', () => {
61
61
  if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
62
62
  expect(
63
63
  res.status,
64
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'a pack requiring an ungranted primitive MUST be refused at install (not at first invocation)'),
64
+ req('openwop.it.runtime-requires-install-gate.install-refuse-an-ungrantable-primitive-pack-runtime-requirement-unmet', 'registry-operations.md §"Runtime-requirement install gate"', 'a pack requiring an ungranted primitive MUST be refused at install (not at first invocation)'),
65
65
  ).toBe(400);
66
66
  expect(
67
67
  res.body.error,
68
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'the refusal MUST carry error code pack_runtime_requirement_unmet'),
68
+ req('openwop.it.runtime-requires-install-gate.install-refuse-an-ungrantable-primitive-pack-runtime-requirement-unmet', 'registry-operations.md §"Runtime-requirement install gate"', 'the refusal MUST carry error code pack_runtime_requirement_unmet'),
69
69
  ).toBe('pack_runtime_requirement_unmet');
70
70
  expect(
71
71
  Array.isArray(res.body.unmet) && (res.body.unmet as unknown[]).includes('net.dns'),
72
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'unmet[] MUST list the ungranted primitive(s) (capability_not_provided envelope)'),
72
+ req('openwop.it.runtime-requires-install-gate.install-refuse-an-ungrantable-primitive-pack-runtime-requirement-unmet', 'registry-operations.md §"Runtime-requirement install gate"', 'unmet[] MUST list the ungranted primitive(s) (capability_not_provided envelope)'),
73
73
  ).toBe(true);
74
74
  expect(
75
75
  typeof res.body.manifest === 'string' && (res.body.manifest as string).includes('vendor.example.http'),
76
- driver.describe('registry-operations.md §"Runtime-requirement install gate"', 'the refusal MUST name the offending manifest (name@version)'),
76
+ req('openwop.it.runtime-requires-install-gate.install-refuse-an-ungrantable-primitive-pack-runtime-requirement-unmet', 'registry-operations.md §"Runtime-requirement install gate"', 'the refusal MUST name the offending manifest (name@version)'),
77
77
  ).toBe(true);
78
78
  });
79
79
 
@@ -87,7 +87,7 @@ describe('runtime-requires install gate (RFC 0076 §A)', () => {
87
87
  const projected = res.body.requiresProjected as unknown;
88
88
  expect(
89
89
  Array.isArray(projected) && ['net.dns', 'net.outbound'].every((t) => (projected as unknown[]).includes(t)),
90
- driver.describe('node-packs.md §"Runtime platform requirements"', 'a non-gating host that projects SHOULD surface the declared runtime.requires[] on the inventory entry verbatim'),
90
+ req('openwop.it.runtime-requires-install-gate.non-sandbox-projection-a-non-gating-host-installs-and-projects-requires-a-should', 'node-packs.md §"Runtime platform requirements"', 'a non-gating host that projects SHOULD surface the declared runtime.requires[] on the inventory entry verbatim'),
91
91
  ).toBe(true);
92
92
  });
93
93
  });
@@ -37,6 +37,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
37
37
  import addFormats from 'ajv-formats';
38
38
  import type { ErrorObject, ValidateFunction } from 'ajv';
39
39
  import { SCHEMAS_DIR } from '../lib/paths.js';
40
+ import { req } from '../lib/requirement-ids.js';
40
41
 
41
42
  const SCHEMA_PATH = join(SCHEMAS_DIR, 'node-pack-manifest.schema.json');
42
43
 
@@ -89,21 +90,21 @@ describe('category: runtime.requires vocabulary + shape (RFC 0076 §A)', () => {
89
90
  const ok = validate(manifest(['net.dns', 'net.outbound']));
90
91
  expect(
91
92
  ok,
92
- `node-packs.md §"Runtime platform requirements": a well-formed runtime.requires MUST validate. Errors: ${JSON.stringify(validate.errors)}`,
93
+ req('openwop.it.runtime-requires-shape.positive-a-manifest-declaring-valid-primitives-validates-cleanly', 'node-packs.md', `node-packs.md §"Runtime platform requirements": a well-formed runtime.requires MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
93
94
  ).toBe(true);
94
95
  });
95
96
 
96
97
  it('positive: runtime.requires is OPTIONAL — a manifest omitting it validates (additive)', () => {
97
98
  expect(
98
99
  validate(manifest(undefined)),
99
- 'node-pack-manifest.schema.json: runtime.requires is additive/OPTIONAL — packs predating RFC 0076 validate unchanged',
100
+ req('openwop.it.runtime-requires-shape.positive-runtime-requires-is-optional-a-manifest-omitting-it-validates-additive', 'node-packs.md', 'node-pack-manifest.schema.json: runtime.requires is additive/OPTIONAL — packs predating RFC 0076 validate unchanged'),
100
101
  ).toBe(true);
101
102
  });
102
103
 
103
104
  it('positive: an empty requires[] validates (equivalent to omission per §A)', () => {
104
105
  expect(
105
106
  validate(manifest([])),
106
- 'node-packs.md §"Runtime platform requirements": runtime.requires:[] is valid and equivalent to omission',
107
+ req('openwop.it.runtime-requires-shape.positive-an-empty-requires-validates-equivalent-to-omission-per-a', 'node-packs.md', 'node-packs.md §"Runtime platform requirements": runtime.requires:[] is valid and equivalent to omission'),
107
108
  ).toBe(true);
108
109
  });
109
110
 
@@ -111,7 +112,7 @@ describe('category: runtime.requires vocabulary + shape (RFC 0076 §A)', () => {
111
112
  for (const token of VOCABULARY) {
112
113
  expect(
113
114
  validate(manifest([token])),
114
- `node-pack-manifest.schema.json: "${token}" is in the RFC 0076 §A vocabulary. Errors: ${JSON.stringify(validate.errors)}`,
115
+ req('openwop.it.runtime-requires-shape.positive-every-vocabulary-token-individually-validates', 'node-packs.md', `node-pack-manifest.schema.json: "${token}" is in the RFC 0076 §A vocabulary. Errors: ${JSON.stringify(validate.errors)}`),
115
116
  ).toBe(true);
116
117
  }
117
118
  });
@@ -120,7 +121,7 @@ describe('category: runtime.requires vocabulary + shape (RFC 0076 §A)', () => {
120
121
  const errs = errorsOn(manifest(['node:dns/promises']));
121
122
  expect(
122
123
  errs.some((e) => e.instancePath.includes('/runtime/requires')),
123
- 'node-packs.md §"Runtime platform requirements": raw language builtin names are NOT in the closed vocabulary — the abstract net.dns is the portable equivalent; the registry/host surfaces this as invalid_manifest',
124
+ req('openwop.it.runtime-requires-shape.negative-a-raw-builtin-name-node-dns-promises-is-rejected-invalid-manifest', 'node-packs.md', 'node-packs.md §"Runtime platform requirements": raw language builtin names are NOT in the closed vocabulary — the abstract net.dns is the portable equivalent; the registry/host surfaces this as invalid_manifest'),
124
125
  ).toBe(true);
125
126
  });
126
127
 
@@ -128,7 +129,7 @@ describe('category: runtime.requires vocabulary + shape (RFC 0076 §A)', () => {
128
129
  const errs = errorsOn(manifest(['net.dns', 'net.dns']));
129
130
  expect(
130
131
  errs.some((e) => e.keyword === 'uniqueItems'),
131
- 'node-pack-manifest.schema.json: runtime.requires has uniqueItems:true',
132
+ req('openwop.it.runtime-requires-shape.negative-a-duplicate-token-is-rejected-uniqueitems', 'node-packs.md', 'node-pack-manifest.schema.json: runtime.requires has uniqueItems:true'),
132
133
  ).toBe(true);
133
134
  });
134
135
  });
@@ -29,71 +29,72 @@
29
29
  */
30
30
 
31
31
  import { describe, it, expect } from 'vitest';
32
- import { driver } from '../lib/driver.js';
33
32
  import { isSafeFetchSupported, isToolHookAuditOn, safeFetch } from '../lib/safeFetch.js';
33
+ import { req } from '../lib/requirement-ids.js';
34
+ import { softSkip } from '../lib/soft-skip.js';
34
35
 
35
36
  describe('safefetch-behavior (RFC 0076 §B / §host.http)', () => {
36
37
  it('blocks a metadata-endpoint target (SSRF guard)', async () => {
37
- if (!(await isSafeFetchSupported())) return; // capability absent — soft-skip
38
+ if (!(await isSafeFetchSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSafeFetchSupported())` returned early (capability absent — soft-skip)'); // capability absent — soft-skip
38
39
  const res = await safeFetch({ url: 'http://169.254.169.254/latest/meta-data/' });
39
- if (res === null) return; // seam absent — soft-skip
40
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
40
41
  expect(
41
42
  res.outcome,
42
- driver.describe('host-capabilities.md §host.http', 'safeFetch MUST NOT connect to a cloud-metadata address'),
43
+ req('openwop.it.safefetch-behavior.blocks-a-metadata-endpoint-target-ssrf-guard', 'host-capabilities.md §host.http', 'safeFetch MUST NOT connect to a cloud-metadata address'),
43
44
  ).toBe('blocked');
44
45
  expect(
45
46
  res.blocked,
46
- driver.describe('host-capabilities.md §host.http', 'a blocked SSRF target reports blocked:"ssrf" (http-client-ssrf-guard invariant)'),
47
+ req('openwop.it.safefetch-behavior.blocks-a-metadata-endpoint-target-ssrf-guard', 'host-capabilities.md §host.http', 'a blocked SSRF target reports blocked:"ssrf" (http-client-ssrf-guard invariant)'),
47
48
  ).toBe('ssrf');
48
49
  });
49
50
 
50
51
  it('blocks a loopback target (SSRF guard)', async () => {
51
- if (!(await isSafeFetchSupported())) return;
52
+ if (!(await isSafeFetchSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSafeFetchSupported())` returned early');
52
53
  const res = await safeFetch({ url: 'http://127.0.0.1:6379/' });
53
- if (res === null) return;
54
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
54
55
  expect(
55
56
  res.outcome,
56
- driver.describe('host-capabilities.md §host.http', 'safeFetch MUST NOT connect to loopback'),
57
+ req('openwop.it.safefetch-behavior.blocks-a-loopback-target-ssrf-guard', 'host-capabilities.md §host.http', 'safeFetch MUST NOT connect to loopback'),
57
58
  ).toBe('blocked');
58
59
  });
59
60
 
60
61
  it('blocks DNS-rebinding (resolved IP is pinned for the connection)', async () => {
61
- if (!(await isSafeFetchSupported())) return;
62
+ if (!(await isSafeFetchSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSafeFetchSupported())` returned early');
62
63
  const res = await safeFetch({ url: 'http://example.com/', simulateRebindTo: '169.254.169.254' });
63
- if (res === null) return;
64
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
64
65
  expect(
65
66
  res.outcome,
66
- driver.describe('host-capabilities.md §host.http', 'a public name that re-resolves to a blocked address MUST be blocked (rebinding defeat)'),
67
+ req('openwop.it.safefetch-behavior.blocks-dns-rebinding-resolved-ip-is-pinned-for-the-connection', 'host-capabilities.md §host.http', 'a public name that re-resolves to a blocked address MUST be blocked (rebinding defeat)'),
67
68
  ).toBe('blocked');
68
69
  });
69
70
 
70
71
  it('refuses a Connection: upgrade request (no 101 socket-hijack escape)', async () => {
71
- if (!(await isSafeFetchSupported())) return;
72
+ if (!(await isSafeFetchSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSafeFetchSupported())` returned early');
72
73
  const res = await safeFetch({ url: 'https://example.com/', init: { headers: { Connection: 'upgrade' } } });
73
- if (res === null) return;
74
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
74
75
  expect(
75
76
  res.outcome,
76
- driver.describe('host-capabilities.md §host.http', 'safeFetch MUST refuse a connection-upgrade attempt'),
77
+ req('openwop.it.safefetch-behavior.refuses-a-connection-upgrade-request-no-101-socket-hijack-escape', 'host-capabilities.md §host.http', 'safeFetch MUST refuse a connection-upgrade attempt'),
77
78
  ).toBe('blocked');
78
79
  expect(
79
80
  res.blocked,
80
- driver.describe('host-capabilities.md §host.http', 'a refused upgrade reports blocked:"upgrade"'),
81
+ req('openwop.it.safefetch-behavior.refuses-a-connection-upgrade-request-no-101-socket-hijack-escape', 'host-capabilities.md §host.http', 'a refused upgrade reports blocked:"upgrade"'),
81
82
  ).toBe('upgrade');
82
83
  });
83
84
 
84
85
  it('emits the tool-hooks audit pair when prePostEvents is also advertised', async () => {
85
- if (!(await isSafeFetchSupported())) return;
86
- if (!(await isToolHookAuditOn())) return; // audit MUST applies only when both advertised
86
+ if (!(await isSafeFetchSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSafeFetchSupported())` returned early');
87
+ if (!(await isToolHookAuditOn())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isToolHookAuditOn())` returned early (audit MUST applies only when both advertised)'); // audit MUST applies only when both advertised
87
88
  const res = await safeFetch({ url: 'https://example.com/' });
88
- if (res === null) return;
89
- if (res.outcome !== 'fetched') return; // only a completed call carries the pair
89
+ if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
90
+ if (res.outcome !== 'fetched') return softSkip('blocked', 'precondition not met — `res.outcome !== \'fetched\'` returned early (only a completed call carries the pair) (seam, prior step, or fixture unavailable)'); // only a completed call carries the pair
90
91
  expect(
91
92
  res.toolCalled !== undefined && res.toolReturned !== undefined,
92
- driver.describe('host-capabilities.md §host.http', 'when toolHooks.prePostEvents + safeFetch are both advertised, a safeFetch call MUST emit the agent.toolCalled/agent.toolReturned pair'),
93
+ req('openwop.it.safefetch-behavior.emits-the-tool-hooks-audit-pair-when-prepostevents-is-also-advertised', 'host-capabilities.md §host.http', 'when toolHooks.prePostEvents + safeFetch are both advertised, a safeFetch call MUST emit the agent.toolCalled/agent.toolReturned pair'),
93
94
  ).toBe(true);
94
95
  expect(
95
96
  (res.toolCalled as { transport?: string } | undefined)?.transport,
96
- driver.describe('host-capabilities.md §host.http', 'the audit pair carries transport:"http"'),
97
+ req('openwop.it.safefetch-behavior.emits-the-tool-hooks-audit-pair-when-prepostevents-is-also-advertised', 'host-capabilities.md §host.http', 'the audit pair carries transport:"http"'),
97
98
  ).toBe('http');
98
99
  });
99
100
  });
@@ -53,10 +53,11 @@
53
53
  */
54
54
 
55
55
  import { describe, it, expect } from 'vitest';
56
- import { driver } from '../lib/driver.js';
57
56
  import { behaviorGate } from '../lib/behavior-gate.js';
58
57
  import { isSafeFetchLiveAuditAdvertised, safeFetchViaRun } from '../lib/safeFetch.js';
59
58
  import { queryTestEvents } from '../lib/event-log-query.js';
59
+ import { req } from '../lib/requirement-ids.js';
60
+ import { softSkip } from '../lib/soft-skip.js';
60
61
 
61
62
  const PROFILE = 'openwop-safefetch-live-audit';
62
63
  const CITE = 'host-capabilities.md §host.http';
@@ -78,7 +79,7 @@ const FETCH_URL = 'https://example.com/';
78
79
  * `false` (caller treats as host-pending soft-skip) only when the event-log
79
80
  * query seam is unavailable; otherwise asserts and returns `true`.
80
81
  */
81
- async function assertDurableHttpPair(runId: string, label: string): Promise<boolean> {
82
+ async function assertDurableHttpPair(requirementId: string, runId: string, label: string): Promise<boolean> {
82
83
  const calledQ = await queryTestEvents(runId, { type: 'agent.toolCalled' });
83
84
  const returnedQ = await queryTestEvents(runId, { type: 'agent.toolReturned' });
84
85
  if (!calledQ.ok || !returnedQ.ok) {
@@ -91,7 +92,7 @@ async function assertDurableHttpPair(runId: string, label: string): Promise<bool
91
92
  const httpCall = calledQ.events.find((e) => (e.payload as { transport?: string }).transport === 'http');
92
93
  expect(
93
94
  httpCall !== undefined,
94
- driver.describe(
95
+ req(requirementId,
95
96
  CITE,
96
97
  `(${label}) when toolHooks.prePostEvents + safeFetch are both advertised, a production ctx.http.safeFetch call MUST persist an agent.toolCalled with transport:"http" to the durable run event log (not just the seam echo), for EVERY invocation incl. blocked ones`,
97
98
  ),
@@ -101,14 +102,14 @@ async function assertDurableHttpPair(runId: string, label: string): Promise<bool
101
102
  const callId = (httpCall.payload as { callId?: string }).callId;
102
103
  expect(
103
104
  typeof callId === 'string' && callId.length > 0,
104
- driver.describe(CITE, `(${label}) the persisted agent.toolCalled MUST carry the required callId (run-event-payloads.schema.json §agentToolCalled)`),
105
+ req(requirementId, CITE, `(${label}) the persisted agent.toolCalled MUST carry the required callId (run-event-payloads.schema.json §agentToolCalled)`),
105
106
  ).toBe(true);
106
107
 
107
108
  // The paired agent.toolReturned — matched by the required callId (RFC 0002 §B pairing).
108
109
  const paired = returnedQ.events.find((e) => (e.payload as { callId?: string }).callId === callId);
109
110
  expect(
110
111
  paired !== undefined,
111
- driver.describe(CITE, `(${label}) the agent.toolCalled MUST be followed by a callId-paired agent.toolReturned in the durable log (no quiet bypass)`),
112
+ req(requirementId, CITE, `(${label}) the agent.toolCalled MUST be followed by a callId-paired agent.toolReturned in the durable log (no quiet bypass)`),
112
113
  ).toBe(true);
113
114
 
114
115
  // Stricter, when the host surfaces causation: RFC 0002 §B says
@@ -117,7 +118,7 @@ async function assertDurableHttpPair(runId: string, label: string): Promise<bool
117
118
  if (paired && typeof paired.causationId === 'string') {
118
119
  expect(
119
120
  paired.causationId,
120
- driver.describe('RFC 0002 §B', 'agent.toolReturned.causationId MUST equal the paired agent.toolCalled.eventId when surfaced'),
121
+ req(requirementId, 'RFC 0002 §B', 'agent.toolReturned.causationId MUST equal the paired agent.toolCalled.eventId when surfaced'),
121
122
  ).toBe(httpCall.eventId);
122
123
  }
123
124
  return true;
@@ -135,7 +136,7 @@ describe('safefetch-live-audit (RFC 0076 §B / RFC 0064 §B — production path,
135
136
  if (run === null) {
136
137
  // eslint-disable-next-line no-console
137
138
  console.warn(`[${PROFILE}] safe-fetch-run seam unwired (404); host-pending — skipping`);
138
- return;
139
+ return softSkip('blocked', 'precondition not met — `run === null` returned early ([…] safe-fetch-run seam unwired (404); host-pending — skipping) (seam, prior step, or fixture unavailable)');
139
140
  }
140
141
 
141
142
  // The metadata IP MUST be refused by a conformant SSRF guard
@@ -144,9 +145,9 @@ describe('safefetch-live-audit (RFC 0076 §B / RFC 0064 §B — production path,
144
145
  // exist — this is the egress-independent floor that makes the bar non-vacuous.
145
146
  expect(
146
147
  typeof run.runId === 'string' && (run.runId as string).length > 0,
147
- driver.describe(CITE, 'the safe-fetch-run seam MUST return the runId of the real run it executed the safeFetch in'),
148
+ req('openwop.it.safefetch-live-audit.a-blocked-real-run-safefetch-emits-the-durable-agent-toolcalled-agent-toolreturn', CITE, 'the safe-fetch-run seam MUST return the runId of the real run it executed the safeFetch in'),
148
149
  ).toBe(true);
149
- await assertDurableHttpPair(run.runId as string, 'blocked');
150
+ await assertDurableHttpPair('openwop.it.safefetch-live-audit.a-blocked-real-run-safefetch-emits-the-durable-agent-toolcalled-agent-toolreturn', run.runId as string, 'blocked');
150
151
  });
151
152
 
152
153
  it('a FETCHED real-run safeFetch also emits the durable pair (success-path coverage — skipped without public egress)', async () => {
@@ -154,7 +155,7 @@ describe('safefetch-live-audit (RFC 0076 §B / RFC 0064 §B — production path,
154
155
  if (!behaviorGate(PROFILE, advertised)) return;
155
156
 
156
157
  const run = await safeFetchViaRun({ url: FETCH_URL });
157
- if (run === null) return; // seam unwired — already warned by the floor test
158
+ if (run === null) return softSkip('blocked', 'precondition not met — `run === null` returned early (seam unwired — already warned by the floor test) (seam, prior step, or fixture unavailable)'); // seam unwired — already warned by the floor test
158
159
 
159
160
  if (run.outcome !== 'fetched') {
160
161
  // No public egress in this environment — the blocked-path floor already
@@ -164,12 +165,12 @@ describe('safefetch-live-audit (RFC 0076 §B / RFC 0064 §B — production path,
164
165
  console.warn(
165
166
  `[${PROFILE}] ${FETCH_URL} did not fetch (outcome=${run.outcome ?? 'n/a'}); no public egress — success-path coverage skipped (the blocked floor covers emission)`,
166
167
  );
167
- return;
168
+ return softSkip('blocked', 'precondition not met — `run.outcome !== \'fetched\'` returned early ([…] … did not fetch (outcome=…); no public egress — success-path coverage skipped (the blocked floor covers emission)) (seam, prior step, or fixture u…');
168
169
  }
169
170
  expect(
170
171
  typeof run.runId === 'string' && (run.runId as string).length > 0,
171
- driver.describe(CITE, 'the safe-fetch-run seam MUST return the runId of the real run it executed the fetch in'),
172
+ req('openwop.it.safefetch-live-audit.a-fetched-real-run-safefetch-also-emits-the-durable-pair-success-path-coverage-s', CITE, 'the safe-fetch-run seam MUST return the runId of the real run it executed the fetch in'),
172
173
  ).toBe(true);
173
- await assertDurableHttpPair(run.runId as string, 'fetched');
174
+ await assertDurableHttpPair('openwop.it.safefetch-live-audit.a-fetched-real-run-safefetch-also-emits-the-durable-pair-success-path-coverage-s', run.runId as string, 'fetched');
174
175
  });
175
176
  });