@openwop/openwop-conformance 1.163.0 → 2.0.0-rc.1

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 (611) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.js +262 -14
  3. package/dist/lib/certification-bundle-v3.js +142 -0
  4. package/dist/lib/paths.js +25 -3
  5. package/dist/lib/requirement-ids.js +57 -4
  6. package/dist/lib/requirement-ledger.js +1 -0
  7. package/dist/lib/scenario-disposition.js +6 -1
  8. package/dist/lib/spec-coherence.js +13 -32
  9. package/dist/spec-artifacts.lock.json +5 -0
  10. package/package.json +11 -33
  11. package/requirements.json +22892 -11701
  12. package/scenario-majors.json +1493 -0
  13. package/schemas/CORPUS-STAMP.json +137 -5
  14. package/src/cli.ts +236 -19
  15. package/src/global-setup.ts +3 -2
  16. package/src/lib/certification-bundle-v3.ts +175 -0
  17. package/src/lib/corpus-stamp.ts +29 -1
  18. package/src/lib/driver.ts +9 -1
  19. package/src/lib/era2-seed.ts +197 -0
  20. package/src/lib/paths.ts +25 -3
  21. package/src/lib/requirement-ids.ts +54 -4
  22. package/src/lib/requirement-ledger.ts +7 -1
  23. package/src/lib/scenario-disposition.ts +6 -1
  24. package/src/lib/seams.ts +45 -0
  25. package/src/lib/spec-coherence.ts +15 -32
  26. package/src/lib/v2.ts +62 -0
  27. package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
  28. package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
  29. package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
  30. package/src/scenarios/a2a-peer-authority.test.ts +7 -6
  31. package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
  32. package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
  33. package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
  34. package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
  35. package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
  36. package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
  37. package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
  38. package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
  39. package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
  40. package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
  41. package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
  42. package/src/scenarios/agent-deployment-shape.test.ts +22 -24
  43. package/src/scenarios/agent-eval-run.test.ts +19 -18
  44. package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
  45. package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
  46. package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
  47. package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
  48. package/src/scenarios/agent-live-structured-output.test.ts +7 -6
  49. package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
  50. package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
  51. package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
  52. package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
  53. package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
  54. package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
  55. package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
  56. package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
  57. package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
  58. package/src/scenarios/agent-platform-profile.test.ts +18 -19
  59. package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
  60. package/src/scenarios/agent-roster-attribution.test.ts +18 -17
  61. package/src/scenarios/agent-roster-shape.test.ts +17 -19
  62. package/src/scenarios/agent-verifier-shape.test.ts +11 -11
  63. package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
  64. package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
  65. package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
  66. package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
  67. package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
  68. package/src/scenarios/agentMessageReducer.test.ts +2 -1
  69. package/src/scenarios/agentMetadata.test.ts +2 -1
  70. package/src/scenarios/agentPackCatalog.test.ts +23 -21
  71. package/src/scenarios/agentPackExport.test.ts +4 -2
  72. package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
  73. package/src/scenarios/agentPackInstall.test.ts +4 -2
  74. package/src/scenarios/agentPackProvenance.test.ts +2 -1
  75. package/src/scenarios/agentReasoningEvents.test.ts +3 -2
  76. package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
  77. package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
  78. package/src/scenarios/ai-envelope-shape.test.ts +31 -29
  79. package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
  80. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
  81. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
  82. package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
  83. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
  84. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
  85. package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
  86. package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
  87. package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
  88. package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
  89. package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
  90. package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
  91. package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
  92. package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
  93. package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
  94. package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
  95. package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
  96. package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
  97. package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
  98. package/src/scenarios/append-ordering.test.ts +7 -5
  99. package/src/scenarios/approval-gate-events.test.ts +4 -3
  100. package/src/scenarios/approval-gate-flow.test.ts +4 -3
  101. package/src/scenarios/approval-payload.test.ts +5 -4
  102. package/src/scenarios/artifact-auth.test.ts +7 -6
  103. package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
  104. package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
  105. package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
  106. package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
  107. package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
  108. package/src/scenarios/audit-log-integrity.test.ts +8 -6
  109. package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
  110. package/src/scenarios/auth-mtls.test.ts +22 -20
  111. package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
  112. package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
  113. package/src/scenarios/auth-saml-profile.test.ts +14 -12
  114. package/src/scenarios/auth-scim-profile.test.ts +3 -2
  115. package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
  116. package/src/scenarios/auth-subject-link.test.ts +11 -10
  117. package/src/scenarios/auth.test.ts +5 -4
  118. package/src/scenarios/authorization-fail-closed.test.ts +3 -2
  119. package/src/scenarios/authorization-roles-shape.test.ts +9 -7
  120. package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
  121. package/src/scenarios/blob-presign-expiry.test.ts +12 -10
  122. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  123. package/src/scenarios/budget-enforcement.test.ts +15 -14
  124. package/src/scenarios/budget-policy-shape.test.ts +18 -19
  125. package/src/scenarios/bulk-cancel.test.ts +9 -8
  126. package/src/scenarios/byok-auth-modes.test.ts +13 -14
  127. package/src/scenarios/byok-roundtrip.test.ts +12 -10
  128. package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
  129. package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
  130. package/src/scenarios/callai-multimodal.test.ts +5 -3
  131. package/src/scenarios/cancellation.test.ts +6 -5
  132. package/src/scenarios/cap-breach.test.ts +15 -14
  133. package/src/scenarios/capability-arm-witness.test.ts +5 -3
  134. package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
  135. package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
  136. package/src/scenarios/certification-bundle-v2.test.ts +11 -10
  137. package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
  138. package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
  139. package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
  140. package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
  141. package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
  142. package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
  143. package/src/scenarios/channel-presence-shape.test.ts +11 -12
  144. package/src/scenarios/channel-ttl.test.ts +6 -5
  145. package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
  146. package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
  147. package/src/scenarios/commitment-fired.test.ts +6 -5
  148. package/src/scenarios/compensation-behavior.test.ts +24 -23
  149. package/src/scenarios/compensation-recovery.test.ts +28 -27
  150. package/src/scenarios/configurable-schema.test.ts +8 -6
  151. package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
  152. package/src/scenarios/conformance-execution-witness.test.ts +9 -8
  153. package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
  154. package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
  155. package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
  156. package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
  157. package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
  158. package/src/scenarios/connection-provider-resolution.test.ts +18 -16
  159. package/src/scenarios/connector-manifest-validity.test.ts +8 -7
  160. package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
  161. package/src/scenarios/context-summarization-replay.test.ts +14 -12
  162. package/src/scenarios/contract-provenance.test.ts +18 -18
  163. package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
  164. package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
  165. package/src/scenarios/conversationLifecycle.test.ts +2 -1
  166. package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
  167. package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
  168. package/src/scenarios/core-standard-profile.test.ts +8 -9
  169. package/src/scenarios/cost-attribution.test.ts +23 -21
  170. package/src/scenarios/credential-payload-redaction.test.ts +4 -3
  171. package/src/scenarios/credentials-capability-shape.test.ts +5 -4
  172. package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
  173. package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
  174. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
  175. package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
  176. package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
  177. package/src/scenarios/data-residency-admission.test.ts +15 -14
  178. package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
  179. package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
  180. package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
  181. package/src/scenarios/debugBundle.test.ts +25 -23
  182. package/src/scenarios/discovery-families-view.test.ts +5 -4
  183. package/src/scenarios/discovery.test.ts +30 -29
  184. package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
  185. package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
  186. package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
  187. package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
  188. package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
  189. package/src/scenarios/dispatchLoop.test.ts +3 -2
  190. package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
  191. package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
  192. package/src/scenarios/distillation-shape.test.ts +4 -4
  193. package/src/scenarios/distillation-stable-archive.test.ts +6 -6
  194. package/src/scenarios/distillation-token-budget.test.ts +5 -5
  195. package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
  196. package/src/scenarios/egress-audience-binding.test.ts +11 -10
  197. package/src/scenarios/egress-decision-content-free.test.ts +6 -5
  198. package/src/scenarios/egress-provenance-shape.test.ts +17 -18
  199. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
  200. package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
  201. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
  202. package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
  203. package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
  204. package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
  205. package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
  206. package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
  207. package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
  208. package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
  209. package/src/scenarios/envelope-truncated.test.ts +19 -17
  210. package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
  211. package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
  212. package/src/scenarios/errors.test.ts +20 -19
  213. package/src/scenarios/eventOrdering.test.ts +16 -14
  214. package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
  215. package/src/scenarios/experimental-tier-shape.test.ts +17 -15
  216. package/src/scenarios/export-bundle-portability.test.ts +17 -17
  217. package/src/scenarios/failure-path.test.ts +7 -6
  218. package/src/scenarios/feedback-capability-shape.test.ts +4 -3
  219. package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
  220. package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
  221. package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
  222. package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
  223. package/src/scenarios/feedback-record-and-list.test.ts +2 -1
  224. package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
  225. package/src/scenarios/fixtures-gating.test.ts +29 -28
  226. package/src/scenarios/fixtures-valid.test.ts +16 -15
  227. package/src/scenarios/form-content-instantiation.test.ts +15 -14
  228. package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
  229. package/src/scenarios/fs-path-traversal.test.ts +14 -12
  230. package/src/scenarios/goal-standing-continuation.test.ts +21 -21
  231. package/src/scenarios/grpc-transport.test.ts +9 -7
  232. package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
  233. package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
  234. package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
  235. package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
  236. package/src/scenarios/highConcurrency.test.ts +14 -13
  237. package/src/scenarios/host-callback-declaration.test.ts +8 -7
  238. package/src/scenarios/http-client-ssrf.test.ts +7 -5
  239. package/src/scenarios/i18n-negotiation.test.ts +14 -12
  240. package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
  241. package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
  242. package/src/scenarios/idempotency.test.ts +8 -7
  243. package/src/scenarios/idempotencyRetry.test.ts +13 -11
  244. package/src/scenarios/identity-owner-shape.test.ts +6 -5
  245. package/src/scenarios/identity-passthrough.test.ts +4 -3
  246. package/src/scenarios/interrupt-approval.test.ts +6 -5
  247. package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
  248. package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
  249. package/src/scenarios/interrupt-clarification.test.ts +4 -3
  250. package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
  251. package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
  252. package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
  253. package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
  254. package/src/scenarios/interruptRace.test.ts +12 -10
  255. package/src/scenarios/kv-atomic-increment.test.ts +11 -9
  256. package/src/scenarios/kv-cas.test.ts +14 -12
  257. package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
  258. package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
  259. package/src/scenarios/localized-content-delivery.test.ts +24 -26
  260. package/src/scenarios/maliciousManifest.test.ts +10 -8
  261. package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
  262. package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
  263. package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
  264. package/src/scenarios/mcp-discoverability.test.ts +9 -7
  265. package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
  266. package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
  267. package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
  268. package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
  269. package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
  270. package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
  271. package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
  272. package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
  273. package/src/scenarios/mcp-stateless-request.test.ts +11 -10
  274. package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
  275. package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
  276. package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
  277. package/src/scenarios/media-url-inline-cap.test.ts +21 -19
  278. package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
  279. package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
  280. package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
  281. package/src/scenarios/memory-attribution-shape.test.ts +4 -3
  282. package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
  283. package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
  284. package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
  285. package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
  286. package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
  287. package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
  288. package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
  289. package/src/scenarios/memory-degraded-projection.test.ts +10 -9
  290. package/src/scenarios/memory-injection-budget.test.ts +15 -14
  291. package/src/scenarios/metric-emission.test.ts +4 -3
  292. package/src/scenarios/model-capability-insufficient.test.ts +19 -17
  293. package/src/scenarios/model-capability-substituted.test.ts +20 -18
  294. package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
  295. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
  296. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
  297. package/src/scenarios/multi-node-ordering.test.ts +4 -3
  298. package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
  299. package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
  300. package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
  301. package/src/scenarios/multi-region-idempotency.test.ts +6 -5
  302. package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
  303. package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
  304. package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
  305. package/src/scenarios/oauth-capability-shape.test.ts +5 -4
  306. package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
  307. package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
  308. package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
  309. package/src/scenarios/orchestratorDispatch.test.ts +2 -1
  310. package/src/scenarios/orchestratorTermination.test.ts +2 -1
  311. package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
  312. package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
  313. package/src/scenarios/otel-emission-grpc.test.ts +3 -2
  314. package/src/scenarios/otel-emission.test.ts +6 -5
  315. package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
  316. package/src/scenarios/otel-trace-propagation.test.ts +2 -1
  317. package/src/scenarios/owner-subject-echo.test.ts +13 -12
  318. package/src/scenarios/owner-subject-shape.test.ts +11 -10
  319. package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
  320. package/src/scenarios/pack-registry-isolation.test.ts +4 -3
  321. package/src/scenarios/pack-registry-publish.test.ts +65 -63
  322. package/src/scenarios/pack-registry.test.ts +38 -36
  323. package/src/scenarios/pause-resume.test.ts +18 -16
  324. package/src/scenarios/policies.test.ts +20 -18
  325. package/src/scenarios/production-backpressure.test.ts +18 -16
  326. package/src/scenarios/production-retention-expiry.test.ts +8 -6
  327. package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
  328. package/src/scenarios/profileDerivation.test.ts +34 -33
  329. package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
  330. package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
  331. package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
  332. package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
  333. package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
  334. package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
  335. package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
  336. package/src/scenarios/prompt-pack-install.test.ts +14 -12
  337. package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
  338. package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
  339. package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
  340. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
  341. package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
  342. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
  343. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
  344. package/src/scenarios/prompt-template-shape.test.ts +30 -28
  345. package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
  346. package/src/scenarios/protocol-versions-array.test.ts +10 -9
  347. package/src/scenarios/provider-usage.test.ts +17 -15
  348. package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
  349. package/src/scenarios/purpose-propagation.test.ts +23 -21
  350. package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
  351. package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
  352. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
  353. package/src/scenarios/rate-limit-envelope.test.ts +6 -5
  354. package/src/scenarios/redaction.test.ts +13 -11
  355. package/src/scenarios/redactionAdversarial.test.ts +11 -9
  356. package/src/scenarios/registry-public.test.ts +12 -11
  357. package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
  358. package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
  359. package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
  360. package/src/scenarios/replay-fork.test.ts +20 -19
  361. package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
  362. package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
  363. package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
  364. package/src/scenarios/replay-retention-expiry.test.ts +11 -9
  365. package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
  366. package/src/scenarios/replayDeterminism.test.ts +13 -12
  367. package/src/scenarios/requirement-ledger.test.ts +15 -14
  368. package/src/scenarios/restart-during-run.test.ts +3 -2
  369. package/src/scenarios/route-coverage.test.ts +20 -19
  370. package/src/scenarios/run-diff.test.ts +22 -20
  371. package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
  372. package/src/scenarios/run-transport-economy.test.ts +13 -11
  373. package/src/scenarios/runner-ledger.test.ts +17 -16
  374. package/src/scenarios/runs-lifecycle.test.ts +7 -6
  375. package/src/scenarios/runtime-capabilities.test.ts +12 -10
  376. package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
  377. package/src/scenarios/runtime-requires-shape.test.ts +7 -6
  378. package/src/scenarios/safefetch-behavior.test.ts +22 -21
  379. package/src/scenarios/safefetch-live-audit.test.ts +14 -13
  380. package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
  381. package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
  382. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
  383. package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
  384. package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
  385. package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
  386. package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
  387. package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
  388. package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
  389. package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
  390. package/src/scenarios/self-hosted-runner.test.ts +26 -24
  391. package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
  392. package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
  393. package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
  394. package/src/scenarios/sql-injection-rejection.test.ts +8 -6
  395. package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
  396. package/src/scenarios/staleClaim.test.ts +5 -4
  397. package/src/scenarios/stream-modes-buffer.test.ts +8 -7
  398. package/src/scenarios/stream-modes-mixed.test.ts +10 -9
  399. package/src/scenarios/stream-modes.test.ts +12 -11
  400. package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
  401. package/src/scenarios/stream-text-fixture.test.ts +14 -13
  402. package/src/scenarios/streamReconnect.test.ts +13 -11
  403. package/src/scenarios/strict-behavior-gate.test.ts +9 -8
  404. package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
  405. package/src/scenarios/subrun-approval-gate.test.ts +3 -3
  406. package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
  407. package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
  408. package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
  409. package/src/scenarios/subworkflow.test.ts +10 -9
  410. package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
  411. package/src/scenarios/table-cursor-pagination.test.ts +8 -6
  412. package/src/scenarios/table-schema-enforcement.test.ts +7 -5
  413. package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
  414. package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
  415. package/src/scenarios/tool-catalog-projection.test.ts +11 -9
  416. package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
  417. package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
  418. package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
  419. package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
  420. package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
  421. package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
  422. package/src/scenarios/tool-hooks-shape.test.ts +3 -3
  423. package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
  424. package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
  425. package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
  426. package/src/scenarios/trigger-ingestion.test.ts +19 -17
  427. package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
  428. package/src/scenarios/v2-approver-enforced.test.ts +97 -0
  429. package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
  430. package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
  431. package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
  432. package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
  433. package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
  434. package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
  435. package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
  436. package/src/scenarios/v2-configurable-closed.test.ts +67 -0
  437. package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
  438. package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
  439. package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
  440. package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
  441. package/src/scenarios/v2-era-key.test.ts +86 -0
  442. package/src/scenarios/v2-error-registry.test.ts +89 -0
  443. package/src/scenarios/v2-event-type-closed.test.ts +97 -0
  444. package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
  445. package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
  446. package/src/scenarios/v2-header-scheme.test.ts +67 -0
  447. package/src/scenarios/v2-id-grammar.test.ts +77 -0
  448. package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
  449. package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
  450. package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
  451. package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
  452. package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
  453. package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
  454. package/src/scenarios/v2-min-client-version.test.ts +48 -0
  455. package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
  456. package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
  457. package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
  458. package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
  459. package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
  460. package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
  461. package/src/scenarios/v2-pack-isolation.test.ts +147 -0
  462. package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
  463. package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
  464. package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
  465. package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
  466. package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
  467. package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
  468. package/src/scenarios/v2-provider-conflict.test.ts +115 -0
  469. package/src/scenarios/v2-refresh-sla.test.ts +78 -0
  470. package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
  471. package/src/scenarios/v2-revocation-honored.test.ts +66 -0
  472. package/src/scenarios/v2-subject-link-record.test.ts +102 -0
  473. package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
  474. package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
  475. package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
  476. package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
  477. package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
  478. package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
  479. package/src/scenarios/verifier-gating.test.ts +8 -6
  480. package/src/scenarios/version-fold.test.ts +9 -8
  481. package/src/scenarios/version-negotiation.test.ts +12 -11
  482. package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
  483. package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
  484. package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
  485. package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
  486. package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
  487. package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
  488. package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
  489. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
  490. package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
  491. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
  492. package/src/scenarios/wasm-pack-load.test.ts +4 -3
  493. package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
  494. package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
  495. package/src/scenarios/webhook-negative.test.ts +11 -9
  496. package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
  497. package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
  498. package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
  499. package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
  500. package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
  501. package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
  502. package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
  503. package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
  504. package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
  505. package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
  506. package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
  507. package/src/scenarios/workflow-variable-format.test.ts +24 -24
  508. package/src/scenarios/workload-identity-behavior.test.ts +15 -13
  509. package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
  510. package/src/scenarios/workspace-behavior.test.ts +19 -18
  511. package/src/scenarios/workspace-capability-shape.test.ts +3 -2
  512. package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
  513. package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
  514. package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
  515. package/src/setup.ts +44 -6
  516. package/vitest.config.ts +5 -1
  517. package/api/.redocly.lint-ignore.yaml +0 -22
  518. package/api/asyncapi.yaml +0 -834
  519. package/api/grpc/openwop.proto +0 -251
  520. package/api/openapi.yaml +0 -2693
  521. package/api/redocly.yaml +0 -23
  522. package/schemas/README.md +0 -144
  523. package/schemas/a2a-task-state.schema.json +0 -78
  524. package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
  525. package/schemas/agent-deployment-transition.schema.json +0 -49
  526. package/schemas/agent-deployment.schema.json +0 -54
  527. package/schemas/agent-eval-suite.schema.json +0 -140
  528. package/schemas/agent-inventory-response.schema.json +0 -115
  529. package/schemas/agent-manifest.schema.json +0 -156
  530. package/schemas/agent-org-chart.schema.json +0 -82
  531. package/schemas/agent-ref.schema.json +0 -63
  532. package/schemas/agent-roster-entry.schema.json +0 -81
  533. package/schemas/agent-roster-response.schema.json +0 -21
  534. package/schemas/ai-envelope.schema.json +0 -134
  535. package/schemas/annotation-create.schema.json +0 -37
  536. package/schemas/annotation.schema.json +0 -56
  537. package/schemas/artifact-type-pack-manifest.schema.json +0 -244
  538. package/schemas/audit-verify-result.schema.json +0 -90
  539. package/schemas/budget-policy.schema.json +0 -18
  540. package/schemas/capabilities.schema.json +0 -4160
  541. package/schemas/certification-bundle-v2.schema.json +0 -118
  542. package/schemas/channel-presence-payload.schema.json +0 -41
  543. package/schemas/channel-written-payload.schema.json +0 -55
  544. package/schemas/chat-card-pack-manifest.schema.json +0 -253
  545. package/schemas/compact-tool-descriptor.schema.json +0 -51
  546. package/schemas/compensation-policy.schema.json +0 -64
  547. package/schemas/conformance-certification-bundle.schema.json +0 -86
  548. package/schemas/connection-pack-manifest.schema.json +0 -353
  549. package/schemas/conversation-event.schema.json +0 -168
  550. package/schemas/conversation-turn.schema.json +0 -117
  551. package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
  552. package/schemas/credential-provenance.schema.json +0 -18
  553. package/schemas/credential-reference.schema.json +0 -21
  554. package/schemas/debug-bundle.schema.json +0 -196
  555. package/schemas/dispatch-config.schema.json +0 -112
  556. package/schemas/envelopes/clarification.request.schema.json +0 -52
  557. package/schemas/envelopes/error.schema.json +0 -30
  558. package/schemas/envelopes/media.audio.schema.json +0 -38
  559. package/schemas/envelopes/media.file.schema.json +0 -37
  560. package/schemas/envelopes/media.image.schema.json +0 -33
  561. package/schemas/envelopes/schema.request.schema.json +0 -26
  562. package/schemas/envelopes/schema.response.schema.json +0 -22
  563. package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
  564. package/schemas/error-envelope.schema.json +0 -25
  565. package/schemas/eval-summary.schema.json +0 -92
  566. package/schemas/export-bundle.schema.json +0 -66
  567. package/schemas/form-content-pack-manifest.schema.json +0 -243
  568. package/schemas/frontend-plugin-manifest.schema.json +0 -109
  569. package/schemas/goal.schema.json +0 -104
  570. package/schemas/heartbeat-evaluated.schema.json +0 -14
  571. package/schemas/heartbeat-state-changed.schema.json +0 -14
  572. package/schemas/localized-content-language-settings.schema.json +0 -26
  573. package/schemas/localized-content-page-response.schema.json +0 -60
  574. package/schemas/localized-content-page.schema.json +0 -62
  575. package/schemas/localized-content-section.schema.json +0 -51
  576. package/schemas/memory-entry.schema.json +0 -36
  577. package/schemas/memory-list-options.schema.json +0 -37
  578. package/schemas/node-pack-manifest.schema.json +0 -654
  579. package/schemas/orchestrator-decision.schema.json +0 -90
  580. package/schemas/org-chart-responsibility-view.schema.json +0 -26
  581. package/schemas/pack-lockfile.schema.json +0 -108
  582. package/schemas/prompt-kind.schema.json +0 -8
  583. package/schemas/prompt-pack-manifest.schema.json +0 -117
  584. package/schemas/prompt-ref.schema.json +0 -40
  585. package/schemas/prompt-template.schema.json +0 -149
  586. package/schemas/proposal.schema.json +0 -84
  587. package/schemas/registry-version-manifest.schema.json +0 -208
  588. package/schemas/residency.schema.json +0 -16
  589. package/schemas/run-ancestry-response.schema.json +0 -54
  590. package/schemas/run-diff-response.schema.json +0 -64
  591. package/schemas/run-event-payloads.schema.json +0 -4452
  592. package/schemas/run-event.schema.json +0 -211
  593. package/schemas/run-options.schema.json +0 -80
  594. package/schemas/run-orchestrator-decided-event.schema.json +0 -20
  595. package/schemas/run-snapshot.schema.json +0 -148
  596. package/schemas/security-advisory.schema.json +0 -109
  597. package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
  598. package/schemas/self-hosted-runner-registration.schema.json +0 -53
  599. package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
  600. package/schemas/subject.schema.json +0 -56
  601. package/schemas/suspend-request.schema.json +0 -207
  602. package/schemas/tool-descriptor.schema.json +0 -63
  603. package/schemas/trigger-event.schema.json +0 -222
  604. package/schemas/trigger-subscription-registration.schema.json +0 -67
  605. package/schemas/trigger-subscription.schema.json +0 -26
  606. package/schemas/ui-plugin-message.schema.json +0 -90
  607. package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
  608. package/schemas/workflow-definition.schema.json +0 -850
  609. package/schemas/workload-identity.schema.json +0 -79
  610. package/schemas/workspace-file-create.schema.json +0 -20
  611. package/schemas/workspace-file.schema.json +0 -39
