@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
@@ -32,11 +32,9 @@ import { join } from 'node:path';
32
32
  import Ajv2020 from 'ajv/dist/2020.js';
33
33
  import addFormats from 'ajv-formats';
34
34
  import { SCHEMAS_DIR } from '../lib/paths.js';
35
- import { driver } from '../lib/driver.js';
36
35
  import { behaviorGate } from '../lib/behavior-gate.js';
37
36
  import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
38
-
39
- const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
37
+ import { req } from '../lib/requirement-ids.js';
40
38
  function loadSchema(name: string): Record<string, unknown> {
41
39
  return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
42
40
  }
@@ -90,12 +88,12 @@ describe('localized-content: capability advertisement shape (localized-content.m
90
88
  it('capabilities schema declares content with its required fields', () => {
91
89
  const caps = loadSchema('capabilities.schema.json');
92
90
  const content = (caps.properties as Record<string, { required?: string[]; properties?: Record<string, unknown> }>).content;
93
- expect(content, why('capabilities.schema.json §content', 'the content block MUST be declared')).toBeDefined();
94
- expect(content?.required, why('localized-content.md §A', 'supported + baseLocale + supportedLocales MUST be required')).toEqual(
91
+ expect(content, req('openwop.it.localized-content-delivery.capabilities-schema-declares-content-with-its-required-fields', 'capabilities.schema.json §content', 'the content block MUST be declared')).toBeDefined();
92
+ expect(content?.required, req('openwop.it.localized-content-delivery.capabilities-schema-declares-content-with-its-required-fields', 'localized-content.md §A', 'supported + baseLocale + supportedLocales MUST be required')).toEqual(
95
93
  expect.arrayContaining(['supported', 'baseLocale', 'supportedLocales']),
96
94
  );
97
95
  for (const f of ['supported', 'baseLocale', 'supportedLocales']) {
98
- expect(content?.properties?.[f], why('localized-content.md §A', `content.${f} MUST be declared`)).toBeDefined();
96
+ expect(content?.properties?.[f], req('openwop.it.localized-content-delivery.capabilities-schema-declares-content-with-its-required-fields', 'localized-content.md §A', `content.${f} MUST be declared`)).toBeDefined();
99
97
  }
100
98
  });
101
99
  });
@@ -119,29 +117,29 @@ describe('localized-content: schema shapes (localized-content.md §B, server-fre
119
117
  };
120
118
 
121
119
  it('a conforming section validates', () => {
122
- expect(section(goodSection), why('RFC 0103 §B', `a conforming section MUST validate. Errors: ${JSON.stringify(section.errors)}`)).toBe(true);
120
+ expect(section(goodSection), req('openwop.it.localized-content-delivery.a-conforming-section-validates', 'RFC 0103 §B', `a conforming section MUST validate. Errors: ${JSON.stringify(section.errors)}`)).toBe(true);
123
121
  });
124
122
  it('a localizations key with wrong case/underscore is rejected', () => {
125
- expect(section({ ...goodSection, localizations: { EN: { heading: 'x' } } }), why('RFC 0103 §B', 'a non-BCP-47-subset key MUST be rejected')).toBe(false);
126
- expect(section({ ...goodSection, localizations: { en_US: { heading: 'x' } } }), why('RFC 0103 §B', 'an underscore locale key MUST be rejected')).toBe(false);
123
+ expect(section({ ...goodSection, localizations: { EN: { heading: 'x' } } }), req('openwop.it.localized-content-delivery.a-localizations-key-with-wrong-case-underscore-is-rejected', 'RFC 0103 §B', 'a non-BCP-47-subset key MUST be rejected')).toBe(false);
124
+ expect(section({ ...goodSection, localizations: { en_US: { heading: 'x' } } }), req('openwop.it.localized-content-delivery.a-localizations-key-with-wrong-case-underscore-is-rejected', 'RFC 0103 §B', 'an underscore locale key MUST be rejected')).toBe(false);
127
125
  });
128
126
  it('a section missing a required field is rejected', () => {
129
127
  const { status: _omit, ...noStatus } = goodSection;
130
- expect(section(noStatus), why('RFC 0103 §B', 'status is REQUIRED')).toBe(false);
128
+ expect(section(noStatus), req('openwop.it.localized-content-delivery.a-section-missing-a-required-field-is-rejected', 'RFC 0103 §B', 'status is REQUIRED')).toBe(false);
131
129
  });
132
130
  it('a status outside the enum is rejected', () => {
133
- expect(section({ ...goodSection, status: 'archived' }), why('RFC 0103 §B', 'status MUST be draft|published')).toBe(false);
131
+ expect(section({ ...goodSection, status: 'archived' }), req('openwop.it.localized-content-delivery.a-status-outside-the-enum-is-rejected', 'RFC 0103 §B', 'status MUST be draft|published')).toBe(false);
134
132
  });
135
133
 
136
134
  it('a conforming page validates; a bad slug is rejected', () => {
137
135
  const goodPage = { pageId: 'home', slug: 'home', name: 'Home', status: 'published', sectionOrder: ['hero'] };
138
- expect(page(goodPage), why('RFC 0103 §B', `a conforming page MUST validate. Errors: ${JSON.stringify(page.errors)}`)).toBe(true);
139
- expect(page({ ...goodPage, slug: 'Home Page' }), why('RFC 0103 §B', 'slug MUST match ^[a-z][a-z0-9-]*$')).toBe(false);
136
+ expect(page(goodPage), req('openwop.it.localized-content-delivery.a-conforming-page-validates-a-bad-slug-is-rejected', 'RFC 0103 §B', `a conforming page MUST validate. Errors: ${JSON.stringify(page.errors)}`)).toBe(true);
137
+ expect(page({ ...goodPage, slug: 'Home Page' }), req('openwop.it.localized-content-delivery.a-conforming-page-validates-a-bad-slug-is-rejected', 'RFC 0103 §B', 'slug MUST match ^[a-z][a-z0-9-]*$')).toBe(false);
140
138
  });
141
139
 
