@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
|
@@ -38,9 +38,7 @@ import { join } from 'node:path';
|
|
|
38
38
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
39
39
|
import addFormats from 'ajv-formats';
|
|
40
40
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
41
|
-
|
|
42
|
-
/** Server-free assertion-message helper. */
|
|
43
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
41
|
+
import { req } from '../lib/requirement-ids.js';
|
|
44
42
|
|
|
45
43
|
function loadSchema(name: string): Record<string, unknown> {
|
|
46
44
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -51,11 +49,11 @@ describe('agent-deployment-shape: capability advertisement (RFC 0082, server-fre
|
|
|
51
49
|
const caps = loadSchema('capabilities.schema.json');
|
|
52
50
|
const agents = (caps.properties as Record<string, { properties?: Record<string, { properties?: Record<string, unknown> }> }>).agents;
|
|
53
51
|
const deployment = agents?.properties?.deployment;
|
|
54
|
-
expect(deployment,
|
|
52
|
+
expect(deployment, req('openwop.it.agent-deployment-shape.the-capabilities-schema-declares-agents-deployment-with-its-sub-flags', 'capabilities.md §agents', 'agents.deployment MUST be declared')).toBeDefined();
|
|
55
53
|
for (const flag of ['supported', 'channels', 'canary', 'rollback', 'states']) {
|
|
56
54
|
expect(
|
|
57
55
|
deployment?.properties?.[flag],
|
|
58
|
-
|
|
56
|
+
req('openwop.it.agent-deployment-shape.the-capabilities-schema-declares-agents-deployment-with-its-sub-flags', 'agent-deployment.md §F', `agents.deployment.${flag} MUST be declared`),
|
|
59
57
|
).toBeDefined();
|
|
60
58
|
}
|
|
61
59
|
});
|
|
@@ -69,16 +67,16 @@ describe('agent-deployment-shape: deployment record + AgentRef binding (RFC 0082
|
|
|
69
67
|
|
|
70
68
|
it('AgentDeployment validates a conforming record and rejects a bad state / out-of-range canary', () => {
|
|
71
69
|
const good = { agentId: 'core.openwop.agents.support-resolver', version: '2.4.0', state: 'active', canaryPercent: 10, channels: ['stable'] };
|
|
72
|
-
expect(record(good),
|
|
73
|
-
expect(record({ ...good, state: 'live' }),
|
|
74
|
-
expect(record({ ...good, canaryPercent: 150 }),
|
|
70
|
+
expect(record(good), req('openwop.it.agent-deployment-shape.agentdeployment-validates-a-conforming-record-and-rejects-a-bad-state-out-of-ran', 'RFC 0082 §C', 'a conforming deployment record MUST validate')).toBe(true);
|
|
71
|
+
expect(record({ ...good, state: 'live' }), req('openwop.it.agent-deployment-shape.agentdeployment-validates-a-conforming-record-and-rejects-a-bad-state-out-of-ran', 'RFC 0082 §C', 'an out-of-enum state MUST be rejected')).toBe(false);
|
|
72
|
+
expect(record({ ...good, canaryPercent: 150 }), req('openwop.it.agent-deployment-shape.agentdeployment-validates-a-conforming-record-and-rejects-a-bad-state-out-of-ran', 'RFC 0082 §C', 'canaryPercent > 100 MUST be rejected')).toBe(false);
|
|
75
73
|
});
|
|
76
74
|
|
|
77
75
|
it('AgentRef channel XOR version: each alone and neither validate; both is rejected (RFC 0082 §A)', () => {
|
|
78
|
-
expect(agentRef({ agentId: 'core.x.y.z', version: '1.0.0' }),
|
|
79
|
-
expect(agentRef({ agentId: 'core.x.y.z', channel: 'stable' }),
|
|
80
|
-
expect(agentRef({ agentId: 'core.x.y.z' }),
|
|
81
|
-
expect(agentRef({ agentId: 'core.x.y.z', version: '1.0.0', channel: 'stable' }),
|
|
76
|
+
expect(agentRef({ agentId: 'core.x.y.z', version: '1.0.0' }), req('openwop.it.agent-deployment-shape.agentref-channel-xor-version-each-alone-and-neither-validate-both-is-rejected-rf', 'RFC 0082 §A', 'version-only AgentRef MUST validate')).toBe(true);
|
|
77
|
+
expect(agentRef({ agentId: 'core.x.y.z', channel: 'stable' }), req('openwop.it.agent-deployment-shape.agentref-channel-xor-version-each-alone-and-neither-validate-both-is-rejected-rf', 'RFC 0082 §A', 'channel-only AgentRef MUST validate')).toBe(true);
|
|
78
|
+
expect(agentRef({ agentId: 'core.x.y.z' }), req('openwop.it.agent-deployment-shape.agentref-channel-xor-version-each-alone-and-neither-validate-both-is-rejected-rf', 'RFC 0082 §A', 'a ref with neither version nor channel MUST validate (host default)')).toBe(true);
|
|
79
|
+
expect(agentRef({ agentId: 'core.x.y.z', version: '1.0.0', channel: 'stable' }), req('openwop.it.agent-deployment-shape.agentref-channel-xor-version-each-alone-and-neither-validate-both-is-rejected-rf', 'RFC 0082 §A', 'a ref with BOTH version and channel MUST be rejected')).toBe(false);
|
|
82
80
|
});
|
|
83
81
|
});
|
|
84
82
|
|
|
@@ -94,29 +92,29 @@ describe('agent-deployment-shape: deployment.* event payloads (RFC 0082, server-
|
|
|
94
92
|
const stateChanged = ajv.getSchema('payloads#/$defs/deploymentStateChanged');
|
|
95
93
|
|
|
96
94
|
it('deployment.promoted validates a content-free promotion record and requires toVersion + toState', () => {
|
|
97
|
-
expect(promoted, 'the deploymentPromoted $def MUST exist').toBeTruthy();
|
|
95
|
+
expect(promoted, req('openwop.it.agent-deployment-shape.deployment-promoted-validates-a-content-free-promotion-record-and-requires-tover', 'RFC 0082', 'the deploymentPromoted $def MUST exist')).toBeTruthy();
|
|
98
96
|
expect(
|
|
99
97
|
promoted!({ agentId: 'core.openwop.agents.support-resolver', toVersion: '2.4.0', toState: 'active', channel: 'stable', canaryPercent: 10, evalRunId: 'run_abc' }),
|
|
100
|
-
|
|
98
|
+
req('openwop.it.agent-deployment-shape.deployment-promoted-validates-a-content-free-promotion-record-and-requires-tover', 'RFC 0082 §D', 'a conforming deployment.promoted payload MUST validate'),
|
|
101
99
|
).toBe(true);
|
|
102
|
-
expect(promoted!({ agentId: 'a' }),
|
|
100
|
+
expect(promoted!({ agentId: 'a' }), req('openwop.it.agent-deployment-shape.deployment-promoted-validates-a-content-free-promotion-record-and-requires-tover', 'RFC 0082 §D', 'deployment.promoted without toVersion/toState MUST be rejected')).toBe(false);
|
|
103
101
|
});
|
|
104
102
|
|
|
105
103
|
it('deployment.rolled-back / canary.adjusted / state.changed validate conforming records', () => {
|
|
106
|
-
expect(rolledBack!({ agentId: 'a', fromVersion: '2.4.0', toVersion: '2.3.1', rollbackPointer: '2.3.1' }),
|
|
107
|
-
expect(canary!({ agentId: 'a', version: '2.4.0', fromPercent: 10, toPercent: 50 }),
|
|
108
|
-
expect(stateChanged!({ agentId: 'a', version: '2.4.0', fromState: 'active', toState: 'paused' }),
|
|
109
|
-
expect(stateChanged!({ agentId: 'a', version: '2.4.0', fromState: 'active', toState: 'live' }),
|
|
104
|
+
expect(rolledBack!({ agentId: 'a', fromVersion: '2.4.0', toVersion: '2.3.1', rollbackPointer: '2.3.1' }), req('openwop.it.agent-deployment-shape.deployment-rolled-back-canary-adjusted-state-changed-validate-conforming-records', 'RFC 0082 §D', 'a conforming deployment.rolled-back MUST validate')).toBe(true);
|
|
105
|
+
expect(canary!({ agentId: 'a', version: '2.4.0', fromPercent: 10, toPercent: 50 }), req('openwop.it.agent-deployment-shape.deployment-rolled-back-canary-adjusted-state-changed-validate-conforming-records', 'RFC 0082 §D', 'a conforming deployment.canary.adjusted MUST validate')).toBe(true);
|
|
106
|
+
expect(stateChanged!({ agentId: 'a', version: '2.4.0', fromState: 'active', toState: 'paused' }), req('openwop.it.agent-deployment-shape.deployment-rolled-back-canary-adjusted-state-changed-validate-conforming-records', 'RFC 0082 §D', 'a conforming deployment.state.changed MUST validate')).toBe(true);
|
|
107
|
+
expect(stateChanged!({ agentId: 'a', version: '2.4.0', fromState: 'active', toState: 'live' }), req('openwop.it.agent-deployment-shape.deployment-rolled-back-canary-adjusted-state-changed-validate-conforming-records', 'RFC 0082 §D', 'an out-of-enum toState MUST be rejected')).toBe(false);
|
|
110
108
|
});
|
|
111
109
|
|
|
112
110
|
it('deployment.* events are content-free — a manifest body and a prompt are rejected (deployment-event-no-content-leak)', () => {
|
|
113
111
|
expect(
|
|
114
112
|
promoted!({ agentId: 'a', toVersion: '2.4.0', toState: 'active', manifestBody: '{...}' }),
|
|
115
|
-
|
|
113
|
+
req('openwop.it.agent-deployment-shape.deployment-events-are-content-free-a-manifest-body-and-a-prompt-are-rejected-dep', 'SECURITY invariant deployment-event-no-content-leak', 'a deployment.promoted MUST NOT carry a manifest body'),
|
|
116
114
|
).toBe(false);
|
|
117
115
|
expect(
|
|
118
116
|
stateChanged!({ agentId: 'a', version: '2.4.0', fromState: 'active', toState: 'paused', prompt: 'system: …' }),
|
|
119
|
-
|
|
117
|
+
req('openwop.it.agent-deployment-shape.deployment-events-are-content-free-a-manifest-body-and-a-prompt-are-rejected-dep', 'SECURITY invariant deployment-event-no-content-leak', 'a deployment.state.changed MUST NOT carry prompt content'),
|
|
120
118
|
).toBe(false);
|
|
121
119
|
});
|
|
122
120
|
});
|
|
@@ -125,15 +123,15 @@ describe('agent-deployment-shape: §B recorded-fact pin + enum (RFC 0082, server
|
|
|
125
123
|
it('agent.invocation.started carries the additive recorded-fact resolvedAgentVersion / resolvedChannel', () => {
|
|
126
124
|
const payloads = loadSchema('run-event-payloads.schema.json');
|
|
127
125
|
const started = ((payloads.$defs as Record<string, { properties?: Record<string, unknown> }>).agentInvocationStarted)?.properties ?? {};
|
|
128
|
-
expect(started.resolvedAgentVersion,
|
|
129
|
-
expect(started.resolvedChannel,
|
|
126
|
+
expect(started.resolvedAgentVersion, req('openwop.it.agent-deployment-shape.agent-invocation-started-carries-the-additive-recorded-fact-resolvedagentversion', 'RFC 0082 §B', 'agent.invocation.started.resolvedAgentVersion MUST be declared (the channel pin)')).toBeDefined();
|
|
127
|
+
expect(started.resolvedChannel, req('openwop.it.agent-deployment-shape.agent-invocation-started-carries-the-additive-recorded-fact-resolvedagentversion', 'RFC 0082 §B', 'agent.invocation.started.resolvedChannel MUST be declared')).toBeDefined();
|
|
130
128
|
});
|
|
131
129
|
|
|
132
130
|
it('all four deployment event names appear in the RunEventType enum', () => {
|
|
133
131
|
const runEvent = loadSchema('run-event.schema.json');
|
|
134
132
|
const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
|
|
135
133
|
for (const e of ['deployment.promoted', 'deployment.rolled-back', 'deployment.canary.adjusted', 'deployment.state.changed']) {
|
|
136
|
-
expect(enumVals).toContain(e);
|
|
134
|
+
expect(enumVals, req('openwop.it.agent-deployment-shape.all-four-deployment-event-names-appear-in-the-runeventtype-enum', 'RFC 0082', 'all four deployment event names appear in the RunEventType enum')).toContain(e);
|
|
137
135
|
}
|
|
138
136
|
});
|
|
139
137
|
});
|
|
@@ -29,7 +29,6 @@ import { readFileSync } from 'node:fs';
|
|
|
29
29
|
import { join } from 'node:path';
|
|
30
30
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
31
31
|
import addFormats from 'ajv-formats';
|
|
32
|
-
import { driver } from '../lib/driver.js';
|
|
33
32
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
34
33
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
35
34
|
import {
|
|
@@ -39,6 +38,8 @@ import {
|
|
|
39
38
|
EVAL_CONTENT_FORBIDDEN,
|
|
40
39
|
} from '../lib/agentEval.js';
|
|
41
40
|
import { queryTestEvents, requireEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
|
|
41
|
+
import { req } from '../lib/requirement-ids.js';
|
|
42
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
42
43
|
|
|
43
44
|
function loadSchema(name: string): Record<string, unknown> {
|
|
44
45
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -48,7 +49,7 @@ function expectContentFree(payload: Record<string, unknown>, where: string): voi
|
|
|
48
49
|
for (const f of EVAL_CONTENT_FORBIDDEN) {
|
|
49
50
|
expect(
|
|
50
51
|
!(f in payload),
|
|
51
|
-
|
|
52
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'RFC 0081 §C (eval-summary-no-content-leak)', `${where} MUST be content-free (no ${f})`),
|
|
52
53
|
).toBe(true);
|
|
53
54
|
}
|
|
54
55
|
}
|
|
@@ -57,10 +58,10 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
57
58
|
it('emits eval.started → per-task eval.scored → eval.completed and serves a content-free EvalSummary', async () => {
|
|
58
59
|
const cap = await readEvalSuiteCap();
|
|
59
60
|
if (!behaviorGate('openwop-eval-run', cap?.supported === true)) return;
|
|
60
|
-
if (!(await isEventLogSeamAvailable())) return; // event-log seam absent — soft-skip
|
|
61
|
+
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
|
|
61
62
|
|
|
62
63
|
const run = await driveEvalRun({ modes: ['golden'] });
|
|
63
|
-
if (run === null) return; // eval-run seam unwired — soft-skip the whole behavioral suite
|
|
64
|
+
if (run === null) return softSkip('blocked', 'precondition not met — `run === null` returned early (eval-run seam unwired — soft-skip the whole behavioral suite) (seam, prior step, or fixture unavailable)'); // eval-run seam unwired — soft-skip the whole behavioral suite
|
|
64
65
|
|
|
65
66
|
// From here the host has ADVERTISED agents.evalSuite AND wired the eval-run
|
|
66
67
|
// seam — missing evidence is a FAILURE, not a soft-skip. A host claiming the
|
|
@@ -68,7 +69,7 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
68
69
|
// normative EvalSummary, or it is advertising a capability it doesn't deliver.
|
|
69
70
|
expect(
|
|
70
71
|
typeof run.runId === 'string' && run.runId.length > 0,
|
|
71
|
-
|
|
72
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §B', 'a wired eval-run seam MUST return the projected runId'),
|
|
72
73
|
).toBe(true);
|
|
73
74
|
const runId = run.runId as string;
|
|
74
75
|
|
|
@@ -87,15 +88,15 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
87
88
|
// ≥1 eval.scored — a wired eval run MUST emit the full sequence.
|
|
88
89
|
expect(
|
|
89
90
|
startedEvents.length === 1,
|
|
90
|
-
|
|
91
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'an eval run MUST emit exactly one eval.started'),
|
|
91
92
|
).toBe(true);
|
|
92
93
|
expect(
|
|
93
94
|
scoredEvents.length >= 1,
|
|
94
|
-
|
|
95
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'an eval run MUST emit at least one eval.scored'),
|
|
95
96
|
).toBe(true);
|
|
96
97
|
expect(
|
|
97
98
|
completedEvents.length === 1,
|
|
98
|
-
|
|
99
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'an eval run MUST emit exactly one eval.completed'),
|
|
99
100
|
).toBe(true);
|
|
100
101
|
const started = startedEvents[0]!;
|
|
101
102
|
const completed = completedEvents[0]!;
|
|
@@ -104,22 +105,22 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
104
105
|
for (const s of scoredEvents) {
|
|
105
106
|
expect(
|
|
106
107
|
started.sequence < s.sequence,
|
|
107
|
-
|
|
108
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'eval.started MUST precede every eval.scored'),
|
|
108
109
|
).toBe(true);
|
|
109
110
|
expect(
|
|
110
111
|
s.sequence < completed.sequence,
|
|
111
|
-
|
|
112
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'every eval.scored MUST precede eval.completed'),
|
|
112
113
|
).toBe(true);
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// One eval.scored per task (count == eval.completed.taskCount).
|
|
116
117
|
expect(
|
|
117
118
|
typeof completed.payload.taskCount === 'number',
|
|
118
|
-
|
|
119
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'run-event-payloads.schema.json#/$defs/evalCompleted', 'eval.completed MUST carry a numeric taskCount'),
|
|
119
120
|
).toBe(true);
|
|
120
121
|
expect(
|
|
121
122
|
scoredEvents.length === completed.payload.taskCount,
|
|
122
|
-
|
|
123
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'one eval.scored per task (count == eval.completed.taskCount)'),
|
|
123
124
|
).toBe(true);
|
|
124
125
|
|
|
125
126
|
// Content-free (§C / eval-summary-no-content-leak) + score ∈ 0..1, passed boolean.
|
|
@@ -129,11 +130,11 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
129
130
|
expectContentFree(s.payload, 'eval.scored');
|
|
130
131
|
expect(
|
|
131
132
|
typeof s.payload.score === 'number' && (s.payload.score as number) >= 0 && (s.payload.score as number) <= 1,
|
|
132
|
-
|
|
133
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'run-event-payloads.schema.json#/$defs/evalScored', 'eval.scored.score MUST be in 0..1'),
|
|
133
134
|
).toBe(true);
|
|
134
135
|
expect(
|
|
135
136
|
typeof s.payload.passed === 'boolean',
|
|
136
|
-
|
|
137
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'run-event-payloads.schema.json#/$defs/evalScored', 'eval.scored.passed MUST be a boolean'),
|
|
137
138
|
).toBe(true);
|
|
138
139
|
}
|
|
139
140
|
|
|
@@ -141,7 +142,7 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
141
142
|
const { status, summary } = await getEvalSummary(runId);
|
|
142
143
|
expect(
|
|
143
144
|
status === 200 && summary !== undefined,
|
|
144
|
-
|
|
145
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', `GET /v1/runs/{runId}/eval-summary MUST serve a 200 EvalSummary for a completed eval run (got ${status})`),
|
|
145
146
|
).toBe(true);
|
|
146
147
|
const sum = summary as Record<string, unknown>;
|
|
147
148
|
const ajv = new Ajv2020({ strict: false, allErrors: true });
|
|
@@ -149,7 +150,7 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
149
150
|
const validate = ajv.compile(loadSchema('eval-summary.schema.json'));
|
|
150
151
|
expect(
|
|
151
152
|
validate(sum),
|
|
152
|
-
|
|
153
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'eval-summary.schema.json', `EvalSummary MUST be schema-valid (${ajv.errorsText(validate.errors)})`),
|
|
153
154
|
).toBe(true);
|
|
154
155
|
|
|
155
156
|
const tasks = (sum.tasks as Array<Record<string, unknown>> | undefined) ?? [];
|
|
@@ -157,11 +158,11 @@ describe('agent-eval-run (RFC 0081 §B/§C)', () => {
|
|
|
157
158
|
const taskCount = sum.taskCount as number | undefined;
|
|
158
159
|
expect(
|
|
159
160
|
typeof passedCount === 'number' && typeof taskCount === 'number',
|
|
160
|
-
|
|
161
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'eval-summary.schema.json', 'EvalSummary MUST carry numeric passedCount + taskCount'),
|
|
161
162
|
).toBe(true);
|
|
162
163
|
expect(
|
|
163
164
|
(passedCount as number) <= (taskCount as number),
|
|
164
|
-
|
|
165
|
+
req('openwop.it.agent-eval-run.emits-eval-started-per-task-eval-scored-eval-completed-and-serves-a-content-free', 'agent-evaluation.md §C', 'EvalSummary.passedCount MUST NOT exceed taskCount'),
|
|
165
166
|
).toBe(true);
|
|
166
167
|
for (const t of tasks) {
|
|
167
168
|
expectContentFree(t, 'EvalSummary.tasks[]');
|
|
@@ -33,9 +33,7 @@ import { join } from 'node:path';
|
|
|
33
33
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
34
34
|
import addFormats from 'ajv-formats';
|
|
35
35
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
36
|
-
|
|
37
|
-
/** Server-free assertion-message helper (mirrors driver.describe's "spec — requirement" shape without requiring OPENWOP_BASE_URL). */
|
|
38
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
36
|
+
import { req } from '../lib/requirement-ids.js';
|
|
39
37
|
|
|
40
38
|
function loadSchema(name: string): Record<string, unknown> {
|
|
41
39
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -48,12 +46,12 @@ describe('agent-eval-suite-shape: capability advertisement (RFC 0081, server-fre
|
|
|
48
46
|
const evalSuite = agents?.properties?.evalSuite;
|
|
49
47
|
expect(
|
|
50
48
|
evalSuite,
|
|
51
|
-
|
|
49
|
+
req('openwop.it.agent-eval-suite-shape.the-capabilities-schema-declares-agents-evalsuite-with-its-sub-flags', 'capabilities.md §agents', 'agents.evalSuite MUST be declared'),
|
|
52
50
|
).toBeDefined();
|
|
53
51
|
for (const flag of ['supported', 'modes']) {
|
|
54
52
|
expect(
|
|
55
53
|
evalSuite?.properties?.[flag],
|
|
56
|
-
|
|
54
|
+
req('openwop.it.agent-eval-suite-shape.the-capabilities-schema-declares-agents-evalsuite-with-its-sub-flags', 'agent-evaluation.md §Capability advertisement', `agents.evalSuite.${flag} MUST be declared`),
|
|
57
55
|
).toBeDefined();
|
|
58
56
|
}
|
|
59
57
|
});
|
|
@@ -75,11 +73,11 @@ describe('agent-eval-suite-shape: AgentEvalSuite + EvalSummary schemas (RFC 0081
|
|
|
75
73
|
{ taskId: 'refund-window', input: { q: 'refund policy?' }, expected: { kind: 'golden', match: { strategy: 'contains', value: '30 days' } } },
|
|
76
74
|
],
|
|
77
75
|
};
|
|
78
|
-
expect(suite(good),
|
|
76
|
+
expect(suite(good), req('openwop.it.agent-eval-suite-shape.agentevalsuite-validates-a-conforming-suite-and-rejects-a-malformed-suiteid-out', 'RFC 0081 §A', 'a conforming AgentEvalSuite MUST validate')).toBe(true);
|
|
79
77
|
// Negative: suiteId must carry the `.evals.` infix.
|
|
80
|
-
expect(suite({ ...good, suiteId: 'core.openwop.support-resolver' }),
|
|
78
|
+
expect(suite({ ...good, suiteId: 'core.openwop.support-resolver' }), req('openwop.it.agent-eval-suite-shape.agentevalsuite-validates-a-conforming-suite-and-rejects-a-malformed-suiteid-out', 'RFC 0081 §A', 'a suiteId without the `.evals.` infix MUST be rejected')).toBe(false);
|
|
81
79
|
// Negative: passScore out of 0..1.
|
|
82
|
-
expect(suite({ ...good, thresholds: { passScore: 1.5 } }),
|
|
80
|
+
expect(suite({ ...good, thresholds: { passScore: 1.5 } }), req('openwop.it.agent-eval-suite-shape.agentevalsuite-validates-a-conforming-suite-and-rejects-a-malformed-suiteid-out', 'RFC 0081 §A', 'thresholds.passScore > 1 MUST be rejected')).toBe(false);
|
|
83
81
|
});
|
|
84
82
|
|
|
85
83
|
it('EvalSummary validates a conforming scorecard and rejects an out-of-range score', () => {
|
|
@@ -92,8 +90,8 @@ describe('agent-eval-suite-shape: AgentEvalSuite + EvalSummary schemas (RFC 0081
|
|
|
92
90
|
passedCount: 2,
|
|
93
91
|
tasks: [{ taskId: 'refund-window', score: 0.9, passed: true, safetyFindings: [{ kind: 'jailbreak', severity: 'low' }] }],
|
|
94
92
|
};
|
|
95
|
-
expect(summary(good),
|
|
96
|
-
expect(summary({ ...good, aggregateScore: 1.4 }),
|
|
93
|
+
expect(summary(good), req('openwop.it.agent-eval-suite-shape.evalsummary-validates-a-conforming-scorecard-and-rejects-an-out-of-range-score', 'RFC 0081 §C', 'a conforming EvalSummary MUST validate')).toBe(true);
|
|
94
|
+
expect(summary({ ...good, aggregateScore: 1.4 }), req('openwop.it.agent-eval-suite-shape.evalsummary-validates-a-conforming-scorecard-and-rejects-an-out-of-range-score', 'RFC 0081 §C', 'aggregateScore > 1 MUST be rejected')).toBe(false);
|
|
97
95
|
});
|
|
98
96
|
|
|
99
97
|
it('EvalSummary is content-free — a task-output body and a safety-finding excerpt are rejected (eval-summary-no-content-leak)', () => {
|
|
@@ -101,12 +99,12 @@ describe('agent-eval-suite-shape: AgentEvalSuite + EvalSummary schemas (RFC 0081
|
|
|
101
99
|
// Negative: a per-task entry carrying the output body.
|
|
102
100
|
expect(
|
|
103
101
|
summary({ ...base, tasks: [{ taskId: 't1', score: 0.5, passed: false, taskOutput: 'the model said …' }] }),
|
|
104
|
-
|
|
102
|
+
req('openwop.it.agent-eval-suite-shape.evalsummary-is-content-free-a-task-output-body-and-a-safety-finding-excerpt-are', 'SECURITY invariant eval-summary-no-content-leak', 'an EvalSummary task entry MUST NOT carry an output body'),
|
|
105
103
|
).toBe(false);
|
|
106
104
|
// Negative: a safety finding carrying excerpted content rather than a {kind, severity} descriptor.
|
|
107
105
|
expect(
|
|
108
106
|
summary({ ...base, tasks: [{ taskId: 't1', score: 0.5, passed: false, safetyFindings: [{ kind: 'pii-leak', severity: 'high', excerpt: 'SSN 123-45-6789' }] }] }),
|
|
109
|
-
|
|
107
|
+
req('openwop.it.agent-eval-suite-shape.evalsummary-is-content-free-a-task-output-body-and-a-safety-finding-excerpt-are', 'SECURITY invariant eval-summary-no-content-leak', 'a safetyFinding MUST NOT carry excerpted content'),
|
|
110
108
|
).toBe(false);
|
|
111
109
|
});
|
|
112
110
|
});
|
|
@@ -122,45 +120,45 @@ describe('agent-eval-suite-shape: eval event payloads (RFC 0081, server-free)',
|
|
|
122
120
|
const completed = ajv.getSchema('payloads#/$defs/evalCompleted');
|
|
123
121
|
|
|
124
122
|
it('eval.started validates a content-free start record and requires the suite provenance', () => {
|
|
125
|
-
expect(started, 'the evalStarted $def MUST exist').toBeTruthy();
|
|
123
|
+
expect(started, req('openwop.it.agent-eval-suite-shape.eval-started-validates-a-content-free-start-record-and-requires-the-suite-proven', 'RFC 0081', 'the evalStarted $def MUST exist')).toBeTruthy();
|
|
126
124
|
expect(
|
|
127
125
|
started!({ suiteId: 'core.openwop.evals.support-resolver', suiteVersion: '1.0.0', taskCount: 12, modes: ['golden'] }),
|
|
128
|
-
|
|
126
|
+
req('openwop.it.agent-eval-suite-shape.eval-started-validates-a-content-free-start-record-and-requires-the-suite-proven', 'RFC 0081 §C', 'a conforming eval.started payload MUST validate'),
|
|
129
127
|
).toBe(true);
|
|
130
128
|
expect(
|
|
131
129
|
started!({ suiteId: 'core.openwop.evals.x' }),
|
|
132
|
-
|
|
130
|
+
req('openwop.it.agent-eval-suite-shape.eval-started-validates-a-content-free-start-record-and-requires-the-suite-proven', 'RFC 0081 §C', 'eval.started without suiteVersion/taskCount/modes MUST be rejected'),
|
|
133
131
|
).toBe(false);
|
|
134
132
|
});
|
|
135
133
|
|
|
136
134
|
it('eval.scored validates a content-free per-task score and requires score + passed', () => {
|
|
137
|
-
expect(scored, 'the evalScored $def MUST exist').toBeTruthy();
|
|
135
|
+
expect(scored, req('openwop.it.agent-eval-suite-shape.eval-scored-validates-a-content-free-per-task-score-and-requires-score-passed', 'RFC 0081', 'the evalScored $def MUST exist')).toBeTruthy();
|
|
138
136
|
expect(
|
|
139
137
|
scored!({ taskId: 'refund-window', score: 0.9, passed: true, costUsd: 0.012 }),
|
|
140
|
-
|
|
138
|
+
req('openwop.it.agent-eval-suite-shape.eval-scored-validates-a-content-free-per-task-score-and-requires-score-passed', 'RFC 0081 §C', 'a conforming eval.scored payload MUST validate'),
|
|
141
139
|
).toBe(true);
|
|
142
140
|
expect(
|
|
143
141
|
scored!({ taskId: 'refund-window' }),
|
|
144
|
-
|
|
142
|
+
req('openwop.it.agent-eval-suite-shape.eval-scored-validates-a-content-free-per-task-score-and-requires-score-passed', 'RFC 0081 §C', 'eval.scored without score/passed MUST be rejected'),
|
|
145
143
|
).toBe(false);
|
|
146
144
|
});
|
|
147
145
|
|
|
148
146
|
it('eval.completed validates a content-free aggregate record', () => {
|
|
149
|
-
expect(completed, 'the evalCompleted $def MUST exist').toBeTruthy();
|
|
147
|
+
expect(completed, req('openwop.it.agent-eval-suite-shape.eval-completed-validates-a-content-free-aggregate-record', 'RFC 0081', 'the evalCompleted $def MUST exist')).toBeTruthy();
|
|
150
148
|
expect(
|
|
151
149
|
completed!({ aggregateScore: 0.86, passed: true, taskCount: 12, passedCount: 11, regressionVsBaseline: 0.04 }),
|
|
152
|
-
|
|
150
|
+
req('openwop.it.agent-eval-suite-shape.eval-completed-validates-a-content-free-aggregate-record', 'RFC 0081 §C', 'a conforming eval.completed payload MUST validate'),
|
|
153
151
|
).toBe(true);
|
|
154
152
|
expect(
|
|
155
153
|
completed!({ aggregateScore: 2 }),
|
|
156
|
-
|
|
154
|
+
req('openwop.it.agent-eval-suite-shape.eval-completed-validates-a-content-free-aggregate-record', 'RFC 0081 §C', 'eval.completed with an out-of-range aggregateScore MUST be rejected'),
|
|
157
155
|
).toBe(false);
|
|
158
156
|
});
|
|
159
157
|
|
|
160
158
|
it('all three eval event names appear in the RunEventType enum', () => {
|
|
161
159
|
const runEvent = loadSchema('run-event.schema.json');
|
|
162
160
|
const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
|
|
163
|
-
expect(enumVals).toContain('eval.started');
|
|
161
|
+
expect(enumVals, req('openwop.it.agent-eval-suite-shape.all-three-eval-event-names-appear-in-the-runeventtype-enum', 'RFC 0081', 'all three eval event names appear in the RunEventType enum')).toContain('eval.started');
|
|
164
162
|
expect(enumVals).toContain('eval.scored');
|
|
165
163
|
expect(enumVals).toContain('eval.completed');
|
|
166
164
|
});
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { describe, it, expect } from 'vitest';
|
|
23
|
-
import { driver } from '../lib/driver.js';
|
|
24
23
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
25
24
|
import { readLiveRuntimeCap, invokeLive } from '../lib/liveRuntime.js';
|
|
26
25
|
import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
27
28
|
|
|
28
29
|
const DISALLOWED_TOOL = 'conformance-disallowed-tool';
|
|
29
30
|
|
|
@@ -32,12 +33,12 @@ describe('agent-live-allowlist-enforced (RFC 0077 §F-1)', () => {
|
|
|
32
33
|
const cap = await readLiveRuntimeCap();
|
|
33
34
|
if (!behaviorGate('openwop-live-allowlist-enforced', cap?.supported === true)) return;
|
|
34
35
|
|
|
35
|
-
if (!(await isEventLogSeamAvailable())) return; // soft-skip
|
|
36
|
+
if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (soft-skip) (seam, prior step, or fixture unavailable)'); // soft-skip
|
|
36
37
|
const res = await invokeLive({ source: 'run-api', attemptTool: DISALLOWED_TOOL });
|
|
37
|
-
if (res === null || !res.runId) return; // seam/hook absent — soft-skip
|
|
38
|
+
if (res === null || !res.runId) return softSkip('blocked', 'precondition not met — `res === null || !res.runId` returned early (seam/hook absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam/hook absent — soft-skip
|
|
38
39
|
|
|
39
40
|
const q = await queryTestEvents(res.runId, { type: 'agent.toolCalled' });
|
|
40
|
-
if (!q.ok) return;
|
|
41
|
+
if (!q.ok) return softSkip('blocked', 'precondition not met — `!q.ok` returned early (seam, prior step, or fixture unavailable)');
|
|
41
42
|
|
|
42
43
|
const calledDisallowed = q.events.some((e) => {
|
|
43
44
|
const tool = e.payload.tool ?? e.payload.toolId ?? e.payload.name;
|
|
@@ -45,7 +46,7 @@ describe('agent-live-allowlist-enforced (RFC 0077 §F-1)', () => {
|
|
|
45
46
|
});
|
|
46
47
|
expect(
|
|
47
48
|
calledDisallowed === false,
|
|
48
|
-
|
|
49
|
+
req('openwop.it.agent-live-allowlist-enforced.does-not-call-a-tool-outside-the-agent-toolallowlist', 'RFC 0077 §F-1 / RFC 0002 §A14', 'a live invocation MUST NOT call a tool outside the agent toolAllowlist'),
|
|
49
50
|
).toBe(true);
|
|
50
51
|
|
|
51
52
|
await resetTestSeam();
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { describe, it, expect } from 'vitest';
|
|
24
|
-
import { driver } from '../lib/driver.js';
|
|
25
24
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
26
25
|
import { readLiveRuntimeCap, invokeLive } from '../lib/liveRuntime.js';
|
|
27
26
|
import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
|
|
27
|
+
import { req } from '../lib/requirement-ids.js';
|
|
28
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
28
29
|
|
|
29
30
|
const SOURCES = ['workflow-node', 'run-api', 'chat-mention'];
|
|
30
31
|
const OUTCOMES = ['completed', 'handed-off', 'escalated', 'refused', 'failed'];
|
|
@@ -35,21 +36,21 @@ describe('agent-live-invocation-bracket (RFC 0077 §E)', () => {
|
|
|
35
36
|
const cap = await readLiveRuntimeCap();
|
|
36
37
|
if (!behaviorGate('openwop-live-invocation-bracket', cap?.supported === true)) return;
|
|
37
38
|
|
|
38
|
-
if (!(await isEventLogSeamAvailable())) return; // event-log seam absent — soft-skip
|
|
39
|
+
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
|
|
39
40
|
const res = await invokeLive({ source: 'run-api' });
|
|
40
|
-
if (res === null || !res.runId) return; // live-invoke seam absent — soft-skip
|
|
41
|
+
if (res === null || !res.runId) return softSkip('blocked', 'precondition not met — `res === null || !res.runId` returned early (live-invoke seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // live-invoke seam absent — soft-skip
|
|
41
42
|
|
|
42
43
|
const q = await queryTestEvents(res.runId);
|
|
43
|
-
if (!q.ok) return;
|
|
44
|
+
if (!q.ok) return softSkip('blocked', 'precondition not met — `!q.ok` returned early (seam, prior step, or fixture unavailable)');
|
|
44
45
|
const events = q.events.slice().sort((a, b) => a.sequence - b.sequence);
|
|
45
46
|
|
|
46
47
|
const started = events.filter((e) => e.type === 'agent.invocation.started');
|
|
47
48
|
const completed = events.filter((e) => e.type === 'agent.invocation.completed');
|
|
48
49
|
expect(
|
|
49
50
|
started.length >= 1 && completed.length >= 1,
|
|
50
|
-
|
|
51
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'multi-agent-execution.md §"Live manifest dispatch"', 'a live invocation MUST emit agent.invocation.started + agent.invocation.completed'),
|
|
51
52
|
).toBe(true);
|
|
52
|
-
if (started.length === 0 || completed.length === 0) return;
|
|
53
|
+
if (started.length === 0 || completed.length === 0) return softSkip('blocked', 'precondition not met — `started.length === 0 || completed.length === 0` returned early (seam, prior step, or fixture unavailable)');
|
|
53
54
|
|
|
54
55
|
const start = started[0]!;
|
|
55
56
|
const end = completed[completed.length - 1]!;
|
|
@@ -58,11 +59,11 @@ describe('agent-live-invocation-bracket (RFC 0077 §E)', () => {
|
|
|
58
59
|
const agentScoped = events.filter((e) => AGENT_SCOPED(e.type));
|
|
59
60
|
expect(
|
|
60
61
|
agentScoped[0]?.type === 'agent.invocation.started',
|
|
61
|
-
|
|
62
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'RFC 0077 §E', 'agent.invocation.started MUST be the first agent-scoped event of the invocation'),
|
|
62
63
|
).toBe(true);
|
|
63
64
|
expect(
|
|
64
65
|
agentScoped[agentScoped.length - 1]?.type === 'agent.invocation.completed',
|
|
65
|
-
|
|
66
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'RFC 0077 §E', 'agent.invocation.completed MUST be the last agent-scoped event of the invocation'),
|
|
66
67
|
).toBe(true);
|
|
67
68
|
|
|
68
69
|
// Matching invocationId across the bracket.
|
|
@@ -70,17 +71,17 @@ describe('agent-live-invocation-bracket (RFC 0077 §E)', () => {
|
|
|
70
71
|
const endId = end.payload.invocationId;
|
|
71
72
|
expect(
|
|
72
73
|
typeof startId === 'string' && startId === endId,
|
|
73
|
-
|
|
74
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'run-event-payloads.schema.json#agentInvocation*', 'the bracket MUST share one invocationId'),
|
|
74
75
|
).toBe(true);
|
|
75
76
|
|
|
76
77
|
// Enum discipline.
|
|
77
78
|
expect(
|
|
78
79
|
typeof start.payload.source === 'string' && SOURCES.includes(start.payload.source as string),
|
|
79
|
-
|
|
80
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'run-event-payloads.schema.json#agentInvocationStarted', 'source MUST be workflow-node|run-api|chat-mention'),
|
|
80
81
|
).toBe(true);
|
|
81
82
|
expect(
|
|
82
83
|
typeof end.payload.outcome === 'string' && OUTCOMES.includes(end.payload.outcome as string),
|
|
83
|
-
|
|
84
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'run-event-payloads.schema.json#agentInvocationCompleted', 'outcome MUST be in the closed enum'),
|
|
84
85
|
).toBe(true);
|
|
85
86
|
|
|
86
87
|
// Content-free: identifiers + metadata only, never prompt/result body.
|
|
@@ -88,7 +89,7 @@ describe('agent-live-invocation-bracket (RFC 0077 §E)', () => {
|
|
|
88
89
|
for (const forbidden of ['prompt', 'result', 'body', 'input', 'output', 'apiKey', 'secret', 'credentials', 'token']) {
|
|
89
90
|
expect(
|
|
90
91
|
!(forbidden in evt.payload),
|
|
91
|
-
|
|
92
|
+
req('openwop.it.agent-live-invocation-bracket.brackets-a-live-invocation-with-started-first-completed-last-matching-invocation', 'RFC 0077', `agent.invocation.* MUST be content-free (no ${forbidden})`),
|
|
92
93
|
).toBe(true);
|
|
93
94
|
}
|
|
94
95
|
}
|
|
@@ -28,9 +28,7 @@ import { join } from 'node:path';
|
|
|
28
28
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
29
29
|
import addFormats from 'ajv-formats';
|
|
30
30
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
31
|
-
|
|
32
|
-
/** Server-free assertion-message helper (mirrors driver.describe's "spec — requirement" shape without requiring OPENWOP_BASE_URL). */
|
|
33
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
32
|
|
|
35
33
|
function loadSchema(name: string): Record<string, unknown> {
|
|
36
34
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -43,12 +41,12 @@ describe('agent-live-runtime-shape: capability advertisement (RFC 0077, server-f
|
|
|
43
41
|
const live = agents?.properties?.liveRuntime;
|
|
44
42
|
expect(
|
|
45
43
|
live,
|
|
46
|
-
|
|
44
|
+
req('openwop.it.agent-live-runtime-shape.the-capabilities-schema-declares-agents-liveruntime-with-its-sub-flags', 'capabilities.md §agents', 'agents.liveRuntime MUST be declared'),
|
|
47
45
|
).toBeDefined();
|
|
48
46
|
for (const flag of ['supported', 'structuredOutput', 'confidenceEscalation', 'sources']) {
|
|
49
47
|
expect(
|
|
50
48
|
live?.properties?.[flag],
|
|
51
|
-
|
|
49
|
+
req('openwop.it.agent-live-runtime-shape.the-capabilities-schema-declares-agents-liveruntime-with-its-sub-flags', 'multi-agent-execution.md §Live manifest dispatch', `agents.liveRuntime.${flag} MUST be declared`),
|
|
52
50
|
).toBeDefined();
|
|
53
51
|
}
|
|
54
52
|
});
|
|
@@ -64,35 +62,35 @@ describe('agent-live-runtime-shape: invocation event payloads (RFC 0077, server-
|
|
|
64
62
|
const completed = ajv.getSchema('payloads#/$defs/agentInvocationCompleted');
|
|
65
63
|
|
|
66
64
|
it('agent.invocation.started validates a content-free start record and requires source', () => {
|
|
67
|
-
expect(started, 'the agentInvocationStarted $def MUST exist').toBeTruthy();
|
|
65
|
+
expect(started, req('openwop.it.agent-live-runtime-shape.agent-invocation-started-validates-a-content-free-start-record-and-requires-sour', 'RFC 0077', 'the agentInvocationStarted $def MUST exist')).toBeTruthy();
|
|
68
66
|
expect(
|
|
69
67
|
started!({ invocationId: 'inv-1', agentId: 'vendor.acme.review.code-reviewer', source: 'run-api', modelClass: 'coding', toolSurfaceCount: 3, memoryBound: false }),
|
|
70
|
-
|
|
68
|
+
req('openwop.it.agent-live-runtime-shape.agent-invocation-started-validates-a-content-free-start-record-and-requires-sour', 'RFC 0077 §C', 'a conforming agent.invocation.started payload MUST validate'),
|
|
71
69
|
).toBe(true);
|
|
72
70
|
// Negative: missing source — every invocation must record its entry point.
|
|
73
71
|
expect(
|
|
74
72
|
started!({ invocationId: 'inv-1', agentId: 'vendor.acme.review.code-reviewer' }),
|
|
75
|
-
|
|
73
|
+
req('openwop.it.agent-live-runtime-shape.agent-invocation-started-validates-a-content-free-start-record-and-requires-sour', 'RFC 0077 §C', 'agent.invocation.started without source MUST be rejected'),
|
|
76
74
|
).toBe(false);
|
|
77
75
|
});
|
|
78
76
|
|
|
79
77
|
it('agent.invocation.completed validates a content-free outcome record and pins the outcome enum', () => {
|
|
80
|
-
expect(completed, 'the agentInvocationCompleted $def MUST exist').toBeTruthy();
|
|
78
|
+
expect(completed, req('openwop.it.agent-live-runtime-shape.agent-invocation-completed-validates-a-content-free-outcome-record-and-pins-the', 'RFC 0077', 'the agentInvocationCompleted $def MUST exist')).toBeTruthy();
|
|
81
79
|
expect(
|
|
82
80
|
completed!({ invocationId: 'inv-1', agentId: 'vendor.acme.review.code-reviewer', outcome: 'completed', schemaValidated: true, confidence: 0.91 }),
|
|
83
|
-
|
|
81
|
+
req('openwop.it.agent-live-runtime-shape.agent-invocation-completed-validates-a-content-free-outcome-record-and-pins-the', 'RFC 0077 §C', 'a conforming agent.invocation.completed payload MUST validate'),
|
|
84
82
|
).toBe(true);
|
|
85
83
|
// Negative: out-of-enum outcome — the canonical value is `completed`, not `done`.
|
|
86
84
|
expect(
|
|
87
85
|
completed!({ invocationId: 'inv-1', agentId: 'a', outcome: 'done' }),
|
|
88
|
-
|
|
86
|
+
req('openwop.it.agent-live-runtime-shape.agent-invocation-completed-validates-a-content-free-outcome-record-and-pins-the', 'RFC 0077 §C', 'agent.invocation.completed with an out-of-enum outcome MUST be rejected'),
|
|
89
87
|
).toBe(false);
|
|
90
88
|
});
|
|
91
89
|
|
|
92
90
|
it('both invocation event names appear in the RunEventType enum', () => {
|
|
93
91
|
const runEvent = loadSchema('run-event.schema.json');
|
|
94
92
|
const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
|
|
95
|
-
expect(enumVals).toContain('agent.invocation.started');
|
|
93
|
+
expect(enumVals, req('openwop.it.agent-live-runtime-shape.both-invocation-event-names-appear-in-the-runeventtype-enum', 'RFC 0077', 'both invocation event names appear in the RunEventType enum')).toContain('agent.invocation.started');
|
|
96
94
|
expect(enumVals).toContain('agent.invocation.completed');
|
|
97
95
|
});
|
|
98
96
|
});
|