@@ -29,8 +29,7 @@ import { readFileSync } from 'node:fs';
29
29
  import { join } from 'node:path';
30
30
  import { SCHEMAS_DIR } from '../lib/paths.js';
31
31
  import { isAgentPlatformPartial, isAgentPlatformFull, agentPlatformStatus, agentPlatformSatisfiedTerms } from '../lib/profiles.js';
32
-
33
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
32
+ import { req } from '../lib/requirement-ids.js';
34
33
 
35
34
  const CORE = {
36
35
  protocolVersion: '1.0',
@@ -59,24 +58,24 @@ function floorPayload(extra: Record<string, unknown> = {}): Record<string, unkno
59
58
  describe('agent-platform-profile: floor (partial) predicate (RFC 0085 §B, server-free)', () => {
60
59
  it('a host meeting all floor flags is partial', () => {
61
60
  const c = floorPayload();
62
- expect(isAgentPlatformPartial(c), why('agent-platform-profile.md §B', 'all floor flags ⇒ partial')).toBe(true);
63
- expect(agentPlatformStatus(c)).toBe('partial');
61
+ expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.a-host-meeting-all-floor-flags-is-partial', 'agent-platform-profile.md §B', 'all floor flags ⇒ partial')).toBe(true);
62
+ expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-meeting-all-floor-flags-is-partial', 'RFC 0085', 'a host meeting all floor flags is partial')).toBe('partial');
64
63
  });
65
64
 
66
65
  it('missing a single floor flag (feedback) ⇒ none', () => {
67
66
  const c = floorPayload({ feedback: { supported: false } });
68
- expect(isAgentPlatformPartial(c), why('agent-platform-profile.md §B', 'a missing floor flag ⇒ not partial')).toBe(false);
69
- expect(agentPlatformStatus(c)).toBe('none');
67
+ expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.missing-a-single-floor-flag-feedback-none', 'agent-platform-profile.md §B', 'a missing floor flag ⇒ not partial')).toBe(false);
68
+ expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.missing-a-single-floor-flag-feedback-none', 'RFC 0085', 'missing a single floor flag (feedback) ⇒ none')).toBe('none');
70
69
  });
71
70
 
72
71
  it('replay-OR-nondeterminism: no replay but declared nondeterminism still meets the floor', () => {
73
72
  const c = floorPayload({ replay: { supported: false }, nondeterminismPolicy: { declared: true } });
74
- expect(isAgentPlatformPartial(c), why('agent-platform-profile.md §B', 'declared nondeterminism satisfies the replay-OR term')).toBe(true);
73
+ expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.replay-or-nondeterminism-no-replay-but-declared-nondeterminism-still-meets-the-f', 'agent-platform-profile.md §B', 'declared nondeterminism satisfies the replay-OR term')).toBe(true);
75
74
  });
76
75
 
77
76
  it('neither replay nor declared nondeterminism ⇒ floor unmet', () => {
78
77
  const c = floorPayload({ replay: { supported: false } });
79
- expect(isAgentPlatformPartial(c), why('agent-platform-profile.md §B', 'neither replay nor declared policy ⇒ not partial')).toBe(false);
78
+ expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.neither-replay-nor-declared-nondeterminism-floor-unmet', 'agent-platform-profile.md §B', 'neither replay nor declared policy ⇒ not partial')).toBe(false);
80
79
  });
81
80
  });
82
81
 
@@ -92,8 +91,8 @@ describe('agent-platform-profile: full predicate + honest-advertisement (RFC 008
92
91
 
93
92
  it('a host meeting floor + all governance terms is full', () => {
94
93
  const c = floorPayload(fullExtra);
95
- expect(isAgentPlatformFull(c), why('agent-platform-profile.md §B', 'floor + governance ⇒ full')).toBe(true);
96
- expect(agentPlatformStatus(c)).toBe('full');
94
+ expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.a-host-meeting-floor-all-governance-terms-is-full', 'agent-platform-profile.md §B', 'floor + governance ⇒ full')).toBe(true);
95
+ expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-meeting-floor-all-governance-terms-is-full', 'RFC 0085', 'a host meeting floor + all governance terms is full')).toBe('full');
97
96
  });
98
97
 
99
98
  it('a host advertising governance flags but missing tenant installScope reports partial, not full', () => {
@@ -101,13 +100,13 @@ describe('agent-platform-profile: full predicate + honest-advertisement (RFC 008
101
100
  ...fullExtra,
102
101
  agents: { manifestRuntime: { supported: true, installScope: 'host' }, liveRuntime: { supported: true } },
103
102
  });
104
- expect(isAgentPlatformFull(c), why('agent-platform-profile.md §D', 'missing a governance term ⇒ MUST NOT be full')).toBe(false);
105
- expect(agentPlatformStatus(c)).toBe('partial');
103
+ expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.a-host-advertising-governance-flags-but-missing-tenant-installscope-reports-part', 'agent-platform-profile.md §D', 'missing a governance term ⇒ MUST NOT be full')).toBe(false);
104
+ expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-advertising-governance-flags-but-missing-tenant-installscope-reports-part', 'RFC 0085', 'a host advertising governance flags but missing tenant installScope reports partial, not full')).toBe('partial');
106
105
  });
107
106
 
108
107
  it('eval/deploy/budget are NOT hard full terms (a full host without them is still full)', () => {
109
108
  const c = floorPayload(fullExtra); // no agents.evalSuite / agents.deployment / budget
110
- expect(isAgentPlatformFull(c), why('agent-platform-profile.md §B', 'platform-plus tier is advisory, not a hard full term')).toBe(true);
109
+ expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.eval-deploy-budget-are-not-hard-full-terms-a-full-host-without-them-is-still-ful', 'agent-platform-profile.md §B', 'platform-plus tier is advisory, not a hard full term')).toBe(true);
111
110
  });
112
111
  });