142
140
  it('a conforming language-settings validates', () => {
143
141
  const good = { baseLocale: 'en', supportedLocales: ['es', 'pt-BR', 'fr'], autoTranslateOnPublish: false };
144
- expect(settings(good), why('RFC 0103 §B', `settings MUST validate. Errors: ${JSON.stringify(settings.errors)}`)).toBe(true);
142
+ expect(settings(good), req('openwop.it.localized-content-delivery.a-conforming-language-settings-validates', 'RFC 0103 §B', `settings MUST validate. Errors: ${JSON.stringify(settings.errors)}`)).toBe(true);
145
143
  });
146
144
 
147
145
  it('a conforming page-response validates', () => {
@@ -153,7 +151,7 @@ describe('localized-content: schema shapes (localized-content.md §B, server-fre
153
151
  page: { pageId: 'home', slug: 'home', name: 'Home' },
154
152
  sections: [{ sectionId: 'hero', sectionType: 'hero', data: { heading: 'Bem-vindo', cta: 'Get started' } }],
155
153
  };
156
- expect(response(good), why('RFC 0103 §D', `a resolved response MUST validate. Errors: ${JSON.stringify(response.errors)}`)).toBe(true);
154
+ expect(response(good), req('openwop.it.localized-content-delivery.a-conforming-page-response-validates', 'RFC 0103 §D', `a resolved response MUST validate. Errors: ${JSON.stringify(response.errors)}`)).toBe(true);
157
155
  });
158
156
  });
159
157
 
@@ -164,43 +162,43 @@ describe('localized-content: per-section field merge (localized-content.md §C,
164
162
  };
165
163
 
166
164
  it('exact-locale hit overrides matching fields', () => {
167
- expect(resolveSection(section, 'es', 'en'), why('RFC 0103 §C', 'exact hit MUST overlay locale fields onto data')).toEqual({
165
+ expect(resolveSection(section, 'es', 'en'), req('openwop.it.localized-content-delivery.exact-locale-hit-overrides-matching-fields', 'RFC 0103 §C', 'exact hit MUST overlay locale fields onto data')).toEqual({
168
166
  heading: 'Bienvenido',
169
167
  cta: 'Empezar',
170
168
  });
171
169
  });
172
170
  it('partial translation falls through to base for missing fields', () => {
173
- expect(resolveSection(section, 'pt-BR', 'en'), why('RFC 0103 §C', 'missing locale fields MUST fall through to data')).toEqual({
171
+ expect(resolveSection(section, 'pt-BR', 'en'), req('openwop.it.localized-content-delivery.partial-translation-falls-through-to-base-for-missing-fields', 'RFC 0103 §C', 'missing locale fields MUST fall through to data')).toEqual({
174
172
  heading: 'Bem-vindo',
175
173
  cta: 'Get started',
176
174
  });
177
175
  });
178
176
  it('language-family fallback applies when exact tag is absent', () => {
179
177
  const s: Section = { data: { h: 'Hi' }, localizations: { pt: { h: 'Oi' } } };
180
- expect(resolveSection(s, 'pt-BR', 'en'), why('RFC 0103 §C', 'pt-BR MUST fall back to the pt family override')).toEqual({ h: 'Oi' });
178
+ expect(resolveSection(s, 'pt-BR', 'en'), req('openwop.it.localized-content-delivery.language-family-fallback-applies-when-exact-tag-is-absent', 'RFC 0103 §C', 'pt-BR MUST fall back to the pt family override')).toEqual({ h: 'Oi' });
181
179
  });
182
180
  it('unsupported/base locale returns base data unchanged', () => {
183
- expect(resolveSection(section, 'de', 'en'), why('RFC 0103 §C', 'no match MUST return base data')).toEqual(section.data);
184
- expect(resolveSection(section, 'en', 'en'), why('RFC 0103 §C', 'base locale MUST return base data')).toEqual(section.data);
181
+ expect(resolveSection(section, 'de', 'en'), req('openwop.it.localized-content-delivery.unsupported-base-locale-returns-base-data-unchanged', 'RFC 0103 §C', 'no match MUST return base data')).toEqual(section.data);
182
+ expect(resolveSection(section, 'en', 'en'), req('openwop.it.localized-content-delivery.unsupported-base-locale-returns-base-data-unchanged', 'RFC 0103 §C', 'base locale MUST return base data')).toEqual(section.data);
185
183
  });
186
184
  });
187
185
 
188
186
  describe('localized-content: §A capability coherence predicate (server-free)', () => {
189
187
  const i18n: I18nCap = { supported: true, defaultLocale: 'en', supportedLocales: ['en', 'es', 'pt-BR', 'fr'] };
190
188
  it('a coherent advertisement passes', () => {
191
- expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['es', 'pt-BR', 'fr'] }, i18n), why('RFC 0103 §A', 'a coherent content block MUST pass')).toBe(true);
189
+ expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['es', 'pt-BR', 'fr'] }, i18n), req('openwop.it.localized-content-delivery.a-coherent-advertisement-passes', 'RFC 0103 §A', 'a coherent content block MUST pass')).toBe(true);
192
190
  });
193
191
  it('content without i18n is incoherent', () => {
194
- expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['es'] }, { supported: false }), why('RFC 0103 §A.1', 'content requires i18n.supported')).toBe(false);
192
+ expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['es'] }, { supported: false }), req('openwop.it.localized-content-delivery.content-without-i18n-is-incoherent', 'RFC 0103 §A.1', 'content requires i18n.supported')).toBe(false);
195
193
  });
196
194
  it('baseLocale != i18n.defaultLocale is incoherent', () => {
197
- expect(contentCoherent({ supported: true, baseLocale: 'es', supportedLocales: ['fr'] }, i18n), why('RFC 0103 §A.2', 'baseLocale MUST equal i18n.defaultLocale')).toBe(false);
195
+ expect(contentCoherent({ supported: true, baseLocale: 'es', supportedLocales: ['fr'] }, i18n), req('openwop.it.localized-content-delivery.baselocale-i18n-defaultlocale-is-incoherent', 'RFC 0103 §A.2', 'baseLocale MUST equal i18n.defaultLocale')).toBe(false);
198
196
  });
