@openwop/openwop-conformance 1.163.0 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/cli.js +262 -14
- package/dist/lib/certification-bundle-v3.js +142 -0
- package/dist/lib/paths.js +25 -3
- package/dist/lib/requirement-ids.js +57 -4
- package/dist/lib/requirement-ledger.js +1 -0
- package/dist/lib/scenario-disposition.js +6 -1
- package/dist/lib/spec-coherence.js +13 -32
- package/dist/spec-artifacts.lock.json +5 -0
- package/package.json +11 -33
- package/requirements.json +22892 -11701
- package/scenario-majors.json +1493 -0
- package/schemas/CORPUS-STAMP.json +137 -5
- package/src/cli.ts +236 -19
- package/src/global-setup.ts +3 -2
- package/src/lib/certification-bundle-v3.ts +175 -0
- package/src/lib/corpus-stamp.ts +29 -1
- package/src/lib/driver.ts +9 -1
- package/src/lib/era2-seed.ts +197 -0
- package/src/lib/paths.ts +25 -3
- package/src/lib/requirement-ids.ts +54 -4
- package/src/lib/requirement-ledger.ts +7 -1
- package/src/lib/scenario-disposition.ts +6 -1
- package/src/lib/seams.ts +45 -0
- package/src/lib/spec-coherence.ts +15 -32
- package/src/lib/v2.ts +62 -0
- 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/v2-approver-enforced.test.ts +97 -0
- package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
- package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
- package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
- package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
- package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
- package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
- package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
- package/src/scenarios/v2-configurable-closed.test.ts +67 -0
- package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
- package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
- package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
- package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
- package/src/scenarios/v2-era-key.test.ts +86 -0
- package/src/scenarios/v2-error-registry.test.ts +89 -0
- package/src/scenarios/v2-event-type-closed.test.ts +97 -0
- package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
- package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
- package/src/scenarios/v2-header-scheme.test.ts +67 -0
- package/src/scenarios/v2-id-grammar.test.ts +77 -0
- package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
- package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
- package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
- package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
- package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
- package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
- package/src/scenarios/v2-min-client-version.test.ts +48 -0
- package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
- package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
- package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
- package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
- package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
- package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
- package/src/scenarios/v2-pack-isolation.test.ts +147 -0
- package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
- package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
- package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
- package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
- package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
- package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
- package/src/scenarios/v2-provider-conflict.test.ts +115 -0
- package/src/scenarios/v2-refresh-sla.test.ts +78 -0
- package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
- package/src/scenarios/v2-revocation-honored.test.ts +66 -0
- package/src/scenarios/v2-subject-link-record.test.ts +102 -0
- package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
- package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
- package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
- package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
- package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
- 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 +44 -6
- 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 -4160
- 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
|
@@ -30,9 +30,8 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
30
30
|
import addFormats from 'ajv-formats';
|
|
31
31
|
import { driver } from '../lib/driver.js';
|
|
32
32
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
36
35
|
|
|
37
36
|
interface AuthModeCapabilities {
|
|
38
37
|
aiProviders?: {
|
|
@@ -70,9 +69,9 @@ describe('byok-auth-modes: schema shape (RFC 0067, server-free)', () => {
|
|
|
70
69
|
| undefined;
|
|
71
70
|
expect(
|
|
72
71
|
authModes,
|
|
73
|
-
|
|
72
|
+
req('openwop.it.byok-auth-modes.the-capabilities-schema-declares-aiproviders-authmodes-with-the-five-mode-enum', 'capabilities.md §aiProviders.authModes', 'the schema MUST declare aiProviders.authModes'),
|
|
74
73
|
).toBeDefined();
|
|
75
|
-
expect(authModes?.additionalProperties?.items?.enum).toEqual([
|
|
74
|
+
expect(authModes?.additionalProperties?.items?.enum, req('openwop.it.byok-auth-modes.the-capabilities-schema-declares-aiproviders-authmodes-with-the-five-mode-enum', 'RFC 0067', 'the capabilities schema declares aiProviders.authModes with the five-mode enum')).toEqual([
|
|
76
75
|
'apiKey',
|
|
77
76
|
'oauth-pkce',
|
|
78
77
|
'oauth-device',
|
|
@@ -85,10 +84,10 @@ describe('byok-auth-modes: schema shape (RFC 0067, server-free)', () => {
|
|
|
85
84
|
const validate = authModesValidator();
|
|
86
85
|
expect(
|
|
87
86
|
validate({ anthropic: ['apiKey'], vertex: ['oauth-pkce'], ollama: ['none'] }),
|
|
88
|
-
|
|
87
|
+
req('openwop.it.byok-auth-modes.a-conforming-authmodes-map-validates-malformed-maps-are-rejected', 'RFC 0067 §A', 'a conforming authModes map MUST validate'),
|
|
89
88
|
).toBe(true);
|
|
90
89
|
// Negative: empty array fails minItems.
|
|
91
|
-
expect(validate({ anthropic: [] })).toBe(false);
|
|
90
|
+
expect(validate({ anthropic: [] }), req('openwop.it.byok-auth-modes.a-conforming-authmodes-map-validates-malformed-maps-are-rejected', 'RFC 0067', 'a conforming authModes map validates; malformed maps are rejected')).toBe(false);
|
|
92
91
|
// Negative: unknown mode (`device` — canonical is `oauth-device`) fails the enum.
|
|
93
92
|
expect(validate({ anthropic: ['device'] })).toBe(false);
|
|
94
93
|
});
|
|
@@ -97,10 +96,10 @@ describe('byok-auth-modes: schema shape (RFC 0067, server-free)', () => {
|
|
|
97
96
|
describe('byok-auth-modes: cross-field consistency (gated on advertisement)', () => {
|
|
98
97
|
it('a host advertising authModes MUST satisfy the §B contract', async () => {
|
|
99
98
|
const res = await driver.get('/.well-known/openwop', { authenticated: false });
|
|
100
|
-
if (res.status !== 200) return; // discovery unavailable — skip cleanly
|
|
99
|
+
if (res.status !== 200) return softSkip('blocked', 'precondition not met — `res.status !== 200` returned early (discovery unavailable — skip cleanly) (seam, prior step, or fixture unavailable)'); // discovery unavailable — skip cleanly
|
|
101
100
|
const caps = res.json as AuthModeCapabilities;
|
|
102
101
|
const authModes = caps.aiProviders?.authModes;
|
|
103
|
-
if (!authModes) return; // host does not advertise authModes — gated skip
|
|
102
|
+
if (!authModes) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!authModes` returned early (host does not advertise authModes — gated skip)'); // host does not advertise authModes — gated skip
|
|
104
103
|
|
|
105
104
|
const supported = new Set(caps.aiProviders?.supported ?? []);
|
|
106
105
|
const byok = new Set(caps.aiProviders?.byok ?? []);
|
|
@@ -110,14 +109,14 @@ describe('byok-auth-modes: cross-field consistency (gated on advertisement)', ()
|
|
|
110
109
|
// §B.1 — every key is in `supported`.
|
|
111
110
|
expect(
|
|
112
111
|
supported.has(provider),
|
|
113
|
-
|
|
112
|
+
req('openwop.it.byok-auth-modes.a-host-advertising-authmodes-must-satisfy-the-b-contract', 'RFC 0067 §B.1', `authModes key '${provider}' MUST appear in aiProviders.supported`),
|
|
114
113
|
).toBe(true);
|
|
115
114
|
|
|
116
115
|
// §B.2 — an `apiKey` provider is in `byok`.
|
|
117
116
|
if (modes.includes('apiKey')) {
|
|
118
117
|
expect(
|
|
119
118
|
byok.has(provider),
|
|
120
|
-
|
|
119
|
+
req('openwop.it.byok-auth-modes.a-host-advertising-authmodes-must-satisfy-the-b-contract', 'RFC 0067 §B.2', `provider '${provider}' with apiKey MUST appear in aiProviders.byok`),
|
|
121
120
|
).toBe(true);
|
|
122
121
|
}
|
|
123
122
|
|
|
@@ -125,7 +124,7 @@ describe('byok-auth-modes: cross-field consistency (gated on advertisement)', ()
|
|
|
125
124
|
if (modes.includes('subscription')) {
|
|
126
125
|
expect(
|
|
127
126
|
byok.has(provider),
|
|
128
|
-
|
|
127
|
+
req('openwop.it.byok-auth-modes.a-host-advertising-authmodes-must-satisfy-the-b-contract', 'RFC 0121 §B.7', `provider '${provider}' with subscription MUST appear in aiProviders.byok`),
|
|
129
128
|
).toBe(true);
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -133,7 +132,7 @@ describe('byok-auth-modes: cross-field consistency (gated on advertisement)', ()
|
|
|
133
132
|
if (modes.length === 1 && modes[0] === 'none') {
|
|
134
133
|
expect(
|
|
135
134
|
byok.has(provider),
|
|
136
|
-
|
|
135
|
+
req('openwop.it.byok-auth-modes.a-host-advertising-authmodes-must-satisfy-the-b-contract', 'RFC 0067 §B.3', `provider '${provider}' with modes ["none"] MUST NOT appear in aiProviders.byok`),
|
|
137
136
|
).toBe(false);
|
|
138
137
|
}
|
|
139
138
|
|
|
@@ -142,7 +141,7 @@ describe('byok-auth-modes: cross-field consistency (gated on advertisement)', ()
|
|
|
142
141
|
if ((modes.includes('oauth-pkce') || modes.includes('oauth-device')) && oauthIds.size > 0) {
|
|
143
142
|
expect(
|
|
144
143
|
oauthIds.has(provider),
|
|
145
|
-
|
|
144
|
+
req('openwop.it.byok-auth-modes.a-host-advertising-authmodes-must-satisfy-the-b-contract', 'RFC 0067 §B.4', `oauth provider '${provider}' SHOULD have a matching capabilities.oauth.providers[].id`),
|
|
146
145
|
).toBe(true);
|
|
147
146
|
}
|
|
148
147
|
}
|
|
@@ -26,6 +26,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
26
26
|
import { driver } from '../lib/driver.js';
|
|
27
27
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
28
28
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
29
|
+
import { req } from '../lib/requirement-ids.js';
|
|
30
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
29
31
|
|
|
30
32
|
/** SHA-256 hex regex — 64 lowercase hex chars exactly. */
|
|
31
33
|
const SHA256_HEX_RE = /^[0-9a-f]{64}$/;
|
|
@@ -42,17 +44,17 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
42
44
|
// Fixture absent OR canary not provisioned — host doesn't opt in.
|
|
43
45
|
// Scenario passes trivially.
|
|
44
46
|
if (create.status === 404 || create.status === 422) {
|
|
45
|
-
return;
|
|
47
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `create.status === 404 || create.status === 422` returned early (Fixture absent OR canary not provisioned — host doesn\'t opt in. Scenario passes trivially.)');
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
expect(create.status,
|
|
50
|
+
expect(create.status, req('openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h',
|
|
49
51
|
'rest-endpoints.md POST /v1/runs',
|
|
50
52
|
'starting openwop-smoke-byok-roundtrip MUST succeed when OPENWOP_CONFORMANCE_FIXTURES=1 is advertised AND openwop-conformance-canary-secret is provisioned',
|
|
51
53
|
)).toBe(201);
|
|
52
54
|
const runId = (create.json as { runId: string }).runId;
|
|
53
55
|
|
|
54
56
|
const terminal = await pollUntilTerminal(runId);
|
|
55
|
-
expect(terminal.status,
|
|
57
|
+
expect(terminal.status, req('openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h',
|
|
56
58
|
'auth.md §"Secret resolution"',
|
|
57
59
|
'BYOK fixture run MUST reach terminal completed when canary is provisioned',
|
|
58
60
|
)).toBe('completed');
|
|
@@ -79,17 +81,17 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
79
81
|
// Host doesn't expose node outputs in variables/outputs map —
|
|
80
82
|
// some hosts only expose them on the events stream. Skip the
|
|
81
83
|
// shape check; the run-completed assertion above is sufficient.
|
|
82
|
-
return;
|
|
84
|
+
return softSkip('blocked', 'precondition not met — `!candidate || typeof candidate !== \'object\'` returned early (Host doesn\'t expose node outputs in variables/outputs map — some hosts only expose them on the events stream. Skip the shape check; …');
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
if ('secretSha256' in candidate && typeof candidate.secretSha256 === 'string') {
|
|
86
|
-
expect(candidate.secretSha256,
|
|
88
|
+
expect(candidate.secretSha256, req('openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h',
|
|
87
89
|
'auth.md §"Secret resolution"',
|
|
88
90
|
'fixture-emitted SHA-256 hex MUST be 64 lowercase hex chars',
|
|
89
91
|
)).toMatch(SHA256_HEX_RE);
|
|
90
92
|
}
|
|
91
93
|
if ('secretLength' in candidate && typeof candidate.secretLength === 'number') {
|
|
92
|
-
expect(candidate.secretLength,
|
|
94
|
+
expect(candidate.secretLength, req('openwop.it.byok-roundtrip.the-canary-fixture-run-must-resolve-a-host-provisioned-secret-and-emit-sha-256-h',
|
|
93
95
|
'auth.md §"Secret resolution"',
|
|
94
96
|
'resolved canary length MUST be > 0 (non-empty)',
|
|
95
97
|
)).toBeGreaterThan(0);
|
|
@@ -101,7 +103,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
101
103
|
workflowId: 'openwop-smoke-byok-roundtrip',
|
|
102
104
|
});
|
|
103
105
|
if (create.status === 404 || create.status === 422) {
|
|
104
|
-
return;
|
|
106
|
+
return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
105
107
|
}
|
|
106
108
|
expect(create.status).toBe(201);
|
|
107
109
|
const runId = (create.json as { runId: string }).runId;
|
|
@@ -116,7 +118,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
116
118
|
const completed = events.filter(
|
|
117
119
|
(e) => e.type === 'node.completed' && e.nodeId === 'resolve-secret',
|
|
118
120
|
);
|
|
119
|
-
expect(completed.length,
|
|
121
|
+
expect(completed.length, req('openwop.it.byok-roundtrip.byok-fixture-run-must-emit-a-node-completed-event-for-the-resolve-step',
|
|
120
122
|
'event-log.md §node.completed',
|
|
121
123
|
'BYOK fixture node MUST emit exactly one node.completed event when secrets.resolve succeeds',
|
|
122
124
|
)).toBe(1);
|
|
@@ -127,7 +129,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
127
129
|
workflowId: 'openwop-smoke-byok-roundtrip',
|
|
128
130
|
});
|
|
129
131
|
if (create.status === 404 || create.status === 422) {
|
|
130
|
-
return;
|
|
132
|
+
return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
131
133
|
}
|
|
132
134
|
expect(create.status).toBe(201);
|
|
133
135
|
const runId = (create.json as { runId: string }).runId;
|
|
@@ -157,7 +159,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('byok: end-to-end credentialRef resolution roun
|
|
|
157
159
|
/"raw_secret"\s*:\s*"[^"]{8,}"/,
|
|
158
160
|
];
|
|
159
161
|
for (const pat of suspiciousPatterns) {
|
|
160
|
-
expect(dump,
|
|
162
|
+
expect(dump, req('openwop.it.byok-roundtrip.byok-fixture-run-event-log-must-not-echo-the-resolved-secret-value-redaction',
|
|
161
163
|
'observability.md §"Redaction"',
|
|
162
164
|
`event log MUST NOT contain a payload matching ${pat} — secret.echo fixture only emits hash + length`,
|
|
163
165
|
)).not.toMatch(pat);
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
import { describe, it, expect } from 'vitest';
|
|
11
11
|
import { driver } from '../lib/driver.js';
|
|
12
12
|
import { discoveryFamilies } from '../lib/discovery-capabilities.js';
|
|
13
|
+
import { req } from '../lib/requirement-ids.js';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
13
15
|
|
|
14
16
|
interface DiscoveryDoc {
|
|
15
17
|
capabilities?: Record<string, unknown>;
|
|
@@ -30,10 +32,10 @@ async function call(tenantId: string, op: string, args: Record<string, unknown>)
|
|
|
30
32
|
describe('cache-cross-tenant-isolation: advertisement shape (RFC 0019)', () => {
|
|
31
33
|
it('capabilities.cache is either absent or a well-formed object', async () => {
|
|
32
34
|
const cap = await readCap();
|
|
33
|
-
if (cap === null) return;
|
|
35
|
+
if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
|
|
34
36
|
expect(
|
|
35
37
|
typeof cap.supported,
|
|
36
|
-
|
|
38
|
+
req('openwop.it.cache-cross-tenant-isolation.capabilities-cache-is-either-absent-or-a-well-formed-object',
|
|
37
39
|
'capabilities.schema.json §cache',
|
|
38
40
|
'capabilities.cache.supported MUST be a boolean when present',
|
|
39
41
|
),
|
|
@@ -44,19 +46,19 @@ describe('cache-cross-tenant-isolation: advertisement shape (RFC 0019)', () => {
|
|
|
44
46
|
describe('cache-cross-tenant-isolation: behavioral (RFC 0019 §B point 2)', () => {
|
|
45
47
|
it('put under tenant A → get under tenant B returns miss', async () => {
|
|
46
48
|
const cap = await readCap();
|
|
47
|
-
if (!cap || cap.supported !== true) return;
|
|
49
|
+
if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early');
|
|
48
50
|
const key = `xtenant-cache-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
49
51
|
|
|
50
52
|
const putRes = await call('tenant-a', 'put', { key, value: 'from-A', ttlSeconds: 60 });
|
|
51
|
-
if (putRes.status === 404) return;
|
|
52
|
-
expect(putRes.status, 'put MUST succeed').toBe(200);
|
|
53
|
+
if (putRes.status === 404) return softSkip('blocked', 'precondition not met — `putRes.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
54
|
+
expect(putRes.status, req('openwop.it.cache-cross-tenant-isolation.put-under-tenant-a-get-under-tenant-b-returns-miss', 'RFC 0019 §B point 2', 'put MUST succeed')).toBe(200);
|
|
53
55
|
|
|
54
56
|
const getRes = await call('tenant-b', 'get', { key });
|
|
55
57
|
expect(getRes.status).toBe(200);
|
|
56
58
|
const body = getRes.json as { hit?: boolean };
|
|
57
59
|
expect(
|
|
58
60
|
body.hit,
|
|
59
|
-
|
|
61
|
+
req('openwop.it.cache-cross-tenant-isolation.put-under-tenant-a-get-under-tenant-b-returns-miss', 'RFC 0019 §B point 2', 'tenant B MUST NOT hit tenant A cache entry at same key'),
|
|
60
62
|
).toBe(false);
|
|
61
63
|
});
|
|
62
64
|
});
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
import { describe, it, expect } from 'vitest';
|
|
17
17
|
import { driver } from '../lib/driver.js';
|
|
18
18
|
import { discoveryFamilies } from '../lib/discovery-capabilities.js';
|
|
19
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
19
21
|
|
|
20
22
|
interface DiscoveryDoc {
|
|
21
23
|
capabilities?: Record<string, unknown>;
|
|
@@ -32,10 +34,10 @@ async function readCap(): Promise<Record<string, unknown> | null> {
|
|
|
32
34
|
describe('cache-ttl-expiry: advertisement shape (RFC 0019)', () => {
|
|
33
35
|
it('capabilities.cache is either absent or a well-formed object', async () => {
|
|
34
36
|
const cap = await readCap();
|
|
35
|
-
if (cap === null) return; // host doesn't advertise — skip
|
|
37
|
+
if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early (host doesn\'t advertise — skip)'); // host doesn't advertise — skip
|
|
36
38
|
expect(
|
|
37
39
|
typeof cap.supported,
|
|
38
|
-
|
|
40
|
+
req('openwop.it.cache-ttl-expiry.capabilities-cache-is-either-absent-or-a-well-formed-object',
|
|
39
41
|
'capabilities.schema.json §cache',
|
|
40
42
|
'capabilities.cache.supported MUST be a boolean when present',
|
|
41
43
|
),
|
|
@@ -50,7 +52,7 @@ async function call(op: string, args: Record<string, unknown>) {
|
|
|
50
52
|
describe('cache-ttl-expiry: behavioral (RFC 0019 §B point 2 — 1s TTL drift)', () => {
|
|
51
53
|
it('put with ttlSeconds=2 → hit within window; miss after expiry', async () => {
|
|
52
54
|
const probe = await call('get', { key: '__cache-probe__' });
|
|
53
|
-
if (probe.status === 404) return;
|
|
55
|
+
if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
54
56
|
const key = `c-ttl-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
55
57
|
const putRes = await call('put', { key, value: 'evicts-soon', ttlSeconds: 2 });
|
|
56
58
|
expect(putRes.status).toBe(200);
|
|
@@ -59,7 +61,7 @@ describe('cache-ttl-expiry: behavioral (RFC 0019 §B point 2 — 1s TTL drift)',
|
|
|
59
61
|
const withinBody = within.json as { value?: unknown; found?: boolean };
|
|
60
62
|
expect(
|
|
61
63
|
withinBody.value,
|
|
62
|
-
|
|
64
|
+
req('openwop.it.cache-ttl-expiry.put-with-ttlseconds-2-hit-within-window-miss-after-expiry', 'RFC 0019 §B point 2', 'cache get within TTL MUST return the stored value'),
|
|
63
65
|
).toBe('evicts-soon');
|
|
64
66
|
|
|
65
67
|
await new Promise((r) => setTimeout(r, 3000));
|
|
@@ -68,7 +70,7 @@ describe('cache-ttl-expiry: behavioral (RFC 0019 §B point 2 — 1s TTL drift)',
|
|
|
68
70
|
const afterBody = after.json as { value?: unknown; found?: boolean };
|
|
69
71
|
expect(
|
|
70
72
|
afterBody.found,
|
|
71
|
-
|
|
73
|
+
req('openwop.it.cache-ttl-expiry.put-with-ttlseconds-2-hit-within-window-miss-after-expiry', 'RFC 0019 §B point 2', 'cache get after TTL expiry MUST surface as found:false (≤1s drift)'),
|
|
72
74
|
).toBe(false);
|
|
73
75
|
});
|
|
74
76
|
});
|
|
@@ -22,6 +22,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
22
22
|
import { driver } from '../lib/driver.js';
|
|
23
23
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
24
24
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
25
27
|
|
|
26
28
|
const ALL_MODALITIES = ['text', 'image', 'audio', 'document'];
|
|
27
29
|
|
|
@@ -60,10 +62,10 @@ describe('callai-multimodal (RFC 0091 §A/§B)', () => {
|
|
|
60
62
|
const okRes = await driver.post(SEAM, {
|
|
61
63
|
messages: [{ role: 'user', content: [{ type: 'text', text: 'describe this' }, okPart] }],
|
|
62
64
|
});
|
|
63
|
-
if (okRes.status === 404) return; // seam unwired — soft-skip the whole behavioral suite
|
|
65
|
+
if (okRes.status === 404) return softSkip('blocked', 'precondition not met — `okRes.status === 404` returned early (seam unwired — soft-skip the whole behavioral suite) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip the whole behavioral suite
|
|
64
66
|
expect(
|
|
65
67
|
errCode(okRes.json) !== 'unsupported_modality',
|
|
66
|
-
|
|
68
|
+
req('openwop.it.callai-multimodal.accepts-an-advertised-non-text-modality-and-rejects-an-unadvertised-one-with-uns', 'RFC 0091 §B', `an advertised modality (${accepted}) MUST NOT be rejected as unsupported_modality`),
|
|
67
69
|
).toBe(true);
|
|
68
70
|
|
|
69
71
|
// 2) An unadvertised modality MUST be rejected with unsupported_modality.
|
|
@@ -79,7 +81,7 @@ describe('callai-multimodal (RFC 0091 §A/§B)', () => {
|
|
|
79
81
|
});
|
|
80
82
|
expect(
|
|
81
83
|
errCode(badRes.json) === 'unsupported_modality',
|
|
82
|
-
|
|
84
|
+
req('openwop.it.callai-multimodal.accepts-an-advertised-non-text-modality-and-rejects-an-unadvertised-one-with-uns', 'RFC 0091 §A', `an unadvertised modality (${unadvertised}) MUST be rejected with unsupported_modality (never silently dropped)`),
|
|
83
85
|
).toBe(true);
|
|
84
86
|
}
|
|
85
87
|
});
|
|
@@ -11,6 +11,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
11
11
|
import { driver } from '../lib/driver.js';
|
|
12
12
|
import { pollUntilStatus } from '../lib/polling.js';
|
|
13
13
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
14
|
+
import { req } from '../lib/requirement-ids.js';
|
|
14
15
|
|
|
15
16
|
const WORKFLOW_ID = 'conformance-cancellable';
|
|
16
17
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
|
|
@@ -21,7 +22,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('cancellation: in-flight :cancel reaches termin
|
|
|
21
22
|
workflowId: WORKFLOW_ID,
|
|
22
23
|
inputs: { delayMs: 10_000 },
|
|
23
24
|
});
|
|
24
|
-
expect(create.status,
|
|
25
|
+
expect(create.status, req('openwop.it.cancellation.post-v1-runs-runid-cancel-returns-200-and-run-terminates-as-cancelled',
|
|
25
26
|
'rest-endpoints.md',
|
|
26
27
|
'POST /v1/runs MUST return 201 on accepted run',
|
|
27
28
|
)).toBe(201);
|
|
@@ -35,7 +36,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('cancellation: in-flight :cancel reaches termin
|
|
|
35
36
|
`/v1/runs/${encodeURIComponent(runId)}/cancel`,
|
|
36
37
|
{ reason: 'conformance-cancellation-test' },
|
|
37
38
|
);
|
|
38
|
-
expect(cancel.status,
|
|
39
|
+
expect(cancel.status, req('openwop.it.cancellation.post-v1-runs-runid-cancel-returns-200-and-run-terminates-as-cancelled',
|
|
39
40
|
'rest-endpoints.md POST /v1/runs/{runId}/cancel',
|
|
40
41
|
'cancel MUST return 200 on accepted cancellation',
|
|
41
42
|
)).toBe(200);
|
|
@@ -43,14 +44,14 @@ describe.skipIf(SKIP_NO_FIXTURE)('cancellation: in-flight :cancel reaches termin
|
|
|
43
44
|
const cancelBody = cancel.json as { status?: string };
|
|
44
45
|
expect(
|
|
45
46
|
['cancelled', 'cancelling'].includes(cancelBody.status ?? ''),
|
|
46
|
-
|
|
47
|
+
req('openwop.it.cancellation.post-v1-runs-runid-cancel-returns-200-and-run-terminates-as-cancelled',
|
|
47
48
|
'rest-endpoints.md POST /v1/runs/{runId}/cancel',
|
|
48
49
|
'cancel response status MUST be one of `cancelled` or `cancelling`',
|
|
49
50
|
),
|
|
50
51
|
).toBe(true);
|
|
51
52
|
|
|
52
53
|
const terminal = await pollUntilStatus(runId, 'cancelled', { timeoutMs: 5_000 });
|
|
53
|
-
expect(terminal.status,
|
|
54
|
+
expect(terminal.status, req('openwop.it.cancellation.post-v1-runs-runid-cancel-returns-200-and-run-terminates-as-cancelled',
|
|
54
55
|
'fixtures.md conformance-cancellable §Terminal status',
|
|
55
56
|
'fixture MUST reach terminal `cancelled` within 5s of cancel',
|
|
56
57
|
)).toBe('cancelled');
|
|
@@ -62,7 +63,7 @@ describe('cancellation: cancelling an unknown run returns 404', () => {
|
|
|
62
63
|
const res = await driver.post('/v1/runs/openwop-conformance-no-such-run/cancel', {});
|
|
63
64
|
expect(
|
|
64
65
|
[403, 404].includes(res.status),
|
|
65
|
-
|
|
66
|
+
req('openwop.it.cancellation.post-v1-runs-nonexistentid-cancel-returns-404', 'rest-endpoints.md', 'cancel on unknown run MUST return 404 or 403'),
|
|
66
67
|
).toBe(true);
|
|
67
68
|
});
|
|
68
69
|
});
|
|
@@ -22,6 +22,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
22
22
|
import { driver } from '../lib/driver.js';
|
|
23
23
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
24
24
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
26
|
|
|
26
27
|
const WORKFLOW_ID = 'conformance-cap-breach';
|
|
27
28
|
const RECURSION_LIMIT = 3;
|
|
@@ -42,7 +43,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
42
43
|
workflowId: WORKFLOW_ID,
|
|
43
44
|
configurable: { recursionLimit: RECURSION_LIMIT },
|
|
44
45
|
});
|
|
45
|
-
expect(create.status,
|
|
46
|
+
expect(create.status, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
46
47
|
'rest-endpoints.md POST /v1/runs',
|
|
47
48
|
'run creation MUST accept the request even when configurable.recursionLimit is below the workflow size',
|
|
48
49
|
)).toBe(201);
|
|
@@ -50,17 +51,17 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
50
51
|
|
|
51
52
|
const terminal = await pollUntilTerminal(runId);
|
|
52
53
|
|
|
53
|
-
expect(terminal.status,
|
|
54
|
+
expect(terminal.status, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
54
55
|
'fixtures.md conformance-cap-breach §Terminal status',
|
|
55
56
|
'fixture MUST reach terminal `failed` when recursion limit is exceeded',
|
|
56
57
|
)).toBe('failed');
|
|
57
58
|
|
|
58
|
-
expect(terminal.error?.code,
|
|
59
|
+
expect(terminal.error?.code, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
59
60
|
'run-options.md §recursionLimit',
|
|
60
61
|
'RunSnapshot.error.code MUST equal "recursion_limit_exceeded"',
|
|
61
62
|
)).toBe('recursion_limit_exceeded');
|
|
62
63
|
|
|
63
|
-
expect(typeof terminal.error?.message,
|
|
64
|
+
expect(typeof terminal.error?.message, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
64
65
|
'rest-endpoints.md RunSnapshot.error.message',
|
|
65
66
|
'RunSnapshot.error.message MUST be a string',
|
|
66
67
|
)).toBe('string');
|
|
@@ -72,7 +73,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
72
73
|
const events = (eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? [];
|
|
73
74
|
|
|
74
75
|
const capBreachEvents = events.filter((e) => e.type === 'cap.breached');
|
|
75
|
-
expect(capBreachEvents.length,
|
|
76
|
+
expect(capBreachEvents.length, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
76
77
|
'observability.md §cap.breached',
|
|
77
78
|
'exactly one cap.breached event MUST be emitted on recursion-limit exceedance',
|
|
78
79
|
)).toBe(1);
|
|
@@ -82,23 +83,23 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
82
83
|
| { kind?: string; limit?: number; observed?: number; nodeId?: string }
|
|
83
84
|
| undefined;
|
|
84
85
|
|
|
85
|
-
expect(payload?.kind,
|
|
86
|
+
expect(payload?.kind, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
86
87
|
'run-event-payloads.schema.json §capBreached.kind',
|
|
87
88
|
'cap.breached payload MUST carry kind="node-executions"',
|
|
88
89
|
)).toBe('node-executions');
|
|
89
90
|
|
|
90
|
-
expect(payload?.limit,
|
|
91
|
+
expect(payload?.limit, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
91
92
|
'run-event-payloads.schema.json §capBreached.limit',
|
|
92
93
|
'cap.breached payload MUST carry the resolved limit (3 from configurable.recursionLimit)',
|
|
93
94
|
)).toBe(RECURSION_LIMIT);
|
|
94
95
|
|
|
95
|
-
expect(typeof payload?.observed,
|
|
96
|
+
expect(typeof payload?.observed, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
96
97
|
'run-event-payloads.schema.json §capBreached.observed',
|
|
97
98
|
'cap.breached payload MUST carry the observed count as a number',
|
|
98
99
|
)).toBe('number');
|
|
99
100
|
expect(payload?.observed).toBeGreaterThan(RECURSION_LIMIT);
|
|
100
101
|
|
|
101
|
-
expect(typeof payload?.nodeId,
|
|
102
|
+
expect(typeof payload?.nodeId, req('openwop.it.cap-breach.emits-cap-breached-transitions-to-terminal-failed-when-configurable-recursionlim',
|
|
102
103
|
'run-event-payloads.schema.json §capBreached.nodeId',
|
|
103
104
|
'cap.breached payload MUST carry the offending nodeId for node-executions kind',
|
|
104
105
|
)).toBe('string');
|
|
@@ -121,10 +122,10 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
121
122
|
const capBreach = events.find((e) => e.type === 'cap.breached');
|
|
122
123
|
const runFailed = events.find((e) => e.type === 'run.failed');
|
|
123
124
|
|
|
124
|
-
expect(capBreach, 'cap.breached MUST be emitted').toBeDefined();
|
|
125
|
-
expect(runFailed, 'run.failed MUST be emitted').toBeDefined();
|
|
125
|
+
expect(capBreach, req('openwop.it.cap-breach.cap-breached-precedes-run-failed-in-the-event-sequence-breach-detected-before-ov', 'observability.md §event ordering', 'cap.breached MUST be emitted')).toBeDefined();
|
|
126
|
+
expect(runFailed, req('openwop.it.cap-breach.cap-breached-precedes-run-failed-in-the-event-sequence-breach-detected-before-ov', 'observability.md §event ordering', 'run.failed MUST be emitted')).toBeDefined();
|
|
126
127
|
|
|
127
|
-
expect(capBreach!.sequence,
|
|
128
|
+
expect(capBreach!.sequence, req('openwop.it.cap-breach.cap-breached-precedes-run-failed-in-the-event-sequence-breach-detected-before-ov',
|
|
128
129
|
'observability.md §event ordering',
|
|
129
130
|
'cap.breached MUST precede run.failed in sequence (breach detected BEFORE over-limit node fires)',
|
|
130
131
|
)).toBeLessThan(runFailed!.sequence);
|
|
@@ -137,11 +138,11 @@ describe.skipIf(SKIP_NO_FIXTURE)('cap-breach: conformance-cap-breach fixture fai
|
|
|
137
138
|
// short) — those would emit fewer than `RECURSION_LIMIT` started
|
|
138
139
|
// events while still satisfying the invariant.
|
|
139
140
|
const nodeStarted = events.filter((e) => e.type === 'node.started');
|
|
140
|
-
expect(nodeStarted.length,
|
|
141
|
+
expect(nodeStarted.length, req('openwop.it.cap-breach.cap-breached-precedes-run-failed-in-the-event-sequence-breach-detected-before-ov',
|
|
141
142
|
'run-options.md §recursionLimit',
|
|
142
143
|
'at most `limit` node.started events MUST be emitted; the over-limit node MUST NOT receive node.started',
|
|
143
144
|
)).toBeLessThanOrEqual(RECURSION_LIMIT);
|
|
144
|
-
expect(nodeStarted.length,
|
|
145
|
+
expect(nodeStarted.length, req('openwop.it.cap-breach.cap-breached-precedes-run-failed-in-the-event-sequence-breach-detected-before-ov',
|
|
145
146
|
'run-options.md §recursionLimit',
|
|
146
147
|
'at least one node MUST start before the breach (otherwise the workflow never executed)',
|
|
147
148
|
)).toBeGreaterThan(0);
|
|
@@ -45,6 +45,8 @@ import { readFileSync } from 'node:fs';
|
|
|
45
45
|
import { join } from 'node:path';
|
|
46
46
|
import { driver } from '../lib/driver.js';
|
|
47
47
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
48
|
+
import { req } from '../lib/requirement-ids.js';
|
|
49
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
48
50
|
|
|
49
51
|
type Arm = 'root-plain' | 'root-dotted' | 'wrapper-plain' | 'wrapper-dotted';
|
|
50
52
|
|
|
@@ -84,11 +86,11 @@ describe('capability-arm-witness: which resolver arm the host lands on (RFC 0144
|
|
|
84
86
|
const res = await driver.get('/.well-known/openwop');
|
|
85
87
|
// No discovery document ⇒ inapplicable. Other scenarios own that failure; this leg is
|
|
86
88
|
// about WHERE families sit, not whether the host has any.
|
|
87
|
-
if (res.status !== 200 || res.json === undefined || res.json === null) return;
|
|
89
|
+
if (res.status !== 200 || res.json === undefined || res.json === null) return softSkip('blocked', 'precondition not met — `res.status !== 200 || res.json === undefined || res.json === null` returned early (No discovery document ⇒ inapplicable. Other scenarios own that failure; this leg is about WHERE families sit, …');
|
|
88
90
|
|
|
89
91
|
const doc = res.json as Record<string, unknown>;
|
|
90
92
|
const placements = classify(doc, declaredFamilies());
|
|
91
|
-
if (placements.length === 0) return; // advertises no declared family — inapplicable
|
|
93
|
+
if (placements.length === 0) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `placements.length === 0` returned early (advertises no declared family — inapplicable)'); // advertises no declared family — inapplicable
|
|
92
94
|
|
|
93
95
|
const canonical = placements.filter((p) => p.arms.includes('root-plain'));
|
|
94
96
|
const rootDotted = placements.filter(
|
|
@@ -110,7 +112,7 @@ describe('capability-arm-witness: which resolver arm the host lands on (RFC 0144
|
|
|
110
112
|
// ASSERT — the existing MUST, not a new one.
|
|
111
113
|
expect(
|
|
112
114
|
wrapperOnly.map((p) => p.family),
|
|
113
|
-
|
|
115
|
+
req('openwop.it.capability-arm-witness.no-capability-family-is-reachable-only-under-the-deprecated-capabilities-wrapper',
|
|
114
116
|
'capabilities.md §"Document-root layout (normative — RFC 0073)"',
|
|
115
117
|
'every family MUST appear at the document root; a host that serves families EXCLUSIVELY under the deprecated `capabilities` wrapper is non-conformant and is graded as such. The suite\'s helpers fall back to the wrapper, so without this leg such a host reads exactly like a migrated one — which is RFC 0144 G1',
|
|
116
118
|
),
|