113
112
 
@@ -126,12 +125,12 @@ describe('agent-platform-profile: satisfiedTerms[] non-contiguous adoption (RFC
126
125
  feedback: { supported: true },
127
126
  replay: { supported: true },
128
127
  } as Record<string, unknown>;
129
- expect(agentPlatformStatus(c), why('agent-platform-profile.md §D', 'floor unmet ⇒ none')).toBe('none');
128
+ expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', 'agent-platform-profile.md §D', 'floor unmet ⇒ none')).toBe('none');
130
129
  const terms = agentPlatformSatisfiedTerms(c);
131
- expect(terms.includes('full:authorization'), why('§D', 'a satisfied full term is reported even at none')).toBe(true);
132
- expect(terms.includes('full:memory.attribution')).toBe(true);
130
+ expect(terms.includes('full:authorization'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', '§D', 'a satisfied full term is reported even at none')).toBe(true);
131
+ expect(terms.includes('full:memory.attribution'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', 'RFC 0085', 'a host honoring full-tier terms but failing floor terms is status none yet has a non-empty satisfiedTerms[]')).toBe(true);
133
132
  expect(terms.includes('full:tenant-installScope')).toBe(true);
134
- expect(terms.includes('floor:agents.liveRuntime'), why('§D', 'an unmet floor term is NOT reported')).toBe(false);
133
+ expect(terms.includes('floor:agents.liveRuntime'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', '§D', 'an unmet floor term is NOT reported')).toBe(false);
135
134
  expect(terms.length).toBeGreaterThan(0); // distinguishable from a 0/16 do-nothing host
136
135
  });
137
136
 
@@ -144,7 +143,7 @@ describe('agent-platform-profile: satisfiedTerms[] non-contiguous adoption (RFC
144
143
  triggerBridge: { supported: true },
145
144
  httpClient: { safeFetch: { supported: true }, egressPolicy: { supported: true } },
146
145
  });
147
- expect(agentPlatformSatisfiedTerms(c).length, why('§D', 'a full host satisfies all 16 terms')).toBe(16);
146
+ expect(agentPlatformSatisfiedTerms(c).length, req('openwop.it.agent-platform-profile.a-full-host-reports-all-sixteen-terms-satisfied', '§D', 'a full host satisfies all 16 terms')).toBe(16);
148
147
  });
149
148
  });
