@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
|
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
23
23
|
import { driver } from '../lib/driver.js';
|
|
24
24
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
25
25
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
26
28
|
|
|
27
29
|
const SEAM = '/v1/host/sample/agents/verify-run';
|
|
28
30
|
|
|
@@ -48,26 +50,26 @@ describe('verifier-gating (RFC 0090 §B)', () => {
|
|
|
48
50
|
|
|
49
51
|
// FAIL verdict → must NOT complete as success; agent.verified{fail} emitted.
|
|
50
52
|
const failRes = await driver.post(SEAM, { simulateVerdict: 'fail' });
|
|
51
|
-
if (failRes.status === 404) return; // seam unwired — soft-skip
|
|
53
|
+
if (failRes.status === 404) return softSkip('blocked', 'precondition not met — `failRes.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
52
54
|
expect(
|
|
53
55
|
verifiedVerdict(failRes.json) === 'fail',
|
|
54
|
-
|
|
56
|
+
req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §A', 'a verify-run forcing a fail MUST emit agent.verified{verdict:"fail"}'),
|
|
55
57
|
).toBe(true);
|
|
56
58
|
expect(
|
|
57
59
|
!isSuccess(failRes.json),
|
|
58
|
-
|
|
60
|
+
req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §B', 'on a gating host a fail verdict MUST block commit/terminate-as-success'),
|
|
59
61
|
).toBe(true);
|
|
60
62
|
|
|
61
63
|
// PASS verdict → completes normally.
|
|
62
64
|
const passRes = await driver.post(SEAM, { simulateVerdict: 'pass' });
|
|
63
|
-
if (passRes.status === 404) return;
|
|
65
|
+
if (passRes.status === 404) return softSkip('blocked', 'precondition not met — `passRes.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
64
66
|
expect(
|
|
65
67
|
verifiedVerdict(passRes.json) === 'pass',
|
|
66
|
-
|
|
68
|
+
req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §A', 'a verify-run forcing a pass MUST emit agent.verified{verdict:"pass"}'),
|
|
67
69
|
).toBe(true);
|
|
68
70
|
expect(
|
|
69
71
|
isSuccess(passRes.json),
|
|
70
|
-
|
|
72
|
+
req('openwop.it.verifier-gating.a-fail-verdict-blocks-commit-on-a-gating-host-a-pass-verdict-completes', 'RFC 0090 §B', 'a pass verdict MUST allow the turn to complete'),
|
|
71
73
|
).toBe(true);
|
|
72
74
|
});
|
|
73
75
|
});
|
|
@@ -39,6 +39,7 @@ import { driver, type OpenWOPResponse } from '../lib/driver.js';
|
|
|
39
39
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
40
40
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
41
41
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
42
|
+
import { req } from '../lib/requirement-ids.js';
|
|
42
43
|
|
|
43
44
|
const FIXTURE_ID = 'conformance-version-fold';
|
|
44
45
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(FIXTURE_ID);
|
|
@@ -94,7 +95,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
94
95
|
);
|
|
95
96
|
expect(
|
|
96
97
|
versions.length,
|
|
97
|
-
|
|
98
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
98
99
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
99
100
|
'forceEngineVersionRange MUST describe a non-empty integer range (min <= max)',
|
|
100
101
|
),
|
|
@@ -109,7 +110,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
109
110
|
}
|
|
110
111
|
expect(
|
|
111
112
|
create.status,
|
|
112
|
-
|
|
113
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
113
114
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
114
115
|
`POST /v1/runs with X-Force-Engine-Version: ${v} (within the advertised range) MUST be accepted on a test key`,
|
|
115
116
|
),
|
|
@@ -120,7 +121,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
120
121
|
const terminal = await pollUntilTerminal(runId);
|
|
121
122
|
expect(
|
|
122
123
|
terminal.status,
|
|
123
|
-
|
|
124
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
124
125
|
'version-negotiation.md §Cross-version interop matrix',
|
|
125
126
|
`the conformance-version-fold noop run MUST complete under forced engine version ${v} (fold-best-effort)`,
|
|
126
127
|
),
|
|
@@ -130,7 +131,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
130
131
|
const snap = await driver.get(`/v1/runs/${encodeURIComponent(runId)}`);
|
|
131
132
|
expect(
|
|
132
133
|
snap.status,
|
|
133
|
-
|
|
134
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
134
135
|
'version-negotiation.md §Cross-version interop matrix',
|
|
135
136
|
`GET /v1/runs/{runId} MUST return a readable RunSnapshot under forced engine version ${v}`,
|
|
136
137
|
),
|
|
@@ -145,7 +146,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
145
146
|
);
|
|
146
147
|
expect(
|
|
147
148
|
events.status,
|
|
148
|
-
|
|
149
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
149
150
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
150
151
|
`the event log MUST be readable via events/poll under forced engine version ${v}`,
|
|
151
152
|
),
|
|
@@ -153,7 +154,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
153
154
|
const eventList = (events.json as { events?: unknown[] } | undefined)?.events ?? [];
|
|
154
155
|
expect(
|
|
155
156
|
eventList.length,
|
|
156
|
-
|
|
157
|
+
req('openwop.it.version-fold.each-version-in-min-current-max-completes-snapshot-and-event-log-stay-readable',
|
|
157
158
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
158
159
|
`events/poll MUST return a non-empty events[] for the forced-version run (v=${v})`,
|
|
159
160
|
),
|
|
@@ -178,14 +179,14 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
178
179
|
}
|
|
179
180
|
expect(
|
|
180
181
|
create.status,
|
|
181
|
-
|
|
182
|
+
req('openwop.it.version-fold.a-forced-version-outside-the-advertised-range-is-rejected-with-400-unsupported-f',
|
|
182
183
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
183
184
|
`X-Force-Engine-Version: ${outOfRange} (outside the advertised range) MUST return 400`,
|
|
184
185
|
),
|
|
185
186
|
).toBe(400);
|
|
186
187
|
expect(
|
|
187
188
|
errCode(create.json),
|
|
188
|
-
|
|
189
|
+
req('openwop.it.version-fold.a-forced-version-outside-the-advertised-range-is-rejected-with-400-unsupported-f',
|
|
189
190
|
'version-negotiation.md §Conformance via X-Force-Engine-Version',
|
|
190
191
|
'the out-of-range refusal MUST carry the canonical unsupported_force_engine_version code',
|
|
191
192
|
),
|
|
@@ -26,6 +26,7 @@ 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';
|
|
29
30
|
|
|
30
31
|
const NOOP_WORKFLOW_ID = 'conformance-noop';
|
|
31
32
|
const SKIP_NO_NOOP = !isFixtureAdvertised(NOOP_WORKFLOW_ID);
|
|
@@ -47,7 +48,7 @@ describe('version-negotiation: Capabilities advertises a protocolVersion', () =>
|
|
|
47
48
|
expect(res.status).toBe(200);
|
|
48
49
|
|
|
49
50
|
const caps = res.json as { protocolVersion?: unknown };
|
|
50
|
-
expect(typeof caps.protocolVersion,
|
|
51
|
+
expect(typeof caps.protocolVersion, req('openwop.it.version-negotiation.get-well-known-openwop-returns-capabilities-with-protocolversion-string',
|
|
51
52
|
'capabilities.md §3 + version-negotiation.md',
|
|
52
53
|
'Capabilities.protocolVersion MUST be a non-empty string',
|
|
53
54
|
)).toBe('string');
|
|
@@ -69,34 +70,34 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: persisted events carry the c
|
|
|
69
70
|
expect(eventsRes.status).toBe(200);
|
|
70
71
|
|
|
71
72
|
const events = (eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? [];
|
|
72
|
-
expect(events.length, 'noop run MUST emit at least one event').toBeGreaterThan(0);
|
|
73
|
+
expect(events.length, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json', 'run-event.schema.json §required', 'noop run MUST emit at least one event')).toBeGreaterThan(0);
|
|
73
74
|
|
|
74
75
|
for (const e of events) {
|
|
75
|
-
expect(typeof e.eventId,
|
|
76
|
+
expect(typeof e.eventId, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
76
77
|
'run-event.schema.json §required',
|
|
77
78
|
'eventId MUST be a string',
|
|
78
79
|
)).toBe('string');
|
|
79
|
-
expect(typeof e.runId,
|
|
80
|
+
expect(typeof e.runId, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
80
81
|
'run-event.schema.json §required',
|
|
81
82
|
'runId MUST be a string',
|
|
82
83
|
)).toBe('string');
|
|
83
|
-
expect(typeof e.type,
|
|
84
|
+
expect(typeof e.type, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
84
85
|
'run-event.schema.json §required',
|
|
85
86
|
'type MUST be a string (RunEventType discriminator)',
|
|
86
87
|
)).toBe('string');
|
|
87
|
-
expect(e.payload,
|
|
88
|
+
expect(e.payload, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
88
89
|
'run-event.schema.json §required',
|
|
89
90
|
'payload MUST be present (any JSON value, including null)',
|
|
90
91
|
)).not.toBe(undefined);
|
|
91
|
-
expect(typeof e.timestamp,
|
|
92
|
+
expect(typeof e.timestamp, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
92
93
|
'run-event.schema.json §required',
|
|
93
94
|
'timestamp MUST be an ISO 8601 string',
|
|
94
95
|
)).toBe('string');
|
|
95
|
-
expect(Number.isInteger(e.sequence),
|
|
96
|
+
expect(Number.isInteger(e.sequence), req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json',
|
|
96
97
|
'run-event.schema.json §required',
|
|
97
98
|
'sequence MUST be a non-negative integer',
|
|
98
99
|
)).toBe(true);
|
|
99
|
-
expect(e.sequence, 'sequence MUST be >= 0').toBeGreaterThanOrEqual(0);
|
|
100
|
+
expect(e.sequence, req('openwop.it.version-negotiation.every-event-has-the-6-required-runeventdoc-fields-per-run-event-schema-json', 'run-event.schema.json §required', 'sequence MUST be >= 0')).toBeGreaterThanOrEqual(0);
|
|
100
101
|
}
|
|
101
102
|
});
|
|
102
103
|
|
|
@@ -118,7 +119,7 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: persisted events carry the c
|
|
|
118
119
|
const curr = sequences[i] ?? -1;
|
|
119
120
|
expect(
|
|
120
121
|
curr,
|
|
121
|
-
|
|
122
|
+
req('openwop.it.version-negotiation.event-sequences-within-a-run-are-strictly-monotonic',
|
|
122
123
|
'run-event.schema.json §sequence + idempotency.md',
|
|
123
124
|
`event[${i}].sequence (${curr}) MUST be > event[${i - 1}].sequence (${prev}) — strictly monotonic per run`,
|
|
124
125
|
),
|
|
@@ -144,7 +145,7 @@ describe.skipIf(SKIP_NO_NOOP)('version-negotiation: events/poll forward-compat t
|
|
|
144
145
|
|
|
145
146
|
expect(
|
|
146
147
|
eventsRes.status,
|
|
147
|
-
|
|
148
|
+
req('openwop.it.version-negotiation.events-poll-with-lastsequence-past-current-end-returns-empty-events-iscomplete',
|
|
148
149
|
'rest-endpoints.md GET /v1/runs/{runId}/events/poll',
|
|
149
150
|
'lastSequence beyond the current end MUST return 200 with empty events, not 4xx',
|
|
150
151
|
),
|
|
@@ -21,6 +21,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
21
21
|
import { driver } from '../lib/driver.js';
|
|
22
22
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
23
23
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
24
26
|
|
|
25
27
|
const SEAM = '/v1/host/sample/voice/barge-in';
|
|
26
28
|
|
|
@@ -40,22 +42,22 @@ describe('voice-bargein-no-partial-leak (RFC 0106 §F INV-3)', () => {
|
|
|
40
42
|
if (!behaviorGate('openwop-voice-bargein', advertised)) return;
|
|
41
43
|
|
|
42
44
|
const res = await driver.post(SEAM, {});
|
|
43
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
45
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
44
46
|
|
|
45
|
-
expect(res.status === 200,
|
|
47
|
+
expect(res.status === 200, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §F', 'the barge-in seam MUST return 200')).toBe(true);
|
|
46
48
|
|
|
47
49
|
const types = eventsOf(res.json).map((e) => e.type);
|
|
48
50
|
const bargeIdx = types.indexOf('voice.barge_in');
|
|
49
51
|
const cancelIdx = types.indexOf('voice.cancelled');
|
|
50
|
-
expect(bargeIdx >= 0,
|
|
51
|
-
expect(cancelIdx >= 0,
|
|
52
|
-
expect(cancelIdx > bargeIdx,
|
|
52
|
+
expect(bargeIdx >= 0, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'a barge-in MUST emit voice.barge_in')).toBe(true);
|
|
53
|
+
expect(cancelIdx >= 0, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'a barge-in that cancels work MUST emit voice.cancelled')).toBe(true);
|
|
54
|
+
expect(cancelIdx > bargeIdx, req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §D', 'voice.cancelled MUST follow voice.barge_in')).toBe(true);
|
|
53
55
|
|
|
54
56
|
// The load-bearing INV-3 assertion: nothing partial after the cancel.
|
|
55
57
|
const afterCancel = types.slice(cancelIdx + 1);
|
|
56
58
|
expect(
|
|
57
59
|
!afterCancel.includes('voice.synthesis_chunk'),
|
|
58
|
-
|
|
60
|
+
req('openwop.it.voice-bargein-no-partial-leak.barge-in-cancels-with-no-synthesis-chunk-emitted-after-voice-cancelled', 'RFC 0106 §F INV-3', 'NO voice.synthesis_chunk (partial output) may be emitted AFTER voice.cancelled'),
|
|
59
61
|
).toBe(true);
|
|
60
62
|
});
|
|
61
63
|
});
|
|
@@ -32,8 +32,7 @@ import { join } from 'node:path';
|
|
|
32
32
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
33
33
|
import addFormats from 'ajv-formats';
|
|
34
34
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
35
|
-
|
|
36
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
37
36
|
|
|
38
37
|
function loadSchema(name: string): Record<string, any> {
|
|
39
38
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, any>;
|
|
@@ -63,7 +62,7 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
|
|
|
63
62
|
it('all seven voice.* types are in the RunEventType enum', () => {
|
|
64
63
|
const enumVals: string[] = loadSchema('run-event.schema.json').$defs.RunEventType.enum;
|
|
65
64
|
for (const t of VOICE_TYPES) {
|
|
66
|
-
expect(enumVals.includes(t),
|
|
65
|
+
expect(enumVals.includes(t), req('openwop.it.voice-event-payloads-shape.all-seven-voice-types-are-in-the-runeventtype-enum', 'run-event.schema.json §RunEventType', `${t} MUST be a RunEventType`)).toBe(true);
|
|
67
66
|
}
|
|
68
67
|
});
|
|
69
68
|
|
|
@@ -71,8 +70,8 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
|
|
|
71
70
|
const payloads = loadSchema('run-event-payloads.schema.json');
|
|
72
71
|
const typeIndex = payloads.$defs._typeIndex.properties as Record<string, { $ref: string }>;
|
|
73
72
|
for (const t of VOICE_TYPES) {
|
|
74
|
-
expect(typeIndex[t],
|
|
75
|
-
expect(payloads.$defs[DEF_KEY[t]],
|
|
73
|
+
expect(typeIndex[t], req('openwop.it.voice-event-payloads-shape.each-voice-type-has-a-payload-def-reachable-via-typeindex', 'run-event-payloads.schema.json §typeIndex', `${t} MUST map to a $def`)).toBeDefined();
|
|
74
|
+
expect(payloads.$defs[DEF_KEY[t]], req('openwop.it.voice-event-payloads-shape.each-voice-type-has-a-payload-def-reachable-via-typeindex', 'run-event-payloads.schema.json', `$defs.${DEF_KEY[t]} MUST exist`)).toBeDefined();
|
|
76
75
|
}
|
|
77
76
|
});
|
|
78
77
|
|
|
@@ -84,15 +83,15 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
|
|
|
84
83
|
|
|
85
84
|
expect(
|
|
86
85
|
validate({ text: 'book a table', isFinal: true, atMs: 1200, contentTrust: 'untrusted' }),
|
|
87
|
-
|
|
86
|
+
req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2', 'a transcript marked untrusted MUST validate'),
|
|
88
87
|
).toBe(true);
|
|
89
88
|
expect(
|
|
90
89
|
validate({ text: 'book a table', isFinal: true, atMs: 1200 }),
|
|
91
|
-
|
|
90
|
+
req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'a transcript WITHOUT contentTrust MUST be rejected'),
|
|
92
91
|
).toBe(false);
|
|
93
92
|
expect(
|
|
94
93
|
validate({ text: 'book a table', isFinal: true, atMs: 1200, contentTrust: 'trusted' }),
|
|
95
|
-
|
|
94
|
+
req('openwop.it.voice-event-payloads-shape.voice-transcript-requires-contenttrust-untrusted-security-voice-transcript-untru', 'RFC 0106 §F INV-2 (voice-transcript-untrusted)', 'contentTrust MUST be the const "untrusted" — never promoted'),
|
|
96
95
|
).toBe(false);
|
|
97
96
|
});
|
|
98
97
|
|
|
@@ -104,11 +103,11 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
|
|
|
104
103
|
|
|
105
104
|
expect(
|
|
106
105
|
validate({ seq: 0, mimeType: 'audio/mpeg', durationMs: 240, url: 'https://host/seg/0', final: false }),
|
|
107
|
-
|
|
106
|
+
req('openwop.it.voice-event-payloads-shape.voice-synthesis-chunk-is-metadata-shaped-seq-mimetype-required-bytes-by-referenc', 'RFC 0106 §C', 'a metadata chunk referencing bytes by url MUST validate'),
|
|
108
107
|
).toBe(true);
|
|
109
108
|
expect(
|
|
110
109
|
validate({ mimeType: 'audio/mpeg' }),
|
|
111
|
-
|
|
110
|
+
req('openwop.it.voice-event-payloads-shape.voice-synthesis-chunk-is-metadata-shaped-seq-mimetype-required-bytes-by-referenc', 'RFC 0106 §C', 'a chunk without seq MUST be rejected'),
|
|
112
111
|
).toBe(false);
|
|
113
112
|
});
|
|
114
113
|
|
|
@@ -120,7 +119,7 @@ describe('voice-event-payloads-shape: the voice.* run-event taxonomy (RFC 0106
|
|
|
120
119
|
const validate = ajv.compile(payloads.$defs[key]);
|
|
121
120
|
expect(
|
|
122
121
|
validate({ atMs: 100, transcriptBody: 'should not be here' }),
|
|
123
|
-
|
|
122
|
+
req('openwop.it.voice-event-payloads-shape.content-free-voice-events-reject-unknown-properties-additionalproperties-false', 'RFC 0106 §D', `${key} MUST reject an unknown (content-bearing) property`),
|
|
124
123
|
).toBe(false);
|
|
125
124
|
}
|
|
126
125
|
});
|
|
@@ -20,6 +20,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
20
20
|
import { driver } from '../lib/driver.js';
|
|
21
21
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
22
22
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
23
|
+
import { req } from '../lib/requirement-ids.js';
|
|
24
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
23
25
|
|
|
24
26
|
const SEAM = '/v1/host/sample/ai/call-transcriber';
|
|
25
27
|
|
|
@@ -42,18 +44,18 @@ describe('voice-interim-not-durable (RFC 0106 §F INV-1)', () => {
|
|
|
42
44
|
if (!behaviorGate('openwop-voice-interim-not-durable', advertised)) return;
|
|
43
45
|
|
|
44
46
|
const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' }, interimResults: true });
|
|
45
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
46
|
-
if (errCode(res.json) === 'transcription_unsupported') return; // §E live transport / no test-seam arm — soft-skip
|
|
47
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
48
|
+
if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (§E live transport / no test-seam arm — soft-skip)'); // §E live transport / no test-seam arm — soft-skip
|
|
47
49
|
|
|
48
50
|
const events = eventsOf(res.json);
|
|
49
|
-
if (events.length === 0) return; // host returned only the result envelope — nothing observable to assert
|
|
51
|
+
if (events.length === 0) return softSkip('blocked', 'precondition not met — `events.length === 0` returned early (host returned only the result envelope — nothing observable to assert) (seam, prior step, or fixture unavailable)'); // host returned only the result envelope — nothing observable to assert
|
|
50
52
|
|
|
51
53
|
const commitIdx = events.findIndex((e) => e.type === 'voice.turn_commit');
|
|
52
|
-
if (commitIdx < 0) return; // no commit observed — soft-skip
|
|
54
|
+
if (commitIdx < 0) return softSkip('blocked', 'precondition not met — `commitIdx < 0` returned early (no commit observed — soft-skip) (seam, prior step, or fixture unavailable)'); // no commit observed — soft-skip
|
|
53
55
|
const afterCommit = events.slice(commitIdx + 1);
|
|
54
56
|
expect(
|
|
55
57
|
!afterCommit.some((e) => e.type === 'voice.transcript' && (e.payload ?? {}).isFinal === false),
|
|
56
|
-
|
|
58
|
+
req('openwop.it.voice-interim-not-durable.no-provisional-isfinal-false-transcript-is-durable-past-voice-turn-commit', 'RFC 0106 §F INV-1', 'a provisional (isFinal:false) transcript MUST NOT appear after voice.turn_commit'),
|
|
57
59
|
).toBe(true);
|
|
58
60
|
});
|
|
59
61
|
});
|
|
@@ -22,6 +22,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
|
|
|
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 SEAM = '/v1/host/sample/ai/call-transcriber';
|
|
27
29
|
|
|
@@ -44,8 +46,8 @@ describe('voice-streamref-tenant-bound (RFC 0106 §F INV-4)', () => {
|
|
|
44
46
|
// conduit to bind cross-tenant — soft-skip (the invariant stays reference-impl
|
|
45
47
|
// until a host with live streamRef transport proves it).
|
|
46
48
|
const res = await driver.post(SEAM, { audio: { streamRef: 'stream:tenant-a/mic' } });
|
|
47
|
-
if (res.status === 404) return;
|
|
48
|
-
if (errCode(res.json) === 'transcription_unsupported') return; // §E — no live transport on this host
|
|
49
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
50
|
+
if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (§E — no live transport on this host)'); // §E — no live transport on this host
|
|
49
51
|
|
|
50
52
|
// A host that DOES accept a live streamRef must bind it: a second tenant presenting
|
|
51
53
|
// tenant-A's streamRef MUST be rejected (cross-handle read forbidden). Exercising the
|
|
@@ -54,7 +56,7 @@ describe('voice-streamref-tenant-bound (RFC 0106 §F INV-4)', () => {
|
|
|
54
56
|
// another tenant's buffered audio for an unknown streamRef.
|
|
55
57
|
expect(
|
|
56
58
|
res.status !== 200 || (res.json as { finalText?: unknown })?.finalText !== undefined,
|
|
57
|
-
|
|
59
|
+
req('openwop.it.voice-streamref-tenant-bound.a-live-streamref-is-tenant-session-bound-host-internal-transport-per-e-soft-skip', 'RFC 0106 §F INV-4', 'a host honoring a live streamRef MUST bind it to its tenant+session'),
|
|
58
60
|
).toBe(true);
|
|
59
61
|
});
|
|
60
62
|
});
|
|
@@ -23,6 +23,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
23
23
|
import { driver } from '../lib/driver.js';
|
|
24
24
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
25
25
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
26
28
|
|
|
27
29
|
const SEAM = '/v1/host/sample/ai/call-speech-synthesizer';
|
|
28
30
|
|
|
@@ -42,36 +44,36 @@ describe('voice-synthesis-streaming (RFC 0106 §C)', () => {
|
|
|
42
44
|
if (!behaviorGate('openwop-voice-synthesis', advertised)) return;
|
|
43
45
|
|
|
44
46
|
const res = await driver.post(SEAM, { text: 'Welcome to the weekly digest.', voiceId: 'host:narrator-test', stream: true });
|
|
45
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
47
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
46
48
|
|
|
47
49
|
expect(
|
|
48
50
|
res.status === 200,
|
|
49
|
-
|
|
51
|
+
req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'an advertised host MUST resolve stream:true with 200'),
|
|
50
52
|
).toBe(true);
|
|
51
53
|
|
|
52
54
|
const audio = (res.json as { audio?: Record<string, unknown> })?.audio;
|
|
53
|
-
expect(audio !== undefined,
|
|
55
|
+
expect(audio !== undefined, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'the response MUST carry the finalized `audio` asset')).toBe(true);
|
|
54
56
|
if (audio) {
|
|
55
57
|
const hasUrl = typeof audio.url === 'string' && (audio.url as string).length > 0;
|
|
56
58
|
const hasB64 = typeof audio.base64 === 'string' && (audio.base64 as string).length > 0;
|
|
57
|
-
expect(hasUrl !== hasB64,
|
|
59
|
+
expect(hasUrl !== hasB64, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'audio MUST carry EXACTLY ONE of url/base64')).toBe(true);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const chunks = eventsOf(res.json).filter((e) => e.type === 'voice.synthesis_chunk');
|
|
61
|
-
expect(chunks.length >= 1,
|
|
63
|
+
expect(chunks.length >= 1, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'MUST emit ≥1 voice.synthesis_chunk run-event')).toBe(true);
|
|
62
64
|
for (const c of chunks) {
|
|
63
65
|
const p = c.payload ?? {};
|
|
64
|
-
expect(typeof p.seq === 'number',
|
|
65
|
-
expect(typeof p.mimeType === 'string',
|
|
66
|
+
expect(typeof p.seq === 'number', req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'each chunk carries a numeric seq')).toBe(true);
|
|
67
|
+
expect(typeof p.mimeType === 'string', req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'each chunk carries a mimeType')).toBe(true);
|
|
66
68
|
// Metadata-only: bytes by reference. An inline base64 is permitted ONLY under the host cap;
|
|
67
69
|
// a chunk over the RFC 0055 256 KiB inline cap MUST be a url/streamRef reference.
|
|
68
70
|
if (typeof p.base64 === 'string') {
|
|
69
|
-
expect((p.base64 as string).length <= 262144,
|
|
71
|
+
expect((p.base64 as string).length <= 262144, req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C (G8)', 'inline chunk base64 MUST stay under the 256 KiB cap; else url/streamRef')).toBe(true);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
expect(
|
|
73
75
|
chunks.some((c) => (c.payload ?? {}).final === true),
|
|
74
|
-
|
|
76
|
+
req('openwop.it.voice-synthesis-streaming.stream-true-resolves-the-finalized-asset-and-emits-metadata-only-voice-synthesis', 'RFC 0106 §C', 'a terminal chunk MUST carry final:true'),
|
|
75
77
|
).toBe(true);
|
|
76
78
|
});
|
|
77
79
|
});
|
|
@@ -23,6 +23,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
|
|
|
23
23
|
import { driver } from '../lib/driver.js';
|
|
24
24
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
25
25
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
26
28
|
|
|
27
29
|
const SEAM = '/v1/host/sample/ai/call-transcriber';
|
|
28
30
|
|
|
@@ -45,21 +47,21 @@ describe('voice-transcription-streaming (RFC 0106 §B)', () => {
|
|
|
45
47
|
if (!behaviorGate('openwop-voice-transcription', advertised)) return;
|
|
46
48
|
|
|
47
49
|
const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' }, languageCode: 'en-US' });
|
|
48
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
50
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
49
51
|
// §E: a stateless host with no live transport honestly rejects a live streamRef.
|
|
50
|
-
if (errCode(res.json) === 'transcription_unsupported') return; // soft-skip (no live transport / no test-seam arm)
|
|
52
|
+
if (errCode(res.json) === 'transcription_unsupported') return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `errCode(res.json) === \'transcription_unsupported\'` returned early (soft-skip (no live transport / no test-seam arm))'); // soft-skip (no live transport / no test-seam arm)
|
|
51
53
|
|
|
52
|
-
expect(res.status === 200,
|
|
54
|
+
expect(res.status === 200, req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'a produced turn MUST return 200')).toBe(true);
|
|
53
55
|
|
|
54
56
|
const finalText = (res.json as { finalText?: unknown })?.finalText;
|
|
55
|
-
expect(typeof finalText === 'string' && (finalText as string).length > 0,
|
|
57
|
+
expect(typeof finalText === 'string' && (finalText as string).length > 0, req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'the turn MUST resolve a non-empty finalText at turn_commit')).toBe(true);
|
|
56
58
|
|
|
57
59
|
const events = eventsOf(res.json);
|
|
58
60
|
if (events.length > 0) {
|
|
59
61
|
for (const ev of events.filter((e) => e.type === 'voice.transcript')) {
|
|
60
|
-
expect((ev.payload ?? {}).contentTrust === 'untrusted',
|
|
62
|
+
expect((ev.payload ?? {}).contentTrust === 'untrusted', req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §F INV-2', 'every voice.transcript MUST carry contentTrust:"untrusted"')).toBe(true);
|
|
61
63
|
}
|
|
62
|
-
expect(events.some((e) => e.type === 'voice.turn_commit'),
|
|
64
|
+
expect(events.some((e) => e.type === 'voice.turn_commit'), req('openwop.it.voice-transcription-streaming.resolves-a-settled-turn-at-voice-turn-commit-with-untrusted-transcript-events', 'RFC 0106 §B', 'the turn MUST terminate with voice.turn_commit')).toBe(true);
|
|
63
65
|
}
|
|
64
66
|
});
|
|
65
67
|
});
|
|
@@ -18,6 +18,8 @@ import { readErrorCode } from '../lib/error-envelope.js';
|
|
|
18
18
|
import { driver } from '../lib/driver.js';
|
|
19
19
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
20
20
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
21
|
+
import { req } from '../lib/requirement-ids.js';
|
|
22
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
21
23
|
|
|
22
24
|
const SEAM = '/v1/host/sample/ai/call-transcriber';
|
|
23
25
|
|
|
@@ -36,12 +38,12 @@ describe('voice-transcription-unadvertised (RFC 0106 §B)', () => {
|
|
|
36
38
|
if (!behaviorGate('openwop-voice-transcription-unadvertised', !advertised)) return;
|
|
37
39
|
|
|
38
40
|
const res = await driver.post(SEAM, { audio: { streamRef: 'stream:conformance/mic' } });
|
|
39
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
41
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
40
42
|
|
|
41
|
-
expect(res.status !== 200,
|
|
43
|
+
expect(res.status !== 200, req('openwop.it.voice-transcription-unadvertised.a-host-not-advertising-realtimevoice-transcription-must-reject-with-transcriptio', 'RFC 0106 §B', 'an unadvertising host MUST NOT return a 200 (never a no-op)')).toBe(true);
|
|
42
44
|
expect(
|
|
43
45
|
errCode(res.json) === 'transcription_unsupported',
|
|
44
|
-
|
|
46
|
+
req('openwop.it.voice-transcription-unadvertised.a-host-not-advertising-realtimevoice-transcription-must-reject-with-transcriptio', 'RFC 0106 §B', 'the call MUST be rejected with `transcription_unsupported`'),
|
|
45
47
|
).toBe(true);
|
|
46
48
|
});
|
|
47
49
|
});
|
|
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
28
28
|
import { softSkip } from '../lib/soft-skip.js';
|
|
29
29
|
import { driver } from '../lib/driver.js';
|
|
30
30
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
31
32
|
|
|
32
33
|
const MISBEHAVING_PACK_NAME = 'vendor.openwop.misbehaving-abi';
|
|
33
34
|
const WELL_BEHAVED_PACK_NAME = 'vendor.openwop.rust-hello';
|
|
@@ -40,7 +41,7 @@ describe('wasm-pack-abi-version-rejection: host advertises supported ABI version
|
|
|
40
41
|
|
|
41
42
|
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
42
43
|
|
|
43
|
-
expect(Array.isArray(wasm.abiVersions),
|
|
44
|
+
expect(Array.isArray(wasm.abiVersions), req('openwop.it.wasm-pack-abi-version-rejection.abiversions-contains-positive-integers-loader-rejects-unsupported-versions',
|
|
44
45
|
'RFCS/0008-wasm-abi.md §H',
|
|
45
46
|
'capabilities.nodePackRuntimes.wasm.abiVersions MUST be an array',
|
|
46
47
|
)).toBe(true);
|
|
@@ -90,7 +91,7 @@ describe('wasm-pack-abi-version-rejection: positive path via misbehaving pack',
|
|
|
90
91
|
|
|
91
92
|
// Core assertion: ABI 999 pack MUST NOT be in loadedPacks[]
|
|
92
93
|
// regardless of filesystem state. The host's loader rejected it.
|
|
93
|
-
expect(wasm.loadedPacks.includes(MISBEHAVING_PACK_NAME),
|
|
94
|
+
expect(wasm.loadedPacks.includes(MISBEHAVING_PACK_NAME), req('openwop.it.wasm-pack-abi-version-rejection.misbehaving-abi-pack-declares-abi-999-must-not-appear-in-loadedpacks',
|
|
94
95
|
'RFCS/0008-wasm-abi.md §H',
|
|
95
96
|
`host MUST reject packs whose declared ABI is not in abiVersions[]; ${MISBEHAVING_PACK_NAME} declares 999 and MUST NOT appear in loadedPacks[]`,
|
|
96
97
|
)).toBe(false);
|
|
@@ -18,6 +18,7 @@ import { driver } from '../lib/driver.js';
|
|
|
18
18
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
19
19
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
20
20
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
21
|
+
import { req } from '../lib/requirement-ids.js';
|
|
21
22
|
|
|
22
23
|
const FIXTURE = 'conformance-wasm-pack-roundtrip';
|
|
23
24
|
|
|
@@ -45,7 +46,7 @@ describe('wasm-pack-invoke-completed: round-trip output', () => {
|
|
|
45
46
|
const runId = (create.json as { runId: string }).runId;
|
|
46
47
|
|
|
47
48
|
const terminal = await pollUntilTerminal(runId, { timeoutMs: 15_000 });
|
|
48
|
-
expect(terminal.status,
|
|
49
|
+
expect(terminal.status, req('openwop.it.wasm-pack-invoke-completed.greet-node-returns-hello-name-and-run-reaches-completed',
|
|
49
50
|
'RFCS/0008-wasm-abi.md §D',
|
|
50
51
|
"WASM 'completed' outcome MUST drive terminal 'completed' run status",
|
|
51
52
|
)).toBe('completed');
|
|
@@ -61,7 +62,7 @@ describe('wasm-pack-invoke-completed: round-trip output', () => {
|
|
|
61
62
|
const fullLog = JSON.stringify(list).toLowerCase();
|
|
62
63
|
expect(
|
|
63
64
|
haystack.includes('hello, openwop') || fullLog.includes('hello, openwop'),
|
|
64
|
-
|
|
65
|
+
req('openwop.it.wasm-pack-invoke-completed.greet-node-returns-hello-name-and-run-reaches-completed',
|
|
65
66
|
'RFCS/0008-wasm-abi.md §D',
|
|
66
67
|
"WASM completion output MUST be surfaced somewhere in the run's event log so consumers can read it",
|
|
67
68
|
),
|
|
@@ -22,6 +22,7 @@ import { driver } from '../lib/driver.js';
|
|
|
22
22
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
23
23
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
24
24
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
26
|
|
|
26
27
|
const FIXTURE = 'conformance-wasm-pack-roundtrip';
|
|
27
28
|
|
|
@@ -60,11 +61,11 @@ describe('wasm-pack-invoke-suspended: suspend → resume round-trip', () => {
|
|
|
60
61
|
const ok =
|
|
61
62
|
haystack.includes('wasm_suspend_not_implemented') ||
|
|
62
63
|
haystack.includes('suspend_not_supported');
|
|
63
|
-
expect(ok,
|
|
64
|
+
expect(ok, req('openwop.it.wasm-pack-invoke-suspended.host-either-suspends-the-run-or-explicitly-reports-wasm-suspend-not-implemented',
|
|
64
65
|
'RFCS/0008-wasm-abi.md §D',
|
|
65
66
|
"if a host doesn't implement WASM-driven suspends it MUST surface a recognizable code",
|
|
66
67
|
)).toBe(true);
|
|
67
|
-
return;
|
|
68
|
+
return softSkip('blocked', 'precondition not met — `terminal.status === \'failed\'` returned early (seam, prior step, or fixture unavailable)');
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
// Completed path: the reference pack never suspends. Asserting
|
|
@@ -17,6 +17,7 @@ import { softSkip } from '../lib/soft-skip.js';
|
|
|
17
17
|
import { driver } from '../lib/driver.js';
|
|
18
18
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
19
19
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
20
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
21
|
|
|
21
22
|
const FIXTURE = 'conformance-wasm-pack-roundtrip';
|
|
22
23
|
|
|
@@ -42,11 +43,11 @@ describe('wasm-pack-load: discovery surfaces WASM runtime support', () => {
|
|
|
42
43
|
console.warn('[wasm-pack-load] host does not advertise WASM support; skipping');
|
|
43
44
|
return softSkip('inapplicable', '[wasm-pack-load] host does not advertise WASM support; skipping');
|
|
44
45
|
}
|
|
45
|
-
expect(Array.isArray(wasm.abiVersions),
|
|
46
|
+
expect(Array.isArray(wasm.abiVersions), req('openwop.it.wasm-pack-load.a-host-claiming-wasm-support-advertises-abiversions-including-1',
|
|
46
47
|
'RFCS/0008-wasm-abi.md §H',
|
|
47
48
|
'capabilities.nodePackRuntimes.wasm.abiVersions MUST be an array',
|
|
48
49
|
)).toBe(true);
|
|
49
|
-
expect(wasm.abiVersions?.includes(1),
|
|
50
|
+
expect(wasm.abiVersions?.includes(1), req('openwop.it.wasm-pack-load.a-host-claiming-wasm-support-advertises-abiversions-including-1',
|
|
50
51
|
'RFCS/0008-wasm-abi.md §H',
|
|
51
52
|
'abiVersions MUST include 1 (this RFC) when supported',
|
|
52
53
|
)).toBe(true);
|
|
@@ -66,7 +67,7 @@ describe('wasm-pack-load: loaded pack typeIds are dispatchable', () => {
|
|
|
66
67
|
// WASM-provided typeId. A host that loaded the pack accepts the
|
|
67
68
|
// POST /v1/runs; one that didn't would return 400/404.
|
|
68
69
|
const create = await driver.post('/v1/runs', { workflowId: FIXTURE, inputs: { name: 'world' } });
|
|
69
|
-
expect(create.status,
|
|
70
|
+
expect(create.status, req('openwop.it.wasm-pack-load.host-accepts-a-workflow-whose-node-typeid-is-provided-by-a-loaded-wasm-pack',
|
|
70
71
|
'RFCS/0008-wasm-abi.md §B + node-packs.md §Reserved typeIds',
|
|
71
72
|
'host MUST accept runs whose nodes reference loaded-pack typeIds',
|
|
72
73
|
)).toBe(201);
|