@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
|
@@ -31,6 +31,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
31
31
|
import { readFileSync } from 'node:fs';
|
|
32
32
|
import { join } from 'node:path';
|
|
33
33
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
34
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
35
|
|
|
35
36
|
const ajv = new Ajv2020({ strict: false, allErrors: true });
|
|
36
37
|
const schema = JSON.parse(
|
|
@@ -70,7 +71,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
70
71
|
it('ui.a2ui-surface.schema.json compiles under Ajv2020', () => {
|
|
71
72
|
expect(
|
|
72
73
|
validate,
|
|
73
|
-
'RFC 0102 §A: the core ui.a2ui-surface payload schema MUST compile',
|
|
74
|
+
req('openwop.it.a2ui-surface-shape.ui-a2ui-surface-schema-json-compiles-under-ajv2020', 'RFC 0102 §A', 'RFC 0102 §A: the core ui.a2ui-surface payload schema MUST compile'),
|
|
74
75
|
).toBeTypeOf('function');
|
|
75
76
|
});
|
|
76
77
|
|
|
@@ -78,7 +79,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
78
79
|
const ok = validate(positivePayload());
|
|
79
80
|
expect(
|
|
80
81
|
ok,
|
|
81
|
-
`RFC 0102 §A: positive surface MUST validate; errors: ${JSON.stringify(validate.errors)}
|
|
82
|
+
req('openwop.it.a2ui-surface-shape.accepts-a-positive-surface-payload-closed-catalog-confined-action', 'RFC 0102 §A', `RFC 0102 §A: positive surface MUST validate; errors: ${JSON.stringify(validate.errors)}`),
|
|
82
83
|
).toBe(true);
|
|
83
84
|
});
|
|
84
85
|
|
|
@@ -87,19 +88,19 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
87
88
|
(p.surface as { components: Array<Record<string, unknown>> }).components = [
|
|
88
89
|
{ component: 'action.button', id: 'send', label: 'Send', action: { target: 'exchange' } },
|
|
89
90
|
];
|
|
90
|
-
expect(validate(p)).toBe(true);
|
|
91
|
+
expect(validate(p), req('openwop.it.a2ui-surface-shape.accepts-an-exchange-targeted-action-the-other-confined-target', 'RFC 0102 §A', 'accepts an exchange-targeted action (the other confined target)')).toBe(true);
|
|
91
92
|
});
|
|
92
93
|
|
|
93
94
|
it('rejects a payload missing required `catalogVersion`', () => {
|
|
94
95
|
const p = positivePayload();
|
|
95
96
|
delete p.catalogVersion;
|
|
96
|
-
expect(validate(p), 'RFC 0102 §A: `catalogVersion` is REQUIRED').toBe(false);
|
|
97
|
+
expect(validate(p), req('openwop.it.a2ui-surface-shape.rejects-a-payload-missing-required-catalogversion', 'RFC 0102 §A', 'RFC 0102 §A: `catalogVersion` is REQUIRED')).toBe(false);
|
|
97
98
|
});
|
|
98
99
|
|
|
99
100
|
it('rejects a payload missing required `surface`', () => {
|
|
100
101
|
const p = positivePayload();
|
|
101
102
|
delete p.surface;
|
|
102
|
-
expect(validate(p), 'RFC 0102 §A: `surface` is REQUIRED').toBe(false);
|
|
103
|
+
expect(validate(p), req('openwop.it.a2ui-surface-shape.rejects-a-payload-missing-required-surface', 'RFC 0102 §A', 'RFC 0102 §A: `surface` is REQUIRED')).toBe(false);
|
|
103
104
|
});
|
|
104
105
|
|
|
105
106
|
it('rejects a `catalogVersion` the schema does not enumerate (unknown version)', () => {
|
|
@@ -107,7 +108,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
107
108
|
p.catalogVersion = '9.9.9';
|
|
108
109
|
expect(
|
|
109
110
|
validate(p),
|
|
110
|
-
'RFC 0102 §A.3: an unadvertised catalogVersion MUST fail the enumerated set',
|
|
111
|
+
req('openwop.it.a2ui-surface-shape.rejects-a-catalogversion-the-schema-does-not-enumerate-unknown-version', 'RFC 0102 §A', 'RFC 0102 §A.3: an unadvertised catalogVersion MUST fail the enumerated set'),
|
|
111
112
|
).toBe(false);
|
|
112
113
|
});
|
|
113
114
|
|
|
@@ -118,7 +119,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
118
119
|
];
|
|
119
120
|
expect(
|
|
120
121
|
validate(p),
|
|
121
|
-
'RFC 0102 §A.1: an out-of-catalog component MUST fail the closed anyOf',
|
|
122
|
+
req('openwop.it.a2ui-surface-shape.rejects-an-out-of-catalog-component-object-additionalproperties-false', 'RFC 0102 §A', 'RFC 0102 §A.1: an out-of-catalog component MUST fail the closed anyOf'),
|
|
122
123
|
).toBe(false);
|
|
123
124
|
});
|
|
124
125
|
|
|
@@ -129,7 +130,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
129
130
|
];
|
|
130
131
|
expect(
|
|
131
132
|
validate(p),
|
|
132
|
-
'RFC 0102 §A.1: additionalProperties:false MUST reject a smuggled code field',
|
|
133
|
+
req('openwop.it.a2ui-surface-shape.rejects-a-known-component-carrying-an-extra-script-bearing-property', 'RFC 0102 §A', 'RFC 0102 §A.1: additionalProperties:false MUST reject a smuggled code field'),
|
|
133
134
|
).toBe(false);
|
|
134
135
|
});
|
|
135
136
|
|
|
@@ -140,7 +141,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
140
141
|
];
|
|
141
142
|
expect(
|
|
142
143
|
validate(p),
|
|
143
|
-
'RFC 0102 §A.4 / SECURITY a2ui-action-confinement: an action target outside resume/exchange MUST be rejected',
|
|
144
|
+
req('openwop.it.a2ui-surface-shape.rejects-an-action-whose-target-is-outside-enum-resume-exchange-action-confinemen', 'RFC 0102 §A', 'RFC 0102 §A.4 / SECURITY a2ui-action-confinement: an action target outside resume/exchange MUST be rejected'),
|
|
144
145
|
).toBe(false);
|
|
145
146
|
});
|
|
146
147
|
|
|
@@ -156,7 +157,7 @@ describe('a2ui-surface-shape: schema compile + round-trip (RFC 0102 §A)', () =>
|
|
|
156
157
|
];
|
|
157
158
|
expect(
|
|
158
159
|
validate(p),
|
|
159
|
-
'RFC 0102 §A.4: action additionalProperties:false MUST reject an arbitrary URL target',
|
|
160
|
+
req('openwop.it.a2ui-surface-shape.rejects-an-action-carrying-an-arbitrary-url-field-no-unconfined-egress-target', 'RFC 0102 §A', 'RFC 0102 §A.4: action additionalProperties:false MUST reject an arbitrary URL target'),
|
|
160
161
|
).toBe(false);
|
|
161
162
|
});
|
|
162
163
|
});
|
|
@@ -20,6 +20,8 @@ import { readFileSync } from 'node:fs';
|
|
|
20
20
|
import { join } from 'node:path';
|
|
21
21
|
import { driver } from '../lib/driver.js';
|
|
22
22
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
23
|
+
import { req } from '../lib/requirement-ids.js';
|
|
24
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
23
25
|
|
|
24
26
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
25
27
|
const schema = JSON.parse(
|
|
@@ -42,14 +44,14 @@ describe('a2ui-surface-version-refusal: enumerated catalogVersion (RFC 0102 §A.
|
|
|
42
44
|
const ok = validate({ catalogVersion: '9.9.9', surface: { components: [] } });
|
|
43
45
|
expect(
|
|
44
46
|
ok,
|
|
45
|
-
'RFC 0102 §A.3: a catalogVersion outside the host-enumerated set MUST fail (→ unknown_schema_version at runtime)',
|
|
47
|
+
req('openwop.it.a2ui-surface-version-refusal.catalogversion-is-a-closed-enum-an-unadvertised-version-fails-validation', 'RFC 0102 §A.3', 'RFC 0102 §A.3: a catalogVersion outside the host-enumerated set MUST fail (→ unknown_schema_version at runtime)'),
|
|
46
48
|
).toBe(false);
|
|
47
49
|
});
|
|
48
50
|
|
|
49
51
|
it('surface payload is self-contained — no external $ref (replay determinism)', () => {
|
|
50
52
|
expect(
|
|
51
53
|
hasAbsoluteRef(schema),
|
|
52
|
-
'RFC 0102 §A.3: the surface MUST be self-contained, never a live external-catalog reference',
|
|
54
|
+
req('openwop.it.a2ui-surface-version-refusal.surface-payload-is-self-contained-no-external-ref-replay-determinism', 'RFC 0102 §A.3', 'RFC 0102 §A.3: the surface MUST be self-contained, never a live external-catalog reference'),
|
|
53
55
|
).toBe(false);
|
|
54
56
|
});
|
|
55
57
|
});
|
|
@@ -67,11 +69,11 @@ describe.skipIf(HTTP_SKIP)('a2ui-surface-version-refusal: live host refuses unad
|
|
|
67
69
|
},
|
|
68
70
|
hostSupportedEnvelopes: ['ui.a2ui-surface'],
|
|
69
71
|
});
|
|
70
|
-
if (res.status === 404) return; // seam absent — soft-skip
|
|
72
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
|
|
71
73
|
const body = res.json as { status?: string; reason?: string };
|
|
72
74
|
expect(
|
|
73
75
|
body.status === 'invalid' || body.status === 'refused',
|
|
74
|
-
|
|
76
|
+
req('openwop.it.a2ui-surface-version-refusal.ui-a2ui-surface-with-an-unadvertised-catalogversion-refused', 'RFC 0102 §A.3', 'an unadvertised catalogVersion MUST be refused'),
|
|
75
77
|
).toBe(true);
|
|
76
78
|
});
|
|
77
79
|
});
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
|
|
22
22
|
import { describe, it, expect } from 'vitest';
|
|
23
23
|
import { driver } from '../lib/driver.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
24
26
|
|
|
25
27
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
26
28
|
const UNIVERSAL_KINDS = ['clarification.request', 'schema.request', 'schema.response', 'error'];
|
|
@@ -29,7 +31,7 @@ describe('a2ui-untrusted-blocks-approval: trust machinery applies (RFC 0102 §A.
|
|
|
29
31
|
it('ui.a2ui-surface is an advertised kind subject to meta.contentTrust gating (not universal/always-allowed)', () => {
|
|
30
32
|
expect(
|
|
31
33
|
UNIVERSAL_KINDS.includes('ui.a2ui-surface'),
|
|
32
|
-
'ai-envelope.md §"A2UI surfaces" / §"Trust boundary": a ui.a2ui-surface is trust-gated like any advertised envelope, so an untrusted surface is subject to untrusted_content_blocks_approval',
|
|
34
|
+
req('openwop.it.a2ui-untrusted-blocks-approval.ui-a2ui-surface-is-an-advertised-kind-subject-to-meta-contenttrust-gating-not-un', 'RFC 0102 §A.5', 'ai-envelope.md §"A2UI surfaces" / §"Trust boundary": a ui.a2ui-surface is trust-gated like any advertised envelope, so an untrusted surface is subject to untrusted_content_blocks_approval'),
|
|
33
35
|
).toBe(false);
|
|
34
36
|
});
|
|
35
37
|
});
|
|
@@ -55,11 +57,11 @@ describe.skipIf(HTTP_SKIP)('a2ui-untrusted-blocks-approval: untrusted surface ca
|
|
|
55
57
|
hostSupportedEnvelopes: ['ui.a2ui-surface'],
|
|
56
58
|
boundInterruptKind: 'approval',
|
|
57
59
|
});
|
|
58
|
-
if (res.status === 404) return; // seam absent — soft-skip
|
|
60
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
|
|
59
61
|
const body = res.json as { status?: string; reason?: string };
|
|
60
62
|
expect(
|
|
61
63
|
body.status === 'blocked' || (body.reason ?? '').includes('untrusted'),
|
|
62
|
-
|
|
64
|
+
req('openwop.it.a2ui-untrusted-blocks-approval.an-untrusted-marked-ui-a2ui-surface-bound-to-an-approval-interrupt-is-refused',
|
|
63
65
|
'RFC 0102 §A.5',
|
|
64
66
|
'an untrusted ui.a2ui-surface MUST NOT advance an approval interrupt (untrusted_content_blocks_approval)',
|
|
65
67
|
),
|
|
@@ -26,9 +26,10 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { describe, it, expect } from 'vitest';
|
|
29
|
-
import { driver } from '../lib/driver.js';
|
|
30
29
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
31
30
|
import { readManifestRuntimeCap, listManifestAgents } from '../lib/agentRuntime.js';
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
32
33
|
|
|
33
34
|
interface InventoryEntry {
|
|
34
35
|
agentId?: string;
|
|
@@ -43,13 +44,13 @@ describe('agent-capability-degraded-projection (RFC 0092 §B)', () => {
|
|
|
43
44
|
if (!behaviorGate('openwop-agent-capability-degraded', mr?.supported === true)) return;
|
|
44
45
|
|
|
45
46
|
const inv = await listManifestAgents();
|
|
46
|
-
if (inv === null) return; // cap advertised but /v1/agents unserved — soft-skip
|
|
47
|
+
if (inv === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `inv === null` returned early (cap advertised but /v1/agents unserved — soft-skip)'); // cap advertised but /v1/agents unserved — soft-skip
|
|
47
48
|
const agents = (inv.agents ?? []) as InventoryEntry[];
|
|
48
49
|
|
|
49
50
|
// Non-vacuity: an advertising + serving host MUST expose its inventory.
|
|
50
51
|
expect(
|
|
51
52
|
agents.length >= 1,
|
|
52
|
-
|
|
53
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0072 §A', 'GET /v1/agents MUST return the installed manifest agents'),
|
|
53
54
|
).toBe(true);
|
|
54
55
|
|
|
55
56
|
// §B well-formedness on EVERY entry: degraded[], when present, is a unique
|
|
@@ -59,18 +60,18 @@ describe('agent-capability-degraded-projection (RFC 0092 §B)', () => {
|
|
|
59
60
|
if (d !== undefined) {
|
|
60
61
|
expect(
|
|
61
62
|
Array.isArray(d),
|
|
62
|
-
|
|
63
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'agent-inventory-response.schema.json', `degraded MUST be an array when present (agent ${a.agentId})`),
|
|
63
64
|
).toBe(true);
|
|
64
65
|
if (Array.isArray(d)) {
|
|
65
66
|
for (const k of d) {
|
|
66
67
|
expect(
|
|
67
68
|
typeof k === 'string' && k.length > 0,
|
|
68
|
-
|
|
69
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0072 §C', `degraded[] members MUST be non-empty strings (agent ${a.agentId}, got ${String(k)})`),
|
|
69
70
|
).toBe(true);
|
|
70
71
|
}
|
|
71
72
|
expect(
|
|
72
73
|
new Set(d as string[]).size === d.length,
|
|
73
|
-
|
|
74
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0092 §B', `degraded[] MUST be unique (agent ${a.agentId})`),
|
|
74
75
|
).toBe(true);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
@@ -82,23 +83,23 @@ describe('agent-capability-degraded-projection (RFC 0092 §B)', () => {
|
|
|
82
83
|
const target = agents.find((a) => a.agentId === degradedId);
|
|
83
84
|
expect(
|
|
84
85
|
target !== undefined,
|
|
85
|
-
|
|
86
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0092 §B', `OPENWOP_DEGRADED_CAPABILITY_AGENT_ID=${degradedId} MUST appear in the inventory`),
|
|
86
87
|
).toBe(true);
|
|
87
88
|
if (target) {
|
|
88
89
|
const d = target.degraded;
|
|
89
90
|
expect(
|
|
90
91
|
Array.isArray(d) && d.length >= 1,
|
|
91
|
-
|
|
92
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0092 §B', 'the named capability-degraded agent MUST carry a non-empty degraded[]'),
|
|
92
93
|
).toBe(true);
|
|
93
94
|
// When the entry also exposes requiresCapabilities, every degraded key
|
|
94
95
|
// MUST be one the agent actually requires (the projection is a subset of
|
|
95
96
|
// requirements, never invented).
|
|
96
97
|
if (Array.isArray(d) && Array.isArray(target.requiresCapabilities)) {
|
|
97
|
-
const
|
|
98
|
+
const required = new Set(target.requiresCapabilities as unknown[]);
|
|
98
99
|
for (const k of d) {
|
|
99
100
|
expect(
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
required.has(k),
|
|
102
|
+
req('openwop.it.agent-capability-degraded-projection.surfaces-unmet-requirescapabilities-in-degraded-and-nothing-on-the-rest', 'RFC 0092 §B', `a degraded[] key MUST be one the agent requires (got ${String(k)})`),
|
|
102
103
|
).toBe(true);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -43,6 +43,8 @@ import { pollUntilTerminal } from '../lib/polling.js';
|
|
|
43
43
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
44
44
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
45
45
|
import { readDeploymentCap, driveDeploymentTransition } from '../lib/agentDeployment.js';
|
|
46
|
+
import { req } from '../lib/requirement-ids.js';
|
|
47
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
46
48
|
|
|
47
49
|
const FIXTURE_ID = 'conformance-agent-channel-dispatch';
|
|
48
50
|
const BOUND_CHANNEL = 'stable';
|
|
@@ -93,7 +95,7 @@ async function startChannelRun(): Promise<string> {
|
|
|
93
95
|
const create = await driver.post('/v1/runs', { workflowId: FIXTURE_ID });
|
|
94
96
|
expect(
|
|
95
97
|
create.status,
|
|
96
|
-
|
|
98
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
97
99
|
'agent-deployment.md §B',
|
|
98
100
|
`a host advertising agents.deployment + the ${FIXTURE_ID} fixture MUST accept a channel-bound run (201)`,
|
|
99
101
|
),
|
|
@@ -111,12 +113,12 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
111
113
|
// Host advertises agents.deployment but hasn't seeded the channel-bound
|
|
112
114
|
// fixture — a host-config precondition, not a conformance failure.
|
|
113
115
|
ctx.skip();
|
|
114
|
-
return;
|
|
116
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE_ID)` returned early');
|
|
115
117
|
}
|
|
116
118
|
const modes = await fetchReplayModes();
|
|
117
119
|
if (!modes.includes('replay')) {
|
|
118
120
|
ctx.skip();
|
|
119
|
-
return;
|
|
121
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'replay\')` returned early');
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// ---- Leg 1: production-path channel resolution + recorded pin (§B) ----
|
|
@@ -124,14 +126,14 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
124
126
|
const started = await firstInvocationStarted(sourceRunId);
|
|
125
127
|
expect(
|
|
126
128
|
started !== null,
|
|
127
|
-
|
|
129
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
128
130
|
'agent-deployment.md §B',
|
|
129
131
|
'a @channel-bound run MUST emit agent.invocation.started',
|
|
130
132
|
),
|
|
131
133
|
).toBe(true);
|
|
132
134
|
expect(
|
|
133
135
|
started!.payload.resolvedChannel,
|
|
134
|
-
|
|
136
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
135
137
|
'agent-deployment.md §B',
|
|
136
138
|
`agent.invocation.started MUST carry the bound channel as resolvedChannel ("${BOUND_CHANNEL}")`,
|
|
137
139
|
),
|
|
@@ -139,7 +141,7 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
139
141
|
const pinnedVersion = started!.payload.resolvedAgentVersion;
|
|
140
142
|
expect(
|
|
141
143
|
typeof pinnedVersion === 'string' && (pinnedVersion as string).length > 0,
|
|
142
|
-
|
|
144
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
143
145
|
'agent-deployment.md §B',
|
|
144
146
|
'a @channel-bound run MUST record a concrete resolvedAgentVersion (the recorded fact a replay re-reads, RFC 0077)',
|
|
145
147
|
),
|
|
@@ -152,22 +154,22 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
152
154
|
);
|
|
153
155
|
if (forkDeclined(fork1.status, 'channel-dispatch replay fork 1')) {
|
|
154
156
|
ctx.skip();
|
|
155
|
-
return;
|
|
157
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(fork1.status, \'channel-dispatch replay fork 1\')` returned early (seam, prior step, or fixture unavailable)');
|
|
156
158
|
}
|
|
157
159
|
expect(
|
|
158
160
|
fork1.status,
|
|
159
|
-
|
|
161
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r', 'rest-endpoints.md POST /v1/runs/{runId}:fork', 'replay fork MUST return 201'),
|
|
160
162
|
).toBe(201);
|
|
161
163
|
const fork1RunId = (fork1.json as { runId: string }).runId;
|
|
162
164
|
await pollUntilTerminal(fork1RunId, { timeoutMs: 15_000 });
|
|
163
165
|
const fork1Started = await firstInvocationStarted(fork1RunId);
|
|
164
166
|
expect(
|
|
165
167
|
fork1Started !== null,
|
|
166
|
-
|
|
168
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r', 'agent-deployment.md §B', 'a replay fork MUST re-emit agent.invocation.started'),
|
|
167
169
|
).toBe(true);
|
|
168
170
|
expect(
|
|
169
171
|
fork1Started!.payload.resolvedAgentVersion,
|
|
170
|
-
|
|
172
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
171
173
|
'agent-deployment.md §B',
|
|
172
174
|
'a replay MUST re-read the recorded resolvedAgentVersion (NOT re-resolve the channel)',
|
|
173
175
|
),
|
|
@@ -196,7 +198,7 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
196
198
|
// evidence; the cross-move proof needs the seam. Honest skip of Leg 3.
|
|
197
199
|
// eslint-disable-next-line no-console
|
|
198
200
|
console.warn('[agent-channel-dispatch] deployment seam absent — skipping the channel-move non-re-resolution leg (Leg 3)');
|
|
199
|
-
return;
|
|
201
|
+
return softSkip('blocked', 'precondition not met — `moved === null` returned early ([agent-channel-dispatch] deployment seam absent — skipping the channel-move non-re-resolution leg (Leg 3)) (seam, prior step, or fixture unavailable)');
|
|
200
202
|
}
|
|
201
203
|
// Confirm the move is OBSERVABLE: a fresh channel-bound run must now resolve
|
|
202
204
|
// to a DIFFERENT version. If it doesn't (canary split, no-op promote), we
|
|
@@ -207,7 +209,7 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
207
209
|
if (typeof movedVersion !== 'string' || movedVersion === pinnedVersion) {
|
|
208
210
|
// eslint-disable-next-line no-console
|
|
209
211
|
console.warn('[agent-channel-dispatch] channel did not observably move — skipping Leg 3 strict assertion');
|
|
210
|
-
return;
|
|
212
|
+
return softSkip('blocked', 'precondition not met — `typeof movedVersion !== \'string\' || movedVersion === pinnedVersion` returned early ([agent-channel-dispatch] channel did not observably move — skipping Leg 3 strict assertion) (seam, prior step…');
|
|
211
213
|
}
|
|
212
214
|
const fork2 = await driver.post(
|
|
213
215
|
`/v1/runs/${encodeURIComponent(sourceRunId)}:fork`,
|
|
@@ -215,25 +217,25 @@ describe.skipIf(HTTP_SKIP)('agent-channel-dispatch (RFC 0082 §B): production ru
|
|
|
215
217
|
);
|
|
216
218
|
if (forkDeclined(fork2.status, 'channel-dispatch replay fork 2')) {
|
|
217
219
|
ctx.skip();
|
|
218
|
-
return;
|
|
220
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(fork2.status, \'channel-dispatch replay fork 2\')` returned early (seam, prior step, or fixture unavailable)');
|
|
219
221
|
}
|
|
220
222
|
expect(
|
|
221
223
|
fork2.status,
|
|
222
|
-
|
|
224
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r', 'rest-endpoints.md POST /v1/runs/{runId}:fork', 'replay fork MUST return 201'),
|
|
223
225
|
).toBe(201);
|
|
224
226
|
const fork2RunId = (fork2.json as { runId: string }).runId;
|
|
225
227
|
await pollUntilTerminal(fork2RunId, { timeoutMs: 15_000 });
|
|
226
228
|
const fork2Started = await firstInvocationStarted(fork2RunId);
|
|
227
229
|
expect(
|
|
228
230
|
fork2Started?.payload.resolvedAgentVersion,
|
|
229
|
-
|
|
231
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
230
232
|
'agent-deployment.md §B',
|
|
231
233
|
'after the channel moves, a replay of the original run MUST still carry the ORIGINAL pin — never re-resolving the moved channel',
|
|
232
234
|
),
|
|
233
235
|
).toBe(pinnedVersion);
|
|
234
236
|
expect(
|
|
235
237
|
fork2Started?.payload.resolvedAgentVersion,
|
|
236
|
-
|
|
238
|
+
req('openwop.it.agent-channel-dispatch.resolves-records-the-channel-pin-on-a-real-run-and-re-reads-it-on-replay-never-r',
|
|
237
239
|
'agent-deployment.md §B',
|
|
238
240
|
'a replay MUST NOT resolve to the post-move version (proves the recorded fact is re-read, not re-resolved)',
|
|
239
241
|
),
|
|
@@ -33,7 +33,6 @@ import { readFileSync } from 'node:fs';
|
|
|
33
33
|
import { join } from 'node:path';
|
|
34
34
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
35
35
|
import addFormats from 'ajv-formats';
|
|
36
|
-
import { driver } from '../lib/driver.js';
|
|
37
36
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
38
37
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
39
38
|
import {
|
|
@@ -43,6 +42,8 @@ import {
|
|
|
43
42
|
DEPLOYMENT_CONTENT_FORBIDDEN,
|
|
44
43
|
} from '../lib/agentDeployment.js';
|
|
45
44
|
import { queryTestEvents, requireEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
|
|
45
|
+
import { req } from '../lib/requirement-ids.js';
|
|
46
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
46
47
|
|
|
47
48
|
function loadSchema(name: string): Record<string, unknown> {
|
|
48
49
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -52,7 +53,7 @@ function expectContentFree(payload: Record<string, unknown>, where: string): voi
|
|
|
52
53
|
for (const f of DEPLOYMENT_CONTENT_FORBIDDEN) {
|
|
53
54
|
expect(
|
|
54
55
|
!(f in payload),
|
|
55
|
-
|
|
56
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'RFC 0082 §D (deployment-event-no-content-leak)', `${where} MUST be content-free (no ${f})`),
|
|
56
57
|
).toBe(true);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
@@ -61,7 +62,7 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
61
62
|
it('promotes via the eval+RBAC+approval gate, fails closed without scope/eval, and pins the channel version', async () => {
|
|
62
63
|
const cap = await readDeploymentCap();
|
|
63
64
|
if (!behaviorGate('openwop-deployment-lifecycle', cap?.supported === true)) return;
|
|
64
|
-
if (!(await isEventLogSeamAvailable())) return; // event-log seam absent — soft-skip
|
|
65
|
+
if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (event-log seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // event-log seam absent — soft-skip
|
|
65
66
|
|
|
66
67
|
const ajv = new Ajv2020({ strict: false, allErrors: true });
|
|
67
68
|
addFormats(ajv);
|
|
@@ -69,22 +70,22 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
69
70
|
|
|
70
71
|
// ---- Leg 1: eval+RBAC+approval-gated promotion (§E) ------------------
|
|
71
72
|
const promote = await driveDeploymentTransition({ scenario: 'promote' });
|
|
72
|
-
if (promote === null) return; // deployment seam unwired — soft-skip the whole behavioral suite
|
|
73
|
+
if (promote === null) return softSkip('blocked', 'precondition not met — `promote === null` returned early (deployment seam unwired — soft-skip the whole behavioral suite) (seam, prior step, or fixture unavailable)'); // deployment seam unwired — soft-skip the whole behavioral suite
|
|
73
74
|
|
|
74
75
|
// The host has ADVERTISED agents.deployment AND wired the seam — missing
|
|
75
76
|
// evidence is a FAILURE, not a soft-skip. A successful promote MUST return
|
|
76
77
|
// a runId + a schema-valid record + emit ≥1 content-free deployment.promoted.
|
|
77
78
|
expect(
|
|
78
79
|
typeof promote.runId === 'string' && (promote.runId as string).length > 0,
|
|
79
|
-
|
|
80
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E', 'a wired promote MUST return the runId'),
|
|
80
81
|
).toBe(true);
|
|
81
82
|
expect(
|
|
82
83
|
promote.record !== undefined && promote.record !== null,
|
|
83
|
-
|
|
84
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E', 'a successful promote MUST return the deployment record'),
|
|
84
85
|
).toBe(true);
|
|
85
86
|
expect(
|
|
86
87
|
validateRecord(promote.record),
|
|
87
|
-
|
|
88
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.schema.json', `a promoted deployment record MUST validate (${ajv.errorsText(validateRecord.errors)})`),
|
|
88
89
|
).toBe(true);
|
|
89
90
|
|
|
90
91
|
const promotedEvents = requireEvents(
|
|
@@ -93,17 +94,17 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
93
94
|
);
|
|
94
95
|
expect(
|
|
95
96
|
promotedEvents.length >= 1,
|
|
96
|
-
|
|
97
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E', 'a successful promote MUST emit at least one deployment.promoted'),
|
|
97
98
|
).toBe(true);
|
|
98
99
|
for (const e of promotedEvents) {
|
|
99
100
|
expectContentFree(e.payload, 'deployment.promoted');
|
|
100
101
|
expect(
|
|
101
102
|
typeof e.payload.toState === 'string' && DEPLOYMENT_STATES.includes(e.payload.toState as string),
|
|
102
|
-
|
|
103
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'run-event-payloads.schema.json#/$defs/deploymentPromoted', 'toState MUST be in the seven-state vocabulary'),
|
|
103
104
|
).toBe(true);
|
|
104
105
|
expect(
|
|
105
106
|
typeof e.payload.toVersion === 'string' && (e.payload.toVersion as string).length > 0,
|
|
106
|
-
|
|
107
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §D', 'deployment.promoted MUST carry the promoted toVersion'),
|
|
107
108
|
).toBe(true);
|
|
108
109
|
}
|
|
109
110
|
|
|
@@ -111,11 +112,11 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
111
112
|
const unauth = await driveDeploymentTransition({ scenario: 'unauthorized' });
|
|
112
113
|
expect(
|
|
113
114
|
unauth !== null && typeof unauth.runId === 'string' && (unauth.runId as string).length > 0,
|
|
114
|
-
|
|
115
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E-1', 'the unauthorized scenario MUST return a runId to evidence the fail-closed denial'),
|
|
115
116
|
).toBe(true);
|
|
116
117
|
expect(
|
|
117
118
|
unauth!.allowed !== true,
|
|
118
|
-
|
|
119
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E-1', 'a principal without deploy:promote MUST be denied (fail-closed)'),
|
|
119
120
|
).toBe(true);
|
|
120
121
|
const unauthPromoted = requireEvents(
|
|
121
122
|
await queryTestEvents(unauth!.runId as string, { type: 'deployment.promoted' }),
|
|
@@ -123,18 +124,18 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
123
124
|
);
|
|
124
125
|
expect(
|
|
125
126
|
unauthPromoted.length === 0,
|
|
126
|
-
|
|
127
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'SECURITY invariant deployment-promotion-fail-closed', 'a denied transition MUST emit NO deployment.promoted'),
|
|
127
128
|
).toBe(true);
|
|
128
129
|
|
|
129
130
|
// ---- Leg 3: eval-gate-unmet denial (§E-3) ----------------------------
|
|
130
131
|
const evalUnmet = await driveDeploymentTransition({ scenario: 'eval-gate-unmet' });
|
|
131
132
|
expect(
|
|
132
133
|
evalUnmet !== null && typeof evalUnmet.runId === 'string' && (evalUnmet.runId as string).length > 0,
|
|
133
|
-
|
|
134
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E-3', 'the eval-gate-unmet scenario MUST return a runId to evidence the denial'),
|
|
134
135
|
).toBe(true);
|
|
135
136
|
expect(
|
|
136
137
|
evalUnmet!.error === 'eval_gate_unmet' || evalUnmet!.allowed !== true,
|
|
137
|
-
|
|
138
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E-3', 'a promote whose eval evidence has passed:false MUST be denied (eval_gate_unmet)'),
|
|
138
139
|
).toBe(true);
|
|
139
140
|
const evalUnmetPromoted = requireEvents(
|
|
140
141
|
await queryTestEvents(evalUnmet!.runId as string, { type: 'deployment.promoted' }),
|
|
@@ -142,14 +143,14 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
142
143
|
);
|
|
143
144
|
expect(
|
|
144
145
|
evalUnmetPromoted.length === 0,
|
|
145
|
-
|
|
146
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §E-3', 'an unmet eval gate MUST emit NO deployment.promoted'),
|
|
146
147
|
).toBe(true);
|
|
147
148
|
|
|
148
149
|
// ---- Leg 4: channel-resolution pin (§B) ------------------------------
|
|
149
150
|
const pin = await driveDeploymentTransition({ scenario: 'channel-pin', channel: 'stable' });
|
|
150
151
|
expect(
|
|
151
152
|
pin !== null && typeof pin.runId === 'string' && (pin.runId as string).length > 0,
|
|
152
|
-
|
|
153
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §B', 'the channel-pin scenario MUST return a runId'),
|
|
153
154
|
).toBe(true);
|
|
154
155
|
const invEvents = requireEvents(
|
|
155
156
|
await queryTestEvents(pin!.runId as string, { type: 'agent.invocation.started' }),
|
|
@@ -157,12 +158,12 @@ describe('agent-deployment-lifecycle (RFC 0082 §B/§E)', () => {
|
|
|
157
158
|
);
|
|
158
159
|
expect(
|
|
159
160
|
invEvents.length >= 1,
|
|
160
|
-
|
|
161
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §B', 'a @channel-bound run MUST emit agent.invocation.started'),
|
|
161
162
|
).toBe(true);
|
|
162
163
|
const startedInv = invEvents.sort((a, b) => a.sequence - b.sequence)[0]!;
|
|
163
164
|
expect(
|
|
164
165
|
typeof startedInv.payload.resolvedAgentVersion === 'string' && (startedInv.payload.resolvedAgentVersion as string).length > 0,
|
|
165
|
-
|
|
166
|
+
req('openwop.it.agent-deployment-lifecycle.promotes-via-the-eval-rbac-approval-gate-fails-closed-without-scope-eval-and-pin', 'agent-deployment.md §B', 'a @channel-bound run MUST record resolvedAgentVersion on agent.invocation.started (the recorded fact a replay re-reads)'),
|
|
166
167
|
).toBe(true);
|
|
167
168
|
|
|
168
169
|
await resetTestSeam();
|