150
149
 
@@ -153,7 +152,7 @@ describe('agent-platform-profile: capability shape (RFC 0085, server-free)', ()
153
152
  const caps = JSON.parse(readFileSync(join(SCHEMAS_DIR, 'capabilities.schema.json'), 'utf8')) as { properties?: Record<string, { properties?: Record<string, unknown> }> };
154
153
  expect(
155
154
  caps.properties?.nondeterminismPolicy?.properties?.declared,
156
- why('agent-platform-profile.md §B', 'capabilities.nondeterminismPolicy.declared MUST be declared'),
155
+ req('openwop.it.agent-platform-profile.capabilities-nondeterminismpolicy-declared-is-declared', 'agent-platform-profile.md §B', 'capabilities.nondeterminismPolicy.declared MUST be declared'),
157
156
  ).toBeDefined();
158
157
  });
159
158
  });
@@ -21,9 +21,9 @@ import { join } from 'node:path';
21
21
  import Ajv2020 from 'ajv/dist/2020.js';
22
22
  import addFormats from 'ajv-formats';
23
23
  import { SCHEMAS_DIR } from '../lib/paths.js';
24
+ import { req } from '../lib/requirement-ids.js';
24
25
 
25
26
  const BASE = 'https://openwop.dev/spec/v1/';
26
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
27
27
  function loadSchema(name: string): Record<string, unknown> {
28
28
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
29
29
  }
