@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
|
@@ -30,6 +30,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
30
30
|
import { softSkip } from '../lib/soft-skip.js';
|
|
31
31
|
import { driver } from '../lib/driver.js';
|
|
32
32
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
33
34
|
|
|
34
35
|
const MEMORY_REF = 'mem_tenant:default_agent:conformance-rfc0012-sr1_longTerm';
|
|
35
36
|
|
|
@@ -77,13 +78,13 @@ describe('memory-compaction-sr1-carry-forward: derived content passes the BYOK r
|
|
|
77
78
|
{ id: `sr1-src-${Date.now()}-3`, content: 'Customer asked about pricing tiers.' },
|
|
78
79
|
],
|
|
79
80
|
});
|
|
80
|
-
expect(seed.status, 'seed endpoint MUST return 201 when reachable').toBe(201);
|
|
81
|
+
expect(seed.status, req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures', 'RFC 0012 §D', 'seed endpoint MUST return 201 when reachable')).toBe(201);
|
|
81
82
|
|
|
82
83
|
// 2. Drive compaction synchronously.
|
|
83
84
|
const compactRes = await driver.post('/v1/test/memory/compact', {
|
|
84
85
|
memoryRef: MEMORY_REF,
|
|
85
86
|
});
|
|
86
|
-
expect(compactRes.status, 'compact MUST return 200 with ≥2 source entries').toBe(200);
|
|
87
|
+
expect(compactRes.status, req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures', 'RFC 0012 §D', 'compact MUST return 200 with ≥2 source entries')).toBe(200);
|
|
87
88
|
|
|
88
89
|
const event = compactRes.json as {
|
|
89
90
|
type?: string;
|
|
@@ -95,7 +96,7 @@ describe('memory-compaction-sr1-carry-forward: derived content passes the BYOK r
|
|
|
95
96
|
// trivially without it.
|
|
96
97
|
outputContent?: string;
|
|
97
98
|
};
|
|
98
|
-
expect(event.type, 'event payload MUST be type=memory.compacted').toBe('memory.compacted');
|
|
99
|
+
expect(event.type, req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures', 'RFC 0012 §D', 'event payload MUST be type=memory.compacted')).toBe('memory.compacted');
|
|
99
100
|
|
|
100
101
|
if (typeof event.outputContent !== 'string') {
|
|
101
102
|
// eslint-disable-next-line no-console
|
|
@@ -107,11 +108,11 @@ describe('memory-compaction-sr1-carry-forward: derived content passes the BYOK r
|
|
|
107
108
|
// future MemoryAdapter.get / list consumers would see) MUST NOT
|
|
108
109
|
// carry source-side form-leak signatures. A host that skips its
|
|
109
110
|
// BYOK redaction pass on derived content fails here.
|
|
110
|
-
expect(event.outputContent.includes('[BYOK:hk_live_canary_42]'),
|
|
111
|
+
expect(event.outputContent.includes('[BYOK:hk_live_canary_42]'), req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures',
|
|
111
112
|
'RFC 0012 §D',
|
|
112
113
|
'derived MemoryEntry.content MUST NOT carry source-side [BYOK:...] form-leak signatures (SR-1 carry-forward)',
|
|
113
114
|
)).toBe(false);
|
|
114
|
-
expect(event.outputContent.includes('<REDACTED:db-prod-creds>'),
|
|
115
|
+
expect(event.outputContent.includes('<REDACTED:db-prod-creds>'), req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures',
|
|
115
116
|
'RFC 0012 §D',
|
|
116
117
|
'derived MemoryEntry.content MUST NOT echo non-canonical <REDACTED:...> markers from sources',
|
|
117
118
|
)).toBe(false);
|
|
@@ -121,7 +122,7 @@ describe('memory-compaction-sr1-carry-forward: derived content passes the BYOK r
|
|
|
121
122
|
// leak. Pinning this prevents a host from "passing" by simply
|
|
122
123
|
// stripping source content rather than redacting it (which would
|
|
123
124
|
// also lose audit signal).
|
|
124
|
-
expect(event.outputContent,
|
|
125
|
+
expect(event.outputContent, req('openwop.it.memory-compaction-sr1-carry-forward.compacted-memoryentry-content-must-not-carry-source-side-form-leak-signatures',
|
|
125
126
|
'RFC 0012 §D',
|
|
126
127
|
'derived MemoryEntry.content MUST carry canonical [REDACTED:...] placeholders where source-side leaks were re-substituted',
|
|
127
128
|
)).toMatch(/\[REDACTED:[^\]]+\]/);
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { describe, it, expect } from 'vitest';
|
|
25
25
|
import { softSkip } from '../lib/soft-skip.js';
|
|
26
26
|
import { driver } from '../lib/driver.js';
|
|
27
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
28
|
|
|
28
29
|
interface ConsolidationCaps {
|
|
29
30
|
agents?: { memoryConsolidation?: { supported?: boolean } };
|
|
@@ -50,11 +51,11 @@ describe('memory-consolidation-idempotent: pass contract (RFC 0068 §D, capabili
|
|
|
50
51
|
});
|
|
51
52
|
if (first.status === 404 || first.status === 501) return softSkip('blocked', 'seam not wired — soft-skip');
|
|
52
53
|
|
|
53
|
-
expect(first.status,
|
|
54
|
+
expect(first.status, req('openwop.it.memory-consolidation-idempotent.a-consolidation-pass-reduces-or-holds-entry-count-and-is-idempotent-on-a-stable', 'RFC 0068 §D', 'an advertised consolidation seam MUST succeed')).toBe(200);
|
|
54
55
|
const r1 = first.json as ConsolidateResult;
|
|
55
56
|
const in1 = r1.event?.inputCount ?? 0;
|
|
56
57
|
const out1 = r1.event?.outputCount ?? 0;
|
|
57
|
-
expect(out1,
|
|
58
|
+
expect(out1, req('openwop.it.memory-consolidation-idempotent.a-consolidation-pass-reduces-or-holds-entry-count-and-is-idempotent-on-a-stable', 'RFC 0068 §D.1', 'outputCount MUST be <= inputCount for a merge/dedup pass')).toBeLessThanOrEqual(in1);
|
|
58
59
|
|
|
59
60
|
// §D.2 — a second pass over the unchanged corpus is a no-op.
|
|
60
61
|
const second = await driver.post('/v1/host/sample/memory/consolidate', {
|
|
@@ -64,14 +65,14 @@ describe('memory-consolidation-idempotent: pass contract (RFC 0068 §D, capabili
|
|
|
64
65
|
const r2 = second.json as ConsolidateResult;
|
|
65
66
|
expect(
|
|
66
67
|
r2.event?.inputCount,
|
|
67
|
-
|
|
68
|
+
req('openwop.it.memory-consolidation-idempotent.a-consolidation-pass-reduces-or-holds-entry-count-and-is-idempotent-on-a-stable', 'RFC 0068 §D.2', 'a second pass over an unchanged corpus MUST be a no-op (inputCount == outputCount)'),
|
|
68
69
|
).toBe(r2.event?.outputCount);
|
|
69
70
|
|
|
70
71
|
// §D.3 — SR-1 carry-forward: a redacted secret stays redacted in the consolidated entry.
|
|
71
72
|
if (typeof r1.secretLeaked === 'boolean') {
|
|
72
73
|
expect(
|
|
73
74
|
r1.secretLeaked,
|
|
74
|
-
|
|
75
|
+
req('openwop.it.memory-consolidation-idempotent.a-consolidation-pass-reduces-or-holds-entry-count-and-is-idempotent-on-a-stable', 'RFC 0068 §D.3 / agent-memory.md §SR-1', 'a redacted secret MUST NOT re-appear in a consolidated entry'),
|
|
75
76
|
).toBe(false);
|
|
76
77
|
}
|
|
77
78
|
});
|
|
@@ -26,9 +26,7 @@ import { join } from 'node:path';
|
|
|
26
26
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
27
27
|
import addFormats from 'ajv-formats';
|
|
28
28
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
29
|
-
|
|
30
|
-
/** Server-free assertion-message helper (mirrors driver.describe's "spec — requirement" shape without requiring OPENWOP_BASE_URL). */
|
|
31
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
29
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
30
|
|
|
33
31
|
function loadSchema(name: string): Record<string, unknown> {
|
|
34
32
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -40,11 +38,11 @@ describe('memory-consolidation-shape: capability advertisement (RFC 0068, server
|
|
|
40
38
|
const agents = (caps.properties as Record<string, { properties?: Record<string, unknown> }>).agents;
|
|
41
39
|
expect(
|
|
42
40
|
agents?.properties?.memoryConsolidation,
|
|
43
|
-
|
|
41
|
+
req('openwop.it.memory-consolidation-shape.the-capabilities-schema-declares-agents-memoryconsolidation-agents-commitments', 'capabilities.md §agents', 'agents.memoryConsolidation MUST be declared'),
|
|
44
42
|
).toBeDefined();
|
|
45
43
|
expect(
|
|
46
44
|
agents?.properties?.commitments,
|
|
47
|
-
|
|
45
|
+
req('openwop.it.memory-consolidation-shape.the-capabilities-schema-declares-agents-memoryconsolidation-agents-commitments', 'capabilities.md §agents', 'agents.commitments MUST be declared'),
|
|
48
46
|
).toBeDefined();
|
|
49
47
|
});
|
|
50
48
|
});
|
|
@@ -59,32 +57,32 @@ describe('memory-consolidation-shape: event payloads (RFC 0068, server-free)', (
|
|
|
59
57
|
const fired = ajv.getSchema('payloads#/$defs/commitmentFired');
|
|
60
58
|
|
|
61
59
|
it('agent.memory.consolidated validates a content-free pass summary', () => {
|
|
62
|
-
expect(consolidated, 'the agentMemoryConsolidated $def MUST exist').toBeTruthy();
|
|
60
|
+
expect(consolidated, req('openwop.it.memory-consolidation-shape.agent-memory-consolidated-validates-a-content-free-pass-summary', 'RFC 0068', 'the agentMemoryConsolidated $def MUST exist')).toBeTruthy();
|
|
63
61
|
expect(
|
|
64
62
|
consolidated!({ memoryRef: 'mem://a/agent-1', inputCount: 240, outputCount: 201, trigger: 'host-managed' }),
|
|
65
|
-
|
|
63
|
+
req('openwop.it.memory-consolidation-shape.agent-memory-consolidated-validates-a-content-free-pass-summary', 'RFC 0068 §B', 'a conforming agent.memory.consolidated payload MUST validate'),
|
|
66
64
|
).toBe(true);
|
|
67
65
|
// Negative: outputCount as string fails the integer type.
|
|
68
66
|
expect(consolidated!({ memoryRef: 'mem://a/agent-1', inputCount: 1, outputCount: 'x' })).toBe(false);
|
|
69
67
|
});
|
|
70
68
|
|
|
71
69
|
it('commitment.fired validates a content-free fire record and requires memoryRef', () => {
|
|
72
|
-
expect(fired, 'the commitmentFired $def MUST exist').toBeTruthy();
|
|
70
|
+
expect(fired, req('openwop.it.memory-consolidation-shape.commitment-fired-validates-a-content-free-fire-record-and-requires-memoryref', 'RFC 0068', 'the commitmentFired $def MUST exist')).toBeTruthy();
|
|
73
71
|
expect(
|
|
74
72
|
fired!({ commitmentId: 'cmt-1', memoryRef: 'mem://a/agent-1', condition: 'predicate', enqueuedRunId: 'run-1' }),
|
|
75
|
-
|
|
73
|
+
req('openwop.it.memory-consolidation-shape.commitment-fired-validates-a-content-free-fire-record-and-requires-memoryref', 'RFC 0068 §C', 'a conforming commitment.fired payload MUST validate'),
|
|
76
74
|
).toBe(true);
|
|
77
75
|
// Negative: missing memoryRef — a commitment with no provenance breaks CTI-1 binding.
|
|
78
76
|
expect(
|
|
79
77
|
fired!({ commitmentId: 'cmt-1', condition: 'time' }),
|
|
80
|
-
|
|
78
|
+
req('openwop.it.memory-consolidation-shape.commitment-fired-validates-a-content-free-fire-record-and-requires-memoryref', 'RFC 0068 §C', 'commitment.fired without memoryRef MUST be rejected'),
|
|
81
79
|
).toBe(false);
|
|
82
80
|
});
|
|
83
81
|
|
|
84
82
|
it('both event names appear in the RunEventType enum', () => {
|
|
85
83
|
const runEvent = loadSchema('run-event.schema.json');
|
|
86
84
|
const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
|
|
87
|
-
expect(enumVals).toContain('agent.memory.consolidated');
|
|
85
|
+
expect(enumVals, req('openwop.it.memory-consolidation-shape.both-event-names-appear-in-the-runeventtype-enum', 'RFC 0068', 'both event names appear in the RunEventType enum')).toContain('agent.memory.consolidated');
|
|
88
86
|
expect(enumVals).toContain('commitment.fired');
|
|
89
87
|
});
|
|
90
88
|
});
|
|
@@ -29,10 +29,11 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import { describe, it, expect } from 'vitest';
|
|
32
|
-
import { driver } from '../lib/driver.js';
|
|
33
32
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
34
33
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
35
34
|
import { readManifestRuntimeCap, listManifestAgents } from '../lib/agentRuntime.js';
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
36
37
|
|
|
37
38
|
/** The CLOSED RFC 0080 §A dimension vocabulary (agent-inventory-response.schema.json
|
|
38
39
|
* `degradedMemoryDimensions` enum). NOT the `memoryShape` keys. */
|
|
@@ -62,13 +63,13 @@ describe('memory-degraded-projection (RFC 0080 §C)', () => {
|
|
|
62
63
|
if (!behaviorGate('openwop-memory-degraded', advertised)) return;
|
|
63
64
|
|
|
64
65
|
const inv = await listManifestAgents();
|
|
65
|
-
if (inv === null) return; // host advertises the cap but doesn't serve /v1/agents — soft-skip
|
|
66
|
+
if (inv === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `inv === null` returned early (host advertises the cap but doesn\'t serve /v1/agents — soft-skip)'); // host advertises the cap but doesn't serve /v1/agents — soft-skip
|
|
66
67
|
const agents = (inv.agents ?? []) as InventoryEntry[];
|
|
67
68
|
|
|
68
69
|
// Non-vacuity: an advertising + serving host MUST expose its inventory.
|
|
69
70
|
expect(
|
|
70
71
|
agents.length >= 1,
|
|
71
|
-
|
|
72
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'agent-memory.md §"Memory capability model"', 'GET /v1/agents MUST return the installed manifest agents'),
|
|
72
73
|
).toBe(true);
|
|
73
74
|
|
|
74
75
|
// §C iff-contract on EVERY entry.
|
|
@@ -79,25 +80,25 @@ describe('memory-degraded-projection (RFC 0080 §C)', () => {
|
|
|
79
80
|
if (degraded) {
|
|
80
81
|
expect(
|
|
81
82
|
Array.isArray(dims) && dims.length >= 1,
|
|
82
|
-
|
|
83
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'RFC 0080 §C', `memoryDegraded:true MUST carry a non-empty degradedMemoryDimensions (agent ${a.agentId})`),
|
|
83
84
|
).toBe(true);
|
|
84
85
|
if (Array.isArray(dims)) {
|
|
85
86
|
for (const d of dims) {
|
|
86
87
|
expect(
|
|
87
88
|
typeof d === 'string' && DIMENSIONS.includes(d),
|
|
88
|
-
|
|
89
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'agent-inventory-response.schema.json', `degradedMemoryDimensions members MUST be RFC 0080 §A dimension names (got ${String(d)})`),
|
|
89
90
|
).toBe(true);
|
|
90
91
|
}
|
|
91
92
|
expect(
|
|
92
93
|
new Set(dims as string[]).size === dims.length,
|
|
93
|
-
|
|
94
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'RFC 0080 §C', 'degradedMemoryDimensions MUST be unique'),
|
|
94
95
|
).toBe(true);
|
|
95
96
|
}
|
|
96
97
|
} else {
|
|
97
98
|
// Not degraded ⇒ no non-empty dimension list (absent or empty both pass).
|
|
98
99
|
expect(
|
|
99
100
|
dims === undefined || (Array.isArray(dims) && dims.length === 0),
|
|
100
|
-
|
|
101
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'RFC 0080 §C', `a non-degraded entry MUST NOT carry a non-empty degradedMemoryDimensions (agent ${a.agentId})`),
|
|
101
102
|
).toBe(true);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
@@ -108,12 +109,12 @@ describe('memory-degraded-projection (RFC 0080 §C)', () => {
|
|
|
108
109
|
const target = agents.find((a) => a.agentId === degradedId);
|
|
109
110
|
expect(
|
|
110
111
|
target !== undefined,
|
|
111
|
-
|
|
112
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'RFC 0080 §C', `OPENWOP_DEGRADED_AGENT_ID=${degradedId} MUST appear in the inventory`),
|
|
112
113
|
).toBe(true);
|
|
113
114
|
if (target) {
|
|
114
115
|
expect(
|
|
115
116
|
target.memoryDegraded === true && Array.isArray(target.degradedMemoryDimensions) && target.degradedMemoryDimensions.length >= 1,
|
|
116
|
-
|
|
117
|
+
req('openwop.it.memory-degraded-projection.stamps-memorydegraded-a-closed-enum-degradedmemorydimensions-on-degraded-agents', 'RFC 0080 §C', 'the named degraded agent MUST project memoryDegraded:true + a non-empty degradedMemoryDimensions'),
|
|
117
118
|
).toBe(true);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
@@ -34,6 +34,7 @@ import { pollUntilTerminal } from '../lib/polling.js';
|
|
|
34
34
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
35
35
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
36
36
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
37
|
+
import { req } from '../lib/requirement-ids.js';
|
|
37
38
|
|
|
38
39
|
const FIXTURE = 'conformance-agent-memory-injection-budget';
|
|
39
40
|
const PROFILE = 'openwop-memory-injection-budget';
|
|
@@ -114,14 +115,14 @@ describe('memory-injection-budget (RFC 0113)', () => {
|
|
|
114
115
|
if (!isFixtureAdvertised(FIXTURE)) return softSkip('inapplicable', `host does not advertise the ${FIXTURE} conformance fixture`);
|
|
115
116
|
|
|
116
117
|
const v = await driveFixtureVariables();
|
|
117
|
-
expect(v, 'fixture MUST surface run variables').toBeDefined();
|
|
118
|
-
if (v === undefined) return;
|
|
118
|
+
expect(v, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'fixture MUST surface run variables')).toBeDefined();
|
|
119
|
+
if (v === undefined) return softSkip('blocked', 'precondition not met — `v === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
119
120
|
|
|
120
121
|
// ── tokenBudget bound (the new lever) ──────────────────────────────
|
|
121
122
|
const tokenBudget = numberOf(v['tokenBudget']);
|
|
122
123
|
const total = numberOf(v['budgetedTokenTotal']);
|
|
123
|
-
expect(tokenBudget, 'fixture MUST echo the requested tokenBudget').toBeDefined();
|
|
124
|
-
expect(total, 'fixture MUST surface the budgeted cumulative token total').toBeDefined();
|
|
124
|
+
expect(tokenBudget, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'fixture MUST echo the requested tokenBudget')).toBeDefined();
|
|
125
|
+
expect(total, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'fixture MUST surface the budgeted cumulative token total')).toBeDefined();
|
|
125
126
|
// Cumulative tokens across the returned prefix MUST NOT exceed the budget.
|
|
126
127
|
if (tokenBudget !== undefined && total !== undefined) {
|
|
127
128
|
expect(total).toBeLessThanOrEqual(tokenBudget);
|
|
@@ -130,21 +131,21 @@ describe('memory-injection-budget (RFC 0113)', () => {
|
|
|
130
131
|
// ── over-budget single entry omitted (not truncated) ───────────────
|
|
131
132
|
expect(
|
|
132
133
|
booleanOf(v['overBudgetEntryOmitted']),
|
|
133
|
-
'an entry larger than the whole budget MUST be omitted, not truncated mid-entry',
|
|
134
|
+
req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'an entry larger than the whole budget MUST be omitted, not truncated mid-entry'),
|
|
134
135
|
).toBe(true);
|
|
135
136
|
const entries = recordArrayOf(v['budgetedEntries']);
|
|
136
|
-
expect(entries, 'fixture MUST surface the budgeted entry slice').toBeDefined();
|
|
137
|
+
expect(entries, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'fixture MUST surface the budgeted entry slice')).toBeDefined();
|
|
137
138
|
const overId = stringOf(v['overBudgetEntryId']);
|
|
138
139
|
if (entries !== undefined && overId !== undefined) {
|
|
139
140
|
const ids = entries.map((e) => stringOf(e['id']));
|
|
140
|
-
expect(ids, 'the over-budget entry MUST NOT appear in the returned slice').not.toContain(overId);
|
|
141
|
+
expect(ids, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'the over-budget entry MUST NOT appear in the returned slice')).not.toContain(overId);
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
// ── SR-1 re-assertion on the budgeted path ─────────────────────────
|
|
144
145
|
// A budgeted/ranked read ranks over already-redacted content; the read
|
|
145
146
|
// surface MUST carry the redaction marker, never the plaintext.
|
|
146
147
|
const redacted = stringOf(v['redactedContentSample']);
|
|
147
|
-
expect(redacted, 'budgeted read MUST surface a redacted-content sample').toBeDefined();
|
|
148
|
+
expect(redacted, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'budgeted read MUST surface a redacted-content sample')).toBeDefined();
|
|
148
149
|
if (redacted !== undefined) {
|
|
149
150
|
expect(redacted).toMatch(/\[REDACTED:[^\]]+\]/);
|
|
150
151
|
}
|
|
@@ -154,9 +155,9 @@ describe('memory-injection-budget (RFC 0113)', () => {
|
|
|
154
155
|
// the cross-tenant probe under the budgeted path MUST return empty.
|
|
155
156
|
const probe = v['crossTenantBudgetedProbe'];
|
|
156
157
|
if (Array.isArray(probe)) {
|
|
157
|
-
expect(probe.length, 'cross-tenant probe on the budgeted path MUST return []').toBe(0);
|
|
158
|
+
expect(probe.length, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'cross-tenant probe on the budgeted path MUST return []')).toBe(0);
|
|
158
159
|
} else {
|
|
159
|
-
expect(probe, 'cross-tenant probe on the budgeted path MUST return [] / null').toBeFalsy();
|
|
160
|
+
expect(probe, req('openwop.it.memory-injection-budget.token-bounds-the-injection-read-omits-the-over-budget-entry-and-preserves-sr-1-c', 'RFC 0113', 'cross-tenant probe on the budgeted path MUST return [] / null')).toBeFalsy();
|
|
160
161
|
}
|
|
161
162
|
});
|
|
162
163
|
|
|
@@ -175,13 +176,13 @@ describe('memory-injection-budget (RFC 0113)', () => {
|
|
|
175
176
|
if (!isFixtureAdvertised(FIXTURE)) return softSkip('inapplicable', `host does not advertise the ${FIXTURE} conformance fixture`);
|
|
176
177
|
|
|
177
178
|
const v = await driveFixtureVariables();
|
|
178
|
-
expect(v, 'fixture MUST surface run variables').toBeDefined();
|
|
179
|
-
if (v === undefined) return;
|
|
179
|
+
expect(v, req('openwop.it.memory-injection-budget.rank-relevance-reorders-vs-recency-only-when-memory-search-semantic-is-also-adve', 'RFC 0113', 'fixture MUST surface run variables')).toBeDefined();
|
|
180
|
+
if (v === undefined) return softSkip('blocked', 'precondition not met — `v === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
180
181
|
|
|
181
182
|
const recencyOrder = stringArrayOf(v['recencyOrder']);
|
|
182
183
|
const relevanceOrder = stringArrayOf(v['relevanceOrder']);
|
|
183
|
-
expect(recencyOrder, 'fixture MUST surface the recency ordering').toBeDefined();
|
|
184
|
-
expect(relevanceOrder, 'fixture MUST surface the relevance ordering').toBeDefined();
|
|
184
|
+
expect(recencyOrder, req('openwop.it.memory-injection-budget.rank-relevance-reorders-vs-recency-only-when-memory-search-semantic-is-also-adve', 'RFC 0113', 'fixture MUST surface the recency ordering')).toBeDefined();
|
|
185
|
+
expect(relevanceOrder, req('openwop.it.memory-injection-budget.rank-relevance-reorders-vs-recency-only-when-memory-search-semantic-is-also-adve', 'RFC 0113', 'fixture MUST surface the relevance ordering')).toBeDefined();
|
|
185
186
|
// The crafted fixture pins a query whose semantic top-k differs from the
|
|
186
187
|
// most-recent-first order — relevance MUST reorder (not echo recency).
|
|
187
188
|
expect(relevanceOrder).not.toEqual(recencyOrder);
|
|
@@ -25,6 +25,7 @@ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
|
|
|
25
25
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
26
26
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
27
27
|
import { getCollector } from '../lib/otel-collector.js';
|
|
28
|
+
import { req } from '../lib/requirement-ids.js';
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Callback-shaped: the host exports OTLP metrics to the suite's collector.
|
|
@@ -96,19 +97,19 @@ describe('metric-emission: canonical openwop.* metrics arrive at the collector',
|
|
|
96
97
|
|
|
97
98
|
// Wait for the host's metric-emit tick to land at the collector.
|
|
98
99
|
const sawBacklog = await waitForMetric('openwop.run.backlog', 5_000);
|
|
99
|
-
expect(sawBacklog,
|
|
100
|
+
expect(sawBacklog, req('openwop.it.metric-emission.host-emits-openwop-run-backlog-openwop-queue-depth-and-openwop-run-duration',
|
|
100
101
|
'observability.md §"Metrics"',
|
|
101
102
|
'host claiming metrics MUST emit openwop.run.backlog',
|
|
102
103
|
)).toBe(true);
|
|
103
104
|
|
|
104
105
|
const sawQueueDepth = await waitForMetric('openwop.queue.depth', 5_000);
|
|
105
|
-
expect(sawQueueDepth,
|
|
106
|
+
expect(sawQueueDepth, req('openwop.it.metric-emission.host-emits-openwop-run-backlog-openwop-queue-depth-and-openwop-run-duration',
|
|
106
107
|
'observability.md §"Metrics"',
|
|
107
108
|
'host claiming metrics MUST emit openwop.queue.depth',
|
|
108
109
|
)).toBe(true);
|
|
109
110
|
|
|
110
111
|
const sawDuration = await waitForMetric('openwop.run.duration', 5_000);
|
|
111
|
-
expect(sawDuration,
|
|
112
|
+
expect(sawDuration, req('openwop.it.metric-emission.host-emits-openwop-run-backlog-openwop-queue-depth-and-openwop-run-duration',
|
|
112
113
|
'observability.md §"Metrics"',
|
|
113
114
|
'host claiming metrics MUST emit openwop.run.duration after a completed run',
|
|
114
115
|
)).toBe(true);
|
|
@@ -39,24 +39,24 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: dispatch refusal (RFC
|
|
|
39
39
|
supportedProviders: ['unknown-vendor'],
|
|
40
40
|
nodeId: 'editor-node',
|
|
41
41
|
});
|
|
42
|
-
if (r.status === 404) return;
|
|
42
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
43
43
|
expect(
|
|
44
44
|
r.body.outcome?.route,
|
|
45
|
-
|
|
45
|
+
req('openwop.it.model-capability-insufficient.unmet-no-fallbackmodel-declared-refuse-with-fallbackattempted-false',
|
|
46
46
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 4',
|
|
47
47
|
'unmet capability + no fallbackModel declared → host MUST refuse',
|
|
48
48
|
),
|
|
49
49
|
).toBe('refuse');
|
|
50
50
|
expect(
|
|
51
51
|
r.body.outcome?.fallbackAttempted,
|
|
52
|
-
|
|
52
|
+
req('openwop.it.model-capability-insufficient.unmet-no-fallbackmodel-declared-refuse-with-fallbackattempted-false',
|
|
53
53
|
'schemas/run-event-payloads.schema.json §modelCapabilityInsufficient',
|
|
54
54
|
'fallbackAttempted MUST be false when no fallbackModel was declared on the NodeModule',
|
|
55
55
|
),
|
|
56
56
|
).toBe(false);
|
|
57
57
|
expect(
|
|
58
58
|
r.body.event?.type,
|
|
59
|
-
|
|
59
|
+
req('openwop.it.model-capability-insufficient.unmet-no-fallbackmodel-declared-refuse-with-fallbackattempted-false',
|
|
60
60
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §D',
|
|
61
61
|
'refuse path MUST emit `model.capability.insufficient` BEFORE the node failure',
|
|
62
62
|
),
|
|
@@ -81,11 +81,11 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: dispatch refusal (RFC
|
|
|
81
81
|
// authenticate per RFC 0031 §B step 3 final clause.
|
|
82
82
|
supportedProviders: ['anthropic', 'unknown-vendor'],
|
|
83
83
|
});
|
|
84
|
-
if (r.status === 404) return;
|
|
84
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
85
85
|
expect(r.body.outcome?.route).toBe('refuse');
|
|
86
86
|
expect(
|
|
87
87
|
r.body.outcome?.fallbackAttempted,
|
|
88
|
-
|
|
88
|
+
req('openwop.it.model-capability-insufficient.unmet-fallback-declared-but-provider-not-in-supportedproviders-refuse-with-fallb',
|
|
89
89
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 3',
|
|
90
90
|
'fallback provider NOT in capabilities.aiProviders.supported[] → host cannot authenticate → fallbackAttempted MUST be true (the attempt failed at credential resolution)',
|
|
91
91
|
),
|
|
@@ -104,11 +104,11 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: dispatch refusal (RFC
|
|
|
104
104
|
substitutionSupported: false,
|
|
105
105
|
supportedProviders: ['anthropic', 'unknown-vendor'],
|
|
106
106
|
});
|
|
107
|
-
if (r.status === 404) return;
|
|
107
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
108
108
|
expect(r.body.outcome?.route).toBe('refuse');
|
|
109
109
|
expect(
|
|
110
110
|
r.body.outcome?.fallbackAttempted,
|
|
111
|
-
|
|
111
|
+
req('openwop.it.model-capability-insufficient.unmet-substitutionsupported-false-host-posture-refuse-with-fallbackattempted-fal',
|
|
112
112
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §E',
|
|
113
113
|
'capabilities.modelCapabilities.substitutionSupported: false → host MUST NOT attempt fallback even when NodeModule.fallbackModel is declared → fallbackAttempted MUST be false (no attempt was made)',
|
|
114
114
|
),
|
|
@@ -130,11 +130,11 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: dispatch refusal (RFC
|
|
|
130
130
|
substitutionSupported: true,
|
|
131
131
|
supportedProviders: ['unknown-vendor', 'unknown-vendor-2'],
|
|
132
132
|
});
|
|
133
|
-
if (r.status === 404) return;
|
|
133
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
134
134
|
expect(r.body.outcome?.route).toBe('refuse');
|
|
135
135
|
expect(
|
|
136
136
|
r.body.outcome?.fallbackAttempted,
|
|
137
|
-
|
|
137
|
+
req('openwop.it.model-capability-insufficient.recursive-fallback-not-permitted-fallback-that-itself-fails-capability-check-ref',
|
|
138
138
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §"Unresolved questions" #3',
|
|
139
139
|
'recursive fallback NOT permitted — when the declared fallback model itself fails the capability check, host MUST refuse with fallbackAttempted: true (NOT chain to another fallback)',
|
|
140
140
|
),
|
|
@@ -152,12 +152,14 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: dispatch refusal (RFC
|
|
|
152
152
|
|
|
153
153
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
154
154
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
155
|
+
import { req } from '../lib/requirement-ids.js';
|
|
156
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
155
157
|
|
|
156
158
|
const E2E_FIXTURE = 'conformance-model-capability-insufficient';
|
|
157
159
|
|
|
158
160
|
describe.skipIf(HTTP_SKIP)('model-capability-insufficient: end-to-end refusal through executor', () => {
|
|
159
161
|
it('workflow with a node declaring requiredModelCapabilities the active provider does not satisfy fails with RunSnapshot.error.code = "capability_not_provided" AND emits model.capability.insufficient into the run event log BEFORE node.failed', async () => {
|
|
160
|
-
if (!isFixtureAdvertised(E2E_FIXTURE)) return; // fixture not seeded — soft-skip
|
|
162
|
+
if (!isFixtureAdvertised(E2E_FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(E2E_FIXTURE)` returned early (fixture not seeded — soft-skip)'); // fixture not seeded — soft-skip
|
|
161
163
|
|
|
162
164
|
const create = await driver.post('/v1/runs', { workflowId: E2E_FIXTURE });
|
|
163
165
|
expect(create.status).toBe(201);
|
|
@@ -167,7 +169,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: end-to-end refusal th
|
|
|
167
169
|
expect(terminal.status).toBe('failed');
|
|
168
170
|
expect(
|
|
169
171
|
(terminal as { error?: { code?: string } }).error?.code,
|
|
170
|
-
|
|
172
|
+
req('openwop.it.model-capability-insufficient.workflow-with-a-node-declaring-requiredmodelcapabilities-the-active-provider-doe',
|
|
171
173
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 4',
|
|
172
174
|
'unmet capability without viable fallback MUST fail with error.code = "capability_not_provided"',
|
|
173
175
|
),
|
|
@@ -178,11 +180,11 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: end-to-end refusal th
|
|
|
178
180
|
const events = ((eventsRes.json as { events?: Array<{ type: string }> } | undefined)?.events ?? []);
|
|
179
181
|
const insufficientIdx = events.findIndex((e) => e.type === 'model.capability.insufficient');
|
|
180
182
|
const nodeFailedIdx = events.findIndex((e) => e.type === 'node.failed');
|
|
181
|
-
expect(insufficientIdx, 'model.capability.insufficient MUST appear in the event log').toBeGreaterThanOrEqual(0);
|
|
182
|
-
expect(nodeFailedIdx, 'node.failed MUST appear in the event log').toBeGreaterThanOrEqual(0);
|
|
183
|
+
expect(insufficientIdx, req('openwop.it.model-capability-insufficient.workflow-with-a-node-declaring-requiredmodelcapabilities-the-active-provider-doe', 'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 4', 'model.capability.insufficient MUST appear in the event log')).toBeGreaterThanOrEqual(0);
|
|
184
|
+
expect(nodeFailedIdx, req('openwop.it.model-capability-insufficient.workflow-with-a-node-declaring-requiredmodelcapabilities-the-active-provider-doe', 'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 4', 'node.failed MUST appear in the event log')).toBeGreaterThanOrEqual(0);
|
|
183
185
|
expect(
|
|
184
186
|
insufficientIdx < nodeFailedIdx,
|
|
185
|
-
|
|
187
|
+
req('openwop.it.model-capability-insufficient.workflow-with-a-node-declaring-requiredmodelcapabilities-the-active-provider-doe',
|
|
186
188
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §D',
|
|
187
189
|
'model.capability.insufficient MUST be emitted BEFORE node.failed (cause precedes effect)',
|
|
188
190
|
),
|
|
@@ -190,7 +192,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: end-to-end refusal th
|
|
|
190
192
|
});
|
|
191
193
|
|
|
192
194
|
it('NO envelope emission occurs after the refusal (no node.completed, provider.usage, or envelope-reliability events)', async () => {
|
|
193
|
-
if (!isFixtureAdvertised(E2E_FIXTURE)) return; // fixture not seeded — soft-skip
|
|
195
|
+
if (!isFixtureAdvertised(E2E_FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(E2E_FIXTURE)` returned early (fixture not seeded — soft-skip)'); // fixture not seeded — soft-skip
|
|
194
196
|
|
|
195
197
|
const create = await driver.post('/v1/runs', { workflowId: E2E_FIXTURE });
|
|
196
198
|
expect(create.status).toBe(201);
|
|
@@ -212,7 +214,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-insufficient: end-to-end refusal th
|
|
|
212
214
|
const leaked = events.filter((e) => forbidden.includes(e.type)).map((e) => e.type);
|
|
213
215
|
expect(
|
|
214
216
|
leaked,
|
|
215
|
-
|
|
217
|
+
req('openwop.it.model-capability-insufficient.no-envelope-emission-occurs-after-the-refusal-no-node-completed-provider-usage-o',
|
|
216
218
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 4',
|
|
217
219
|
'a refused dispatch MUST NOT emit any downstream envelope-emission events — the node never ran',
|
|
218
220
|
),
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
import { describe, it, expect } from 'vitest';
|
|
19
19
|
import { driver } from '../lib/driver.js';
|
|
20
20
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
21
|
+
import { req } from '../lib/requirement-ids.js';
|
|
22
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
21
23
|
|
|
22
24
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
23
25
|
|
|
@@ -64,12 +66,12 @@ async function evaluateGate(input: Record<string, unknown>): Promise<{ status: n
|
|
|
64
66
|
describe.skipIf(HTTP_SKIP)('model-capability-substituted: advertisement shape (RFC 0031 §E)', () => {
|
|
65
67
|
it('capabilities.modelCapabilities (when present) conforms to RFC 0031 §E', async () => {
|
|
66
68
|
const d = await readDiscovery();
|
|
67
|
-
if (d === null) return;
|
|
69
|
+
if (d === null) return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
68
70
|
const mc = capabilityFamily(d, 'modelCapabilities');
|
|
69
|
-
if (mc === undefined) return;
|
|
71
|
+
if (mc === undefined) return softSkip('blocked', 'precondition not met — `mc === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
70
72
|
expect(
|
|
71
73
|
typeof mc.supported,
|
|
72
|
-
|
|
74
|
+
req('openwop.it.model-capability-substituted.capabilities-modelcapabilities-when-present-conforms-to-rfc-0031-e',
|
|
73
75
|
'schemas/capabilities.schema.json §modelCapabilities',
|
|
74
76
|
'capabilities.modelCapabilities.supported MUST be boolean when the block is advertised',
|
|
75
77
|
),
|
|
@@ -77,7 +79,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: advertisement shape (R
|
|
|
77
79
|
if (mc.advertised !== undefined) {
|
|
78
80
|
expect(
|
|
79
81
|
Array.isArray(mc.advertised),
|
|
80
|
-
|
|
82
|
+
req('openwop.it.model-capability-substituted.capabilities-modelcapabilities-when-present-conforms-to-rfc-0031-e', 'RFCS/0031-envelope-variants-and-model-capabilities.md §E', 'modelCapabilities.advertised MUST be an array of capability identifiers'),
|
|
81
83
|
).toBe(true);
|
|
82
84
|
// RFC 0031 §C's five, PLUS the four modality identifiers RFC 0055 §A
|
|
83
85
|
// promoted into the formal vocabulary (Accepted 2026-05-26; registered in
|
|
@@ -89,13 +91,13 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: advertisement shape (R
|
|
|
89
91
|
'vision-input', 'audio-input', 'audio-output', 'image-output',
|
|
90
92
|
];
|
|
91
93
|
for (const id of mc.advertised as unknown[]) {
|
|
92
|
-
expect(typeof id, 'each advertised identifier MUST be a string').toBe('string');
|
|
94
|
+
expect(typeof id, req('openwop.it.model-capability-substituted.capabilities-modelcapabilities-when-present-conforms-to-rfc-0031-e', 'RFCS/0031-envelope-variants-and-model-capabilities.md §E', 'each advertised identifier MUST be a string')).toBe('string');
|
|
93
95
|
const idStr = String(id);
|
|
94
96
|
const isReserved = SPEC_RESERVED.includes(idStr);
|
|
95
97
|
const isHostExt = /^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$/.test(idStr);
|
|
96
98
|
expect(
|
|
97
99
|
isReserved || isHostExt,
|
|
98
|
-
|
|
100
|
+
req('openwop.it.model-capability-substituted.capabilities-modelcapabilities-when-present-conforms-to-rfc-0031-e',
|
|
99
101
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §C',
|
|
100
102
|
`advertised identifier "${idStr}" MUST be spec-reserved (RFC 0031: structured-output, discriminator-enum, long-context, reasoning, function-calling; RFC 0055: vision-input, audio-input, audio-output, image-output) or match the x-host-<host>-<key> extension pattern`,
|
|
101
103
|
),
|
|
@@ -103,7 +105,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: advertisement shape (R
|
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
if (mc.substitutionSupported !== undefined) {
|
|
106
|
-
expect(typeof mc.substitutionSupported, 'substitutionSupported MUST be boolean').toBe('boolean');
|
|
108
|
+
expect(typeof mc.substitutionSupported, req('openwop.it.model-capability-substituted.capabilities-modelcapabilities-when-present-conforms-to-rfc-0031-e', 'RFCS/0031-envelope-variants-and-model-capabilities.md §C', 'substitutionSupported MUST be boolean')).toBe('boolean');
|
|
107
109
|
}
|
|
108
110
|
});
|
|
109
111
|
});
|
|
@@ -117,15 +119,15 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: dispatch behavior (RFC
|
|
|
117
119
|
substitutionSupported: true,
|
|
118
120
|
supportedProviders: ['anthropic', 'openai'],
|
|
119
121
|
});
|
|
120
|
-
if (r.status === 404) return; // host doesn't expose the seam
|
|
122
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (host doesn\'t expose the seam) (seam, prior step, or fixture unavailable)'); // host doesn't expose the seam
|
|
121
123
|
expect(
|
|
122
124
|
r.body.outcome?.route,
|
|
123
|
-
|
|
125
|
+
req('openwop.it.model-capability-substituted.all-required-capabilities-met-outcome-dispatch-no-event-emitted',
|
|
124
126
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 2',
|
|
125
127
|
'all required model capabilities met → route MUST be "dispatch" (gate is a no-op)',
|
|
126
128
|
),
|
|
127
129
|
).toBe('dispatch');
|
|
128
|
-
expect(r.body.event, 'no event emitted when gate is a no-op').toBeNull();
|
|
130
|
+
expect(r.body.event, req('openwop.it.model-capability-substituted.all-required-capabilities-met-outcome-dispatch-no-event-emitted', 'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 2', 'no event emitted when gate is a no-op')).toBeNull();
|
|
129
131
|
});
|
|
130
132
|
|
|
131
133
|
it('unmet + fallback declared + authenticatable → outcome: substitute + event with originalProvider/originalModel/fallbackProvider/fallbackModel/missingCapabilities', async () => {
|
|
@@ -148,23 +150,23 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: dispatch behavior (RFC
|
|
|
148
150
|
supportedProviders: ['anthropic', 'openai', 'unknown-vendor'],
|
|
149
151
|
nodeId: 'writer-node',
|
|
150
152
|
});
|
|
151
|
-
if (r.status === 404) return;
|
|
153
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
152
154
|
expect(
|
|
153
155
|
r.body.outcome?.route,
|
|
154
|
-
|
|
156
|
+
req('openwop.it.model-capability-substituted.unmet-fallback-declared-authenticatable-outcome-substitute-event-with-originalpr',
|
|
155
157
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §B step 3',
|
|
156
158
|
'unmet capability + declared fallback + fallback provider authenticatable → route MUST be "substitute"',
|
|
157
159
|
),
|
|
158
160
|
).toBe('substitute');
|
|
159
161
|
expect(
|
|
160
162
|
r.body.event?.type,
|
|
161
|
-
|
|
163
|
+
req('openwop.it.model-capability-substituted.unmet-fallback-declared-authenticatable-outcome-substitute-event-with-originalpr',
|
|
162
164
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §D',
|
|
163
165
|
'substitute path MUST emit `model.capability.substituted`',
|
|
164
166
|
),
|
|
165
167
|
).toBe('model.capability.substituted');
|
|
166
168
|
const payload = (r.body.event?.payload ?? {}) as Record<string, unknown>;
|
|
167
|
-
expect(payload.nodeId, 'payload.nodeId MUST mirror the request').toBe('writer-node');
|
|
169
|
+
expect(payload.nodeId, req('openwop.it.model-capability-substituted.unmet-fallback-declared-authenticatable-outcome-substitute-event-with-originalpr', 'RFCS/0031-envelope-variants-and-model-capabilities.md §D', 'payload.nodeId MUST mirror the request')).toBe('writer-node');
|
|
168
170
|
expect(payload.originalProvider).toBe('unknown-vendor');
|
|
169
171
|
expect(payload.originalModel).toBe('unknown-model');
|
|
170
172
|
expect(payload.fallbackProvider).toBe('anthropic');
|
|
@@ -172,7 +174,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: dispatch behavior (RFC
|
|
|
172
174
|
expect(
|
|
173
175
|
Array.isArray(payload.missingCapabilities) &&
|
|
174
176
|
(payload.missingCapabilities as string[]).includes('structured-output'),
|
|
175
|
-
|
|
177
|
+
req('openwop.it.model-capability-substituted.unmet-fallback-declared-authenticatable-outcome-substitute-event-with-originalpr',
|
|
176
178
|
'schemas/run-event-payloads.schema.json §modelCapabilitySubstituted',
|
|
177
179
|
'missingCapabilities[] MUST include the subset of required capabilities the active model did not satisfy',
|
|
178
180
|
),
|
|
@@ -192,10 +194,10 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: dispatch behavior (RFC
|
|
|
192
194
|
substitutionSupported: false,
|
|
193
195
|
supportedProviders: ['anthropic', 'unknown-vendor'],
|
|
194
196
|
});
|
|
195
|
-
if (r.status === 404) return;
|
|
197
|
+
if (r.status === 404) return softSkip('blocked', 'precondition not met — `r.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
196
198
|
expect(
|
|
197
199
|
r.body.outcome?.route,
|
|
198
|
-
|
|
200
|
+
req('openwop.it.model-capability-substituted.unmet-substitutionsupported-false-outcome-refuse-with-fallbackattempted-false-ho',
|
|
199
201
|
'RFCS/0031-envelope-variants-and-model-capabilities.md §E',
|
|
200
202
|
'capabilities.modelCapabilities.substitutionSupported: false → host MUST refuse on any unmet capability even when NodeModule.fallbackModel is declared',
|
|
201
203
|
),
|
|
@@ -203,7 +205,7 @@ describe.skipIf(HTTP_SKIP)('model-capability-substituted: dispatch behavior (RFC
|
|
|
203
205
|
expect(r.body.event?.type).toBe('model.capability.insufficient');
|
|
204
206
|
expect(
|
|
205
207
|
(r.body.event?.payload as { fallbackAttempted?: boolean }).fallbackAttempted,
|
|
206
|
-
|
|
208
|
+
req('openwop.it.model-capability-substituted.unmet-substitutionsupported-false-outcome-refuse-with-fallbackattempted-false-ho',
|
|
207
209
|
'schemas/run-event-payloads.schema.json §modelCapabilityInsufficient',
|
|
208
210
|
'fallbackAttempted MUST be false when the refusal is driven by substitutionSupported: false (host posture, not fallback failure)',
|
|
209
211
|
),
|