199
197
  it('a supportedLocales not ⊆ i18n.supportedLocales is incoherent', () => {
200
- expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['de'] }, i18n), why('RFC 0103 §A.3', 'content locales MUST be a subset of i18n locales')).toBe(false);
198
+ expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['de'] }, i18n), req('openwop.it.localized-content-delivery.a-supportedlocales-not-i18n-supportedlocales-is-incoherent', 'RFC 0103 §A.3', 'content locales MUST be a subset of i18n locales')).toBe(false);
201
199
  });
202
200
  it('baseLocale appearing in supportedLocales is incoherent', () => {
203
- expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['en', 'es'] }, i18n), why('RFC 0103 §A.4', 'baseLocale MUST NOT appear in supportedLocales')).toBe(false);
201
+ expect(contentCoherent({ supported: true, baseLocale: 'en', supportedLocales: ['en', 'es'] }, i18n), req('openwop.it.localized-content-delivery.baselocale-appearing-in-supportedlocales-is-incoherent', 'RFC 0103 §A.4', 'baseLocale MUST NOT appear in supportedLocales')).toBe(false);
204
202
  });
205
203
  });
206
204
 
@@ -215,7 +213,7 @@ describe.skipIf(HTTP_SKIP)('localized-content: live advertisement coherence (loc
215
213
  const i18n = (await readCapabilityFamily<I18nCap>('i18n')) ?? {};
216
214
  expect(
217
215
  contentCoherent(content!, i18n),
218
- driver.describe('localized-content.md §A', 'the advertised content block MUST satisfy the i18n-subset + baseLocale invariants'),
216
+ req('openwop.it.localized-content-delivery.advertised-content-block-is-coherent-with-the-advertised-i18n-block', 'localized-content.md §A', 'the advertised content block MUST satisfy the i18n-subset + baseLocale invariants'),
219
217
  ).toBe(true);
220
218
  });
221
219
  });
@@ -35,6 +35,8 @@
35
35
 
36
36
  import { describe, it, expect } from 'vitest';
37
37
  import { driver } from '../lib/driver.js';
38
+ import { req } from '../lib/requirement-ids.js';
39
+ import { softSkip } from '../lib/soft-skip.js';
38
40
 