@@ -47,18 +47,18 @@ describe('agent-requires-capabilities-shape: AgentManifest.requiresCapabilities
47
47
  it('a manifest WITH requiresCapabilities validates', () => {
48
48
  expect(
49
49
  manifest({ ...base, requiresCapabilities: ['host.workspace', 'aiProviders.toolCalling'] }),
50
- why('RFC 0092 §A', 'a manifest declaring requiresCapabilities MUST validate'),
50
+ req('openwop.it.agent-requires-capabilities-shape.a-manifest-with-requirescapabilities-validates', 'RFC 0092 §A', 'a manifest declaring requiresCapabilities MUST validate'),
51
51
  ).toBe(true);
52
52
  });
53
53
 
54
54
  it('a manifest WITHOUT it still validates (absent ⇒ no requirements)', () => {
55
- expect(manifest(base), why('RFC 0092 §A', 'requiresCapabilities is optional')).toBe(true);
55
+ expect(manifest(base), req('openwop.it.agent-requires-capabilities-shape.a-manifest-without-it-still-validates-absent-no-requirements', 'RFC 0092 §A', 'requiresCapabilities is optional')).toBe(true);
56
56
  });
57
57
 
58
58
  it('rejects a non-string-array value', () => {
59
59
  expect(
60
60
  manifest({ ...base, requiresCapabilities: [123] }),
61
- why('RFC 0092 §A', 'requiresCapabilities items MUST be non-empty strings'),
61
+ req('openwop.it.agent-requires-capabilities-shape.rejects-a-non-string-array-value', 'RFC 0092 §A', 'requiresCapabilities items MUST be non-empty strings'),
62
62
  ).toBe(false);
63
63
  });
64
64
  });
@@ -34,7 +34,6 @@
34
34
  */
35
35
 
36
36
  import { describe, it, expect } from 'vitest';
37
- import { driver } from '../lib/driver.js';
38
37
  import { behaviorGate } from '../lib/behavior-gate.js';
39
38
  import { readRosterCap, listRoster, getRosterEntry, fireRosterPortfolio } from '../lib/agentRoster.js';
40
39
  import {
@@ -43,6 +42,8 @@ import {
43
42
  resetTestSeam,
44
43
  type TestEvent,
45
44
  } from '../lib/event-log-query.js';
45
+ import { req } from '../lib/requirement-ids.js';
46
+ import { softSkip } from '../lib/soft-skip.js';
46
47
 
47
48
  const ROSTER_ID_RE = /^host:[a-z0-9][a-z0-9._-]*$/;
48
49
 
@@ -62,42 +63,42 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
62
63
  const installScope = typeof cap?.installScope === 'string' ? cap.installScope : 'host';
63
64
  expect(
64
65
  installScope === 'host' || installScope === 'tenant',
65
- driver.describe('RFC 0086 §F / RFC 0074 §B', "agents.roster.installScope (when present) MUST be 'host' or 'tenant'"),
66
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'RFC 0086 §F / RFC 0074 §B', "agents.roster.installScope (when present) MUST be 'host' or 'tenant'"),
66
67
  ).toBe(true);
67
68
 
68
69
  // ---- Leg 1: normative read (black-box on any roster host) -------------
69
70
  const body = await listRoster();
70
- if (body === null) return; // host advertises roster but doesn't serve the read yet — soft-skip
71
+ if (body === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `body === null` returned early (host advertises roster but doesn\'t serve the read yet — soft-skip)'); // host advertises roster but doesn't serve the read yet — soft-skip
71
72
  const roster = body.roster ?? [];
72
73
  expect(
73
74
  Array.isArray(roster),
74
- driver.describe('agent-roster.md §B', 'GET /v1/agents/roster MUST return a roster[] array'),
75
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B', 'GET /v1/agents/roster MUST return a roster[] array'),
75
76
  ).toBe(true);
76
77
  expect(
77
78
  body.total === roster.length,
78
- driver.describe('agent-roster-response.schema.json', 'total MUST equal roster.length'),
79
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster-response.schema.json', 'total MUST equal roster.length'),
79
80
  ).toBe(true);
80
81
  for (const entry of roster) {
81
82
  expect(
82
83
  typeof entry.rosterId === 'string' && ROSTER_ID_RE.test(entry.rosterId),
83
- driver.describe('agent-roster-entry.schema.json', 'each entry MUST carry a host:<id> rosterId'),
84
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster-entry.schema.json', 'each entry MUST carry a host:<id> rosterId'),
84
85
  ).toBe(true);
85
86
  expect(
86
87
  typeof entry.persona === 'string' && entry.persona.length > 0,
87
- driver.describe('agent-roster.md §A', 'each entry MUST carry a non-empty persona'),
88
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §A', 'each entry MUST carry a non-empty persona'),
88
89
  ).toBe(true);
89
90
  expect(
90
91
  typeof entry.agentRef?.agentId === 'string',
91
- driver.describe('agent-roster.md §A', 'each entry MUST reference an agentRef.agentId'),
92
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §A', 'each entry MUST reference an agentRef.agentId'),
92
93
  ).toBe(true);
93
94
  expect(
94
95
  typeof entry.owner?.tenantId === 'string',
95
- driver.describe('agent-roster.md §B / RFC 0074', 'each entry MUST carry an owner.tenantId scope'),
96
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B / RFC 0074', 'each entry MUST carry an owner.tenantId scope'),
96
97
  ).toBe(true);
97
98
  // RFC 0082 §A XOR: an agentRef MUST NOT pin both version and channel.
98
99
  expect(
99
100
  !(entry.agentRef?.version !== undefined && entry.agentRef?.channel !== undefined),
100
- driver.describe('RFC 0082 §A', 'agentRef MUST NOT carry both version and channel'),
101
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'RFC 0082 §A', 'agentRef MUST NOT carry both version and channel'),
101
102
  ).toBe(true);
102
103
  }
103
104
 
@@ -111,7 +112,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
111
112
  const init = firstOf(q.events, ['roster.run.initiated']);
112
113
  expect(
113
114
  init !== undefined,
114
- driver.describe('agent-roster.md §C', 'a portfolio fire MUST emit roster.run.initiated'),
115
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'a portfolio fire MUST emit roster.run.initiated'),
115
116
  ).toBe(true);
116
117
 
117
118
  if (init) {
@@ -124,7 +125,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
124
125
  if (firstAgent) {
125
126
  expect(
126
127
  init.sequence < firstAgent.sequence,
127
- driver.describe('agent-roster.md §C', 'roster.run.initiated MUST precede any agent.* event in the run'),
128
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'roster.run.initiated MUST precede any agent.* event in the run'),
128
129
  ).toBe(true);
129
130
  }
130
131
 
@@ -133,18 +134,18 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
133
134
  for (const key of ['rosterId', 'persona', 'agentId', 'workflowId', 'triggerSource']) {
134
135
  expect(
135
136
  typeof p[key] === 'string' && (p[key] as string).length > 0,
136
- driver.describe('run-event-payloads.schema.json#rosterRunInitiated', `roster.run.initiated MUST carry ${key}`),
137
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'run-event-payloads.schema.json#rosterRunInitiated', `roster.run.initiated MUST carry ${key}`),
137
138
  ).toBe(true);
138
139
  }
139
140
  for (const forbidden of ['body', 'prompt', 'input', 'payload', 'apiKey', 'secret', 'credentials', 'token']) {
140
141
  expect(
141
142
  !(forbidden in p),
142
- driver.describe('SECURITY roster-attribution-no-content', `roster.run.initiated MUST be content-free (no ${forbidden})`),
143
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'SECURITY roster-attribution-no-content', `roster.run.initiated MUST be content-free (no ${forbidden})`),
143
144
  ).toBe(true);
144
145
  }
145
146
  expect(
146
147
  typeof p.rosterId === 'string' && ROSTER_ID_RE.test(p.rosterId),
147
- driver.describe('agent-roster.md §C', 'roster.run.initiated.rosterId MUST be a host:<id> AgentRef id'),
148
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'roster.run.initiated.rosterId MUST be a host:<id> AgentRef id'),
148
149
  ).toBe(true);
149
150
  }
150
151
  }
@@ -158,7 +159,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
158
159
  const p = q.events[0].payload;
159
160
  expect(
160
161
  typeof p.triggerSubscriptionId === 'string' && (p.triggerSubscriptionId as string).length > 0,
161
- driver.describe('agent-roster.md §D / RFC 0083', 'a durable work-item fire MUST carry triggerSubscriptionId for trigger→run→roster ancestry'),
162
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §D / RFC 0083', 'a durable work-item fire MUST carry triggerSubscriptionId for trigger→run→roster ancestry'),
162
163
  ).toBe(true);
163
164
  }
164
165
  }
@@ -172,7 +173,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
172
173
  const probe = await getRosterEntry(crossTenantId);
