@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.
- package/README.md +11 -2
- package/dist/cli.js +54 -1
- package/dist/lib/paths.js +25 -3
- package/dist/lib/requirement-ids.js +34 -4
- package/dist/lib/scenario-disposition.js +1 -0
- package/dist/lib/spec-coherence.js +13 -32
- package/dist/spec-artifacts.lock.json +5 -0
- package/package.json +11 -33
- package/requirements.json +20303 -11809
- package/scenario-majors.json +1343 -0
- package/schemas/CORPUS-STAMP.json +138 -6
- package/src/cli.ts +47 -1
- package/src/global-setup.ts +3 -2
- package/src/lib/corpus-stamp.ts +29 -1
- package/src/lib/paths.ts +25 -3
- package/src/lib/requirement-ids.ts +33 -4
- package/src/lib/scenario-disposition.ts +1 -0
- package/src/lib/spec-coherence.ts +15 -32
- package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
- package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
- package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
- package/src/scenarios/a2a-peer-authority.test.ts +7 -6
- package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
- package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
- package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
- package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
- package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
- package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
- package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
- package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
- package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
- package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
- package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
- package/src/scenarios/agent-deployment-shape.test.ts +22 -24
- package/src/scenarios/agent-eval-run.test.ts +19 -18
- package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
- package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
- package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
- package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
- package/src/scenarios/agent-live-structured-output.test.ts +7 -6
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
- package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
- package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
- package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
- package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
- package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
- package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
- package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
- package/src/scenarios/agent-platform-profile.test.ts +18 -19
- package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
- package/src/scenarios/agent-roster-attribution.test.ts +18 -17
- package/src/scenarios/agent-roster-shape.test.ts +17 -19
- package/src/scenarios/agent-verifier-shape.test.ts +11 -11
- package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
- package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
- package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
- package/src/scenarios/agentMessageReducer.test.ts +2 -1
- package/src/scenarios/agentMetadata.test.ts +2 -1
- package/src/scenarios/agentPackCatalog.test.ts +23 -21
- package/src/scenarios/agentPackExport.test.ts +4 -2
- package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
- package/src/scenarios/agentPackInstall.test.ts +4 -2
- package/src/scenarios/agentPackProvenance.test.ts +2 -1
- package/src/scenarios/agentReasoningEvents.test.ts +3 -2
- package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
- package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
- package/src/scenarios/ai-envelope-shape.test.ts +31 -29
- package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
- package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
- package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
- package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
- package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
- package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
- package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
- package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
- package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
- package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
- package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
- package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
- package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
- package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
- package/src/scenarios/append-ordering.test.ts +7 -5
- package/src/scenarios/approval-gate-events.test.ts +4 -3
- package/src/scenarios/approval-gate-flow.test.ts +4 -3
- package/src/scenarios/approval-payload.test.ts +5 -4
- package/src/scenarios/artifact-auth.test.ts +7 -6
- package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
- package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
- package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
- package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
- package/src/scenarios/audit-log-integrity.test.ts +8 -6
- package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
- package/src/scenarios/auth-mtls.test.ts +22 -20
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
- package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
- package/src/scenarios/auth-saml-profile.test.ts +14 -12
- package/src/scenarios/auth-scim-profile.test.ts +3 -2
- package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
- package/src/scenarios/auth-subject-link.test.ts +11 -10
- package/src/scenarios/auth.test.ts +5 -4
- package/src/scenarios/authorization-fail-closed.test.ts +3 -2
- package/src/scenarios/authorization-roles-shape.test.ts +9 -7
- package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/blob-presign-expiry.test.ts +12 -10
- package/src/scenarios/blob-roundtrip.test.ts +0 -0
- package/src/scenarios/budget-enforcement.test.ts +15 -14
- package/src/scenarios/budget-policy-shape.test.ts +18 -19
- package/src/scenarios/bulk-cancel.test.ts +9 -8
- package/src/scenarios/byok-auth-modes.test.ts +13 -14
- package/src/scenarios/byok-roundtrip.test.ts +12 -10
- package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
- package/src/scenarios/callai-multimodal.test.ts +5 -3
- package/src/scenarios/cancellation.test.ts +6 -5
- package/src/scenarios/cap-breach.test.ts +15 -14
- package/src/scenarios/capability-arm-witness.test.ts +5 -3
- package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
- package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
- package/src/scenarios/certification-bundle-v2.test.ts +11 -10
- package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
- package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
- package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
- package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
- package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
- package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
- package/src/scenarios/channel-presence-shape.test.ts +11 -12
- package/src/scenarios/channel-ttl.test.ts +6 -5
- package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
- package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/commitment-fired.test.ts +6 -5
- package/src/scenarios/compensation-behavior.test.ts +24 -23
- package/src/scenarios/compensation-recovery.test.ts +28 -27
- package/src/scenarios/configurable-schema.test.ts +8 -6
- package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
- package/src/scenarios/conformance-execution-witness.test.ts +9 -8
- package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
- package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
- package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
- package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
- package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
- package/src/scenarios/connection-provider-resolution.test.ts +18 -16
- package/src/scenarios/connector-manifest-validity.test.ts +8 -7
- package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
- package/src/scenarios/context-summarization-replay.test.ts +14 -12
- package/src/scenarios/contract-provenance.test.ts +18 -18
- package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
- package/src/scenarios/conversationLifecycle.test.ts +2 -1
- package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
- package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
- package/src/scenarios/core-standard-profile.test.ts +8 -9
- package/src/scenarios/cost-attribution.test.ts +23 -21
- package/src/scenarios/credential-payload-redaction.test.ts +4 -3
- package/src/scenarios/credentials-capability-shape.test.ts +5 -4
- package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
- package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
- package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
- package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
- package/src/scenarios/data-residency-admission.test.ts +15 -14
- package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
- package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
- package/src/scenarios/debugBundle.test.ts +25 -23
- package/src/scenarios/discovery-families-view.test.ts +5 -4
- package/src/scenarios/discovery.test.ts +30 -29
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
- package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
- package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
- package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
- package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
- package/src/scenarios/dispatchLoop.test.ts +3 -2
- package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
- package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
- package/src/scenarios/distillation-shape.test.ts +4 -4
- package/src/scenarios/distillation-stable-archive.test.ts +6 -6
- package/src/scenarios/distillation-token-budget.test.ts +5 -5
- package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
- package/src/scenarios/egress-audience-binding.test.ts +11 -10
- package/src/scenarios/egress-decision-content-free.test.ts +6 -5
- package/src/scenarios/egress-provenance-shape.test.ts +17 -18
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
- package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
- package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
- package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
- package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
- package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
- package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
- package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
- package/src/scenarios/envelope-truncated.test.ts +19 -17
- package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
- package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
- package/src/scenarios/errors.test.ts +20 -19
- package/src/scenarios/eventOrdering.test.ts +16 -14
- package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
- package/src/scenarios/experimental-tier-shape.test.ts +17 -15
- package/src/scenarios/export-bundle-portability.test.ts +17 -17
- package/src/scenarios/failure-path.test.ts +7 -6
- package/src/scenarios/feedback-capability-shape.test.ts +4 -3
- package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
- package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
- package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
- package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
- package/src/scenarios/feedback-record-and-list.test.ts +2 -1
- package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
- package/src/scenarios/fixtures-gating.test.ts +29 -28
- package/src/scenarios/fixtures-valid.test.ts +16 -15
- package/src/scenarios/form-content-instantiation.test.ts +15 -14
- package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
- package/src/scenarios/fs-path-traversal.test.ts +14 -12
- package/src/scenarios/goal-standing-continuation.test.ts +21 -21
- package/src/scenarios/grpc-transport.test.ts +9 -7
- package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
- package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
- package/src/scenarios/highConcurrency.test.ts +14 -13
- package/src/scenarios/host-callback-declaration.test.ts +8 -7
- package/src/scenarios/http-client-ssrf.test.ts +7 -5
- package/src/scenarios/i18n-negotiation.test.ts +14 -12
- package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
- package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
- package/src/scenarios/idempotency.test.ts +8 -7
- package/src/scenarios/idempotencyRetry.test.ts +13 -11
- package/src/scenarios/identity-owner-shape.test.ts +6 -5
- package/src/scenarios/identity-passthrough.test.ts +4 -3
- package/src/scenarios/interrupt-approval.test.ts +6 -5
- package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
- package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
- package/src/scenarios/interrupt-clarification.test.ts +4 -3
- package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
- package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
- package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
- package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
- package/src/scenarios/interruptRace.test.ts +12 -10
- package/src/scenarios/kv-atomic-increment.test.ts +11 -9
- package/src/scenarios/kv-cas.test.ts +14 -12
- package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
- package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
- package/src/scenarios/localized-content-delivery.test.ts +24 -26
- package/src/scenarios/maliciousManifest.test.ts +10 -8
- package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
- package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
- package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
- package/src/scenarios/mcp-discoverability.test.ts +9 -7
- package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
- package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
- package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
- package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
- package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
- package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
- package/src/scenarios/mcp-stateless-request.test.ts +11 -10
- package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
- package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
- package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
- package/src/scenarios/media-url-inline-cap.test.ts +21 -19
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
- package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
- package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
- package/src/scenarios/memory-attribution-shape.test.ts +4 -3
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
- package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
- package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
- package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
- package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
- package/src/scenarios/memory-degraded-projection.test.ts +10 -9
- package/src/scenarios/memory-injection-budget.test.ts +15 -14
- package/src/scenarios/metric-emission.test.ts +4 -3
- package/src/scenarios/model-capability-insufficient.test.ts +19 -17
- package/src/scenarios/model-capability-substituted.test.ts +20 -18
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
- package/src/scenarios/multi-node-ordering.test.ts +4 -3
- package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
- package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
- package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
- package/src/scenarios/multi-region-idempotency.test.ts +6 -5
- package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
- package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
- package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
- package/src/scenarios/oauth-capability-shape.test.ts +5 -4
- package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
- package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
- package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
- package/src/scenarios/orchestratorDispatch.test.ts +2 -1
- package/src/scenarios/orchestratorTermination.test.ts +2 -1
- package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
- package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
- package/src/scenarios/otel-emission-grpc.test.ts +3 -2
- package/src/scenarios/otel-emission.test.ts +6 -5
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
- package/src/scenarios/otel-trace-propagation.test.ts +2 -1
- package/src/scenarios/owner-subject-echo.test.ts +13 -12
- package/src/scenarios/owner-subject-shape.test.ts +11 -10
- package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
- package/src/scenarios/pack-registry-isolation.test.ts +4 -3
- package/src/scenarios/pack-registry-publish.test.ts +65 -63
- package/src/scenarios/pack-registry.test.ts +38 -36
- package/src/scenarios/pause-resume.test.ts +18 -16
- package/src/scenarios/policies.test.ts +20 -18
- package/src/scenarios/production-backpressure.test.ts +18 -16
- package/src/scenarios/production-retention-expiry.test.ts +8 -6
- package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
- package/src/scenarios/profileDerivation.test.ts +34 -33
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
- package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
- package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
- package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
- package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
- package/src/scenarios/prompt-pack-install.test.ts +14 -12
- package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
- package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
- package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
- package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
- package/src/scenarios/prompt-template-shape.test.ts +30 -28
- package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
- package/src/scenarios/protocol-versions-array.test.ts +10 -9
- package/src/scenarios/provider-usage.test.ts +17 -15
- package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
- package/src/scenarios/purpose-propagation.test.ts +23 -21
- package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
- package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
- package/src/scenarios/rate-limit-envelope.test.ts +6 -5
- package/src/scenarios/redaction.test.ts +13 -11
- package/src/scenarios/redactionAdversarial.test.ts +11 -9
- package/src/scenarios/registry-public.test.ts +12 -11
- package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
- package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
- package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
- package/src/scenarios/replay-fork.test.ts +20 -19
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
- package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
- package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
- package/src/scenarios/replay-retention-expiry.test.ts +11 -9
- package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
- package/src/scenarios/replayDeterminism.test.ts +13 -12
- package/src/scenarios/requirement-ledger.test.ts +15 -14
- package/src/scenarios/restart-during-run.test.ts +3 -2
- package/src/scenarios/route-coverage.test.ts +20 -19
- package/src/scenarios/run-diff.test.ts +22 -20
- package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
- package/src/scenarios/run-transport-economy.test.ts +13 -11
- package/src/scenarios/runner-ledger.test.ts +17 -16
- package/src/scenarios/runs-lifecycle.test.ts +7 -6
- package/src/scenarios/runtime-capabilities.test.ts +12 -10
- package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
- package/src/scenarios/runtime-requires-shape.test.ts +7 -6
- package/src/scenarios/safefetch-behavior.test.ts +22 -21
- package/src/scenarios/safefetch-live-audit.test.ts +14 -13
- package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
- package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
- package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
- package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
- package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
- package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
- package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
- package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
- package/src/scenarios/self-hosted-runner.test.ts +26 -24
- package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
- package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
- package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
- package/src/scenarios/sql-injection-rejection.test.ts +8 -6
- package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
- package/src/scenarios/staleClaim.test.ts +5 -4
- package/src/scenarios/stream-modes-buffer.test.ts +8 -7
- package/src/scenarios/stream-modes-mixed.test.ts +10 -9
- package/src/scenarios/stream-modes.test.ts +12 -11
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
- package/src/scenarios/stream-text-fixture.test.ts +14 -13
- package/src/scenarios/streamReconnect.test.ts +13 -11
- package/src/scenarios/strict-behavior-gate.test.ts +9 -8
- package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
- package/src/scenarios/subrun-approval-gate.test.ts +3 -3
- package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
- package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
- package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
- package/src/scenarios/subworkflow.test.ts +10 -9
- package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/table-cursor-pagination.test.ts +8 -6
- package/src/scenarios/table-schema-enforcement.test.ts +7 -5
- package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
- package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
- package/src/scenarios/tool-catalog-projection.test.ts +11 -9
- package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
- package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
- package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
- package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
- package/src/scenarios/tool-hooks-shape.test.ts +3 -3
- package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
- package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
- package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
- package/src/scenarios/trigger-ingestion.test.ts +19 -17
- package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
- package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
- package/src/scenarios/verifier-gating.test.ts +8 -6
- package/src/scenarios/version-fold.test.ts +9 -8
- package/src/scenarios/version-negotiation.test.ts +12 -11
- package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
- package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
- package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
- package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
- package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
- package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
- package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
- package/src/scenarios/wasm-pack-load.test.ts +4 -3
- package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
- package/src/scenarios/webhook-negative.test.ts +11 -9
- package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
- package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
- package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
- package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
- package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
- package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
- package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
- package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
- package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
- package/src/scenarios/workflow-variable-format.test.ts +24 -24
- package/src/scenarios/workload-identity-behavior.test.ts +15 -13
- package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
- package/src/scenarios/workspace-behavior.test.ts +19 -18
- package/src/scenarios/workspace-capability-shape.test.ts +3 -2
- package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
- package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
- package/src/setup.ts +4 -2
- package/vitest.config.ts +5 -1
- package/api/.redocly.lint-ignore.yaml +0 -22
- package/api/asyncapi.yaml +0 -834
- package/api/grpc/openwop.proto +0 -251
- package/api/openapi.yaml +0 -2693
- package/api/redocly.yaml +0 -23
- package/schemas/README.md +0 -144
- package/schemas/a2a-task-state.schema.json +0 -78
- package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
- package/schemas/agent-deployment-transition.schema.json +0 -49
- package/schemas/agent-deployment.schema.json +0 -54
- package/schemas/agent-eval-suite.schema.json +0 -140
- package/schemas/agent-inventory-response.schema.json +0 -115
- package/schemas/agent-manifest.schema.json +0 -156
- package/schemas/agent-org-chart.schema.json +0 -82
- package/schemas/agent-ref.schema.json +0 -63
- package/schemas/agent-roster-entry.schema.json +0 -81
- package/schemas/agent-roster-response.schema.json +0 -21
- package/schemas/ai-envelope.schema.json +0 -134
- package/schemas/annotation-create.schema.json +0 -37
- package/schemas/annotation.schema.json +0 -56
- package/schemas/artifact-type-pack-manifest.schema.json +0 -244
- package/schemas/audit-verify-result.schema.json +0 -90
- package/schemas/budget-policy.schema.json +0 -18
- package/schemas/capabilities.schema.json +0 -4124
- package/schemas/certification-bundle-v2.schema.json +0 -118
- package/schemas/channel-presence-payload.schema.json +0 -41
- package/schemas/channel-written-payload.schema.json +0 -55
- package/schemas/chat-card-pack-manifest.schema.json +0 -253
- package/schemas/compact-tool-descriptor.schema.json +0 -51
- package/schemas/compensation-policy.schema.json +0 -64
- package/schemas/conformance-certification-bundle.schema.json +0 -86
- package/schemas/connection-pack-manifest.schema.json +0 -353
- package/schemas/conversation-event.schema.json +0 -168
- package/schemas/conversation-turn.schema.json +0 -117
- package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
- package/schemas/credential-provenance.schema.json +0 -18
- package/schemas/credential-reference.schema.json +0 -21
- package/schemas/debug-bundle.schema.json +0 -196
- package/schemas/dispatch-config.schema.json +0 -112
- package/schemas/envelopes/clarification.request.schema.json +0 -52
- package/schemas/envelopes/error.schema.json +0 -30
- package/schemas/envelopes/media.audio.schema.json +0 -38
- package/schemas/envelopes/media.file.schema.json +0 -37
- package/schemas/envelopes/media.image.schema.json +0 -33
- package/schemas/envelopes/schema.request.schema.json +0 -26
- package/schemas/envelopes/schema.response.schema.json +0 -22
- package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
- package/schemas/error-envelope.schema.json +0 -25
- package/schemas/eval-summary.schema.json +0 -92
- package/schemas/export-bundle.schema.json +0 -66
- package/schemas/form-content-pack-manifest.schema.json +0 -243
- package/schemas/frontend-plugin-manifest.schema.json +0 -109
- package/schemas/goal.schema.json +0 -104
- package/schemas/heartbeat-evaluated.schema.json +0 -14
- package/schemas/heartbeat-state-changed.schema.json +0 -14
- package/schemas/localized-content-language-settings.schema.json +0 -26
- package/schemas/localized-content-page-response.schema.json +0 -60
- package/schemas/localized-content-page.schema.json +0 -62
- package/schemas/localized-content-section.schema.json +0 -51
- package/schemas/memory-entry.schema.json +0 -36
- package/schemas/memory-list-options.schema.json +0 -37
- package/schemas/node-pack-manifest.schema.json +0 -654
- package/schemas/orchestrator-decision.schema.json +0 -90
- package/schemas/org-chart-responsibility-view.schema.json +0 -26
- package/schemas/pack-lockfile.schema.json +0 -108
- package/schemas/prompt-kind.schema.json +0 -8
- package/schemas/prompt-pack-manifest.schema.json +0 -117
- package/schemas/prompt-ref.schema.json +0 -40
- package/schemas/prompt-template.schema.json +0 -149
- package/schemas/proposal.schema.json +0 -84
- package/schemas/registry-version-manifest.schema.json +0 -208
- package/schemas/residency.schema.json +0 -16
- package/schemas/run-ancestry-response.schema.json +0 -54
- package/schemas/run-diff-response.schema.json +0 -64
- package/schemas/run-event-payloads.schema.json +0 -4452
- package/schemas/run-event.schema.json +0 -211
- package/schemas/run-options.schema.json +0 -80
- package/schemas/run-orchestrator-decided-event.schema.json +0 -20
- package/schemas/run-snapshot.schema.json +0 -148
- package/schemas/security-advisory.schema.json +0 -109
- package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
- package/schemas/self-hosted-runner-registration.schema.json +0 -53
- package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
- package/schemas/subject.schema.json +0 -56
- package/schemas/suspend-request.schema.json +0 -207
- package/schemas/tool-descriptor.schema.json +0 -63
- package/schemas/trigger-event.schema.json +0 -222
- package/schemas/trigger-subscription-registration.schema.json +0 -67
- package/schemas/trigger-subscription.schema.json +0 -26
- package/schemas/ui-plugin-message.schema.json +0 -90
- package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
- package/schemas/workflow-definition.schema.json +0 -850
- package/schemas/workload-identity.schema.json +0 -79
- package/schemas/workspace-file-create.schema.json +0 -20
- package/schemas/workspace-file.schema.json +0 -39
|
@@ -41,6 +41,8 @@ import { loadEnv } from '../lib/env.js';
|
|
|
41
41
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
42
42
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
43
43
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
44
|
+
import { req } from '../lib/requirement-ids.js';
|
|
45
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
44
46
|
|
|
45
47
|
interface BackpressureCaps {
|
|
46
48
|
supported?: boolean;
|
|
@@ -72,12 +74,12 @@ describe('production-backpressure: capability shape', () => {
|
|
|
72
74
|
return;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
expect(prod?.supported,
|
|
77
|
+
expect(prod?.supported, req('openwop.it.production-backpressure.host-that-claims-openwop-production-with-backpressure-advertises-required-fields',
|
|
76
78
|
'production-profile.md §Compatibility baseline',
|
|
77
79
|
'capabilities.production.supported MUST be true when claiming the openwop-production profile',
|
|
78
80
|
)).toBe(true);
|
|
79
81
|
|
|
80
|
-
expect(prod?.backpressure?.supported,
|
|
82
|
+
expect(prod?.backpressure?.supported, req('openwop.it.production-backpressure.host-that-claims-openwop-production-with-backpressure-advertises-required-fields',
|
|
81
83
|
'production-profile.md §Backpressure',
|
|
82
84
|
'capabilities.production.backpressure.supported MUST be true for production-profile claimants',
|
|
83
85
|
)).toBe(true);
|
|
@@ -86,7 +88,7 @@ describe('production-backpressure: capability shape', () => {
|
|
|
86
88
|
expect(
|
|
87
89
|
Number.isInteger(prod.backpressure.inflightCap) &&
|
|
88
90
|
prod.backpressure.inflightCap >= 1,
|
|
89
|
-
|
|
91
|
+
req('openwop.it.production-backpressure.host-that-claims-openwop-production-with-backpressure-advertises-required-fields',
|
|
90
92
|
'capabilities.schema.json production.backpressure.inflightCap',
|
|
91
93
|
'inflightCap MUST be an integer ≥ 1 when advertised',
|
|
92
94
|
),
|
|
@@ -97,7 +99,7 @@ describe('production-backpressure: capability shape', () => {
|
|
|
97
99
|
expect(
|
|
98
100
|
Number.isInteger(prod.backpressure.retryAfterSeconds) &&
|
|
99
101
|
prod.backpressure.retryAfterSeconds >= 0,
|
|
100
|
-
|
|
102
|
+
req('openwop.it.production-backpressure.host-that-claims-openwop-production-with-backpressure-advertises-required-fields',
|
|
101
103
|
'capabilities.schema.json production.backpressure.retryAfterSeconds',
|
|
102
104
|
'retryAfterSeconds MUST be a non-negative integer when advertised',
|
|
103
105
|
),
|
|
@@ -120,7 +122,7 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
120
122
|
console.warn(
|
|
121
123
|
'[production-backpressure] host does not advertise inflightCap; skipping saturation assertion',
|
|
122
124
|
);
|
|
123
|
-
return;
|
|
125
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === undefined` returned early ([production-backpressure] host does not advertise inflightCap; skipping saturation assertion)');
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
// Use the conformance-delay fixture to hold inflight slots via
|
|
@@ -132,7 +134,7 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
132
134
|
console.warn(
|
|
133
135
|
`[production-backpressure] ${FIXTURE} not advertised; skipping saturation (host doesn't seed the long-running fixture)`,
|
|
134
136
|
);
|
|
135
|
-
return;
|
|
137
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE)` returned early ([production-backpressure] … not advertised; skipping saturation (host doesn\'t seed the long-running fixture))');
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
// Create `cap` long-running runs and open SSE streams against each
|
|
@@ -210,7 +212,7 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
214
|
await Promise.allSettled(slotPromises);
|
|
213
|
-
return;
|
|
215
|
+
return softSkip('blocked', 'precondition not met — `saturationEarlyExit` returned early (seam, prior step, or fixture unavailable)');
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
// Let SSE connections register.
|
|
@@ -231,11 +233,11 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
231
233
|
console.warn(
|
|
232
234
|
`[production-backpressure] expected 503 at cap+1=${cap + 1}, got ${blocked.status}; saturation may need tuning`,
|
|
233
235
|
);
|
|
234
|
-
return;
|
|
236
|
+
return softSkip('blocked', 'precondition not met — `blocked.status !== 503` returned early ([production-backpressure] expected 503 at cap+1=…, got …; saturation may need tuning) (seam, prior step, or fixture unavailable)');
|
|
235
237
|
}
|
|
236
238
|
|
|
237
239
|
const retryAfterHeader = blocked.headers.get('retry-after');
|
|
238
|
-
expect(retryAfterHeader,
|
|
240
|
+
expect(retryAfterHeader, req('openwop.it.production-backpressure.saturating-advertised-inflightcap-returns-503-retry-after-canonical-envelope',
|
|
239
241
|
'production-profile.md §Backpressure',
|
|
240
242
|
'503 response MUST include a Retry-After header',
|
|
241
243
|
)).toBeTruthy();
|
|
@@ -247,7 +249,7 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
247
249
|
details?: { retryAfter?: number };
|
|
248
250
|
};
|
|
249
251
|
|
|
250
|
-
expect(body.error,
|
|
252
|
+
expect(body.error, req('openwop.it.production-backpressure.saturating-advertised-inflightcap-returns-503-retry-after-canonical-envelope',
|
|
251
253
|
'production-profile.md §Backpressure',
|
|
252
254
|
'503 envelope MUST have error: "service_unavailable"',
|
|
253
255
|
)).toBe('service_unavailable');
|
|
@@ -255,14 +257,14 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
255
257
|
expect(typeof body.message).toBe('string');
|
|
256
258
|
expect((body.message ?? '').length).toBeGreaterThan(0);
|
|
257
259
|
|
|
258
|
-
expect(typeof body.details?.retryAfter,
|
|
260
|
+
expect(typeof body.details?.retryAfter, req('openwop.it.production-backpressure.saturating-advertised-inflightcap-returns-503-retry-after-canonical-envelope',
|
|
259
261
|
'production-profile.md §Backpressure',
|
|
260
262
|
'details.retryAfter MUST be present and numeric',
|
|
261
263
|
)).toBe('number');
|
|
262
264
|
|
|
263
265
|
// details.retryAfter MUST equal the Retry-After header in seconds.
|
|
264
266
|
const headerSeconds = Number.parseInt(retryAfterHeader ?? '', 10);
|
|
265
|
-
expect(body.details?.retryAfter,
|
|
267
|
+
expect(body.details?.retryAfter, req('openwop.it.production-backpressure.saturating-advertised-inflightcap-returns-503-retry-after-canonical-envelope',
|
|
266
268
|
'production-profile.md §Backpressure',
|
|
267
269
|
'details.retryAfter MUST equal Retry-After header in seconds',
|
|
268
270
|
)).toBe(headerSeconds);
|
|
@@ -270,7 +272,7 @@ describe('production-backpressure: 503 envelope under saturation', () => {
|
|
|
270
272
|
// If retryAfterSeconds is advertised, both equal it.
|
|
271
273
|
const advertised = prod?.backpressure?.retryAfterSeconds;
|
|
272
274
|
if (advertised !== undefined) {
|
|
273
|
-
expect(headerSeconds,
|
|
275
|
+
expect(headerSeconds, req('openwop.it.production-backpressure.saturating-advertised-inflightcap-returns-503-retry-after-canonical-envelope',
|
|
274
276
|
'capabilities.schema.json production.backpressure.retryAfterSeconds',
|
|
275
277
|
'Retry-After MUST equal advertised retryAfterSeconds when both are present',
|
|
276
278
|
)).toBe(advertised);
|
|
@@ -319,11 +321,11 @@ describe('production-backpressure: discovery exempt from cap', () => {
|
|
|
319
321
|
// Without advertised cap we can't saturate deterministically;
|
|
320
322
|
// fall back to a single discovery probe.
|
|
321
323
|
const probe = await driver.get('/.well-known/openwop');
|
|
322
|
-
expect(probe.status,
|
|
324
|
+
expect(probe.status, req('openwop.it.production-backpressure.get-well-known-openwop-returns-200-even-when-inflight-is-saturated',
|
|
323
325
|
'production-profile.md §Backpressure',
|
|
324
326
|
'discovery MUST answer regardless of load',
|
|
325
327
|
)).toBe(200);
|
|
326
|
-
return;
|
|
328
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === undefined` returned early');
|
|
327
329
|
}
|
|
328
330
|
|
|
329
331
|
// Issue many concurrent discovery probes; all MUST succeed.
|
|
@@ -333,7 +335,7 @@ describe('production-backpressure: discovery exempt from cap', () => {
|
|
|
333
335
|
),
|
|
334
336
|
);
|
|
335
337
|
for (const probe of probes) {
|
|
336
|
-
expect(probe.status,
|
|
338
|
+
expect(probe.status, req('openwop.it.production-backpressure.get-well-known-openwop-returns-200-even-when-inflight-is-saturated',
|
|
337
339
|
'production-profile.md §Backpressure',
|
|
338
340
|
'discovery MUST bypass the inflight cap (health probes always answer)',
|
|
339
341
|
)).toBe(200);
|
|
@@ -32,6 +32,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
32
32
|
import { driver } from '../lib/driver.js';
|
|
33
33
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
34
34
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
35
37
|
|
|
36
38
|
interface RetentionCaps {
|
|
37
39
|
supported?: boolean;
|
|
@@ -63,12 +65,12 @@ describe('production-retention-expiry: capability shape', () => {
|
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
expect(prod?.retention?.supported,
|
|
68
|
+
expect(prod?.retention?.supported, req('openwop.it.production-retention-expiry.host-claiming-openwop-production-with-retention-advertises-required-fields',
|
|
67
69
|
'production-profile.md §"Event retention"',
|
|
68
70
|
'capabilities.production.retention.supported MUST be true for production-profile claimants',
|
|
69
71
|
)).toBe(true);
|
|
70
72
|
|
|
71
|
-
expect(prod?.retention?.minWindowSeconds,
|
|
73
|
+
expect(prod?.retention?.minWindowSeconds, req('openwop.it.production-retention-expiry.host-claiming-openwop-production-with-retention-advertises-required-fields',
|
|
72
74
|
'production-profile.md §"Event retention"',
|
|
73
75
|
'capabilities.production.retention.minWindowSeconds MUST be advertised when retention.supported is true',
|
|
74
76
|
)).toBeDefined();
|
|
@@ -76,7 +78,7 @@ describe('production-retention-expiry: capability shape', () => {
|
|
|
76
78
|
expect(
|
|
77
79
|
Number.isInteger(prod?.retention?.minWindowSeconds) &&
|
|
78
80
|
(prod?.retention?.minWindowSeconds ?? 0) >= SEVEN_DAYS_SECONDS,
|
|
79
|
-
|
|
81
|
+
req('openwop.it.production-retention-expiry.host-claiming-openwop-production-with-retention-advertises-required-fields',
|
|
80
82
|
'production-profile.md §"Event retention"',
|
|
81
83
|
'minWindowSeconds MUST be an integer ≥ 604800 (7 days) for public production-profile claimants',
|
|
82
84
|
),
|
|
@@ -126,14 +128,14 @@ describe('production-retention-expiry: 410/404 envelope on expired run', () => {
|
|
|
126
128
|
console.warn(
|
|
127
129
|
'[production-retention-expiry] no expired runId available (set OPENWOP_TEST_EXPIRED_RUN_ID or advertise testForceExpire + provide OPENWOP_TEST_FORCE_EXPIRE_URL); skipping envelope assertion',
|
|
128
130
|
);
|
|
129
|
-
return;
|
|
131
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `expiredRunId === undefined` returned early ([production-retention-expiry] no expired runId available (set OPENWOP_TEST_EXPIRED_RUN_ID or advertise testForceExp…');
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
const res = await driver.get(`/v1/runs/${encodeURIComponent(expiredRunId)}`);
|
|
133
135
|
|
|
134
136
|
expect(
|
|
135
137
|
res.status === 410 || res.status === 404,
|
|
136
|
-
|
|
138
|
+
req('openwop.it.production-retention-expiry.get-v1-runs-expiredrunid-returns-410-or-404-with-canonical-envelope',
|
|
137
139
|
'production-profile.md §"Event retention"',
|
|
138
140
|
'expired run MUST return 410 Gone (preferred) or 404 Not Found',
|
|
139
141
|
),
|
|
@@ -145,7 +147,7 @@ describe('production-retention-expiry: 410/404 envelope on expired run', () => {
|
|
|
145
147
|
details?: { expiredAt?: string };
|
|
146
148
|
};
|
|
147
149
|
|
|
148
|
-
expect(typeof body.error,
|
|
150
|
+
expect(typeof body.error, req('openwop.it.production-retention-expiry.get-v1-runs-expiredrunid-returns-410-or-404-with-canonical-envelope',
|
|
149
151
|
'production-profile.md §"Event retention"',
|
|
150
152
|
'expired-run response MUST use the canonical error envelope ({error, message, details?})',
|
|
151
153
|
)).toBe('string');
|
|
@@ -30,6 +30,8 @@ import { join } from 'node:path';
|
|
|
30
30
|
import { driver } from '../lib/driver.js';
|
|
31
31
|
import { PROFILE_NAMES, deriveProfiles, hasProfile, type DiscoveryPayload } from '../lib/profiles.js';
|
|
32
32
|
import { V1_DIR } from '../lib/paths.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
33
35
|
|
|
34
36
|
const CANONICAL = 'openwop-discovery-core';
|
|
35
37
|
const ALIAS = 'openwop-core';
|
|
@@ -59,7 +61,7 @@ describe('RFC 0155 §A — openwop-discovery-core is canonical, openwop-core is
|
|
|
59
61
|
expect(PROFILE_NAMES).toContain(ALIAS);
|
|
60
62
|
expect(
|
|
61
63
|
PROFILE_NAMES.indexOf(CANONICAL),
|
|
62
|
-
'the canonical name precedes its alias so derived sets read canonical-first',
|
|
64
|
+
req('openwop.it.profile-discovery-core-alias.both-names-are-in-the-closed-catalog-canonical-first', 'RFC 0155 §A', 'the canonical name precedes its alias so derived sets read canonical-first'),
|
|
63
65
|
).toBeLessThan(PROFILE_NAMES.indexOf(ALIAS));
|
|
64
66
|
});
|
|
65
67
|
|
|
@@ -69,26 +71,26 @@ describe('RFC 0155 §A — openwop-discovery-core is canonical, openwop-core is
|
|
|
69
71
|
for (const [label, c] of PAYLOADS) {
|
|
70
72
|
const canonical = hasProfile(c, CANONICAL);
|
|
71
73
|
const alias = hasProfile(c, ALIAS);
|
|
72
|
-
expect(alias, `${label}: hasProfile(alias) MUST equal hasProfile(canonical)`).toBe(canonical);
|
|
74
|
+
expect(alias, req('openwop.it.profile-discovery-core-alias.the-alias-derives-exactly-when-the-canonical-name-derives-for-payloads-on-both-s', 'RFC 0155 §A', `${label}: hasProfile(alias) MUST equal hasProfile(canonical)`)).toBe(canonical);
|
|
73
75
|
const derived = deriveProfiles(c);
|
|
74
76
|
expect(
|
|
75
77
|
derived.includes(ALIAS),
|
|
76
|
-
`${label}: deriveProfiles MUST emit the alias iff it emits the canonical name (never the alias alone)
|
|
78
|
+
req('openwop.it.profile-discovery-core-alias.the-alias-derives-exactly-when-the-canonical-name-derives-for-payloads-on-both-s', 'RFC 0155 §A', `${label}: deriveProfiles MUST emit the alias iff it emits the canonical name (never the alias alone)`),
|
|
77
79
|
).toBe(derived.includes(CANONICAL));
|
|
78
80
|
if (canonical) trueCount++;
|
|
79
81
|
else falseCount++;
|
|
80
82
|
}
|
|
81
83
|
// Non-vacuity: an equivalence over payloads that all derive (or none do)
|
|
82
84
|
// proves nothing about the other side.
|
|
83
|
-
expect(trueCount, 'at least one payload MUST derive the predicate').toBeGreaterThan(0);
|
|
84
|
-
expect(falseCount, 'at least one payload MUST fail the predicate').toBeGreaterThan(0);
|
|
85
|
+
expect(trueCount, req('openwop.it.profile-discovery-core-alias.the-alias-derives-exactly-when-the-canonical-name-derives-for-payloads-on-both-s', 'RFC 0155 §A', 'at least one payload MUST derive the predicate')).toBeGreaterThan(0);
|
|
86
|
+
expect(falseCount, req('openwop.it.profile-discovery-core-alias.the-alias-derives-exactly-when-the-canonical-name-derives-for-payloads-on-both-s', 'RFC 0155 §A', 'at least one payload MUST fail the predicate')).toBeGreaterThan(0);
|
|
85
87
|
});
|
|
86
88
|
|
|
87
89
|
it('a derived set that carries the alias carries the canonical name immediately before it', () => {
|
|
88
90
|
const derived = deriveProfiles(CORE);
|
|
89
91
|
const i = derived.indexOf(CANONICAL);
|
|
90
92
|
expect(i).toBeGreaterThanOrEqual(0);
|
|
91
|
-
expect(derived[i + 1], 'alias rides directly beside its canonical name').toBe(ALIAS);
|
|
93
|
+
expect(derived[i + 1], req('openwop.it.profile-discovery-core-alias.a-derived-set-that-carries-the-alias-carries-the-canonical-name-immediately-befo', 'RFC 0155 §A', 'alias rides directly beside its canonical name')).toBe(ALIAS);
|
|
92
94
|
});
|
|
93
95
|
});
|
|
94
96
|
|
|
@@ -99,7 +101,7 @@ describe.skipIf(V1_DIR === null)('RFC 0155 §A — profiles.md states the rename
|
|
|
99
101
|
const md = doc();
|
|
100
102
|
expect(md).toMatch(/###\s+`openwop-discovery-core`\s+\(canonical\)/);
|
|
101
103
|
expect(md).toMatch(/alias `openwop-core` \(deprecated\)/);
|
|
102
|
-
expect(md, 'the alias MUST be defined as deriving exactly when the canonical name derives').toMatch(
|
|
104
|
+
expect(md, req('openwop.it.profile-discovery-core-alias.names-the-canonical-profile-and-marks-openwop-core-as-a-deprecated-alias', 'RFC 0155 §A', 'the alias MUST be defined as deriving exactly when the canonical name derives')).toMatch(
|
|
103
105
|
/derives \*\*exactly when\*\* `openwop-discovery-core` derives/,
|
|
104
106
|
);
|
|
105
107
|
});
|
|
@@ -107,7 +109,7 @@ describe.skipIf(V1_DIR === null)('RFC 0155 §A — profiles.md states the rename
|
|
|
107
109
|
it('states that an unqualified conformance claim means openwop-core-standard', () => {
|
|
108
110
|
const md = doc();
|
|
109
111
|
expect(md).toMatch(/unqualified\*\* "OpenWOP conformant".*\*\*MUST\*\* mean \*\*`openwop-core-standard`\*\*/s);
|
|
110
|
-
expect(md, 'discovery-only claims MUST say openwop-discovery-core').toMatch(
|
|
112
|
+
expect(md, req('openwop.it.profile-discovery-core-alias.states-that-an-unqualified-conformance-claim-means-openwop-core-standard', 'RFC 0155 §A', 'discovery-only claims MUST say openwop-discovery-core')).toMatch(
|
|
111
113
|
/discovery-only\*\* claim \*\*MUST\*\* say \*\*`openwop-discovery-core`\*\*/,
|
|
112
114
|
);
|
|
113
115
|
});
|
|
@@ -116,7 +118,7 @@ describe.skipIf(V1_DIR === null)('RFC 0155 §A — profiles.md states the rename
|
|
|
116
118
|
const md = doc();
|
|
117
119
|
const canonicalLine = md.indexOf("'openwop-discovery-core' if openwop-discovery-core(c)");
|
|
118
120
|
const aliasLine = md.indexOf("'openwop-core' if openwop-discovery-core(c)");
|
|
119
|
-
expect(canonicalLine).toBeGreaterThan(0);
|
|
121
|
+
expect(canonicalLine, req('openwop.it.profile-discovery-core-alias.the-reference-derivation-lists-the-alias-beside-the-canonical-name-never-alone', 'RFC 0155 §A', 'the reference derivation lists the alias beside the canonical name, never alone')).toBeGreaterThan(0);
|
|
120
122
|
expect(aliasLine).toBeGreaterThan(canonicalLine);
|
|
121
123
|
});
|
|
122
124
|
});
|
|
@@ -124,11 +126,11 @@ describe.skipIf(V1_DIR === null)('RFC 0155 §A — profiles.md states the rename
|
|
|
124
126
|
describe.skipIf(!process.env.OPENWOP_BASE_URL)('RFC 0155 §A — a live host derives both names or neither', () => {
|
|
125
127
|
it('the discovery payload derives the alias iff it derives the canonical name', async () => {
|
|
126
128
|
const res = await driver.get('/.well-known/openwop');
|
|
127
|
-
if (res.status !== 200) return; // discovery is witnessed elsewhere; this leg is about the alias rule
|
|
129
|
+
if (res.status !== 200) return softSkip('blocked', 'precondition not met — `res.status !== 200` returned early (discovery is witnessed elsewhere; this leg is about the alias rule) (seam, prior step, or fixture unavailable)'); // discovery is witnessed elsewhere; this leg is about the alias rule
|
|
128
130
|
const derived = deriveProfiles(res.json as DiscoveryPayload);
|
|
129
131
|
expect(
|
|
130
132
|
derived.includes(ALIAS),
|
|
131
|
-
|
|
133
|
+
req('openwop.it.profile-discovery-core-alias.the-discovery-payload-derives-the-alias-iff-it-derives-the-canonical-name',
|
|
132
134
|
'profiles.md §"openwop-discovery-core"',
|
|
133
135
|
'the deprecated alias MUST derive exactly when the canonical name derives — a host is never `openwop-core` without being `openwop-discovery-core`',
|
|
134
136
|
),
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type DiscoveryPayload,
|
|
26
26
|
type ProfileName,
|
|
27
27
|
} from '../lib/profiles.js';
|
|
28
|
+
import { req } from '../lib/requirement-ids.js';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Minimum payload that satisfies `openwop-core`. Other fixtures extend this.
|
|
@@ -42,16 +43,16 @@ const CORE_PAYLOAD: DiscoveryPayload = {
|
|
|
42
43
|
|
|
43
44
|
describe('profiles: openwop-core predicate per spec/v1/profiles.md §`openwop-core`', () => {
|
|
44
45
|
it('accepts the minimum-conforming payload', () => {
|
|
45
|
-
expect(isCore(CORE_PAYLOAD)).toBe(true);
|
|
46
|
+
expect(isCore(CORE_PAYLOAD), req('openwop.it.profileDerivation.accepts-the-minimum-conforming-payload', 'spec/v1/profiles.md', 'accepts the minimum-conforming payload')).toBe(true);
|
|
46
47
|
});
|
|
47
48
|
|
|
48
49
|
it('rejects payload without protocolVersion', () => {
|
|
49
50
|
const { protocolVersion: _omit, ...rest } = CORE_PAYLOAD;
|
|
50
|
-
expect(isCore(rest as DiscoveryPayload)).toBe(false);
|
|
51
|
+
expect(isCore(rest as DiscoveryPayload), req('openwop.it.profileDerivation.rejects-payload-without-protocolversion', 'spec/v1/profiles.md', 'rejects payload without protocolVersion')).toBe(false);
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
it('rejects v2.x protocolVersion', () => {
|
|
54
|
-
expect(isCore({ ...CORE_PAYLOAD, protocolVersion: '2.0.0' })).toBe(false);
|
|
55
|
+
expect(isCore({ ...CORE_PAYLOAD, protocolVersion: '2.0.0' }), req('openwop.it.profileDerivation.rejects-v2-x-protocolversion', 'spec/v1/profiles.md', 'rejects v2.x protocolVersion')).toBe(false);
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
it('rejects negative limits (RFC 2119 MUST: non-negative integers)', () => {
|
|
@@ -59,7 +60,7 @@ describe('profiles: openwop-core predicate per spec/v1/profiles.md §`openwop-co
|
|
|
59
60
|
isCore({
|
|
60
61
|
...CORE_PAYLOAD,
|
|
61
62
|
limits: { ...CORE_PAYLOAD.limits!, clarificationRounds: -1 },
|
|
62
|
-
}),
|
|
63
|
+
}), req('openwop.it.profileDerivation.rejects-negative-limits-rfc-2119-must-non-negative-integers', 'RFC 2119', 'rejects negative limits (RFC 2119 MUST: non-negative integers)'),
|
|
63
64
|
).toBe(false);
|
|
64
65
|
});
|
|
65
66
|
|
|
@@ -68,17 +69,17 @@ describe('profiles: openwop-core predicate per spec/v1/profiles.md §`openwop-co
|
|
|
68
69
|
isCore({
|
|
69
70
|
...CORE_PAYLOAD,
|
|
70
71
|
limits: { ...CORE_PAYLOAD.limits!, schemaRounds: 1.5 },
|
|
71
|
-
}),
|
|
72
|
+
}), req('openwop.it.profileDerivation.rejects-fractional-limits', 'spec/v1/profiles.md', 'rejects fractional limits'),
|
|
72
73
|
).toBe(false);
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
it('accepts empty supportedEnvelopes array (engine-only host)', () => {
|
|
76
|
-
expect(isCore({ ...CORE_PAYLOAD, supportedEnvelopes: [] })).toBe(true);
|
|
77
|
+
expect(isCore({ ...CORE_PAYLOAD, supportedEnvelopes: [] }), req('openwop.it.profileDerivation.accepts-empty-supportedenvelopes-array-engine-only-host', 'spec/v1/profiles.md', 'accepts empty supportedEnvelopes array (engine-only host)')).toBe(true);
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
it('rejects non-array supportedEnvelopes', () => {
|
|
80
81
|
expect(
|
|
81
|
-
isCore({ ...CORE_PAYLOAD, supportedEnvelopes: 'prd.create' as unknown as string[] }),
|
|
82
|
+
isCore({ ...CORE_PAYLOAD, supportedEnvelopes: 'prd.create' as unknown as string[] }), req('openwop.it.profileDerivation.rejects-non-array-supportedenvelopes', 'spec/v1/profiles.md', 'rejects non-array supportedEnvelopes'),
|
|
82
83
|
).toBe(false);
|
|
83
84
|
});
|
|
84
85
|
});
|
|
@@ -89,12 +90,12 @@ describe('profiles: openwop-interrupts predicate per spec/v1/profiles.md §`open
|
|
|
89
90
|
isInterrupts({
|
|
90
91
|
...CORE_PAYLOAD,
|
|
91
92
|
supportedEnvelopes: ['prd.create', 'clarification.request'],
|
|
92
|
-
}),
|
|
93
|
+
}), req('openwop.it.profileDerivation.passes-when-clarification-request-is-in-supportedenvelopes', 'spec/v1/profiles.md', 'passes when clarification.request is in supportedEnvelopes'),
|
|
93
94
|
).toBe(true);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
it('fails when clarification.request is absent (fire-and-forget host)', () => {
|
|
97
|
-
expect(isInterrupts(CORE_PAYLOAD)).toBe(false);
|
|
98
|
+
expect(isInterrupts(CORE_PAYLOAD), req('openwop.it.profileDerivation.fails-when-clarification-request-is-absent-fire-and-forget-host', 'spec/v1/profiles.md', 'fails when clarification.request is absent (fire-and-forget host)')).toBe(false);
|
|
98
99
|
});
|
|
99
100
|
|
|
100
101
|
it('implies openwop-core', () => {
|
|
@@ -103,7 +104,7 @@ describe('profiles: openwop-interrupts predicate per spec/v1/profiles.md §`open
|
|
|
103
104
|
protocolVersion: '2.0.0',
|
|
104
105
|
supportedEnvelopes: ['clarification.request'],
|
|
105
106
|
};
|
|
106
|
-
expect(isInterrupts(broken)).toBe(false);
|
|
107
|
+
expect(isInterrupts(broken), req('openwop.it.profileDerivation.implies-openwop-core', 'spec/v1/profiles.md', 'implies openwop-core')).toBe(false);
|
|
107
108
|
});
|
|
108
109
|
});
|
|
109
110
|
|
|
@@ -113,7 +114,7 @@ describe('profiles: openwop-secrets predicate per spec/v1/profiles.md §`openwop
|
|
|
113
114
|
isSecrets({
|
|
114
115
|
...CORE_PAYLOAD,
|
|
115
116
|
secrets: { supported: true, scopes: ['user'] },
|
|
116
|
-
}),
|
|
117
|
+
}), req('openwop.it.profileDerivation.passes-when-secrets-supported-true-and-scopes-includes-user', 'spec/v1/profiles.md', 'passes when secrets.supported=true and scopes includes user'),
|
|
117
118
|
).toBe(true);
|
|
118
119
|
});
|
|
119
120
|
|
|
@@ -122,7 +123,7 @@ describe('profiles: openwop-secrets predicate per spec/v1/profiles.md §`openwop
|
|
|
122
123
|
isSecrets({
|
|
123
124
|
...CORE_PAYLOAD,
|
|
124
125
|
secrets: { supported: true, scopes: ['user', 'tenant'] },
|
|
125
|
-
}),
|
|
126
|
+
}), req('openwop.it.profileDerivation.passes-with-multiple-scopes', 'spec/v1/profiles.md', 'passes with multiple scopes'),
|
|
126
127
|
).toBe(true);
|
|
127
128
|
});
|
|
128
129
|
|
|
@@ -131,7 +132,7 @@ describe('profiles: openwop-secrets predicate per spec/v1/profiles.md §`openwop
|
|
|
131
132
|
isSecrets({
|
|
132
133
|
...CORE_PAYLOAD,
|
|
133
134
|
secrets: { supported: true, scopes: ['tenant'] },
|
|
134
|
-
}),
|
|
135
|
+
}), req('openwop.it.profileDerivation.fails-when-scopes-omits-user', 'spec/v1/profiles.md', 'fails when scopes omits user'),
|
|
135
136
|
).toBe(false);
|
|
136
137
|
});
|
|
137
138
|
|
|
@@ -140,12 +141,12 @@ describe('profiles: openwop-secrets predicate per spec/v1/profiles.md §`openwop
|
|
|
140
141
|
isSecrets({
|
|
141
142
|
...CORE_PAYLOAD,
|
|
142
143
|
secrets: { supported: false, scopes: ['user'] },
|
|
143
|
-
}),
|
|
144
|
+
}), req('openwop.it.profileDerivation.fails-when-secrets-supported-false', 'spec/v1/profiles.md', 'fails when secrets.supported=false'),
|
|
144
145
|
).toBe(false);
|
|
145
146
|
});
|
|
146
147
|
|
|
147
148
|
it('fails when secrets field is absent', () => {
|
|
148
|
-
expect(isSecrets(CORE_PAYLOAD)).toBe(false);
|
|
149
|
+
expect(isSecrets(CORE_PAYLOAD), req('openwop.it.profileDerivation.fails-when-secrets-field-is-absent', 'spec/v1/profiles.md', 'fails when secrets field is absent')).toBe(false);
|
|
149
150
|
});
|
|
150
151
|
});
|
|
151
152
|
|
|
@@ -158,7 +159,7 @@ describe('profiles: openwop-provider-policy predicate per spec/v1/profiles.md §
|
|
|
158
159
|
supported: ['anthropic'],
|
|
159
160
|
policies: { modes: ['optional', 'required'] },
|
|
160
161
|
},
|
|
161
|
-
}),
|
|
162
|
+
}), req('openwop.it.profileDerivation.passes-when-policies-modes-contains-optional', 'spec/v1/profiles.md', 'passes when policies.modes contains optional'),
|
|
162
163
|
).toBe(true);
|
|
163
164
|
});
|
|
164
165
|
|
|
@@ -170,7 +171,7 @@ describe('profiles: openwop-provider-policy predicate per spec/v1/profiles.md §
|
|
|
170
171
|
supported: ['anthropic'],
|
|
171
172
|
policies: { modes: [] },
|
|
172
173
|
},
|
|
173
|
-
}),
|
|
174
|
+
}), req('openwop.it.profileDerivation.fails-when-policies-modes-is-empty-per-spec-empty-not-a-valid-third-state', 'spec/v1/profiles.md', 'fails when policies.modes is empty (per spec: empty {} not a valid third state)'),
|
|
174
175
|
).toBe(false);
|
|
175
176
|
});
|
|
176
177
|
|
|
@@ -182,7 +183,7 @@ describe('profiles: openwop-provider-policy predicate per spec/v1/profiles.md §
|
|
|
182
183
|
supported: ['anthropic'],
|
|
183
184
|
policies: { modes: ['required'] },
|
|
184
185
|
},
|
|
185
|
-
}),
|
|
186
|
+
}), req('openwop.it.profileDerivation.fails-when-policies-modes-omits-optional-cannot-satisfy-default-no-restriction-c', 'spec/v1/profiles.md', 'fails when policies.modes omits optional (cannot satisfy default-no-restriction case)'),
|
|
186
187
|
).toBe(false);
|
|
187
188
|
});
|
|
188
189
|
|
|
@@ -191,23 +192,23 @@ describe('profiles: openwop-provider-policy predicate per spec/v1/profiles.md §
|
|
|
191
192
|
isProviderPolicy({
|
|
192
193
|
...CORE_PAYLOAD,
|
|
193
194
|
aiProviders: { supported: ['anthropic'] },
|
|
194
|
-
}),
|
|
195
|
+
}), req('openwop.it.profileDerivation.fails-when-policies-field-is-absent', 'spec/v1/profiles.md', 'fails when policies field is absent'),
|
|
195
196
|
).toBe(false);
|
|
196
197
|
});
|
|
197
198
|
});
|
|
198
199
|
|
|
199
200
|
describe('profiles: openwop-fixtures predicate per spec/v1/profiles.md §`openwop-fixtures` (RFC 0003)', () => {
|
|
200
201
|
it('rejects payloads missing `fixtures`', () => {
|
|
201
|
-
expect(isFixtures(CORE_PAYLOAD)).toBe(false);
|
|
202
|
+
expect(isFixtures(CORE_PAYLOAD), req('openwop.it.profileDerivation.rejects-payloads-missing-fixtures', 'spec/v1/profiles.md', 'rejects payloads missing `fixtures`')).toBe(false);
|
|
202
203
|
});
|
|
203
204
|
|
|
204
205
|
it('rejects empty `fixtures` array', () => {
|
|
205
|
-
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: [] })).toBe(false);
|
|
206
|
+
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: [] }), req('openwop.it.profileDerivation.rejects-empty-fixtures-array', 'spec/v1/profiles.md', 'rejects empty `fixtures` array')).toBe(false);
|
|
206
207
|
});
|
|
207
208
|
|
|
208
209
|
it('accepts non-empty string array', () => {
|
|
209
210
|
expect(
|
|
210
|
-
isFixtures({ ...CORE_PAYLOAD, fixtures: ['conformance-noop'] }),
|
|
211
|
+
isFixtures({ ...CORE_PAYLOAD, fixtures: ['conformance-noop'] }), req('openwop.it.profileDerivation.accepts-non-empty-string-array', 'spec/v1/profiles.md', 'accepts non-empty string array'),
|
|
211
212
|
).toBe(true);
|
|
212
213
|
});
|
|
213
214
|
|
|
@@ -216,16 +217,16 @@ describe('profiles: openwop-fixtures predicate per spec/v1/profiles.md §`openwo
|
|
|
216
217
|
isFixtures({
|
|
217
218
|
...CORE_PAYLOAD,
|
|
218
219
|
fixtures: ['conformance-noop', 'openwop.smoke.byok'],
|
|
219
|
-
}),
|
|
220
|
+
}), req('openwop.it.profileDerivation.accepts-vendor-prefixed-fixture-ids', 'spec/v1/profiles.md', 'accepts vendor-prefixed fixture ids'),
|
|
220
221
|
).toBe(true);
|
|
221
222
|
});
|
|
222
223
|
|
|
223
224
|
it('rejects array with empty-string entries', () => {
|
|
224
|
-
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: ['', 'conformance-noop'] })).toBe(false);
|
|
225
|
+
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: ['', 'conformance-noop'] }), req('openwop.it.profileDerivation.rejects-array-with-empty-string-entries', 'spec/v1/profiles.md', 'rejects array with empty-string entries')).toBe(false);
|
|
225
226
|
});
|
|
226
227
|
|
|
227
228
|
it('rejects non-array `fixtures`', () => {
|
|
228
|
-
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: 'conformance-noop' })).toBe(false);
|
|
229
|
+
expect(isFixtures({ ...CORE_PAYLOAD, fixtures: 'conformance-noop' }), req('openwop.it.profileDerivation.rejects-non-array-fixtures', 'spec/v1/profiles.md', 'rejects non-array `fixtures`')).toBe(false);
|
|
229
230
|
expect(
|
|
230
231
|
isFixtures({ ...CORE_PAYLOAD, fixtures: { 'conformance-noop': true } }),
|
|
231
232
|
).toBe(false);
|
|
@@ -233,12 +234,12 @@ describe('profiles: openwop-fixtures predicate per spec/v1/profiles.md §`openwo
|
|
|
233
234
|
|
|
234
235
|
it('rejects array with non-string entries', () => {
|
|
235
236
|
expect(
|
|
236
|
-
isFixtures({ ...CORE_PAYLOAD, fixtures: ['conformance-noop', 42] as unknown[] }),
|
|
237
|
+
isFixtures({ ...CORE_PAYLOAD, fixtures: ['conformance-noop', 42] as unknown[] }), req('openwop.it.profileDerivation.rejects-array-with-non-string-entries', 'spec/v1/profiles.md', 'rejects array with non-string entries'),
|
|
237
238
|
).toBe(false);
|
|
238
239
|
});
|
|
239
240
|
|
|
240
241
|
it('rejects when openwop-core fails (predicate is layered)', () => {
|
|
241
|
-
expect(isFixtures({ fixtures: ['conformance-noop'] })).toBe(false);
|
|
242
|
+
expect(isFixtures({ fixtures: ['conformance-noop'] }), req('openwop.it.profileDerivation.rejects-when-openwop-core-fails-predicate-is-layered', 'spec/v1/profiles.md', 'rejects when openwop-core fails (predicate is layered)')).toBe(false);
|
|
242
243
|
});
|
|
243
244
|
});
|
|
244
245
|
|
|
@@ -249,7 +250,7 @@ describe('profiles: deriveProfiles produces the full set', () => {
|
|
|
249
250
|
// (no supportedTransports set => permitted), openwop-node-packs (discovery-
|
|
250
251
|
// only predicate is openwop-core).
|
|
251
252
|
const result = deriveProfiles(CORE_PAYLOAD);
|
|
252
|
-
expect(result).toContain('openwop-core');
|
|
253
|
+
expect(result, req('openwop.it.profileDerivation.returns-openwop-core-stream-node-packs-for-the-minimum-payload', 'spec/v1/profiles.md', 'returns openwop-core + stream-* + node-packs for the minimum payload')).toContain('openwop-core');
|
|
253
254
|
expect(result).toContain('openwop-stream-sse');
|
|
254
255
|
expect(result).toContain('openwop-stream-poll');
|
|
255
256
|
expect(result).toContain('openwop-node-packs');
|
|
@@ -282,7 +283,7 @@ describe('profiles: deriveProfiles produces the full set', () => {
|
|
|
282
283
|
'openwop-node-packs',
|
|
283
284
|
'openwop-fixtures',
|
|
284
285
|
];
|
|
285
|
-
expect(result).toEqual(expected);
|
|
286
|
+
expect(result, req('openwop.it.profileDerivation.returns-the-full-set-for-a-richly-advertised-host', 'spec/v1/profiles.md', 'returns the full set for a richly-advertised host')).toEqual(expected);
|
|
286
287
|
});
|
|
287
288
|
|
|
288
289
|
it('returns stable order matching PROFILE_NAMES', () => {
|
|
@@ -293,7 +294,7 @@ describe('profiles: deriveProfiles produces the full set', () => {
|
|
|
293
294
|
};
|
|
294
295
|
const first = deriveProfiles(rich);
|
|
295
296
|
const second = deriveProfiles(rich);
|
|
296
|
-
expect(first).toEqual(second);
|
|
297
|
+
expect(first, req('openwop.it.profileDerivation.returns-stable-order-matching-profile-names', 'spec/v1/profiles.md', 'returns stable order matching PROFILE_NAMES')).toEqual(second);
|
|
297
298
|
// Specifically: openwop-interrupts before openwop-secrets even though openwop-secrets
|
|
298
299
|
// was added to the payload "second."
|
|
299
300
|
expect(first.indexOf('openwop-interrupts')).toBeLessThan(first.indexOf('openwop-secrets'));
|
|
@@ -301,13 +302,13 @@ describe('profiles: deriveProfiles produces the full set', () => {
|
|
|
301
302
|
|
|
302
303
|
it('returns empty for a non-conforming payload', () => {
|
|
303
304
|
const broken: DiscoveryPayload = { protocolVersion: '0.9.0' };
|
|
304
|
-
expect(deriveProfiles(broken)).toEqual([]);
|
|
305
|
+
expect(deriveProfiles(broken), req('openwop.it.profileDerivation.returns-empty-for-a-non-conforming-payload', 'spec/v1/profiles.md', 'returns empty for a non-conforming payload')).toEqual([]);
|
|
305
306
|
});
|
|
306
307
|
|
|
307
308
|
it('is deterministic across calls (same input → same output)', () => {
|
|
308
309
|
const calls = Array.from({ length: 10 }, () => deriveProfiles(CORE_PAYLOAD));
|
|
309
310
|
for (let i = 1; i < calls.length; i++) {
|
|
310
|
-
expect(calls[i]).toEqual(calls[0]);
|
|
311
|
+
expect(calls[i], req('openwop.it.profileDerivation.is-deterministic-across-calls-same-input-same-output', 'spec/v1/profiles.md', 'is deterministic across calls (same input → same output)')).toEqual(calls[0]);
|
|
311
312
|
}
|
|
312
313
|
});
|
|
313
314
|
});
|
|
@@ -330,7 +331,7 @@ describe('profiles: hasProfile is consistent with deriveProfiles', () => {
|
|
|
330
331
|
'openwop-node-packs',
|
|
331
332
|
'openwop-fixtures',
|
|
332
333
|
] as const) {
|
|
333
|
-
expect(hasProfile(rich, p)).toBe(derived.has(p));
|
|
334
|
+
expect(hasProfile(rich, p), req('openwop.it.profileDerivation.membership-matches-the-derived-set-for-every-profile', 'spec/v1/profiles.md', 'membership matches the derived set for every profile')).toBe(derived.has(p));
|
|
334
335
|
}
|
|
335
336
|
});
|
|
336
337
|
});
|
|
@@ -35,6 +35,8 @@ import { pollUntilTerminal } from '../lib/polling.js';
|
|
|
35
35
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
36
36
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
37
37
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
38
|
+
import { req } from '../lib/requirement-ids.js';
|
|
39
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
38
40
|
|
|
39
41
|
const WORKFLOW_ID = 'conformance-prompt-all-four-kinds';
|
|
40
42
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
|
|
@@ -85,7 +87,7 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
85
87
|
const create = await driver.post('/v1/runs', { workflowId: WORKFLOW_ID });
|
|
86
88
|
expect(
|
|
87
89
|
create.status,
|
|
88
|
-
|
|
90
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
89
91
|
'spec/v1/rest-endpoints.md',
|
|
90
92
|
'POST /v1/runs MUST return 201 on accepted creation',
|
|
91
93
|
),
|
|
@@ -95,7 +97,7 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
95
97
|
const terminal = await pollUntilTerminal(runId);
|
|
96
98
|
expect(
|
|
97
99
|
terminal.status,
|
|
98
|
-
|
|
100
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
99
101
|
'fixtures.md conformance-prompt-all-four-kinds §Terminal status',
|
|
100
102
|
'fixture MUST reach terminal `completed`',
|
|
101
103
|
),
|
|
@@ -120,7 +122,7 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
120
122
|
for (const expectedKind of ['system', 'user', 'schema-hint', 'few-shot']) {
|
|
121
123
|
expect(
|
|
122
124
|
resolvedKinds.includes(expectedKind),
|
|
123
|
-
|
|
125
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
124
126
|
'spec/v1/prompts.md §"PromptKind"',
|
|
125
127
|
`host MUST emit \`agent.promptResolved\` with kind: "${expectedKind}" when the node carries the matching ref`,
|
|
126
128
|
),
|
|
@@ -144,14 +146,14 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
144
146
|
for (const expectedRef of expectedTemplates) {
|
|
145
147
|
expect(
|
|
146
148
|
resolvedRefs.includes(expectedRef),
|
|
147
|
-
|
|
149
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
148
150
|
'spec/v1/prompts.md §"Resolution chain (normative)"',
|
|
149
151
|
`\`agent.promptResolved.resolved\` MUST surface "${expectedRef}" — the fixture carries it on the node config and the resolver MUST return it (multi-entry few-shot[slotIndex] regression pin)`,
|
|
150
152
|
),
|
|
151
153
|
).toBe(true);
|
|
152
154
|
expect(
|
|
153
155
|
composedRefs.includes(expectedRef),
|
|
154
|
-
|
|
156
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
155
157
|
'spec/v1/prompts.md §"Composition + observability"',
|
|
156
158
|
`\`prompt.composed.refs[]\` MUST contain "${expectedRef}" — one composition per resolved ref`,
|
|
157
159
|
),
|
|
@@ -161,7 +163,7 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
161
163
|
// silently dropped non-zero few-shot indices would emit fewer.
|
|
162
164
|
expect(
|
|
163
165
|
composedRefs.length,
|
|
164
|
-
|
|
166
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-agent-promptresolved-prompt-composed-for-system-user-schema-hint-and-few-s',
|
|
165
167
|
'spec/v1/prompts.md §"Composition + observability"',
|
|
166
168
|
'host MUST emit one `prompt.composed` event per composed body (5 refs → 5 events when all five resolve, including both few-shot entries)',
|
|
167
169
|
),
|
|
@@ -172,7 +174,7 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
172
174
|
const d = await readDiscovery();
|
|
173
175
|
if (!behaviorGate('prompts-supported', promptsSupported(d))) return;
|
|
174
176
|
const create = await driver.post('/v1/runs', { workflowId: WORKFLOW_ID });
|
|
175
|
-
if (create.status !== 201) return;
|
|
177
|
+
if (create.status !== 201) return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
|
|
176
178
|
const { runId } = create.json as { runId: string };
|
|
177
179
|
await pollUntilTerminal(runId);
|
|
178
180
|
const events = await readAllEvents(runId);
|
|
@@ -186,11 +188,11 @@ describe.skipIf(SKIP_NO_FIXTURE || HTTP_SKIP)('prompt-all-four-kinds-events: eac
|
|
|
186
188
|
const firstComposedIdx = events.findIndex((e) => e.type === 'prompt.composed');
|
|
187
189
|
expect(
|
|
188
190
|
firstResolvedIdx >= 0 && firstComposedIdx >= 0,
|
|
189
|
-
'both event types MUST appear in the event log',
|
|
191
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-the-first-agent-promptresolved-before-the-first-prompt-composed-resolution', 'spec/v1/prompts.md §"Composition + observability"', 'both event types MUST appear in the event log'),
|
|
190
192
|
).toBe(true);
|
|
191
193
|
expect(
|
|
192
194
|
firstResolvedIdx,
|
|
193
|
-
|
|
195
|
+
req('openwop.it.prompt-all-four-kinds-events.emits-the-first-agent-promptresolved-before-the-first-prompt-composed-resolution',
|
|
194
196
|
'spec/v1/prompts.md §"Composition + observability"',
|
|
195
197
|
'resolution events MUST precede the first composition event in the run log (composition cannot start before any resolution completes)',
|
|
196
198
|
),
|