39
41
  interface RegistryProbe {
40
42
  available: boolean;
@@ -57,7 +59,7 @@ async function probeRegistry(): Promise<RegistryProbe> {
57
59
  describe('malicious-manifest: pack-name validation per spec/v1/node-packs.md §Naming', () => {
58
60
  it('GET /v1/packs/{bad-name}/-/{version}.json returns 400 invalid_pack_name', async () => {
59
61
  const probe = await probeRegistry();
60
- if (!probe.available) return; // host doesn't claim openwop-node-packs
62
+ if (!probe.available) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!probe.available` returned early (host doesn\'t claim openwop-node-packs)'); // host doesn't claim openwop-node-packs
61
63
 
62
64
  // Bad name shapes the registry SHOULD reject:
63
65
  // - Reserved scope without authorization (`core.foo`)
@@ -71,7 +73,7 @@ describe('malicious-manifest: pack-name validation per spec/v1/node-packs.md §N
71
73
  );
72
74
  expect(
73
75
  [400, 404].includes(res.status),
74
- driver.describe(
76
+ req('openwop.it.maliciousManifest.get-v1-packs-bad-name-version-json-returns-400-invalid-pack-name',
75
77
  'spec/v1/node-packs.md §Registry HTTP API',
76
78
  `bad pack name "${badName}" MUST yield 400 (invalid_pack_name) or 404 (treated as unknown)`,
77
79
  ),
@@ -83,7 +85,7 @@ describe('malicious-manifest: pack-name validation per spec/v1/node-packs.md §N
83
85
  describe('malicious-manifest: version validation', () => {
84
86
  it('GET /v1/packs/{name}/-/{bad-version}.json returns 400 invalid_version', async () => {
85
87
  const probe = await probeRegistry();
86
- if (!probe.available) return;
88
+ if (!probe.available) return softSkip('blocked', 'precondition not met — `!probe.available` returned early (seam, prior step, or fixture unavailable)');
87
89
 
88
90
  const badVersions = ['not-semver', '1', '1.0.0', 'v1.0'];
89
91
 
@@ -93,7 +95,7 @@ describe('malicious-manifest: version validation', () => {
93
95
  );
94
96
  expect(
95
97
  [400, 404].includes(res.status),
96
- driver.describe(
98
+ req('openwop.it.maliciousManifest.get-v1-packs-name-bad-version-json-returns-400-invalid-version',
97
99
  'spec/v1/node-packs.md §Registry HTTP API',
98
100
  `bad version "${bad}" MUST yield 400 (invalid_version) or 404`,
99
101
  ),
@@ -105,10 +107,10 @@ describe('malicious-manifest: version validation', () => {
105
107
  describe('malicious-manifest: signature endpoint contract per openwop/openwop@434c8f2', () => {
106
108
  it('GET /v1/packs/{name}/-/{version}.sig of a non-existent pack returns 404 signature_not_available', async () => {
107
109
  const probe = await probeRegistry();
108
- if (!probe.available) return;
110
+ if (!probe.available) return softSkip('blocked', 'precondition not met — `!probe.available` returned early (seam, prior step, or fixture unavailable)');
109
111
 
110
112
  const res = await driver.get('/v1/packs/community.no-such-pack/-/1.0.sig');
111
- expect(res.status, driver.describe(
113
+ expect(res.status, req('openwop.it.maliciousManifest.get-v1-packs-name-version-sig-of-a-non-existent-pack-returns-404-signature-not-a',
112
114
  'spec/v1/node-packs.md §`GET .sig`',
113
115
  'missing/yanked/unsigned signature MUST return 404',
114
116
  )).toBe(404);
@@ -120,7 +122,7 @@ describe('malicious-manifest: signature endpoint contract per openwop/openwop@43
120
122
  // shape; the assertion is permissive on the error code itself
121
123
  // but strict on the status.
122
124
  if (typeof body.error === 'string') {
123
- expect(body.error.length, driver.describe(
125
+ expect(body.error.length, req('openwop.it.maliciousManifest.get-v1-packs-name-version-sig-of-a-non-existent-pack-returns-404-signature-not-a',
124
126
  'spec/v1/node-packs.md',
125
127
  '404 response MUST carry a structured error envelope with a non-empty error code',
126
128
  )).toBeGreaterThan(0);
@@ -146,7 +148,7 @@ describe('malicious-manifest: documented error catalog (per openwop/openwop@434c
146
148
  'tarball_path_traversal',
147
149
  'tarball_tar_parse_failed',
148
150
  ] as const;
149
- expect(TARBALL_ERRORS.length, driver.describe(
151
+ expect(TARBALL_ERRORS.length, req('openwop.it.maliciousManifest.lists-are-non-empty-sanity-check-on-doc-drift',
150
152
  'spec/v1/node-packs.md',
151
153
  'documented tarball-error catalog is non-empty',
152
154
  )).toBe(9);
@@ -30,6 +30,7 @@ import { mcpServerMount } from '../lib/mcp-mount.js';
30
30
  import { behaviorGate } from '../lib/behavior-gate.js';
31
31
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
32
32
  import { McpFakeServer, MCP_ERR } from '../lib/mcp-fake-server.js';
33
+ import { req } from '../lib/requirement-ids.js';
33
34
 
34
35
  // The first describe drives the in-process McpFakeServer itself; the second (gated) describe
35
36
  // talks to the host's own MCP server mount and hands it nothing harness-hosted.
@@ -58,7 +59,7 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
58
59
 
59
60
  it('server/discover: resultType complete, supportedVersions, capabilities, cache hints, _meta.serverInfo', async () => {
60
61
  const r = await call(server.endpoint(), 'server/discover', {}, { version: '2026-07-28', mcpMethod: 'server/discover' });
61
- expect(r.error).toBeUndefined();
62
+ expect(r.error, req('openwop.it.mcp-2026-07-28-discover.server-discover-resulttype-complete-supportedversions-capabilities-cache-hints-m', 'RFC 0153 §B', 'server/discover: resultType complete, supportedVersions, capabilities, cache hints, _meta.serverInfo')).toBeUndefined();
62
63
  expect(r.result?.['resultType']).toBe('complete');
63
64
  expect(r.result?.['supportedVersions']).toEqual(['2026-07-28', '2025-06-18']);
64
65
  expect(typeof r.result?.['ttlMs']).toBe('number');
@@ -68,13 +69,13 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
68
69
 
69
70
  it('a request without _meta.protocolVersion under the current revision is refused -32020', async () => {
70
71
  const r = await call(server.endpoint(), 'tools/list', {}, { version: '2026-07-28', withMeta: false });
71
- expect(r.status).toBe(400);
72
+ expect(r.status, req('openwop.it.mcp-2026-07-28-discover.a-request-without-meta-protocolversion-under-the-current-revision-is-refused-320', 'RFC 0153 §B', 'a request without _meta.protocolVersion under the current revision is refused -32020')).toBe(400);
72
73
  expect(r.error?.code).toBe(MCP_ERR.HEADER_MISMATCH);
73
74
  });
74
75
 
75
76
  it('header ≠ body revision ⇒ -32020 HeaderMismatch (400); Mcp-Method ≠ method ⇒ -32020', async () => {
76
77
  const r1 = await call(server.endpoint(), 'tools/list', { _meta: { [META_V]: '2025-11-25', [META_C]: {} } }, { version: '2026-07-28', withMeta: false });
77
- expect(r1.status).toBe(400);
78
+ expect(r1.status, req('openwop.it.mcp-2026-07-28-discover.header-body-revision-32020-headermismatch-400-mcp-method-method-32020', 'RFC 0153 §B', 'header ≠ body revision ⇒ -32020 HeaderMismatch (400); Mcp-Method ≠ method ⇒ -32020')).toBe(400);
78
79
  expect(r1.error?.code).toBe(MCP_ERR.HEADER_MISMATCH);
79
80
  const r2 = await call(server.endpoint(), 'tools/list', {}, { version: '2026-07-28', mcpMethod: 'tools/call' });
80
81
  expect(r2.error?.code).toBe(MCP_ERR.HEADER_MISMATCH);
@@ -82,7 +83,7 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
82
83
 
83
84
  it('an unsupported revision ⇒ -32022 UnsupportedProtocolVersion with data.supported[] (400)', async () => {
84
85
  const r = await call(server.endpoint(), 'tools/list', {}, { version: '1999-01-01' });
85
- expect(r.status).toBe(400);
86
+ expect(r.status, req('openwop.it.mcp-2026-07-28-discover.an-unsupported-revision-32022-unsupportedprotocolversion-with-data-supported-400', 'RFC 0153 §B', 'an unsupported revision ⇒ -32022 UnsupportedProtocolVersion with data.supported[] (400)')).toBe(400);
86
87
  expect(r.error?.code).toBe(MCP_ERR.UNSUPPORTED_PROTOCOL_VERSION);
87
88
  expect(r.error?.data?.['supported']).toEqual(['2026-07-28', '2025-06-18']);
88
89
  expect(r.error?.data?.['requested']).toBe('1999-01-01');
@@ -90,7 +91,7 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
90
91
 
91
92
  it('header-less ⇒ legacy semantics on a dual-era server (initialize works); ⇒ -32022 on a current-only server', async () => {
92
93
  const legacy = await call(server.endpoint(), 'initialize', { protocolVersion: '2025-06-18', capabilities: {}, clientInfo: { name: 'x', version: '0' } });
93
- expect(legacy.error).toBeUndefined();
94
+ expect(legacy.error, req('openwop.it.mcp-2026-07-28-discover.header-less-legacy-semantics-on-a-dual-era-server-initialize-works-32022-on-a-cu', 'RFC 0153 §B', 'header-less ⇒ legacy semantics on a dual-era server (initialize works); ⇒ -32022 on a current-only server')).toBeUndefined();
94
95
  expect(typeof legacy.result?.['protocolVersion']).toBe('string');
95
96
  const only = new McpFakeServer({ protocolVersions: ['2026-07-28'] });
96
97
  await only.start(0);
@@ -105,13 +106,13 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
105
106
 
106
107
  it('initialize under 2026-07-28 is method-not-found — the handshake does not exist in this revision', async () => {
107
108
  const r = await call(server.endpoint(), 'initialize', {}, { version: '2026-07-28' });
108
- expect(r.status).toBe(404);
109
+ expect(r.status, req('openwop.it.mcp-2026-07-28-discover.initialize-under-2026-07-28-is-method-not-found-the-handshake-does-not-exist-in', 'RFC 0153 §B', 'initialize under 2026-07-28 is method-not-found — the handshake does not exist in this revision')).toBe(404);
109
110
  expect(r.error?.code).toBe(-32601);
110
111
  });
111
112
 
112
113
  it('tools/list @2026-07-28 carries resultType + CacheableResult hints and lists the MRTR tool', async () => {
113
114
  const r = await call(server.endpoint(), 'tools/list', {}, { version: '2026-07-28', mcpMethod: 'tools/list' });
114
- expect(r.result?.['resultType']).toBe('complete');
115
+ expect(r.result?.['resultType'], req('openwop.it.mcp-2026-07-28-discover.tools-list-2026-07-28-carries-resulttype-cacheableresult-hints-and-lists-the-mrt', 'RFC 0153 §B', 'tools/list @2026-07-28 carries resultType + CacheableResult hints and lists the MRTR tool')).toBe('complete');
115
116
  expect(typeof r.result?.['ttlMs']).toBe('number');
116
117
  expect(r.result?.['cacheScope']).toBe('public');
117
118
  const names = (r.result?.['tools'] as Array<{ name: string }>).map((t) => t.name);
@@ -124,7 +125,7 @@ describe('RFC 0153 §B — the suite MCP server speaks 2026-07-28 (dual-era McpF
124
125
  it('MRTR: needs_input answers input_required (elicitation + opaque requestState) and completes on the retry; missing capability ⇒ -32021', async () => {
125
126
  server.reset();
126
127
  const noCap = await call(server.endpoint(), 'tools/call', { name: 'needs_input', arguments: {} }, { version: '2026-07-28', mcpMethod: 'tools/call', mcpName: 'needs_input' });
127
- expect(noCap.error?.code).toBe(MCP_ERR.MISSING_REQUIRED_CLIENT_CAPABILITY);
128
+ expect(noCap.error?.code, req('openwop.it.mcp-2026-07-28-discover.mrtr-needs-input-answers-input-required-elicitation-opaque-requeststate-and-comp', 'RFC 0153 §B', 'MRTR: needs_input answers input_required (elicitation + opaque requestState) and completes on the retry; missing capability ⇒ -32021')).toBe(MCP_ERR.MISSING_REQUIRED_CLIENT_CAPABILITY);
128
129
  expect(noCap.error?.data?.['requiredCapabilities']).toEqual(['elicitation']);
129
130
 
130
131
  const first = await call(server.endpoint(), 'tools/call', { name: 'needs_input', arguments: {}, _meta: { [META_C]: { elicitation: {} } } }, { version: '2026-07-28', mcpMethod: 'tools/call', mcpName: 'needs_input' });
@@ -182,10 +183,10 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §B — host as MCP ser
182
183
  const caps = (await mcp())!;
183
184
  const r = await hostRpc('server/discover', { _meta: { [META_V]: '2026-07-28', [META_C]: {} } }, { 'MCP-Protocol-Version': '2026-07-28', 'Mcp-Method': 'server/discover' });
184
185
  if (r.status === 404 || r.status === 403) return seamAbsent(`host advertises an MCP server mount but the mount (capabilities.mcp.serverUrls[0], else /v1/host/sample/mcp) answered ${r.status} — RFC 0153 §B is unobservable at the path the host itself advertised`);
185
- expect(r.status, driver.describe('mcp-integration.md §B', 'server/discover is a server MUST under 2026-07-28')).toBe(200);
186
+ expect(r.status, req('openwop.it.mcp-2026-07-28-discover.server-discover-reports-supportedversions-equal-to-capabilities-mcp-protocolvers', 'mcp-integration.md §B', 'server/discover is a server MUST under 2026-07-28')).toBe(200);
186
187
  expect(r.body.result?.['resultType']).toBe('complete');
187
- expect([...((r.body.result?.['supportedVersions'] as string[] | undefined) ?? [])].sort(), driver.describe('mcp-integration.md §B', 'server/discover.supportedVersions MUST equal capabilities.mcp.protocolVersions — two documents, one fact')).toEqual([...(caps.protocolVersions ?? [])].sort());
188
- expect(typeof r.body.result?.['ttlMs'], driver.describe('mcp-integration.md §D', 'server/discover is cacheable: ttlMs REQUIRED')).toBe('number');
188
+ expect([...((r.body.result?.['supportedVersions'] as string[] | undefined) ?? [])].sort(), req('openwop.it.mcp-2026-07-28-discover.server-discover-reports-supportedversions-equal-to-capabilities-mcp-protocolvers', 'mcp-integration.md §B', 'server/discover.supportedVersions MUST equal capabilities.mcp.protocolVersions — two documents, one fact')).toEqual([...(caps.protocolVersions ?? [])].sort());
189
+ expect(typeof r.body.result?.['ttlMs'], req('openwop.it.mcp-2026-07-28-discover.server-discover-reports-supportedversions-equal-to-capabilities-mcp-protocolvers', 'mcp-integration.md §D', 'server/discover is cacheable: ttlMs REQUIRED')).toBe('number');
189
190
  expect(['public', 'private']).toContain(r.body.result?.['cacheScope']);
190
191
  });
191
192
 
@@ -199,11 +200,11 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §B — host as MCP ser
199
200
  // (mcp-integration.md §B: agreement is checked before selection).
200
201
  const mismatch = await hostRpc('tools/list', { _meta: { [META_V]: '2025-06-18', [META_C]: {} } }, { 'MCP-Protocol-Version': '2026-07-28', 'Mcp-Method': 'tools/list' });
201
202
  if (mismatch.status === 404 || mismatch.status === 403) return seamAbsent(`host advertises an MCP server mount but the mount (capabilities.mcp.serverUrls[0], else /v1/host/sample/mcp) answered ${mismatch.status} — RFC 0153 §B is unobservable at the path the host itself advertised`);
202
- expect(mismatch.status, driver.describe('mcp-integration.md §B', 'header ≠ body MUST be refused 400 (HeaderMismatchError -32020) — fail closed')).toBe(400);
203
+ expect(mismatch.status, req('openwop.it.mcp-2026-07-28-discover.a-header-body-revision-mismatch-is-refused-400-32020-an-unsupported-revision-400', 'mcp-integration.md §B', 'header ≠ body MUST be refused 400 (HeaderMismatchError -32020) — fail closed')).toBe(400);
203
204
  expect(mismatch.body.error?.code).toBe(MCP_ERR.HEADER_MISMATCH);
204
205
  const unsupported = await hostRpc('tools/list', { _meta: { [META_V]: '1999-01-01', [META_C]: {} } }, { 'MCP-Protocol-Version': '1999-01-01', 'Mcp-Method': 'tools/list' });
205
- expect(unsupported.status, driver.describe('mcp-integration.md §B', 'an unsupported revision MUST be refused 400 (UnsupportedProtocolVersionError -32022)')).toBe(400);
206
+ expect(unsupported.status, req('openwop.it.mcp-2026-07-28-discover.a-header-body-revision-mismatch-is-refused-400-32020-an-unsupported-revision-400', 'mcp-integration.md §B', 'an unsupported revision MUST be refused 400 (UnsupportedProtocolVersionError -32022)')).toBe(400);
206
207
  expect(unsupported.body.error?.code).toBe(MCP_ERR.UNSUPPORTED_PROTOCOL_VERSION);
207
- expect(Array.isArray(unsupported.body.error?.data?.['supported']), driver.describe('mcp-integration.md §B', 'the refusal MUST list data.supported[]')).toBe(true);
208
+ expect(Array.isArray(unsupported.body.error?.data?.['supported']), req('openwop.it.mcp-2026-07-28-discover.a-header-body-revision-mismatch-is-refused-400-32020-an-unsupported-revision-400', 'mcp-integration.md §B', 'the refusal MUST list data.supported[]')).toBe(true);
208
209
  });
209
210
  });
@@ -22,10 +22,11 @@
22
22
 
23
23
  import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
- import { seamAbsent } from '../lib/soft-skip.js';
25
+ import { seamAbsent, softSkip } from '../lib/soft-skip.js';
26
26
  import { mcpServerMount } from '../lib/mcp-mount.js';
27
27
  import { behaviorGate } from '../lib/behavior-gate.js';
28
28
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
29
+ import { req } from '../lib/requirement-ids.js';
29
30
 
30
31
  const PROFILE = 'mcp-2026-07-28';
31
32
  const META_V = 'io.modelcontextprotocol/protocolVersion';
@@ -49,19 +50,19 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §D — mcp-cache-tenan
49
50
  if (!behaviorGate(PROFILE, await claimsCurrent())) return;
50
51
  const mine = await listAs();
51
52
  if (mine.status === 404 || mine.status === 403) return seamAbsent(`host advertises an MCP server mount but the mount (capabilities.mcp.serverUrls[0], else /v1/host/sample/mcp) answered ${mine.status} — RFC 0153 §B is unobservable at the path the host itself advertised`);
52
- expect(['public', 'private'], driver.describe('mcp-integration.md §D', 'cacheScope MUST be present on tools/list')).toContain(mine.body.result?.cacheScope);
53
+ expect(['public', 'private'], req('openwop.it.mcp-cache-tenant-scope.a-per-caller-list-is-cachescope-private-a-public-list-is-byte-identical-across-c', 'mcp-integration.md §D', 'cacheScope MUST be present on tools/list')).toContain(mine.body.result?.cacheScope);
53
54
  const other = process.env.OPENWOP_TEST_SECONDARY_API_KEY;
54
55
  if (!other) {
55
56
  // Shape only; the cross-caller half is unobservable without a second credential.
56
57
  // eslint-disable-next-line no-console
57
58
  console.warn('[mcp-cache-tenant-scope] OPENWOP_TEST_SECONDARY_API_KEY not set — cross-caller half not exercised (blocked)');
58
- return;
59
+ return softSkip('blocked', 'precondition not met — `!other` returned early ([mcp-cache-tenant-scope] OPENWOP_TEST_SECONDARY_API_KEY not set — cross-caller half not exercised (blocked)) (seam, prior step, or fixture unavailable)');
59
60
  }
60
61
  const theirs = await listAs(other);
61
- if (theirs.status !== 200) return;
62
+ if (theirs.status !== 200) return softSkip('blocked', 'precondition not met — `theirs.status !== 200` returned early (seam, prior step, or fixture unavailable)');
62
63
  const same = JSON.stringify(mine.body.result?.tools) === JSON.stringify(theirs.body.result?.tools);
63
64
  if (!same) {
64
- expect(mine.body.result?.cacheScope, driver.describe('mcp-integration.md §D', 'a list that differs per caller MUST be cacheScope private — a public list that differs is cross-context cache poisoning (mcp-cache-tenant-scoped)')).toBe('private');
65
+ expect(mine.body.result?.cacheScope, req('openwop.it.mcp-cache-tenant-scope.a-per-caller-list-is-cachescope-private-a-public-list-is-byte-identical-across-c', 'mcp-integration.md §D', 'a list that differs per caller MUST be cacheScope private — a public list that differs is cross-context cache poisoning (mcp-cache-tenant-scoped)')).toBe('private');
65
66
  expect(theirs.body.result?.cacheScope).toBe('private');
66
67
  }
67
68
  });
@@ -18,10 +18,11 @@
18
18
 
19
19
  import { describe, it, expect } from 'vitest';
20
20
  import { driver } from '../lib/driver.js';
21
- import { seamAbsent } from '../lib/soft-skip.js';
21
+ import { seamAbsent, softSkip } from '../lib/soft-skip.js';
22
22
  import { mcpServerMount } from '../lib/mcp-mount.js';
23
23
  import { behaviorGate } from '../lib/behavior-gate.js';
24
24
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
25
+ import { req } from '../lib/requirement-ids.js';
25
26
 
26
27
  const PROFILE = 'mcp-2026-07-28';
27
28
  const META_V = 'io.modelcontextprotocol/protocolVersion';
@@ -50,16 +51,16 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §E — mcp-current-aut
50
51
  if (!behaviorGate(PROFILE, claims)) return;
51
52
  const authed = await driver.post(await mcpServerMount(), REQ, { headers: HDR });
52
53
  if (authed.status === 404 || authed.status === 403) return seamAbsent(`host advertises an MCP server mount but the mount (capabilities.mcp.serverUrls[0], else /v1/host/sample/mcp) answered ${authed.status} — RFC 0153 §B is unobservable at the path the host itself advertised`);
53
- expect(authed.status, driver.describe('mcp-integration.md §E', 'the authenticated call MUST succeed at the same path, so a refusal below is not a wrong path')).toBe(200);
54
+ expect(authed.status, req('openwop.it.mcp-current-auth-boundary.an-unauthenticated-current-profile-request-is-refused-unless-anonymousactor-is-a', 'mcp-integration.md §E', 'the authenticated call MUST succeed at the same path, so a refusal below is not a wrong path')).toBe(200);
54
55
  const anonymous = await driver.post(await mcpServerMount(), REQ, { headers: HDR, authenticated: false });
55
56
  if (anon?.supported === true) {
56
57
  // Anonymous is permitted only through the RFC 0132 surface; a 200 here is that surface answering.
57
58
  expect([200, 401, 403]).toContain(anonymous.status);
58
- return;
59
+ return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `anon?.supported === true` returned early');
59
60
  }
60
61
  expect(
61
62
  [401, 403],
62
- driver.describe('mcp-integration.md §E', 'an anonymous MCP principal MUST NOT be the production default for an advertised current profile — refuse (401/403) or advertise anonymousActor'),
63
+ req('openwop.it.mcp-current-auth-boundary.an-unauthenticated-current-profile-request-is-refused-unless-anonymousactor-is-a', 'mcp-integration.md §E', 'an anonymous MCP principal MUST NOT be the production default for an advertised current profile — refuse (401/403) or advertise anonymousActor'),
63
64
  ).toContain(anonymous.status);
64
65
 
65
66
  // S30 (2026-08-17, openwop-app H43): a cookie-posture host may MINT an anonymous
@@ -72,12 +73,12 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §E — mcp-current-aut
72
73
  ...setCookies(anonymous.headers),
73
74
  ...setCookies((await driver.get('/.well-known/openwop', { authenticated: false })).headers),
74
75
  ];
75
- if (minted.length === 0) return; // host mints no anonymous session; the bare probe was the whole observation
76
+ if (minted.length === 0) return softSkip('blocked', 'precondition not met — `minted.length === 0` returned early (host mints no anonymous session; the bare probe was the whole observation) (seam, prior step, or fixture unavailable)'); // host mints no anonymous session; the bare probe was the whole observation
76
77
  const cookie = minted.map((c) => c.split(';')[0]).join('; ');
77
78
  const withSession = await driver.post(await mcpServerMount(), REQ, { headers: { ...HDR, Cookie: cookie }, authenticated: false });
78
79
  expect(
79
80
  [401, 403],
80
- driver.describe('mcp-integration.md §E', 'a caller holding only a host-minted anonymous session cookie is still an anonymous principal — refuse (401/403) unless anonymousActor is advertised (S30)'),
81
+ req('openwop.it.mcp-current-auth-boundary.an-unauthenticated-current-profile-request-is-refused-unless-anonymousactor-is-a', 'mcp-integration.md §E', 'a caller holding only a host-minted anonymous session cookie is still an anonymous principal — refuse (401/403) unless anonymousActor is advertised (S30)'),
81
82
  ).toContain(withSession.status);
82
83
  });
83
84
  });
@@ -29,6 +29,8 @@
29
29
 
30
30
  import { describe, it, expect } from 'vitest';
31
31
  import { driver } from '../lib/driver.js';
32
+ import { req } from '../lib/requirement-ids.js';
33
+ import { softSkip } from '../lib/soft-skip.js';
32
34
 
33
35
  interface McpAdvertisement {
34
36
  supported?: unknown;
@@ -75,28 +77,28 @@ async function fetchMcpAdvertisements(): Promise<DiscoveredMcp[]> {
75
77
  describe('mcp: discoverability shape', () => {
76
78
  it('any advertised MCP capability has well-formed shape ({supported, serverUrls})', async () => {
77
79
  const advertisements = await fetchMcpAdvertisements();
78
- if (advertisements.length === 0) return; // skip-equivalent: host does not advertise MCP
80
+ if (advertisements.length === 0) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `advertisements.length === 0` returned early (skip-equivalent: host does not advertise MCP)'); // skip-equivalent: host does not advertise MCP
79
81
 
80
82
  for (const { path, ad } of advertisements) {
81
- expect(typeof ad.supported, driver.describe(
83
+ expect(typeof ad.supported, req('openwop.it.mcp-discoverability.any-advertised-mcp-capability-has-well-formed-shape-supported-serverurls',
82
84
  'spec/v1/mcp-integration.md §"Conformance + interop"',
83
85
  `${path}.supported MUST be boolean when advertised`,
84
86
  )).toBe('boolean');
85
87
 
86
88
  if (ad.supported === true) {
87
- expect(Array.isArray(ad.serverUrls), driver.describe(
89
+ expect(Array.isArray(ad.serverUrls), req('openwop.it.mcp-discoverability.any-advertised-mcp-capability-has-well-formed-shape-supported-serverurls',
88
90
  'spec/v1/mcp-integration.md',
89
91
  `${path}.serverUrls MUST be an array when supported:true`,
90
92
  )).toBe(true);
91
93
 
92
94
  if (Array.isArray(ad.serverUrls)) {
93
- expect(ad.serverUrls.length, driver.describe(
95
+ expect(ad.serverUrls.length, req('openwop.it.mcp-discoverability.any-advertised-mcp-capability-has-well-formed-shape-supported-serverurls',
94
96
  'spec/v1/mcp-integration.md',
95
97
  `${path}.serverUrls MUST be non-empty when supported:true`,
96
98
  )).toBeGreaterThan(0);
97
99
 
98
100
  for (const url of ad.serverUrls) {
99
- expect(typeof url, driver.describe(
101
+ expect(typeof url, req('openwop.it.mcp-discoverability.any-advertised-mcp-capability-has-well-formed-shape-supported-serverurls',
100
102
  'spec/v1/mcp-integration.md',
101
103
  `${path}.serverUrls entries MUST be strings`,
102
104
  )).toBe('string');
@@ -108,7 +110,7 @@ describe('mcp: discoverability shape', () => {
108
110
 
109
111
  it('serverUrls are valid URL paths or absolute URLs', async () => {
110
112
  const advertisements = await fetchMcpAdvertisements();
111
- if (advertisements.length === 0) return; // skip-equivalent
113
+ if (advertisements.length === 0) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `advertisements.length === 0` returned early (skip-equivalent)'); // skip-equivalent
112
114
 
113
115
  for (const { path, ad } of advertisements) {
114
116
  if (ad.supported !== true || !Array.isArray(ad.serverUrls)) continue;
@@ -119,7 +121,7 @@ describe('mcp: discoverability shape', () => {
119
121
  // ambiguous to a client trying to connect.
120
122
  const isHostRelative = url.startsWith('/');
121
123
  const isAbsoluteHttp = url.startsWith('http://') || url.startsWith('https://');
122
- expect(isHostRelative || isAbsoluteHttp, driver.describe(
124
+ expect(isHostRelative || isAbsoluteHttp, req('openwop.it.mcp-discoverability.serverurls-are-valid-url-paths-or-absolute-urls',
123
125
  'spec/v1/mcp-integration.md',
124
126
  `${path}.serverUrls entry "${url}" MUST be a leading-slash path or absolute http(s) URL`,
125
127
  )).toBe(true);
@@ -27,6 +27,7 @@ import { mcpServerMount } from '../lib/mcp-mount.js';
27
27
  import { behaviorGate } from '../lib/behavior-gate.js';
28
28
  import { capabilityFamily } from '../lib/discovery-capabilities.js';
29
29
  import { getMcpFakeServer } from '../lib/mcp-fake-server.js';
30
+ import { req } from '../lib/requirement-ids.js';
30
31
 
31
32
  export const REQUIRES_HOST_CALLBACK = "the host issues MCP JSON-RPC calls to the suite's fake server via /v1/host/sample/mcp/invoke (serverUrl), which the server records";
32
33
 
@@ -53,14 +54,14 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §D — mcp-extension-o
53
54
  // an advertised-missing seam (RFC 0148 §B). A 403 is NOT a pass.
54
55
  return seamAbsent(`host advertises mcp-2026-07-28 but the invoke seam /v1/host/sample/mcp/invoke answered ${drive.status}`);
55
56
  }
56
- expect(server.invocations().some((i) => i.method === 'tools/call'), 'the host MUST have called the tool').toBe(true);
57
+ expect(server.invocations().some((i) => i.method === 'tools/call'), req('openwop.it.mcp-extension-opacity.client-half-an-extension-meta-asserting-authority-in-a-tool-result-changes-nothi', 'host-sample-test-seams.md §23', 'the host MUST have called the tool')).toBe(true);
57
58
  const rep = (drive.json as { extensionAuthority?: { scopesWidened?: boolean; approvalAdvanced?: boolean } }).extensionAuthority;
58
59
  if (rep === undefined) {
59
- expect(rep, driver.describe('host-sample-test-seams.md §23', 'the seam SHOULD report `extensionAuthority: { scopesWidened, approvalAdvanced }` for scenario "extension-asserts-authority"; until it does the requirement is `blocked`, not passed')).toBeDefined();
60
- return;
60
+ expect(rep, req('openwop.it.mcp-extension-opacity.client-half-an-extension-meta-asserting-authority-in-a-tool-result-changes-nothi', 'host-sample-test-seams.md §23', 'the seam SHOULD report `extensionAuthority: { scopesWidened, approvalAdvanced }` for scenario "extension-asserts-authority"; until it does the requirement is `blocked`, not passed')).toBeDefined();
61
+ return softSkip('blocked', 'precondition not met — `rep === undefined` returned early (seam, prior step, or fixture unavailable)');
61
62
  }
62
- expect(rep.scopesWidened, driver.describe('mcp-integration.md §D', 'an extension MUST NOT gain tool authority or scope by appearing in _meta (mcp-extension-no-authority)')).toBe(false);
63
- expect(rep.approvalAdvanced, driver.describe('mcp-integration.md §D/§E', 'MCP content MUST NOT advance approval gates')).toBe(false);
63
+ expect(rep.scopesWidened, req('openwop.it.mcp-extension-opacity.client-half-an-extension-meta-asserting-authority-in-a-tool-result-changes-nothi', 'mcp-integration.md §D', 'an extension MUST NOT gain tool authority or scope by appearing in _meta (mcp-extension-no-authority)')).toBe(false);
64
+ expect(rep.approvalAdvanced, req('openwop.it.mcp-extension-opacity.client-half-an-extension-meta-asserting-authority-in-a-tool-result-changes-nothi', 'mcp-integration.md §D/§E', 'MCP content MUST NOT advance approval gates')).toBe(false);
64
65
  });
65
66
 
66
67
  it('server half: unknown _meta extension keys on a request are ignored, not refused and not honoured', async () => {
@@ -73,7 +74,7 @@ describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0153 §D — mcp-extension-o
73
74
  }, { headers: { 'MCP-Protocol-Version': '2026-07-28', 'Mcp-Method': 'tools/list' } });
74
75
  if (res.status === 404 || res.status === 403) return seamAbsent(`host advertises mcp-2026-07-28 but the MCP server mount /v1/host/sample/mcp answered ${res.status}`);
75
76
  const body = res.json as { result?: { resultType?: string }; error?: { code: number } };
76
- expect(res.status, driver.describe('mcp-integration.md §D', 'an unknown extension is opaque: the request MUST be processed normally, neither refused nor granted anything')).toBe(200);
77
+ expect(res.status, req('openwop.it.mcp-extension-opacity.server-half-unknown-meta-extension-keys-on-a-request-are-ignored-not-refused-and', 'mcp-integration.md §D', 'an unknown extension is opaque: the request MUST be processed normally, neither refused nor granted anything')).toBe(200);
77
78
  expect(body.error).toBeUndefined();
78
79
  expect(body.result?.resultType).toBe('complete');
79
80
  });