173
174
  expect(
174
175
  probe.status === 404,
175
- driver.describe('agent-roster.md §B / RFC 0074', "GET /v1/agents/roster/{id} for a cross-tenant id MUST 404 (no cross-tenant disclosure)"),
176
+ req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B / RFC 0074', "GET /v1/agents/roster/{id} for a cross-tenant id MUST 404 (no cross-tenant disclosure)"),
176
177
  ).toBe(true);
177
178
  }
178
179
  });
@@ -35,9 +35,7 @@ import { join } from 'node:path';
35
35
  import Ajv2020 from 'ajv/dist/2020.js';
36
36
  import addFormats from 'ajv-formats';
37
37
  import { SCHEMAS_DIR } from '../lib/paths.js';
38
-
39
- /** Server-free assertion-message helper. */
40
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
38
+ import { req } from '../lib/requirement-ids.js';
41
39
 
42
40
  function loadSchema(name: string): Record<string, unknown> {
43
41
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
@@ -48,9 +46,9 @@ describe('agent-roster-shape: capability advertisement (RFC 0086, server-free)',
48
46
  const caps = loadSchema('capabilities.schema.json');
49
47
  const agents = (caps.properties as Record<string, { properties?: Record<string, { properties?: Record<string, unknown> }> }>).agents;
50
48
  const roster = agents?.properties?.roster;
51
- expect(roster, why('capabilities.md §agents', 'agents.roster MUST be declared')).toBeDefined();
49
+ expect(roster, req('openwop.it.agent-roster-shape.the-capabilities-schema-declares-agents-roster-with-its-sub-flags', 'capabilities.md §agents', 'agents.roster MUST be declared')).toBeDefined();
52
50
  for (const flag of ['supported', 'installScope', 'portfolioTriggerSources']) {
53
- expect(roster?.properties?.[flag], why('agent-roster.md §F', `agents.roster.${flag} MUST be declared`)).toBeDefined();
51
+ expect(roster?.properties?.[flag], req('openwop.it.agent-roster-shape.the-capabilities-schema-declares-agents-roster-with-its-sub-flags', 'agent-roster.md §F', `agents.roster.${flag} MUST be declared`)).toBeDefined();
54
52
  }
55
53
  });
56
54
  });
@@ -69,7 +67,7 @@ describe('agent-roster-shape: roster entry (RFC 0086 §A, server-free)', () => {
69
67
  owner: { tenantId: 'acme', workspaceId: 'growth' },
70
68
  enabled: true,
71
69
  };
72
- expect(entry(good), why('RFC 0086 §A', 'a conforming roster entry MUST validate')).toBe(true);
70
+ expect(entry(good), req('openwop.it.agent-roster-shape.agentrosterentry-validates-a-conforming-entry', 'RFC 0086 §A', 'a conforming roster entry MUST validate')).toBe(true);
73
71
  });
74
72
 
75
73
  it('rejects a non-host: rosterId and an agentRef carrying both version and channel', () => {
@@ -79,12 +77,12 @@ describe('agent-roster-shape: roster entry (RFC 0086 §A, server-free)', () => {
79
77
  agentRef: { agentId: 'core.openwop.agents.brief-writer' },
80
78
  owner: { tenantId: 'acme' },
81
79
  };
82
- expect(entry({ ...base, rosterId: 'core.openwop.agents.sally' }), why('RFC 0086 §A', 'a non-`host:` rosterId MUST be rejected')).toBe(false);
80
+ expect(entry({ ...base, rosterId: 'core.openwop.agents.sally' }), req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0086 §A', 'a non-`host:` rosterId MUST be rejected')).toBe(false);
83
81
  expect(
84
82
  entry({ ...base, agentRef: { agentId: 'core.x.y.z', version: '1.0.0', channel: 'stable' } }),
85
- why('RFC 0082 §A', 'an agentRef with BOTH version and channel MUST be rejected'),
83
+ req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0082 §A', 'an agentRef with BOTH version and channel MUST be rejected'),
86
84
  ).toBe(false);
87
- expect(entry({ persona: 'x', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }), why('RFC 0086 §A', 'a roster entry without rosterId MUST be rejected')).toBe(false);
85
+ expect(entry({ persona: 'x', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }), req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0086 §A', 'a roster entry without rosterId MUST be rejected')).toBe(false);
88
86
  });
89
87
  });
90
88
 
@@ -96,23 +94,23 @@ describe('agent-roster-shape: roster.run.initiated event (RFC 0086 §C, server-f
96
94
  const initiated = ajv.getSchema('payloads#/$defs/rosterRunInitiated');
97
95
 
98
96
  it('roster.run.initiated validates a content-free attribution record and requires its ids', () => {
99
- expect(initiated, 'the rosterRunInitiated $def MUST exist').toBeTruthy();
97
+ expect(initiated, req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086', 'the rosterRunInitiated $def MUST exist')).toBeTruthy();
100
98
  expect(
101
99
  initiated!({ rosterId: 'host:sally-marketing', persona: 'Sally', agentId: 'core.openwop.agents.brief-writer', workflowId: 'marketing-email-campaign', triggerSource: 'schedule' }),
102
- why('RFC 0086 §C', 'a conforming roster.run.initiated payload MUST validate'),
100
+ req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086 §C', 'a conforming roster.run.initiated payload MUST validate'),
103
101
  ).toBe(true);
104
- expect(initiated!({ rosterId: 'host:s', persona: 'S' }), why('RFC 0086 §C', 'roster.run.initiated without agentId/workflowId/triggerSource MUST be rejected')).toBe(false);
102
+ expect(initiated!({ rosterId: 'host:s', persona: 'S' }), req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086 §C', 'roster.run.initiated without agentId/workflowId/triggerSource MUST be rejected')).toBe(false);
105
103
  });
106
104
 
107
105
  it('roster.run.initiated is content-free — a work-item body and a prompt are rejected (roster-attribution-no-content)', () => {
108
106
  const base = { rosterId: 'host:s', persona: 'S', agentId: 'a.b.c.d', workflowId: 'wf', triggerSource: 'queue' };
109
107
  expect(
110
108
  initiated!({ ...base, body: 'the card description' }),
111
- why('SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry the work-item body'),
109
+ req('openwop.it.agent-roster-shape.roster-run-initiated-is-content-free-a-work-item-body-and-a-prompt-are-rejected', 'SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry the work-item body'),
112
110
  ).toBe(false);
113
111
  expect(
114
112
  initiated!({ ...base, prompt: 'system: …' }),
115
- why('SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry prompt content'),
113
+ req('openwop.it.agent-roster-shape.roster-run-initiated-is-content-free-a-work-item-body-and-a-prompt-are-rejected', 'SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry prompt content'),
116
114
  ).toBe(false);
117
115
  });
118
116
  });
@@ -121,13 +119,13 @@ describe('agent-roster-shape: inventory projection + enum (RFC 0086 §B, server-
121
119
  it('AgentInventoryEntry carries the additive optional roster portfolio projection', () => {
122
120
  const inv = loadSchema('agent-inventory-response.schema.json');
123
121
  const entry = (inv.$defs as Record<string, { properties?: Record<string, unknown> }>).AgentInventoryEntry?.properties ?? {};
124
- expect(entry.roster, why('RFC 0086 §B', 'AgentInventoryEntry.roster (the portfolio projection) MUST be declared')).toBeDefined();
122
+ expect(entry.roster, req('openwop.it.agent-roster-shape.agentinventoryentry-carries-the-additive-optional-roster-portfolio-projection', 'RFC 0086 §B', 'AgentInventoryEntry.roster (the portfolio projection) MUST be declared')).toBeDefined();
125
123
  });
126
124
 
127
125
  it('roster.run.initiated appears in the RunEventType enum', () => {
128
126
  const runEvent = loadSchema('run-event.schema.json');
129
127
  const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
130
- expect(enumVals).toContain('roster.run.initiated');
128
+ expect(enumVals, req('openwop.it.agent-roster-shape.roster-run-initiated-appears-in-the-runeventtype-enum', 'RFC 0086', 'roster.run.initiated appears in the RunEventType enum')).toContain('roster.run.initiated');
131
129
  });
132
130
 
133
131
  it('the GET /v1/agents/roster response schema validates + rejects extras (RFC 0086 §B)', () => {
@@ -139,8 +137,8 @@ describe('agent-roster-shape: inventory projection + enum (RFC 0086 §B, server-
139
137
  roster: [{ rosterId: 'host:sally', persona: 'Sally', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }],
140
138
  total: 1,
141
139
  };
142
- expect(resp(good), why('RFC 0086 §B', 'a conforming GET /v1/agents/roster response MUST validate')).toBe(true);
143
- expect(resp({ ...good, unexpected: true }), why('RFC 0086 §B', 'an extra top-level property MUST be rejected')).toBe(false);
144
- expect(resp({ roster: [] }), why('RFC 0086 §B', 'the response MUST require `total`')).toBe(false);
140
+ expect(resp(good), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'a conforming GET /v1/agents/roster response MUST validate')).toBe(true);
141
+ expect(resp({ ...good, unexpected: true }), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'an extra top-level property MUST be rejected')).toBe(false);
142
+ expect(resp({ roster: [] }), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'the response MUST require `total`')).toBe(false);
145
143
  });
