@openwop/openwop-conformance 1.162.0 → 2.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/cli.js +54 -1
- package/dist/lib/paths.js +25 -3
- package/dist/lib/requirement-ids.js +34 -4
- package/dist/lib/scenario-disposition.js +1 -0
- package/dist/lib/spec-coherence.js +13 -32
- package/dist/spec-artifacts.lock.json +5 -0
- package/package.json +11 -33
- package/requirements.json +20303 -11809
- package/scenario-majors.json +1343 -0
- package/schemas/CORPUS-STAMP.json +138 -6
- package/src/cli.ts +47 -1
- package/src/global-setup.ts +3 -2
- package/src/lib/corpus-stamp.ts +29 -1
- package/src/lib/paths.ts +25 -3
- package/src/lib/requirement-ids.ts +33 -4
- package/src/lib/scenario-disposition.ts +1 -0
- package/src/lib/spec-coherence.ts +15 -32
- package/src/scenarios/a2a-1-0-agent-card.test.ts +17 -16
- package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +11 -10
- package/src/scenarios/a2a-card-runtime-consistency.test.ts +18 -17
- package/src/scenarios/a2a-peer-authority.test.ts +7 -6
- package/src/scenarios/a2a-task-roundtrip.test.ts +30 -29
- package/src/scenarios/a2a-version-negotiation.test.ts +16 -14
- package/src/scenarios/a2ui-surface-degrades.test.ts +5 -3
- package/src/scenarios/a2ui-surface-delta-transport.test.ts +35 -33
- package/src/scenarios/a2ui-surface-replay.test.ts +6 -4
- package/src/scenarios/a2ui-surface-shape.test.ts +11 -10
- package/src/scenarios/a2ui-surface-version-refusal.test.ts +6 -4
- package/src/scenarios/a2ui-untrusted-blocks-approval.test.ts +5 -3
- package/src/scenarios/agent-capability-degraded-projection.test.ts +12 -11
- package/src/scenarios/agent-channel-dispatch.test.ts +18 -16
- package/src/scenarios/agent-deployment-lifecycle.test.ts +20 -19
- package/src/scenarios/agent-deployment-shape.test.ts +22 -24
- package/src/scenarios/agent-eval-run.test.ts +19 -18
- package/src/scenarios/agent-eval-suite-shape.test.ts +20 -22
- package/src/scenarios/agent-live-allowlist-enforced.test.ts +6 -5
- package/src/scenarios/agent-live-invocation-bracket.test.ts +13 -12
- package/src/scenarios/agent-live-runtime-shape.test.ts +10 -12
- package/src/scenarios/agent-live-structured-output.test.ts +7 -6
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -3
- package/src/scenarios/agent-loop-stateful-resume.test.ts +2 -2
- package/src/scenarios/agent-loop-version5-shape.test.ts +4 -4
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +3 -3
- package/src/scenarios/agent-manifest-role-profile.test.ts +9 -9
- package/src/scenarios/agent-manifest-runtime.test.ts +13 -12
- package/src/scenarios/agent-org-chart-scoping.test.ts +14 -13
- package/src/scenarios/agent-org-chart-shape.test.ts +11 -13
- package/src/scenarios/agent-platform-aggregate-evidence.test.ts +5 -4
- package/src/scenarios/agent-platform-profile.test.ts +18 -19
- package/src/scenarios/agent-requires-capabilities-shape.test.ts +4 -4
- package/src/scenarios/agent-roster-attribution.test.ts +18 -17
- package/src/scenarios/agent-roster-shape.test.ts +17 -19
- package/src/scenarios/agent-verifier-shape.test.ts +11 -11
- package/src/scenarios/agentConfidenceEscalation.test.ts +2 -1
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +6 -5
- package/src/scenarios/agentMemoryRedactionContract.test.ts +2 -1
- package/src/scenarios/agentMemoryRoundTrip.test.ts +2 -1
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +4 -3
- package/src/scenarios/agentMessageReducer.test.ts +2 -1
- package/src/scenarios/agentMetadata.test.ts +2 -1
- package/src/scenarios/agentPackCatalog.test.ts +23 -21
- package/src/scenarios/agentPackExport.test.ts +4 -2
- package/src/scenarios/agentPackHandoffSchemaValidation.test.ts +5 -4
- package/src/scenarios/agentPackInstall.test.ts +4 -2
- package/src/scenarios/agentPackProvenance.test.ts +2 -1
- package/src/scenarios/agentReasoningEvents.test.ts +3 -2
- package/src/scenarios/agentReasoningStreaming.test.ts +11 -10
- package/src/scenarios/agents-run-tool-allowlist.test.ts +14 -12
- package/src/scenarios/ai-envelope-shape.test.ts +31 -29
- package/src/scenarios/aiEnvelope.capBreached.test.ts +26 -24
- package/src/scenarios/aiEnvelope.contractRefusal.test.ts +36 -34
- package/src/scenarios/aiEnvelope.correlationReplay.test.ts +17 -15
- package/src/scenarios/aiEnvelope.redaction.test.ts +22 -20
- package/src/scenarios/aiEnvelope.schemaDrift.test.ts +18 -16
- package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +38 -36
- package/src/scenarios/aiEnvelope.universalKinds.test.ts +31 -29
- package/src/scenarios/aiproviders-input-shape.test.ts +5 -5
- package/src/scenarios/aiproviders-realtimevoice-shape.test.ts +14 -16
- package/src/scenarios/aiproviders-selfhosted-honesty.test.ts +6 -4
- package/src/scenarios/aiproviders-selfhosted-shape.test.ts +15 -17
- package/src/scenarios/aiproviders-speechsynth-shape.test.ts +6 -8
- package/src/scenarios/aiproviders-subscription-scope.test.ts +7 -8
- package/src/scenarios/anonymous-actor-audit-opaque.test.ts +9 -8
- package/src/scenarios/anonymous-actor-default-deny.test.ts +10 -9
- package/src/scenarios/anonymous-actor-egress-guarded.test.ts +6 -5
- package/src/scenarios/anonymous-actor-no-secret-reach.test.ts +7 -6
- package/src/scenarios/anonymous-actor-shape.test.ts +17 -19
- package/src/scenarios/anonymous-actor-write-gated.test.ts +9 -8
- package/src/scenarios/append-ordering.test.ts +7 -5
- package/src/scenarios/approval-gate-events.test.ts +4 -3
- package/src/scenarios/approval-gate-flow.test.ts +4 -3
- package/src/scenarios/approval-payload.test.ts +5 -4
- package/src/scenarios/artifact-auth.test.ts +7 -6
- package/src/scenarios/artifact-type-pack-install.test.ts +6 -6
- package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/artifact-type-registration-source.test.ts +20 -20
- package/src/scenarios/artifact-type-store-emission.test.ts +15 -18
- package/src/scenarios/artifact-type-store-without-render.test.ts +4 -4
- package/src/scenarios/audit-log-integrity.test.ts +8 -6
- package/src/scenarios/auth-api-key-rotation.test.ts +11 -9
- package/src/scenarios/auth-mtls.test.ts +22 -20
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +16 -14
- package/src/scenarios/auth-oidc-user-bearer.test.ts +26 -24
- package/src/scenarios/auth-saml-profile.test.ts +14 -12
- package/src/scenarios/auth-scim-profile.test.ts +3 -2
- package/src/scenarios/auth-subject-link-key-class.test.ts +8 -7
- package/src/scenarios/auth-subject-link.test.ts +11 -10
- package/src/scenarios/auth.test.ts +5 -4
- package/src/scenarios/authorization-fail-closed.test.ts +3 -2
- package/src/scenarios/authorization-roles-shape.test.ts +9 -7
- package/src/scenarios/blob-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/blob-presign-expiry.test.ts +12 -10
- package/src/scenarios/blob-roundtrip.test.ts +0 -0
- package/src/scenarios/budget-enforcement.test.ts +15 -14
- package/src/scenarios/budget-policy-shape.test.ts +18 -19
- package/src/scenarios/bulk-cancel.test.ts +9 -8
- package/src/scenarios/byok-auth-modes.test.ts +13 -14
- package/src/scenarios/byok-roundtrip.test.ts +12 -10
- package/src/scenarios/cache-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/cache-ttl-expiry.test.ts +7 -5
- package/src/scenarios/callai-multimodal.test.ts +5 -3
- package/src/scenarios/cancellation.test.ts +6 -5
- package/src/scenarios/cap-breach.test.ts +15 -14
- package/src/scenarios/capability-arm-witness.test.ts +5 -3
- package/src/scenarios/certification-bundle-non-vacuous.test.ts +20 -19
- package/src/scenarios/certification-bundle-redaction.test.ts +11 -10
- package/src/scenarios/certification-bundle-v2.test.ts +11 -10
- package/src/scenarios/chain-compensation-expansion.test.ts +14 -13
- package/src/scenarios/chain-produced-var-roundtrip.test.ts +13 -14
- package/src/scenarios/chain-subchain-cycle-rejected.test.ts +9 -10
- package/src/scenarios/chain-subchain-fanout.test.ts +8 -9
- package/src/scenarios/chain-subchain-sibling.test.ts +14 -16
- package/src/scenarios/channel-presence-behavioral.test.ts +9 -7
- package/src/scenarios/channel-presence-shape.test.ts +11 -12
- package/src/scenarios/channel-ttl.test.ts +6 -5
- package/src/scenarios/chat-card-pack-execution.test.ts +4 -4
- package/src/scenarios/chat-card-pack-manifest-validation.test.ts +9 -8
- package/src/scenarios/commitment-fired.test.ts +6 -5
- package/src/scenarios/compensation-behavior.test.ts +24 -23
- package/src/scenarios/compensation-recovery.test.ts +28 -27
- package/src/scenarios/configurable-schema.test.ts +8 -6
- package/src/scenarios/conformance-advertised-seam-required.test.ts +6 -5
- package/src/scenarios/conformance-execution-witness.test.ts +9 -8
- package/src/scenarios/connection-pack-apihosts.test.ts +19 -17
- package/src/scenarios/connection-pack-manifest-valid.test.ts +12 -11
- package/src/scenarios/connection-pack-no-credential-material.test.ts +8 -6
- package/src/scenarios/connection-pack-reach-exclusive.test.ts +5 -4
- package/src/scenarios/connection-pack-write-reconsent.test.ts +6 -4
- package/src/scenarios/connection-provider-resolution.test.ts +18 -16
- package/src/scenarios/connector-manifest-validity.test.ts +8 -7
- package/src/scenarios/context-budget-transcript-bound.test.ts +17 -15
- package/src/scenarios/context-summarization-replay.test.ts +14 -12
- package/src/scenarios/contract-provenance.test.ts +18 -18
- package/src/scenarios/conversation-turn-model-provenance-shape.test.ts +14 -15
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +2 -1
- package/src/scenarios/conversationLifecycle.test.ts +2 -1
- package/src/scenarios/conversationReplayDeterminism.test.ts +4 -2
- package/src/scenarios/conversationVsLegacySuspend.test.ts +2 -1
- package/src/scenarios/core-standard-profile.test.ts +8 -9
- package/src/scenarios/cost-attribution.test.ts +23 -21
- package/src/scenarios/credential-payload-redaction.test.ts +4 -3
- package/src/scenarios/credentials-capability-shape.test.ts +5 -4
- package/src/scenarios/cross-engine-append-behavior.test.ts +11 -10
- package/src/scenarios/cross-engine-append-ordering.test.ts +4 -3
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +11 -10
- package/src/scenarios/cross-host-causation-shape.test.ts +7 -6
- package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
- package/src/scenarios/data-residency-admission.test.ts +15 -14
- package/src/scenarios/deadletter-capability-shape.test.ts +6 -4
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +4 -3
- package/src/scenarios/debug-bundle-truncation.test.ts +9 -7
- package/src/scenarios/debugBundle.test.ts +25 -23
- package/src/scenarios/discovery-families-view.test.ts +5 -4
- package/src/scenarios/discovery.test.ts +30 -29
- package/src/scenarios/dispatch-cross-worker-handoff.test.ts +10 -8
- package/src/scenarios/dispatch-fanout-parallel.test.ts +24 -22
- package/src/scenarios/dispatch-input-mapping.test.ts +12 -10
- package/src/scenarios/dispatch-output-mapping.test.ts +9 -7
- package/src/scenarios/dispatch-per-item-input.test.ts +22 -20
- package/src/scenarios/dispatchLoop.test.ts +3 -2
- package/src/scenarios/distillation-index-roundtrip.test.ts +3 -3
- package/src/scenarios/distillation-secret-carryforward.test.ts +2 -2
- package/src/scenarios/distillation-shape.test.ts +4 -4
- package/src/scenarios/distillation-stable-archive.test.ts +6 -6
- package/src/scenarios/distillation-token-budget.test.ts +5 -5
- package/src/scenarios/durability-poison-exhaustion.test.ts +7 -6
- package/src/scenarios/egress-audience-binding.test.ts +11 -10
- package/src/scenarios/egress-decision-content-free.test.ts +6 -5
- package/src/scenarios/egress-provenance-shape.test.ts +17 -18
- package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +27 -25
- package/src/scenarios/envelope-nl-to-format-engaged.test.ts +19 -17
- package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +28 -26
- package/src/scenarios/envelope-reasoning-shape.test.ts +19 -17
- package/src/scenarios/envelope-recovery-applied.test.ts +24 -22
- package/src/scenarios/envelope-refusal-shape.test.ts +31 -29
- package/src/scenarios/envelope-rendering-hint.test.ts +5 -4
- package/src/scenarios/envelope-retry-attempted.test.ts +33 -31
- package/src/scenarios/envelope-retry-exhausted.test.ts +22 -20
- package/src/scenarios/envelope-tier-one-subset-static.test.ts +9 -7
- package/src/scenarios/envelope-truncated.test.ts +19 -17
- package/src/scenarios/envelope-truncation-cap-exhaustion.test.ts +19 -17
- package/src/scenarios/envelope-variant-discriminator-static.test.ts +4 -3
- package/src/scenarios/errors.test.ts +20 -19
- package/src/scenarios/eventOrdering.test.ts +16 -14
- package/src/scenarios/exec-not-protocol-tier.test.ts +5 -7
- package/src/scenarios/experimental-tier-shape.test.ts +17 -15
- package/src/scenarios/export-bundle-portability.test.ts +17 -17
- package/src/scenarios/failure-path.test.ts +7 -6
- package/src/scenarios/feedback-capability-shape.test.ts +4 -3
- package/src/scenarios/feedback-correction-redaction.test.ts +2 -1
- package/src/scenarios/feedback-cross-tenant-isolation.test.ts +2 -1
- package/src/scenarios/feedback-fork-not-copied.test.ts +3 -2
- package/src/scenarios/feedback-on-terminal-run.test.ts +3 -2
- package/src/scenarios/feedback-record-and-list.test.ts +2 -1
- package/src/scenarios/feedback-unsupported-501.test.ts +2 -1
- package/src/scenarios/fixtures-gating.test.ts +29 -28
- package/src/scenarios/fixtures-valid.test.ts +16 -15
- package/src/scenarios/form-content-instantiation.test.ts +15 -14
- package/src/scenarios/frontend-plugin-packs.test.ts +29 -27
- package/src/scenarios/fs-path-traversal.test.ts +14 -12
- package/src/scenarios/goal-standing-continuation.test.ts +21 -21
- package/src/scenarios/grpc-transport.test.ts +9 -7
- package/src/scenarios/heartbeat-capability-shape.test.ts +3 -3
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +2 -2
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +3 -3
- package/src/scenarios/heartbeat-runtime-bound.test.ts +2 -2
- package/src/scenarios/highConcurrency.test.ts +14 -13
- package/src/scenarios/host-callback-declaration.test.ts +8 -7
- package/src/scenarios/http-client-ssrf.test.ts +7 -5
- package/src/scenarios/i18n-negotiation.test.ts +14 -12
- package/src/scenarios/idempotency-concurrent-claim.test.ts +14 -13
- package/src/scenarios/idempotency-key-determinism.test.ts +20 -18
- package/src/scenarios/idempotency.test.ts +8 -7
- package/src/scenarios/idempotencyRetry.test.ts +13 -11
- package/src/scenarios/identity-owner-shape.test.ts +6 -5
- package/src/scenarios/identity-passthrough.test.ts +4 -3
- package/src/scenarios/interrupt-approval.test.ts +6 -5
- package/src/scenarios/interrupt-approver-routing.test.ts +15 -15
- package/src/scenarios/interrupt-auth-required-resume.test.ts +5 -3
- package/src/scenarios/interrupt-clarification.test.ts +4 -3
- package/src/scenarios/interrupt-external-event-correlation.test.ts +6 -5
- package/src/scenarios/interrupt-parent-child-cascade.test.ts +4 -3
- package/src/scenarios/interrupt-quorum-resolution.test.ts +5 -4
- package/src/scenarios/interrupt-token-matrix.test.ts +8 -6
- package/src/scenarios/interruptRace.test.ts +12 -10
- package/src/scenarios/kv-atomic-increment.test.ts +11 -9
- package/src/scenarios/kv-cas.test.ts +14 -12
- package/src/scenarios/kv-cross-tenant-isolation.test.ts +12 -10
- package/src/scenarios/kv-ttl-expiry.test.ts +7 -5
- package/src/scenarios/localized-content-delivery.test.ts +24 -26
- package/src/scenarios/maliciousManifest.test.ts +10 -8
- package/src/scenarios/mcp-2026-07-28-discover.test.ts +15 -14
- package/src/scenarios/mcp-cache-tenant-scope.test.ts +6 -5
- package/src/scenarios/mcp-current-auth-boundary.test.ts +7 -6
- package/src/scenarios/mcp-discoverability.test.ts +9 -7
- package/src/scenarios/mcp-extension-opacity.test.ts +7 -6
- package/src/scenarios/mcp-mrtr-roundtrip.test.ts +18 -17
- package/src/scenarios/mcp-server-elicitation-bridge.test.ts +13 -12
- package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-resource-roundtrip.test.ts +11 -10
- package/src/scenarios/mcp-server-sampling-bridge.test.ts +12 -11
- package/src/scenarios/mcp-server-tool-roundtrip.test.ts +14 -13
- package/src/scenarios/mcp-server-untrusted-args.test.ts +14 -13
- package/src/scenarios/mcp-stateless-request.test.ts +11 -10
- package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
- package/src/scenarios/mcp-toolcall-redaction.test.ts +4 -3
- package/src/scenarios/mcp-version-negotiation.test.ts +15 -14
- package/src/scenarios/media-url-inline-cap.test.ts +21 -19
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +5 -5
- package/src/scenarios/memory-attribution-no-content.test.ts +4 -4
- package/src/scenarios/memory-attribution-replay-stable.test.ts +4 -3
- package/src/scenarios/memory-attribution-shape.test.ts +4 -3
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +3 -3
- package/src/scenarios/memory-capability-model-shape.test.ts +14 -15
- package/src/scenarios/memory-compaction-event-emitted.test.ts +7 -6
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +3 -2
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +7 -6
- package/src/scenarios/memory-consolidation-idempotent.test.ts +5 -4
- package/src/scenarios/memory-consolidation-shape.test.ts +9 -11
- package/src/scenarios/memory-degraded-projection.test.ts +10 -9
- package/src/scenarios/memory-injection-budget.test.ts +15 -14
- package/src/scenarios/metric-emission.test.ts +4 -3
- package/src/scenarios/model-capability-insufficient.test.ts +19 -17
- package/src/scenarios/model-capability-substituted.test.ts +20 -18
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +12 -11
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +10 -9
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +11 -10
- package/src/scenarios/multi-node-ordering.test.ts +4 -3
- package/src/scenarios/multi-party-conversation-behavioral.test.ts +6 -6
- package/src/scenarios/multi-party-conversation-shape.test.ts +21 -23
- package/src/scenarios/multi-region-idempotency-behavior.test.ts +16 -15
- package/src/scenarios/multi-region-idempotency.test.ts +6 -5
- package/src/scenarios/node-failed-payload-shape.test.ts +5 -4
- package/src/scenarios/node-module-required-capabilities-shape.test.ts +10 -8
- package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +5 -4
- package/src/scenarios/oauth-capability-shape.test.ts +5 -4
- package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
- package/src/scenarios/openapi-resolved-paths.test.ts +6 -5
- package/src/scenarios/orchestratorConservativePath.test.ts +2 -1
- package/src/scenarios/orchestratorDispatch.test.ts +2 -1
- package/src/scenarios/orchestratorTermination.test.ts +2 -1
- package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -2
- package/src/scenarios/otel-collector-canary-inspection.test.ts +8 -7
- package/src/scenarios/otel-emission-grpc.test.ts +3 -2
- package/src/scenarios/otel-emission.test.ts +6 -5
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +7 -6
- package/src/scenarios/otel-trace-propagation.test.ts +2 -1
- package/src/scenarios/owner-subject-echo.test.ts +13 -12
- package/src/scenarios/owner-subject-shape.test.ts +11 -10
- package/src/scenarios/pack-manifest-extension-opacity.test.ts +8 -8
- package/src/scenarios/pack-registry-isolation.test.ts +4 -3
- package/src/scenarios/pack-registry-publish.test.ts +65 -63
- package/src/scenarios/pack-registry.test.ts +38 -36
- package/src/scenarios/pause-resume.test.ts +18 -16
- package/src/scenarios/policies.test.ts +20 -18
- package/src/scenarios/production-backpressure.test.ts +18 -16
- package/src/scenarios/production-retention-expiry.test.ts +8 -6
- package/src/scenarios/profile-discovery-core-alias.test.ts +13 -11
- package/src/scenarios/profileDerivation.test.ts +34 -33
- package/src/scenarios/prompt-all-four-kinds-events.test.ts +11 -9
- package/src/scenarios/prompt-composed-secret-redaction.test.ts +11 -9
- package/src/scenarios/prompt-composed-trust-marker.test.ts +10 -8
- package/src/scenarios/prompt-end-to-end-events.test.ts +17 -15
- package/src/scenarios/prompt-list-and-fetch.test.ts +16 -14
- package/src/scenarios/prompt-mutable-lifecycle.test.ts +13 -11
- package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +6 -4
- package/src/scenarios/prompt-pack-install.test.ts +14 -12
- package/src/scenarios/prompt-prefix-cache.test.ts +19 -17
- package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +11 -9
- package/src/scenarios/prompt-render-deterministic.test.ts +19 -17
- package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +7 -5
- package/src/scenarios/prompt-resolution-chain-event.test.ts +12 -10
- package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +10 -8
- package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +8 -6
- package/src/scenarios/prompt-template-shape.test.ts +30 -28
- package/src/scenarios/proposal-reviewable-learning.test.ts +19 -19
- package/src/scenarios/protocol-versions-array.test.ts +10 -9
- package/src/scenarios/provider-usage.test.ts +17 -15
- package/src/scenarios/providerPolicyEnforcement.test.ts +16 -14
- package/src/scenarios/purpose-propagation.test.ts +23 -21
- package/src/scenarios/queue-ack-nack-dlq.test.ts +12 -10
- package/src/scenarios/queue-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/queue-publish-consume-roundtrip.test.ts +10 -8
- package/src/scenarios/rate-limit-envelope.test.ts +6 -5
- package/src/scenarios/redaction.test.ts +13 -11
- package/src/scenarios/redactionAdversarial.test.ts +11 -9
- package/src/scenarios/registry-public.test.ts +12 -11
- package/src/scenarios/replay-divergence-at-refusal.test.ts +16 -15
- package/src/scenarios/replay-fanout-suppression.test.ts +16 -15
- package/src/scenarios/replay-fork-arbitrary.test.ts +24 -23
- package/src/scenarios/replay-fork.test.ts +20 -19
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +11 -9
- package/src/scenarios/replay-llm-cache-key.test.ts +22 -21
- package/src/scenarios/replay-observable-sequence-determinism.test.ts +4 -3
- package/src/scenarios/replay-retention-expiry.test.ts +11 -9
- package/src/scenarios/replay-side-effect-suppression.test.ts +21 -19
- package/src/scenarios/replayDeterminism.test.ts +13 -12
- package/src/scenarios/requirement-ledger.test.ts +15 -14
- package/src/scenarios/restart-during-run.test.ts +3 -2
- package/src/scenarios/route-coverage.test.ts +20 -19
- package/src/scenarios/run-diff.test.ts +22 -20
- package/src/scenarios/run-execution-bounds-shape.test.ts +14 -12
- package/src/scenarios/run-transport-economy.test.ts +13 -11
- package/src/scenarios/runner-ledger.test.ts +17 -16
- package/src/scenarios/runs-lifecycle.test.ts +7 -6
- package/src/scenarios/runtime-capabilities.test.ts +12 -10
- package/src/scenarios/runtime-requires-install-gate.test.ts +8 -8
- package/src/scenarios/runtime-requires-shape.test.ts +7 -6
- package/src/scenarios/safefetch-behavior.test.ts +22 -21
- package/src/scenarios/safefetch-live-audit.test.ts +14 -13
- package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
- package/src/scenarios/sandbox-mvp-behavior.test.ts +24 -23
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +3 -2
- package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
- package/src/scenarios/sandbox-wasm-isolation.test.ts +14 -15
- package/src/scenarios/sandbox-wasm-timeout.test.ts +5 -6
- package/src/scenarios/scheduling-capability-shape.test.ts +8 -6
- package/src/scenarios/scheduling-cron-fires-once.test.ts +8 -6
- package/src/scenarios/search-bm25-roundtrip.test.ts +8 -6
- package/src/scenarios/secret-leakage-otel-attribute.test.ts +22 -20
- package/src/scenarios/self-hosted-runner.test.ts +26 -24
- package/src/scenarios/semantic-digest-vectors.test.ts +8 -7
- package/src/scenarios/speech-synthesis-roundtrip.test.ts +9 -7
- package/src/scenarios/speech-synthesis-unadvertised.test.ts +5 -3
- package/src/scenarios/sql-injection-rejection.test.ts +8 -6
- package/src/scenarios/sql-transaction-atomicity.test.ts +10 -8
- package/src/scenarios/staleClaim.test.ts +5 -4
- package/src/scenarios/stream-modes-buffer.test.ts +8 -7
- package/src/scenarios/stream-modes-mixed.test.ts +10 -9
- package/src/scenarios/stream-modes.test.ts +12 -11
- package/src/scenarios/stream-subscribe-from-beginning.test.ts +11 -9
- package/src/scenarios/stream-text-fixture.test.ts +14 -13
- package/src/scenarios/streamReconnect.test.ts +13 -11
- package/src/scenarios/strict-behavior-gate.test.ts +9 -8
- package/src/scenarios/subrun-approval-fail-closed.test.ts +2 -2
- package/src/scenarios/subrun-approval-gate.test.ts +3 -3
- package/src/scenarios/subrun-attestation-shape.test.ts +2 -2
- package/src/scenarios/subrun-checksum-stable.test.ts +4 -4
- package/src/scenarios/subworkflow-input-mapping.test.ts +16 -14
- package/src/scenarios/subworkflow.test.ts +10 -9
- package/src/scenarios/table-cross-tenant-isolation.test.ts +8 -6
- package/src/scenarios/table-cursor-pagination.test.ts +8 -6
- package/src/scenarios/table-schema-enforcement.test.ts +7 -5
- package/src/scenarios/test-seam-unauthenticated.test.ts +2 -2
- package/src/scenarios/tool-catalog-compact-projection.test.ts +10 -8
- package/src/scenarios/tool-catalog-projection.test.ts +11 -9
- package/src/scenarios/tool-descriptor-shape.test.ts +14 -15
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -3
- package/src/scenarios/tool-hooks-content-free.test.ts +4 -4
- package/src/scenarios/tool-hooks-failure-honesty.test.ts +4 -4
- package/src/scenarios/tool-hooks-rate-limit.test.ts +2 -2
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +2 -2
- package/src/scenarios/tool-hooks-shape.test.ts +3 -3
- package/src/scenarios/tool-session-lifecycle.test.ts +14 -13
- package/src/scenarios/trigger-bridge-delivery.test.ts +14 -14
- package/src/scenarios/trigger-bridge-shape.test.ts +19 -20
- package/src/scenarios/trigger-ingestion.test.ts +19 -17
- package/src/scenarios/trigger-stream-cdc-sources.test.ts +16 -14
- package/src/scenarios/vector-knn-roundtrip.test.ts +9 -7
- package/src/scenarios/verifier-gating.test.ts +8 -6
- package/src/scenarios/version-fold.test.ts +9 -8
- package/src/scenarios/version-negotiation.test.ts +12 -11
- package/src/scenarios/voice-bargein-no-partial-leak.test.ts +8 -6
- package/src/scenarios/voice-event-payloads-shape.test.ts +10 -11
- package/src/scenarios/voice-interim-not-durable.test.ts +7 -5
- package/src/scenarios/voice-streamref-tenant-bound.test.ts +5 -3
- package/src/scenarios/voice-synthesis-streaming.test.ts +11 -9
- package/src/scenarios/voice-transcription-streaming.test.ts +8 -6
- package/src/scenarios/voice-transcription-unadvertised.test.ts +5 -3
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
- package/src/scenarios/wasm-pack-load.test.ts +4 -3
- package/src/scenarios/wasm-pack-memory-cap.test.ts +5 -4
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -1
- package/src/scenarios/webhook-negative.test.ts +11 -9
- package/src/scenarios/webhook-receiver-adversarial.test.ts +8 -7
- package/src/scenarios/webhook-sig-algorithm.test.ts +5 -3
- package/src/scenarios/webhook-signed-delivery.test.ts +16 -15
- package/src/scenarios/webhook-tenant-isolation.test.ts +16 -14
- package/src/scenarios/workflow-chain-deferred-parameters.test.ts +28 -30
- package/src/scenarios/workflow-chain-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-host-expansion.test.ts +21 -20
- package/src/scenarios/workflow-chain-pack-manifest-validation.test.ts +14 -12
- package/src/scenarios/workflow-chain-pack-signature-verification.test.ts +5 -4
- package/src/scenarios/workflow-chain-unresolvable-typeid.test.ts +9 -8
- package/src/scenarios/workflow-primary-output-annotation.test.ts +7 -6
- package/src/scenarios/workflow-variable-format.test.ts +24 -24
- package/src/scenarios/workload-identity-behavior.test.ts +15 -13
- package/src/scenarios/workload-identity-chain-bounds.test.ts +18 -17
- package/src/scenarios/workspace-behavior.test.ts +19 -18
- package/src/scenarios/workspace-capability-shape.test.ts +3 -2
- package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +6 -5
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +7 -6
- package/src/scenarios/x-openwop-form-pack-manifest.test.ts +8 -7
- package/src/setup.ts +4 -2
- package/vitest.config.ts +5 -1
- package/api/.redocly.lint-ignore.yaml +0 -22
- package/api/asyncapi.yaml +0 -834
- package/api/grpc/openwop.proto +0 -251
- package/api/openapi.yaml +0 -2693
- package/api/redocly.yaml +0 -23
- package/schemas/README.md +0 -144
- package/schemas/a2a-task-state.schema.json +0 -78
- package/schemas/a2ui-surface-delta-frame.schema.json +0 -48
- package/schemas/agent-deployment-transition.schema.json +0 -49
- package/schemas/agent-deployment.schema.json +0 -54
- package/schemas/agent-eval-suite.schema.json +0 -140
- package/schemas/agent-inventory-response.schema.json +0 -115
- package/schemas/agent-manifest.schema.json +0 -156
- package/schemas/agent-org-chart.schema.json +0 -82
- package/schemas/agent-ref.schema.json +0 -63
- package/schemas/agent-roster-entry.schema.json +0 -81
- package/schemas/agent-roster-response.schema.json +0 -21
- package/schemas/ai-envelope.schema.json +0 -134
- package/schemas/annotation-create.schema.json +0 -37
- package/schemas/annotation.schema.json +0 -56
- package/schemas/artifact-type-pack-manifest.schema.json +0 -244
- package/schemas/audit-verify-result.schema.json +0 -90
- package/schemas/budget-policy.schema.json +0 -18
- package/schemas/capabilities.schema.json +0 -4124
- package/schemas/certification-bundle-v2.schema.json +0 -118
- package/schemas/channel-presence-payload.schema.json +0 -41
- package/schemas/channel-written-payload.schema.json +0 -55
- package/schemas/chat-card-pack-manifest.schema.json +0 -253
- package/schemas/compact-tool-descriptor.schema.json +0 -51
- package/schemas/compensation-policy.schema.json +0 -64
- package/schemas/conformance-certification-bundle.schema.json +0 -86
- package/schemas/connection-pack-manifest.schema.json +0 -353
- package/schemas/conversation-event.schema.json +0 -168
- package/schemas/conversation-turn.schema.json +0 -117
- package/schemas/core-conformance-mock-agent-config.schema.json +0 -152
- package/schemas/credential-provenance.schema.json +0 -18
- package/schemas/credential-reference.schema.json +0 -21
- package/schemas/debug-bundle.schema.json +0 -196
- package/schemas/dispatch-config.schema.json +0 -112
- package/schemas/envelopes/clarification.request.schema.json +0 -52
- package/schemas/envelopes/error.schema.json +0 -30
- package/schemas/envelopes/media.audio.schema.json +0 -38
- package/schemas/envelopes/media.file.schema.json +0 -37
- package/schemas/envelopes/media.image.schema.json +0 -33
- package/schemas/envelopes/schema.request.schema.json +0 -26
- package/schemas/envelopes/schema.response.schema.json +0 -22
- package/schemas/envelopes/ui.a2ui-surface.schema.json +0 -154
- package/schemas/error-envelope.schema.json +0 -25
- package/schemas/eval-summary.schema.json +0 -92
- package/schemas/export-bundle.schema.json +0 -66
- package/schemas/form-content-pack-manifest.schema.json +0 -243
- package/schemas/frontend-plugin-manifest.schema.json +0 -109
- package/schemas/goal.schema.json +0 -104
- package/schemas/heartbeat-evaluated.schema.json +0 -14
- package/schemas/heartbeat-state-changed.schema.json +0 -14
- package/schemas/localized-content-language-settings.schema.json +0 -26
- package/schemas/localized-content-page-response.schema.json +0 -60
- package/schemas/localized-content-page.schema.json +0 -62
- package/schemas/localized-content-section.schema.json +0 -51
- package/schemas/memory-entry.schema.json +0 -36
- package/schemas/memory-list-options.schema.json +0 -37
- package/schemas/node-pack-manifest.schema.json +0 -654
- package/schemas/orchestrator-decision.schema.json +0 -90
- package/schemas/org-chart-responsibility-view.schema.json +0 -26
- package/schemas/pack-lockfile.schema.json +0 -108
- package/schemas/prompt-kind.schema.json +0 -8
- package/schemas/prompt-pack-manifest.schema.json +0 -117
- package/schemas/prompt-ref.schema.json +0 -40
- package/schemas/prompt-template.schema.json +0 -149
- package/schemas/proposal.schema.json +0 -84
- package/schemas/registry-version-manifest.schema.json +0 -208
- package/schemas/residency.schema.json +0 -16
- package/schemas/run-ancestry-response.schema.json +0 -54
- package/schemas/run-diff-response.schema.json +0 -64
- package/schemas/run-event-payloads.schema.json +0 -4452
- package/schemas/run-event.schema.json +0 -211
- package/schemas/run-options.schema.json +0 -80
- package/schemas/run-orchestrator-decided-event.schema.json +0 -20
- package/schemas/run-snapshot.schema.json +0 -148
- package/schemas/security-advisory.schema.json +0 -109
- package/schemas/self-hosted-runner-dispatch-frame.schema.json +0 -79
- package/schemas/self-hosted-runner-registration.schema.json +0 -53
- package/schemas/self-hosted-runner-result-frame.schema.json +0 -38
- package/schemas/subject.schema.json +0 -56
- package/schemas/suspend-request.schema.json +0 -207
- package/schemas/tool-descriptor.schema.json +0 -63
- package/schemas/trigger-event.schema.json +0 -222
- package/schemas/trigger-subscription-registration.schema.json +0 -67
- package/schemas/trigger-subscription.schema.json +0 -26
- package/schemas/ui-plugin-message.schema.json +0 -90
- package/schemas/workflow-chain-pack-manifest.schema.json +0 -615
- package/schemas/workflow-definition.schema.json +0 -850
- package/schemas/workload-identity.schema.json +0 -79
- package/schemas/workspace-file-create.schema.json +0 -20
- package/schemas/workspace-file.schema.json +0 -39
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
isReasoningStreamingSupported,
|
|
30
30
|
getReasoningVerbosity,
|
|
31
31
|
} from '../lib/multi-agent-capabilities.js';
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
33
|
|
|
33
34
|
const FIXTURE = 'conformance-agent-reasoning-streaming';
|
|
34
35
|
/** Expected concatenation of the fixture's `streamChunks` — kept in sync
|
|
@@ -64,14 +65,14 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
64
65
|
|
|
65
66
|
expect(
|
|
66
67
|
deltas.length,
|
|
67
|
-
|
|
68
|
+
req('openwop.it.agentReasoningStreaming.emits-n-agent-reasoning-delta-events-followed-by-exactly-one-closing-agent-reaso',
|
|
68
69
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
69
70
|
'streaming host MUST emit one agent.reasoning.delta per streamChunks entry',
|
|
70
71
|
),
|
|
71
72
|
).toBe(EXPECTED_CHUNKS.length);
|
|
72
73
|
expect(
|
|
73
74
|
finals.length,
|
|
74
|
-
|
|
75
|
+
req('openwop.it.agentReasoningStreaming.emits-n-agent-reasoning-delta-events-followed-by-exactly-one-closing-agent-reaso',
|
|
75
76
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
76
77
|
'streaming host MUST emit exactly one closing agent.reasoned event after the deltas',
|
|
77
78
|
),
|
|
@@ -95,7 +96,7 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
95
96
|
|
|
96
97
|
expect(
|
|
97
98
|
sequences,
|
|
98
|
-
|
|
99
|
+
req('openwop.it.agentReasoningStreaming.agent-reasoning-delta-sequence-starts-at-0-and-increments-by-1-within-the-block',
|
|
99
100
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
100
101
|
'`sequence` MUST start at 0 and increment by 1 per delta within a block',
|
|
101
102
|
),
|
|
@@ -113,15 +114,15 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
113
114
|
const list = (events.json as { events: Array<{ type: string; payload?: Record<string, unknown> }> }).events;
|
|
114
115
|
|
|
115
116
|
const finalEvent = list.find((e) => e.type === 'agent.reasoned');
|
|
116
|
-
expect(finalEvent, 'closing agent.reasoned must be present').toBeDefined();
|
|
117
|
+
expect(finalEvent, req('openwop.it.agentReasoningStreaming.closing-agent-reasoned-reasoning-is-the-concatenation-of-the-deltas-authoritativ', 'RFCS/0024-agent-reasoning-streaming.md §Proposal', 'closing agent.reasoned must be present')).toBeDefined();
|
|
117
118
|
const reasoning = finalEvent?.payload?.reasoning;
|
|
118
|
-
expect(typeof reasoning, 'closing event MUST carry a reasoning string').toBe('string');
|
|
119
|
+
expect(typeof reasoning, req('openwop.it.agentReasoningStreaming.closing-agent-reasoned-reasoning-is-the-concatenation-of-the-deltas-authoritativ', 'RFCS/0024-agent-reasoning-streaming.md §Proposal', 'closing event MUST carry a reasoning string')).toBe('string');
|
|
119
120
|
// The mock-agent's contract: closing reasoning equals concat(streamChunks).
|
|
120
121
|
// Real hosts MAY transform at finalize (summary truncation, redaction);
|
|
121
122
|
// for the mock-agent fixture, no transform applies — exact equality.
|
|
122
123
|
expect(
|
|
123
124
|
reasoning,
|
|
124
|
-
|
|
125
|
+
req('openwop.it.agentReasoningStreaming.closing-agent-reasoned-reasoning-is-the-concatenation-of-the-deltas-authoritativ',
|
|
125
126
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
126
127
|
'closing agent.reasoned.reasoning is authoritative; for the mock-agent fixture, equals delta concatenation',
|
|
127
128
|
),
|
|
@@ -149,7 +150,7 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
149
150
|
|
|
150
151
|
expect(
|
|
151
152
|
agentIds.size,
|
|
152
|
-
|
|
153
|
+
req('openwop.it.agentReasoningStreaming.agentid-is-consistent-across-all-streaming-closing-events-in-a-block',
|
|
153
154
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
154
155
|
'agentId MUST be consistent across all `agent.reasoning.delta` events AND the closing `agent.reasoned` for a given block',
|
|
155
156
|
),
|
|
@@ -168,7 +169,7 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
168
169
|
const arr = Array.isArray(list) ? list : list.events;
|
|
169
170
|
|
|
170
171
|
const closingIdx = arr.findIndex((e) => e.type === 'agent.reasoned');
|
|
171
|
-
expect(closingIdx, 'closing event present').toBeGreaterThan(-1);
|
|
172
|
+
expect(closingIdx, req('openwop.it.agentReasoningStreaming.all-agent-reasoning-delta-events-arrive-before-the-closing-agent-reasoned', 'RFCS/0024-agent-reasoning-streaming.md §Proposal', 'closing event present')).toBeGreaterThan(-1);
|
|
172
173
|
const lastDeltaIdx = arr.map((e) => e.type).lastIndexOf('agent.reasoning.delta');
|
|
173
174
|
|
|
174
175
|
// Guard against vacuous pass: a host advertising streaming but
|
|
@@ -177,14 +178,14 @@ describe.skipIf(SKIP)('agentReasoningStreaming: RFC 0024 incremental + closing e
|
|
|
177
178
|
// one delta MUST appear in the event log.
|
|
178
179
|
expect(
|
|
179
180
|
lastDeltaIdx,
|
|
180
|
-
|
|
181
|
+
req('openwop.it.agentReasoningStreaming.all-agent-reasoning-delta-events-arrive-before-the-closing-agent-reasoned',
|
|
181
182
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
182
183
|
'streaming host MUST emit at least one `agent.reasoning.delta` for a fixture with non-empty `streamChunks`',
|
|
183
184
|
),
|
|
184
185
|
).toBeGreaterThan(-1);
|
|
185
186
|
expect(
|
|
186
187
|
lastDeltaIdx,
|
|
187
|
-
|
|
188
|
+
req('openwop.it.agentReasoningStreaming.all-agent-reasoning-delta-events-arrive-before-the-closing-agent-reasoned',
|
|
188
189
|
'RFCS/0024-agent-reasoning-streaming.md §Proposal',
|
|
189
190
|
'every `agent.reasoning.delta` MUST precede the closing `agent.reasoned` for the same block',
|
|
190
191
|
),
|
|
@@ -36,6 +36,8 @@ import { describe, it, expect, beforeAll } from 'vitest';
|
|
|
36
36
|
import { existsSync } from 'node:fs';
|
|
37
37
|
import { dirname, resolve } from 'node:path';
|
|
38
38
|
import { fileURLToPath } from 'node:url';
|
|
39
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
39
41
|
|
|
40
42
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
41
43
|
const PACK_PATH = resolve(__dirname, '../../../packs/core.openwop.agents/index.mjs');
|
|
@@ -83,14 +85,14 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
83
85
|
it('skips cleanly when pack source is not bundled', () => {
|
|
84
86
|
if (!packAvailable) {
|
|
85
87
|
console.warn('[agents-run-tool-allowlist] pack source not present; skipping');
|
|
86
|
-
expect(packAvailable).toBe(false);
|
|
87
|
-
return;
|
|
88
|
+
expect(packAvailable, req('openwop.it.agents-run-tool-allowlist.skips-cleanly-when-pack-source-is-not-bundled', 'threat-model-prompt-injection.md', 'skips cleanly when pack source is not bundled')).toBe(false);
|
|
89
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early ([agents-run-tool-allowlist] pack source not present; skipping)');
|
|
88
90
|
}
|
|
89
91
|
expect(packAvailable).toBe(true);
|
|
90
92
|
});
|
|
91
93
|
|
|
92
94
|
it('rejects function-typed tool.handler (the defect path)', async () => {
|
|
93
|
-
if (!packAvailable) return;
|
|
95
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
94
96
|
// The 1.0.0 defect: a workflow author could supply executable JS via
|
|
95
97
|
// tools[].handler and the pack would await it directly with ctx. Closed
|
|
96
98
|
// in 1.0.1 — the validator throws INVALID_TOOL_DECLARATION at the run
|
|
@@ -109,7 +111,7 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
109
111
|
});
|
|
110
112
|
|
|
111
113
|
it('rejects tool declaration missing a name', async () => {
|
|
112
|
-
if (!packAvailable) return;
|
|
114
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
113
115
|
await expectRejection(
|
|
114
116
|
() => agentRun({ config: {}, inputs: { userPrompt: 'x', tools: [{ kind: 'workflow' }] } }),
|
|
115
117
|
'INVALID_TOOL_DECLARATION',
|
|
@@ -118,7 +120,7 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
118
120
|
});
|
|
119
121
|
|
|
120
122
|
it('rejects tool declaration missing a kind discriminator', async () => {
|
|
121
|
-
if (!packAvailable) return;
|
|
123
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
122
124
|
await expectRejection(
|
|
123
125
|
() => agentRun({ config: {}, inputs: { userPrompt: 'x', tools: [{ name: 't1' }] } }),
|
|
124
126
|
'INVALID_TOOL_DECLARATION',
|
|
@@ -127,7 +129,7 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
127
129
|
});
|
|
128
130
|
|
|
129
131
|
it('rejects tool-driven runs when host does not provide agentRuntime', async () => {
|
|
130
|
-
if (!packAvailable) return;
|
|
132
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
131
133
|
// Tool dispatch MUST go through a host-resolved runtime — the 1.0.0
|
|
132
134
|
// inline-handler fallback is gone.
|
|
133
135
|
await expectRejection(
|
|
@@ -141,7 +143,7 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
141
143
|
});
|
|
142
144
|
|
|
143
145
|
it('tool-less run succeeds via callAIWithTools (safe fallback preserved)', async () => {
|
|
144
|
-
if (!packAvailable) return;
|
|
146
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
145
147
|
let toolsSeen: unknown = 'never-called';
|
|
146
148
|
const ctx: AgentRunCtx = {
|
|
147
149
|
config: {},
|
|
@@ -154,11 +156,11 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
154
156
|
const result = await agentRun(ctx);
|
|
155
157
|
expect(result.outputs.result).toBe('hello back');
|
|
156
158
|
expect(result.outputs.finishReason).toBe('complete');
|
|
157
|
-
expect(toolsSeen, 'tool-less fallback MUST pass an empty tools array — no LLM-driven dispatch').toEqual([]);
|
|
159
|
+
expect(toolsSeen, req('openwop.it.agents-run-tool-allowlist.tool-less-run-succeeds-via-callaiwithtools-safe-fallback-preserved', 'threat-model-prompt-injection.md', 'tool-less fallback MUST pass an empty tools array — no LLM-driven dispatch')).toEqual([]);
|
|
158
160
|
});
|
|
159
161
|
|
|
160
162
|
it('agentRuntime.run path threads through unchanged when host provides it', async () => {
|
|
161
|
-
if (!packAvailable) return;
|
|
163
|
+
if (!packAvailable) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!packAvailable` returned early');
|
|
162
164
|
let receivedTools: unknown;
|
|
163
165
|
const ctx: AgentRunCtx = {
|
|
164
166
|
config: {},
|
|
@@ -167,15 +169,15 @@ describe('category: core.openwop.agents.run — tool-allowlist enforcement (OPEN
|
|
|
167
169
|
tools: [{ name: 't1', kind: 'workflow', ref: 'vendor.acme.demo' }],
|
|
168
170
|
},
|
|
169
171
|
agentRuntime: {
|
|
170
|
-
run: async (
|
|
171
|
-
receivedTools = (
|
|
172
|
+
run: async (reqBody: unknown) => {
|
|
173
|
+
receivedTools = (reqBody as { tools?: unknown[] }).tools;
|
|
172
174
|
return { result: 'from-runtime', toolCalls: [{ name: 't1' }] };
|
|
173
175
|
},
|
|
174
176
|
},
|
|
175
177
|
};
|
|
176
178
|
const result = await agentRun(ctx);
|
|
177
179
|
expect(result.outputs.result).toBe('from-runtime');
|
|
178
|
-
expect(receivedTools, 'host MUST receive the validated tools array').toEqual([
|
|
180
|
+
expect(receivedTools, req('openwop.it.agents-run-tool-allowlist.agentruntime-run-path-threads-through-unchanged-when-host-provides-it', 'threat-model-prompt-injection.md', 'host MUST receive the validated tools array')).toEqual([
|
|
179
181
|
{ name: 't1', kind: 'workflow', ref: 'vendor.acme.demo' },
|
|
180
182
|
]);
|
|
181
183
|
});
|
|
@@ -25,6 +25,8 @@ import { join } from 'node:path';
|
|
|
25
25
|
import { driver } from '../lib/driver.js';
|
|
26
26
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
27
27
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
28
|
+
import { req } from '../lib/requirement-ids.js';
|
|
29
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
28
30
|
|
|
29
31
|
type DiscoveryDoc = Record<string, unknown>;
|
|
30
32
|
|
|
@@ -65,16 +67,16 @@ const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
|
65
67
|
describe.skipIf(HTTP_SKIP)('ai-envelope-shape: advertisement contract (RFC 0021 §C)', () => {
|
|
66
68
|
it('capabilities.supportedEnvelopes is an array of strings (when present)', async () => {
|
|
67
69
|
const d = await readDiscovery();
|
|
68
|
-
if (d === null) return;
|
|
70
|
+
if (d === null) return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
69
71
|
const env = supportedEnvelopes(d);
|
|
70
72
|
// No assertion if absent — the field is optional. When present, each entry MUST be a string.
|
|
71
73
|
for (const k of env) {
|
|
72
|
-
expect(typeof k,
|
|
74
|
+
expect(typeof k, req('openwop.it.ai-envelope-shape.capabilities-supportedenvelopes-is-an-array-of-strings-when-present', 'capabilities.md §supportedEnvelopes', 'each entry MUST be a string')).toBe('string');
|
|
73
75
|
}
|
|
74
76
|
// Re-affirm shape: array if present (root-first per RFC 0073).
|
|
75
77
|
const advertised = capabilityFamily<unknown>(d, 'supportedEnvelopes');
|
|
76
78
|
if (advertised !== undefined) {
|
|
77
|
-
expect(Array.isArray(advertised), 'supportedEnvelopes MUST be an array').toBe(true);
|
|
79
|
+
expect(Array.isArray(advertised), req('openwop.it.ai-envelope-shape.capabilities-supportedenvelopes-is-an-array-of-strings-when-present', 'capabilities.md §supportedEnvelopes', 'supportedEnvelopes MUST be an array')).toBe(true);
|
|
78
80
|
}
|
|
79
81
|
});
|
|
80
82
|
});
|
|
@@ -88,7 +90,7 @@ describe('ai-envelope-shape: schema compile (RFC 0021 §A + §B)', () => {
|
|
|
88
90
|
it('top-level ai-envelope.schema.json compiles under Ajv2020', () => {
|
|
89
91
|
const schema = load('ai-envelope.schema.json');
|
|
90
92
|
const validate = ajv.compile(schema);
|
|
91
|
-
expect(validate, 'RFC 0021 §A: ai-envelope.schema.json MUST compile').toBeTypeOf('function');
|
|
93
|
+
expect(validate, req('openwop.it.ai-envelope-shape.top-level-ai-envelope-schema-json-compiles-under-ajv2020', 'RFC 0021 §D', 'RFC 0021 §A: ai-envelope.schema.json MUST compile')).toBeTypeOf('function');
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
for (const kind of UNIVERSAL_KINDS) {
|
|
@@ -97,7 +99,7 @@ describe('ai-envelope-shape: schema compile (RFC 0021 §A + §B)', () => {
|
|
|
97
99
|
const validate = ajv.compile(schema);
|
|
98
100
|
expect(
|
|
99
101
|
validate,
|
|
100
|
-
`RFC 0021 §B: envelopes/${kind}.schema.json MUST compile
|
|
102
|
+
req('openwop.it.ai-envelope-shape.universal-kind-schema-envelopes-schema-json-compiles-under-ajv2020', 'RFC 0021 §D', `RFC 0021 §B: envelopes/${kind}.schema.json MUST compile`),
|
|
101
103
|
).toBeTypeOf('function');
|
|
102
104
|
});
|
|
103
105
|
}
|
|
@@ -124,7 +126,7 @@ describe('ai-envelope-shape: round-trip validation (RFC 0021 §A)', () => {
|
|
|
124
126
|
},
|
|
125
127
|
};
|
|
126
128
|
const ok = validate(positive);
|
|
127
|
-
expect(ok, `positive fixture MUST validate; errors: ${JSON.stringify(validate.errors)}`).toBe(true);
|
|
129
|
+
expect(ok, req('openwop.it.ai-envelope-shape.accepts-a-positive-aienvelope-fixture', 'RFC 0021 §D', `positive fixture MUST validate; errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
|
|
128
130
|
});
|
|
129
131
|
|
|
130
132
|
it('rejects a negative AIEnvelope fixture missing required `meta`', () => {
|
|
@@ -137,7 +139,7 @@ describe('ai-envelope-shape: round-trip validation (RFC 0021 §A)', () => {
|
|
|
137
139
|
// meta omitted on purpose
|
|
138
140
|
};
|
|
139
141
|
const ok = validate(negative);
|
|
140
|
-
expect(ok, 'RFC 0021 §A: envelope MUST require meta block').toBe(false);
|
|
142
|
+
expect(ok, req('openwop.it.ai-envelope-shape.rejects-a-negative-aienvelope-fixture-missing-required-meta', 'RFC 0021 §D', 'RFC 0021 §A: envelope MUST require meta block')).toBe(false);
|
|
141
143
|
});
|
|
142
144
|
|
|
143
145
|
it('rejects an envelope with unknown top-level property (additionalProperties:false)', () => {
|
|
@@ -151,7 +153,7 @@ describe('ai-envelope-shape: round-trip validation (RFC 0021 §A)', () => {
|
|
|
151
153
|
unknownTopLevel: 'should reject',
|
|
152
154
|
};
|
|
153
155
|
const ok = validate(negative);
|
|
154
|
-
expect(ok, 'RFC 0021 §A: top-level additionalProperties:false MUST reject unknown fields').toBe(false);
|
|
156
|
+
expect(ok, req('openwop.it.ai-envelope-shape.rejects-an-envelope-with-unknown-top-level-property-additionalproperties-false', 'RFC 0021 §D', 'RFC 0021 §A: top-level additionalProperties:false MUST reject unknown fields')).toBe(false);
|
|
155
157
|
});
|
|
156
158
|
});
|
|
157
159
|
|
|
@@ -167,12 +169,12 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
167
169
|
meta: { source: 'ai-generation', ts: '2026-05-18T10:00:00Z' },
|
|
168
170
|
},
|
|
169
171
|
});
|
|
170
|
-
if (res.status === 404) return; // host doesn't expose the seam
|
|
172
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (host doesn\'t expose the seam) (seam, prior step, or fixture unavailable)'); // host doesn't expose the seam
|
|
171
173
|
expect(res.status).toBe(200);
|
|
172
174
|
const body = res.json as { status?: string };
|
|
173
175
|
expect(
|
|
174
176
|
body.status,
|
|
175
|
-
|
|
177
|
+
req('openwop.it.ai-envelope-shape.valid-clarification-request-envelope-status-accepted', 'RFC 0021 §A point 1-3', 'valid envelope MUST be accepted'),
|
|
176
178
|
).toBe('accepted');
|
|
177
179
|
});
|
|
178
180
|
|
|
@@ -187,14 +189,14 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
187
189
|
// meta omitted
|
|
188
190
|
},
|
|
189
191
|
});
|
|
190
|
-
if (res.status === 404) return;
|
|
192
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
191
193
|
expect(res.status).toBe(200);
|
|
192
194
|
const body = res.json as { status?: string; details?: unknown[] };
|
|
193
195
|
expect(
|
|
194
196
|
body.status,
|
|
195
|
-
|
|
197
|
+
req('openwop.it.ai-envelope-shape.envelope-missing-required-meta-block-status-invalid', 'RFC 0021 §A point 1', 'envelope missing required field MUST be invalid'),
|
|
196
198
|
).toBe('invalid');
|
|
197
|
-
expect(Array.isArray(body.details), 'invalid outcome MUST carry validation details').toBe(true);
|
|
199
|
+
expect(Array.isArray(body.details), req('openwop.it.ai-envelope-shape.envelope-missing-required-meta-block-status-invalid', 'RFC 0021 §A point 1', 'invalid outcome MUST carry validation details')).toBe(true);
|
|
198
200
|
});
|
|
199
201
|
|
|
200
202
|
it('vendor-namespaced kind not in supportedEnvelopes → status: gated', async () => {
|
|
@@ -209,14 +211,14 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
209
211
|
},
|
|
210
212
|
hostSupportedEnvelopes: ['vendor.acme.prd.create'], // does not include the gated kind
|
|
211
213
|
});
|
|
212
|
-
if (res.status === 404) return;
|
|
214
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
213
215
|
expect(res.status).toBe(200);
|
|
214
216
|
const body = res.json as { status?: string; allowedKinds?: string[] };
|
|
215
217
|
expect(
|
|
216
218
|
body.status,
|
|
217
|
-
|
|
219
|
+
req('openwop.it.ai-envelope-shape.vendor-namespaced-kind-not-in-supportedenvelopes-status-gated', 'RFC 0021 §A point 2', 'unadvertised kind MUST be gated'),
|
|
218
220
|
).toBe('gated');
|
|
219
|
-
expect(Array.isArray(body.allowedKinds), 'gated outcome MUST list the allowed kinds').toBe(true);
|
|
221
|
+
expect(Array.isArray(body.allowedKinds), req('openwop.it.ai-envelope-shape.vendor-namespaced-kind-not-in-supportedenvelopes-status-gated', 'RFC 0021 §A point 2', 'gated outcome MUST list the allowed kinds')).toBe(true);
|
|
220
222
|
});
|
|
221
223
|
|
|
222
224
|
it('counter at cap → status: breached', async () => {
|
|
@@ -231,12 +233,12 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
231
233
|
},
|
|
232
234
|
counters: { envelopesPerTurn: { current: 32, cap: 32 } },
|
|
233
235
|
});
|
|
234
|
-
if (res.status === 404) return;
|
|
236
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
235
237
|
expect(res.status).toBe(200);
|
|
236
238
|
const body = res.json as { status?: string; capKind?: string };
|
|
237
239
|
expect(
|
|
238
240
|
body.status,
|
|
239
|
-
|
|
241
|
+
req('openwop.it.ai-envelope-shape.counter-at-cap-status-breached', 'RFC 0021 §"Universal kinds"', 'envelope at cap MUST be breached'),
|
|
240
242
|
).toBe('breached');
|
|
241
243
|
expect(body.capKind).toBe('envelopes');
|
|
242
244
|
});
|
|
@@ -255,13 +257,13 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
255
257
|
},
|
|
256
258
|
runTrustBoundary: 'untrusted',
|
|
257
259
|
});
|
|
258
|
-
if (res.status === 404) return;
|
|
260
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
259
261
|
expect(res.status).toBe(200);
|
|
260
262
|
const body = res.json as { status?: string; normalizedMeta?: { contentTrust?: string } };
|
|
261
263
|
expect(body.status).toBe('accepted');
|
|
262
264
|
expect(
|
|
263
265
|
body.normalizedMeta?.contentTrust,
|
|
264
|
-
|
|
266
|
+
req('openwop.it.ai-envelope-shape.accepted-outcome-carries-normalizedmeta-contenttrust-per-rfc-0021-a-point-6',
|
|
265
267
|
'RFC 0021 §A point 6',
|
|
266
268
|
'host MUST propagate runTrustBoundary onto normalizedMeta.contentTrust when envelope meta.contentTrust is absent',
|
|
267
269
|
),
|
|
@@ -280,12 +282,12 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
280
282
|
},
|
|
281
283
|
runTrustBoundary: 'untrusted', // explicitly conflicts; envelope wins
|
|
282
284
|
});
|
|
283
|
-
if (res.status === 404) return;
|
|
285
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
284
286
|
const body = res.json as { status?: string; normalizedMeta?: { contentTrust?: string } };
|
|
285
287
|
expect(body.status).toBe('accepted');
|
|
286
288
|
expect(
|
|
287
289
|
body.normalizedMeta?.contentTrust,
|
|
288
|
-
|
|
290
|
+
req('openwop.it.ai-envelope-shape.envelope-supplied-meta-contenttrust-takes-precedence-over-runtrustboundary',
|
|
289
291
|
'RFC 0021 §A point 6',
|
|
290
292
|
'envelope meta.contentTrust MUST take precedence over runTrustBoundary',
|
|
291
293
|
),
|
|
@@ -303,9 +305,9 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
303
305
|
meta: { source: 'ai-generation', ts: 'tomorrow' },
|
|
304
306
|
},
|
|
305
307
|
});
|
|
306
|
-
if (res.status === 404) return;
|
|
308
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
307
309
|
const body = res.json as { status?: string; reason?: string };
|
|
308
|
-
expect(body.status, 'malformed timestamp MUST be rejected').toBe('invalid');
|
|
310
|
+
expect(body.status, req('openwop.it.ai-envelope-shape.non-iso-8601-meta-ts-status-invalid-format-defense-in-depth', 'RFC 0021 §D', 'malformed timestamp MUST be rejected')).toBe('invalid');
|
|
309
311
|
expect(body.reason).toContain('ISO 8601');
|
|
310
312
|
});
|
|
311
313
|
|
|
@@ -321,12 +323,12 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
321
323
|
},
|
|
322
324
|
nodeAllowedKinds: ['vendor.acme.prd.create'], // doesn't include clarification.request
|
|
323
325
|
});
|
|
324
|
-
if (res.status === 404) return;
|
|
326
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
325
327
|
expect(res.status).toBe(200);
|
|
326
328
|
const body = res.json as { status?: string };
|
|
327
329
|
expect(
|
|
328
330
|
body.status,
|
|
329
|
-
|
|
331
|
+
req('openwop.it.ai-envelope-shape.universal-kind-allowed-regardless-of-nodeallowedkinds-always-allowed-per-univers',
|
|
330
332
|
'RFC 0021 §"Universal kinds (normative)"',
|
|
331
333
|
'universal kinds MUST be allowed even when node allowlist excludes them',
|
|
332
334
|
),
|
|
@@ -337,12 +339,12 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: behavioral acceptEnvelope round-t
|
|
|
337
339
|
describe.skipIf(HTTP_SKIP)('ai-envelope-shape: universal-kind advertisement (RFC 0021 §C)', () => {
|
|
338
340
|
it('host advertising any universal kind has a matching schema on disk', async () => {
|
|
339
341
|
const d = await readDiscovery();
|
|
340
|
-
if (d === null || !aiProvidersSupported(d)) return; // capability-gated
|
|
342
|
+
if (d === null || !aiProvidersSupported(d)) return softSkip('blocked', 'precondition not met — `d === null || !aiProvidersSupported(d)` returned early (capability-gated) (seam, prior step, or fixture unavailable)'); // capability-gated
|
|
341
343
|
const env = supportedEnvelopes(d);
|
|
342
344
|
const advertisedUniversals = env.filter((k): k is (typeof UNIVERSAL_KINDS)[number] =>
|
|
343
345
|
(UNIVERSAL_KINDS as readonly string[]).includes(k),
|
|
344
346
|
);
|
|
345
|
-
if (advertisedUniversals.length === 0) return; // host doesn't claim any universal
|
|
347
|
+
if (advertisedUniversals.length === 0) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `advertisedUniversals.length === 0` returned early (host doesn\'t claim any universal)'); // host doesn't claim any universal
|
|
346
348
|
// Each advertised universal MUST have its schema compileable (already
|
|
347
349
|
// covered by the per-kind compile test above; this assertion just makes
|
|
348
350
|
// the linkage between advertisement + schema explicit).
|
|
@@ -351,7 +353,7 @@ describe.skipIf(HTTP_SKIP)('ai-envelope-shape: universal-kind advertisement (RFC
|
|
|
351
353
|
const schema = JSON.parse(readFileSync(join(SCHEMAS_DIR, `envelopes/${k}.schema.json`), 'utf8')) as Record<string, unknown>;
|
|
352
354
|
expect(
|
|
353
355
|
ajv.compile(schema),
|
|
354
|
-
`RFC 0021 §B: advertised universal ${k} MUST resolve to a compileable schema
|
|
356
|
+
req('openwop.it.ai-envelope-shape.host-advertising-any-universal-kind-has-a-matching-schema-on-disk', 'RFC 0021 §D', `RFC 0021 §B: advertised universal ${k} MUST resolve to a compileable schema`),
|
|
355
357
|
).toBeTypeOf('function');
|
|
356
358
|
}
|
|
357
359
|
});
|
|
@@ -42,14 +42,14 @@ describe('aiEnvelope.capBreached: advertisement shape (already required v1)', ()
|
|
|
42
42
|
const limits = await readLimits();
|
|
43
43
|
expect(
|
|
44
44
|
limits,
|
|
45
|
-
|
|
45
|
+
req('openwop.it.aiEnvelope.capBreached.limits-envelopesperturn-is-a-non-negative-integer',
|
|
46
46
|
'capabilities.schema.json §limits',
|
|
47
47
|
'limits MUST be present on /.well-known/openwop (required v1)',
|
|
48
48
|
),
|
|
49
49
|
).not.toBeNull();
|
|
50
50
|
expect(
|
|
51
51
|
Number.isInteger(limits!.envelopesPerTurn) && limits!.envelopesPerTurn >= 0,
|
|
52
|
-
|
|
52
|
+
req('openwop.it.aiEnvelope.capBreached.limits-envelopesperturn-is-a-non-negative-integer',
|
|
53
53
|
'capabilities.schema.json §limits.envelopesPerTurn',
|
|
54
54
|
'envelopesPerTurn MUST be a non-negative integer (required v1)',
|
|
55
55
|
),
|
|
@@ -58,10 +58,10 @@ describe('aiEnvelope.capBreached: advertisement shape (already required v1)', ()
|
|
|
58
58
|
|
|
59
59
|
it('limits.schemaRounds is a non-negative integer', async () => {
|
|
60
60
|
const limits = await readLimits();
|
|
61
|
-
if (limits === null) return;
|
|
61
|
+
if (limits === null) return softSkip('blocked', 'precondition not met — `limits === null` returned early (seam, prior step, or fixture unavailable)');
|
|
62
62
|
expect(
|
|
63
63
|
Number.isInteger(limits.schemaRounds) && limits.schemaRounds >= 0,
|
|
64
|
-
|
|
64
|
+
req('openwop.it.aiEnvelope.capBreached.limits-schemarounds-is-a-non-negative-integer',
|
|
65
65
|
'capabilities.schema.json §limits.schemaRounds',
|
|
66
66
|
'schemaRounds MUST be a non-negative integer (required v1)',
|
|
67
67
|
),
|
|
@@ -70,10 +70,10 @@ describe('aiEnvelope.capBreached: advertisement shape (already required v1)', ()
|
|
|
70
70
|
|
|
71
71
|
it('limits.clarificationRounds is a non-negative integer', async () => {
|
|
72
72
|
const limits = await readLimits();
|
|
73
|
-
if (limits === null) return;
|
|
73
|
+
if (limits === null) return softSkip('blocked', 'precondition not met — `limits === null` returned early (seam, prior step, or fixture unavailable)');
|
|
74
74
|
expect(
|
|
75
75
|
Number.isInteger(limits.clarificationRounds) && limits.clarificationRounds >= 0,
|
|
76
|
-
|
|
76
|
+
req('openwop.it.aiEnvelope.capBreached.limits-clarificationrounds-is-a-non-negative-integer',
|
|
77
77
|
'capabilities.schema.json §limits.clarificationRounds',
|
|
78
78
|
'clarificationRounds MUST be a non-negative integer (required v1)',
|
|
79
79
|
),
|
|
@@ -101,10 +101,10 @@ describe('aiEnvelope.capBreached: behavioral cap enforcement (FINAL v1.1)', () =
|
|
|
101
101
|
},
|
|
102
102
|
{ counters: { envelopesPerTurn: { current: 32, cap: 32 } } },
|
|
103
103
|
);
|
|
104
|
-
if (r.status === 404) return;
|
|
104
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
105
105
|
expect(
|
|
106
106
|
r.body.status,
|
|
107
|
-
|
|
107
|
+
req('openwop.it.aiEnvelope.capBreached.envelopesperturn-at-cap-status-breached-capkind-envelopes', 'ai-envelope.md §"Engine-enforced limits"', 'over-cap envelope MUST be breached'),
|
|
108
108
|
).toBe('breached');
|
|
109
109
|
expect(r.body.capKind).toBe('envelopes');
|
|
110
110
|
});
|
|
@@ -121,8 +121,8 @@ describe('aiEnvelope.capBreached: behavioral cap enforcement (FINAL v1.1)', () =
|
|
|
121
121
|
},
|
|
122
122
|
{ counters: { clarificationRounds: { current: 5, cap: 5 } } },
|
|
123
123
|
);
|
|
124
|
-
if (r.status === 404) return;
|
|
125
|
-
expect(r.body.status).toBe('breached');
|
|
124
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
125
|
+
expect(r.body.status, req('openwop.it.aiEnvelope.capBreached.clarificationrounds-at-cap-status-breached-capkind-clarification', 'spec/v1/ai-envelope.md', 'clarificationRounds at cap → status: breached { capKind: "clarification" }')).toBe('breached');
|
|
126
126
|
expect(r.body.capKind).toBe('clarification');
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -138,8 +138,8 @@ describe('aiEnvelope.capBreached: behavioral cap enforcement (FINAL v1.1)', () =
|
|
|
138
138
|
},
|
|
139
139
|
{ counters: { schemaRounds: { current: 3, cap: 3 } } },
|
|
140
140
|
);
|
|
141
|
-
if (r.status === 404) return;
|
|
142
|
-
expect(r.body.status).toBe('breached');
|
|
141
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
142
|
+
expect(r.body.status, req('openwop.it.aiEnvelope.capBreached.schemarounds-at-cap-status-breached-capkind-schema', 'spec/v1/ai-envelope.md', 'schemaRounds at cap → status: breached { capKind: "schema" }')).toBe('breached');
|
|
143
143
|
expect(r.body.capKind).toBe('schema');
|
|
144
144
|
});
|
|
145
145
|
|
|
@@ -155,8 +155,8 @@ describe('aiEnvelope.capBreached: behavioral cap enforcement (FINAL v1.1)', () =
|
|
|
155
155
|
},
|
|
156
156
|
{ counters: { envelopesPerTurn: { current: 32, cap: 32 } } },
|
|
157
157
|
);
|
|
158
|
-
if (r.status === 404) return;
|
|
159
|
-
expect(r.body.reason).toContain('envelopesPerTurn');
|
|
158
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
159
|
+
expect(r.body.reason, req('openwop.it.aiEnvelope.capBreached.breached-reason-cites-the-limit-and-cap-value', 'spec/v1/ai-envelope.md', 'breached reason cites the limit and cap value')).toContain('envelopesPerTurn');
|
|
160
160
|
expect(r.body.reason).toContain('32');
|
|
161
161
|
});
|
|
162
162
|
});
|
|
@@ -167,10 +167,12 @@ describe('aiEnvelope.capBreached: behavioral cap enforcement (FINAL v1.1)', () =
|
|
|
167
167
|
// soft-skip on HTTP 404 when the seam isn't exposed.
|
|
168
168
|
import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
|
|
169
169
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
170
|
+
import { req } from '../lib/requirement-ids.js';
|
|
171
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
170
172
|
|
|
171
173
|
describe('aiEnvelope.capBreached: engine projection via event-log seam (capabilities.md §"cap.breached")', () => {
|
|
172
174
|
it('breached outcome projects to cap.breached { kind: "envelopes" } event with causationId chain', async () => {
|
|
173
|
-
if (!(await isEventLogSeamAvailable())) return;
|
|
175
|
+
if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
|
|
174
176
|
const runId = `r-cap-env-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
175
177
|
const correlationId = `${runId}:node-1:turn-0:cap-env`;
|
|
176
178
|
const r = await accept(
|
|
@@ -187,14 +189,14 @@ describe('aiEnvelope.capBreached: engine projection via event-log seam (capabili
|
|
|
187
189
|
projectTo: { runId, nodeId: 'node-1' },
|
|
188
190
|
},
|
|
189
191
|
);
|
|
190
|
-
if (r.status === 404) return;
|
|
192
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
191
193
|
expect(r.body.status).toBe('breached');
|
|
192
194
|
|
|
193
195
|
const events = await queryTestEvents(runId, { type: 'cap.breached' });
|
|
194
|
-
if (!events.ok) return;
|
|
196
|
+
if (!events.ok) return softSkip('blocked', 'precondition not met — `!events.ok` returned early (seam, prior step, or fixture unavailable)');
|
|
195
197
|
expect(
|
|
196
198
|
events.events.length,
|
|
197
|
-
|
|
199
|
+
req('openwop.it.aiEnvelope.capBreached.breached-outcome-projects-to-cap-breached-kind-envelopes-event-with-causationid', 'capabilities.md §"Engine-enforced limits and the cap.breached event"', 'breached outcome MUST project to exactly one cap.breached event'),
|
|
198
200
|
).toBe(1);
|
|
199
201
|
const evt = events.events[0]!;
|
|
200
202
|
expect(evt.payload.kind).toBe('envelopes');
|
|
@@ -203,7 +205,7 @@ describe('aiEnvelope.capBreached: engine projection via event-log seam (capabili
|
|
|
203
205
|
});
|
|
204
206
|
|
|
205
207
|
it('cap.breached payload includes limit, observed, and nodeId per capabilities.md', async () => {
|
|
206
|
-
if (!(await isEventLogSeamAvailable())) return;
|
|
208
|
+
if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
|
|
207
209
|
const runId = `r-cap-payload-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
208
210
|
await accept(
|
|
209
211
|
{
|
|
@@ -220,19 +222,19 @@ describe('aiEnvelope.capBreached: engine projection via event-log seam (capabili
|
|
|
220
222
|
},
|
|
221
223
|
);
|
|
222
224
|
const events = await queryTestEvents(runId, { type: 'cap.breached' });
|
|
223
|
-
if (!events.ok || events.events.length === 0) return;
|
|
225
|
+
if (!events.ok || events.events.length === 0) return softSkip('blocked', 'precondition not met — `!events.ok || events.events.length === 0` returned early (seam, prior step, or fixture unavailable)');
|
|
224
226
|
const evt = events.events[0]!;
|
|
225
227
|
expect(evt.payload.kind).toBe('clarification');
|
|
226
228
|
expect(
|
|
227
229
|
typeof evt.payload.limit,
|
|
228
|
-
|
|
230
|
+
req('openwop.it.aiEnvelope.capBreached.cap-breached-payload-includes-limit-observed-and-nodeid-per-capabilities-md', 'capabilities.md §"cap.breached"', 'payload.limit MUST be present as a number'),
|
|
229
231
|
).toBe('number');
|
|
230
232
|
expect(evt.payload.nodeId).toBe('node-2');
|
|
231
233
|
await resetTestSeam();
|
|
232
234
|
});
|
|
233
235
|
|
|
234
236
|
it('cap.breached MUST be paired with a terminal node.failed transition', async () => {
|
|
235
|
-
if (!(await isEventLogSeamAvailable())) return;
|
|
237
|
+
if (!(await isEventLogSeamAvailable())) return softSkip('blocked', 'precondition not met — `!(await isEventLogSeamAvailable())` returned early (seam, prior step, or fixture unavailable)');
|
|
236
238
|
const runId = `r-cap-fail-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
237
239
|
await accept(
|
|
238
240
|
{
|
|
@@ -250,11 +252,11 @@ describe('aiEnvelope.capBreached: engine projection via event-log seam (capabili
|
|
|
250
252
|
);
|
|
251
253
|
const breached = await queryTestEvents(runId, { type: 'cap.breached' });
|
|
252
254
|
const failed = await queryTestEvents(runId, { type: 'node.failed' });
|
|
253
|
-
if (!breached.ok || !failed.ok) return;
|
|
255
|
+
if (!breached.ok || !failed.ok) return softSkip('blocked', 'precondition not met — `!breached.ok || !failed.ok` returned early (seam, prior step, or fixture unavailable)');
|
|
254
256
|
expect(breached.events.length).toBe(1);
|
|
255
257
|
expect(
|
|
256
258
|
failed.events.length,
|
|
257
|
-
|
|
259
|
+
req('openwop.it.aiEnvelope.capBreached.cap-breached-must-be-paired-with-a-terminal-node-failed-transition', 'capabilities.md §"cap.breached"', 'cap.breached MUST be paired with a terminal node.failed event'),
|
|
258
260
|
).toBe(1);
|
|
259
261
|
expect((failed.events[0]!.payload.error as { code?: string }).code).toBe('cap_breached');
|
|
260
262
|
await resetTestSeam();
|