146
144
  });
@@ -25,9 +25,9 @@ import { join } from 'node:path';
25
25
  import Ajv2020 from 'ajv/dist/2020.js';
26
26
  import addFormats from 'ajv-formats';
27
27
  import { SCHEMAS_DIR } from '../lib/paths.js';
28
+ import { req } from '../lib/requirement-ids.js';
28
29
 
29
30
  const BASE = 'https://openwop.dev/spec/v1/';
30
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
31
31
  function loadSchema(name: string): Record<string, unknown> {
32
32
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
33
33
  }
@@ -52,21 +52,21 @@ describe('agent-verifier-shape: agent.verified payload (RFC 0090 §A, server-fre
52
52
  const verified = ajv.getSchema(`${BASE}run-event-payloads.schema.json#/$defs/agentVerified`);
53
53
 
54
54
  it('a conforming content-free verdict validates', () => {
55
- expect(verified, 'the agentVerified $def MUST exist').toBeTruthy();
55
+ expect(verified, req('openwop.it.agent-verifier-shape.a-conforming-content-free-verdict-validates', 'RFC 0090', 'the agentVerified $def MUST exist')).toBeTruthy();
56
56
  expect(
57
57
  verified!({ agentId: 'core.openwop.verifier', target: 'evt-42', verdict: 'pass', criteria: ['grounded'], confidence: 0.9 }),
58
- why('RFC 0090 §A', 'a conforming agent.verified payload MUST validate'),
58
+ req('openwop.it.agent-verifier-shape.a-conforming-content-free-verdict-validates', 'RFC 0090 §A', 'a conforming agent.verified payload MUST validate'),
59
59
  ).toBe(true);
60
60
  });
61
61
 
62
62
  it('rejects an out-of-enum verdict', () => {
63
- expect(verified!({ agentId: 'c', target: 'e', verdict: 'ok' }), why('RFC 0090 §A', 'verdict MUST be pass|fail|revise')).toBe(false);
63
+ expect(verified!({ agentId: 'c', target: 'e', verdict: 'ok' }), req('openwop.it.agent-verifier-shape.rejects-an-out-of-enum-verdict', 'RFC 0090 §A', 'verdict MUST be pass|fail|revise')).toBe(false);
64
64
  });
65
65
 
66
66
  it('rejects a content-carrying payload (verifier-no-content-leak)', () => {
67
67
  expect(
68
68
  verified!({ agentId: 'c', target: 'e', verdict: 'fail', result: 'the secret answer' }),
69
- why('RFC 0090 §SECURITY', 'agent.verified MUST be content-free (additionalProperties:false)'),
69
+ req('openwop.it.agent-verifier-shape.rejects-a-content-carrying-payload-verifier-no-content-leak', 'RFC 0090 §SECURITY', 'agent.verified MUST be content-free (additionalProperties:false)'),
70
70
  ).toBe(false);
71
71
  });
72
72
  });
@@ -78,7 +78,7 @@ describe('agent-verifier-shape: RunEventType + terminate + capability (RFC 0090)
78
78
  const runEvent = loadSchema('run-event.schema.json') as { $defs?: { RunEventType?: { enum?: string[] } } };
79
79
  expect(
80
80
  runEvent.$defs?.RunEventType?.enum?.includes('agent.verified'),
81
- why('RFC 0090 §A', 'agent.verified MUST appear in the RunEventType enum'),
81
+ req('openwop.it.agent-verifier-shape.agent-verified-is-registered-in-the-runeventtype-enum', 'RFC 0090 §A', 'agent.verified MUST appear in the RunEventType enum'),
82
82
  ).toBe(true);
83
83
  });
84
84
 
@@ -86,21 +86,21 @@ describe('agent-verifier-shape: RunEventType + terminate + capability (RFC 0090)
86
86
  const decision = ajv.getSchema(`${BASE}orchestrator-decision.schema.json`)!;
87
87
  expect(
88
88
  decision({ kind: 'terminate', reason: 'goal-reached', successCriteria: [{ key: 'goal-answered', met: true }] }),
89
- why('RFC 0090 §C', 'terminate MUST accept successCriteria[{key,met}]'),
89
+ req('openwop.it.agent-verifier-shape.the-terminate-decision-accepts-the-additive-successcriteria', 'RFC 0090 §C', 'terminate MUST accept successCriteria[{key,met}]'),
90
90
  ).toBe(true);
91
91
  expect(
92
92
  decision({ kind: 'terminate', successCriteria: [{ key: 'x' }] }),
93
- why('RFC 0090 §C', 'a successCriteria entry MUST require both key and met'),
93
+ req('openwop.it.agent-verifier-shape.the-terminate-decision-accepts-the-additive-successcriteria', 'RFC 0090 §C', 'a successCriteria entry MUST require both key and met'),
94
94
  ).toBe(false);
95
95
  });
96
96
 
97
97
  it('capabilities accepts executionModel.version 6 + verifier sub-block', () => {
98
98
  const execModel = ajv.getSchema(`${BASE}capabilities.schema.json#/properties/multiAgent/properties/executionModel`);
99
- expect(execModel, 'the executionModel sub-schema MUST exist').toBeTruthy();
99
+ expect(execModel, req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090', 'the executionModel sub-schema MUST exist')).toBeTruthy();
100
100
  expect(
101
101
  execModel!({ supported: true, version: 6, verifier: { supported: true, gating: true } }),
102
- why('RFC 0090 §D', 'version:6 + verifier{supported,gating} MUST validate'),
102
+ req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090 §D', 'version:6 + verifier{supported,gating} MUST validate'),
103
103
  ).toBe(true);
104
- expect(execModel!({ supported: true, version: 7 }), why('RFC 0090 §D', 'version above the ceiling MUST be rejected')).toBe(false);
104
+ expect(execModel!({ supported: true, version: 7 }), req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090 §D', 'version above the ceiling MUST be rejected')).toBe(false);
105
105
  });
106
106
  });
@@ -21,6 +21,7 @@ import { describe, it, expect } from 'vitest';
21
21
  import { driver } from '../lib/driver.js';
22
22
  import { isFixtureAdvertised } from '../lib/fixtures.js';
23
23
  import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
24
+ import { req } from '../lib/requirement-ids.js';
24
25
 
25
26
  const FIXTURE = 'conformance-agent-low-confidence';
26
27
  const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
@@ -51,7 +52,7 @@ describe.skipIf(SKIP)('agentConfidenceEscalation: confidence < threshold → low
51
52
  const lowConfSuspend = list.find(
52
53
  (e) => e.type === 'node.suspended' && e.payload?.reason === 'low-confidence',
53
54
  );
54
- expect(lowConfSuspend, 'CP-1: low-confidence agent.decided MUST emit node.suspended { reason: low-confidence }').toBeDefined();
55
+ expect(lowConfSuspend, req('openwop.it.agentConfidenceEscalation.low-confidence-agent-decided-suspends-with-reason-low-confidence-and-run-reaches', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'CP-1: low-confidence agent.decided MUST emit node.suspended { reason: low-confidence }')).toBeDefined();
55
56
 
56
57
  const payload = lowConfSuspend!.payload as Record<string, unknown>;
57
58
  expect(typeof payload.agentId).toBe('string');
@@ -20,6 +20,7 @@ import { driver } from '../lib/driver.js';
20
20
  import { pollUntilTerminal } from '../lib/polling.js';
21
21
  import { isFixtureAdvertised } from '../lib/fixtures.js';
22
22
  import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
23
+ import { req } from '../lib/requirement-ids.js';
23
24
 
24
25
  const FIXTURE = 'conformance-agent-memory-cross-tenant';
25
26
  const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
@@ -50,13 +51,13 @@ describe.skipIf(SKIP)('agentMemoryCrossTenantIsolation: CTI-1 invariant', () =>
50
51
  const ownerProbe = vars.ownerProbe;
51
52
  expect(
52
53
  Array.isArray(ownerProbe) && ownerProbe.length > 0,
53
- driver.describe('agent-memory.md §CTI-1 / fixtures.md conformance-agent-memory-cross-tenant', 'ownerProbe MUST be a NON-EMPTY array — the run\'s own tenant can read the entry it just wrote (positive control; an unset or empty ownerProbe means the probe never ran)'),
54
+ req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1 / fixtures.md conformance-agent-memory-cross-tenant', 'ownerProbe MUST be a NON-EMPTY array — the run\'s own tenant can read the entry it just wrote (positive control; an unset or empty ownerProbe means the probe never ran)'),
54
55
  ).toBe(true);
55
56
  const ownerEntryId = vars.ownerEntryId;
56
57
  if (typeof ownerEntryId === 'string' && ownerEntryId.length > 0) {
57
58
  expect(
58
59
  (ownerProbe as Array<{ id?: unknown }>).some((e) => e && typeof e === 'object' && e.id === ownerEntryId),
59
- driver.describe('agent-memory.md §CTI-1', `ownerProbe MUST contain the entry the host reports writing (ownerEntryId=${ownerEntryId})`),
60
+ req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', `ownerProbe MUST contain the entry the host reports writing (ownerEntryId=${ownerEntryId})`),
60
61
  ).toBe(true);
61
62
  }
62
63
 
@@ -65,12 +66,12 @@ describe.skipIf(SKIP)('agentMemoryCrossTenantIsolation: CTI-1 invariant', () =>
65
66
  const crossTenantResult = vars.crossTenantProbe;
66
67
  expect(
67
68
  crossTenantResult !== undefined,
68
- driver.describe('agent-memory.md §CTI-1', 'crossTenantProbe MUST be set — an unset variable means the cross-tenant probe was never issued, which proves nothing'),
69
+ req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'crossTenantProbe MUST be set — an unset variable means the cross-tenant probe was never issued, which proves nothing'),
69
70
  ).toBe(true);
70
71
  if (Array.isArray(crossTenantResult)) {
71
- expect(crossTenantResult.length, driver.describe('agent-memory.md §CTI-1', 'a cross-tenant memoryRef probe MUST return [] — no entries of another tenant')).toBe(0);
72
+ expect(crossTenantResult.length, req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'a cross-tenant memoryRef probe MUST return [] — no entries of another tenant')).toBe(0);
72
73
  } else {
73
- expect(crossTenantResult, driver.describe('agent-memory.md §CTI-1', 'a non-array cross-tenant probe result MUST be null')).toBeNull();
74
+ expect(crossTenantResult, req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'a non-array cross-tenant probe result MUST be null')).toBeNull();
74
75
  }
75
76
  }
76
77
  });
@@ -20,6 +20,7 @@ import { driver } from '../lib/driver.js';
20
20
  import { pollUntilTerminal } from '../lib/polling.js';
21
21
  import { isFixtureAdvertised } from '../lib/fixtures.js';
22
22
  import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
23
+ import { req } from '../lib/requirement-ids.js';
23
24
 
24
25
  const FIXTURE = 'conformance-agent-memory-redaction';
25
26
  const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
@@ -27,7 +28,7 @@ const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
27
28
  describe.skipIf(SKIP)('agentMemoryRedactionContract: SR-1 invariant', () => {
28
29
  it('BYOK plaintext is redacted to [REDACTED:<secretId>] at the read surface', async () => {
29
30
  const create = await driver.post('/v1/runs', { workflowId: FIXTURE });
30
- expect(create.status).toBe(201);
31
+ expect(create.status, req('openwop.it.agentMemoryRedactionContract.byok-plaintext-is-redacted-to-redacted-secretid-at-the-read-surface', 'RFCS/0004-memory-layer.md', 'BYOK plaintext is redacted to [REDACTED:<secretId>] at the read surface')).toBe(201);
31
32
  const runId = (create.json as { runId: string }).runId;
32
33
 
33
34
  const terminal = await pollUntilTerminal(runId);
@@ -19,6 +19,7 @@ import { driver } from '../lib/driver.js';
19
19
  import { pollUntilTerminal } from '../lib/polling.js';
20
20
  import { isFixtureAdvertised } from '../lib/fixtures.js';
21
21
  import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
22
+ import { req } from '../lib/requirement-ids.js';
22
23
 
23
24
  const FIXTURE = 'conformance-agent-memory-roundtrip';
24
25
  const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
@@ -26,7 +27,7 @@ const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
26
27
  describe.skipIf(SKIP)('agentMemoryRoundTrip: write → read via MemoryAdapter', () => {
27
28
  it('memory entries written during a run are readable via the resolved memoryRef', async () => {
28
29
  const create = await driver.post('/v1/runs', { workflowId: FIXTURE });
29
- expect(create.status).toBe(201);
30
+ expect(create.status, req('openwop.it.agentMemoryRoundTrip.memory-entries-written-during-a-run-are-readable-via-the-resolved-memoryref', 'RFCS/0004-memory-layer.md', 'memory entries written during a run are readable via the resolved memoryRef')).toBe(201);
30
31
  const runId = (create.json as { runId: string }).runId;
31
32
 
32
33
  const terminal = await pollUntilTerminal(runId);
@@ -18,6 +18,7 @@ import { driver } from '../lib/driver.js';
18
18
  import { pollUntilTerminal } from '../lib/polling.js';
19
19
  import { isFixtureAdvertised } from '../lib/fixtures.js';
20
20
  import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
21
+ import { req } from '../lib/requirement-ids.js';
21
22
 
22
23
  const FIXTURE = 'conformance-agent-memory-ttl';
23
24
  const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
@@ -52,15 +53,15 @@ describe.skipIf(SKIP)('agentMemoryTtlExpiry: expired entries are excluded from l
52
53
  const expiredId = body.variables?.expiredId;
53
54
  expect(
54
55
  typeof freshId === 'string' && freshId.length > 0 && typeof expiredId === 'string' && expiredId.length > 0,
55
- driver.describe('fixtures.md conformance-agent-memory-ttl', 'the host MUST land freshId and expiredId (the ids of the two entries it wrote) so the list can be checked on both sides'),
56
+ req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'fixtures.md conformance-agent-memory-ttl', 'the host MUST land freshId and expiredId (the ids of the two entries it wrote) so the list can be checked on both sides'),
56
57
  ).toBe(true);
57
58
  expect(
58
59
  listResult!.some((e) => e.id === freshId),
59
- driver.describe('agent-memory.md §TTL', `list() MUST include the fresh entry (freshId=${String(freshId)})`),
60
+ req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'agent-memory.md §TTL', `list() MUST include the fresh entry (freshId=${String(freshId)})`),
60
61
  ).toBe(true);
61
62
  expect(
62
63
  listResult!.some((e) => e.id === expiredId),
63
- driver.describe('agent-memory.md §TTL', `list() MUST NOT include the expired entry (expiredId=${String(expiredId)})`),
64
+ req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'agent-memory.md §TTL', `list() MUST NOT include the expired entry (expiredId=${String(expiredId)})`),
64
65
  ).toBe(false);
65
66
  });
66
67
  });
@@ -23,6 +23,7 @@ import { driver } from '../lib/driver.js';
23
23
  import { pollUntilTerminal } from '../lib/polling.js';
24
24
  import { isFixtureAdvertised } from '../lib/fixtures.js';
25
25
  import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
26
+ import { req } from '../lib/requirement-ids.js';
26
27
 
27
28
  const FIXTURE = 'conformance-message-reducer';
28
29
  const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
@@ -44,7 +45,7 @@ describe.skipIf(SKIP)('agentMessageReducer: message reducer idempotency + append
44
45
  // fixture convention is `conversation` or `messages`).
45
46
  const channelEntries = Object.entries(body.channels ?? {});
46
47
  const messageChannel = channelEntries.find(([, val]) => Array.isArray(val));
47
- expect(messageChannel, 'fixture MUST expose at least one message-reducer channel').toBeDefined();
48
+ expect(messageChannel, req('openwop.it.agentMessageReducer.duplicate-messageid-emissions-fold-to-a-single-channel-entry', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'fixture MUST expose at least one message-reducer channel')).toBeDefined();
48
49
 
49
50
  const messages = messageChannel![1] as Array<{ messageId?: string }>;
50
51
  const messageIds = messages
@@ -23,6 +23,7 @@ import { driver } from '../lib/driver.js';
23
23
  import { pollUntilTerminal } from '../lib/polling.js';
24
24
  import { isFixtureAdvertised } from '../lib/fixtures.js';
25
25
  import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
26
+ import { req } from '../lib/requirement-ids.js';
26
27
 
27
28
  const FIXTURE = 'conformance-agent-identity';
28
29
  const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
@@ -44,7 +45,7 @@ describe.skipIf(SKIP)('agentMetadata: RunSnapshot.agent + runOrchestrator wire-s
44
45
  const hasOrch = body.runOrchestrator && typeof body.runOrchestrator.agentId === 'string';
45
46
  expect(
46
47
  hasAgent || hasOrch,
47
- 'fixture-runs MUST populate at least one of RunSnapshot.agent / runOrchestrator',
48
+ req('openwop.it.agentMetadata.host-populates-agentref-shaped-agent-identity-on-runsnapshot', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'fixture-runs MUST populate at least one of RunSnapshot.agent / runOrchestrator'),
48
49
  ).toBe(true);
49
50
 
50
51
  if (hasAgent) {