@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
|
@@ -52,6 +52,7 @@ import { driver } from '../lib/driver.js';
|
|
|
52
52
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
53
53
|
import { pollUntil } from '../lib/polling.js';
|
|
54
54
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
55
|
+
import { req } from '../lib/requirement-ids.js';
|
|
55
56
|
|
|
56
57
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
57
58
|
const FIXTURE = 'conformance-multi-agent-confidence-escalation';
|
|
@@ -92,7 +93,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-confidence-escalation: capability shape
|
|
|
92
93
|
if (floor === undefined) return softSkip('blocked', 'precondition not met — `floor === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
93
94
|
expect(
|
|
94
95
|
typeof floor === 'number' && Number.isFinite(floor) && floor >= 0.5 && floor <= 1.0,
|
|
95
|
-
|
|
96
|
+
req('openwop.it.multi-agent-confidence-escalation.confidenceescalationfloor-when-advertised-must-be-in-0-5-1-0',
|
|
96
97
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A',
|
|
97
98
|
'confidenceEscalationFloor MUST be number in [0.5, 1.0]; values below the spec floor are non-conformant',
|
|
98
99
|
),
|
|
@@ -140,7 +141,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
140
141
|
const expectedStatus = advertisedKind === 'clarification' ? 'waiting-clarification' : 'waiting-approval';
|
|
141
142
|
expect(
|
|
142
143
|
terminal.status,
|
|
143
|
-
|
|
144
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
144
145
|
'RFCS/0044-confidence-escalation-interrupt-kind-advertisement.md §B',
|
|
145
146
|
`host advertising confidenceEscalationInterruptKind: "${advertisedKind}" MUST surface the run as "${expectedStatus}" per spec/v1/interrupt.md §"Interrupt kinds"`,
|
|
146
147
|
),
|
|
@@ -149,7 +150,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
149
150
|
const status = terminal.status as string;
|
|
150
151
|
expect(
|
|
151
152
|
typeof status === 'string' && status.startsWith('waiting-'),
|
|
152
|
-
|
|
153
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
153
154
|
'RFCS/0044-confidence-escalation-interrupt-kind-advertisement.md §B',
|
|
154
155
|
`host advertising vendor confidenceEscalationInterruptKind ("${advertisedKind}") MUST surface the run as a waiting-* status; the suffix is determined by the host's interrupt.md mapping (see the host's vendor-extensions doc per RFC 0044 §C)`,
|
|
155
156
|
),
|
|
@@ -159,7 +160,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
159
160
|
const acceptedStatuses = ['waiting-clarification', 'waiting-approval'];
|
|
160
161
|
expect(
|
|
161
162
|
acceptedStatuses.includes(terminal.status as string),
|
|
162
|
-
|
|
163
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
163
164
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A + spec/v1/interrupt.md',
|
|
164
165
|
'a host below the confidence floor MUST surface the run as `waiting-clarification` (clarify-kind escalation) OR `waiting-approval` (escalate-kind escalation) per RFC 0039 §A; the low-confidence decision MUST NOT reach `completed` because no dispatch fired',
|
|
165
166
|
),
|
|
@@ -171,21 +172,21 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
171
172
|
const events = ((eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? []);
|
|
172
173
|
|
|
173
174
|
const escalated = events.filter((e) => e.type === 'core.workflowChain.confidence-escalated');
|
|
174
|
-
expect(escalated.length,
|
|
175
|
+
expect(escalated.length, req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
175
176
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A',
|
|
176
177
|
'low-confidence decision MUST emit exactly one core.workflowChain.confidence-escalated event',
|
|
177
178
|
)).toBe(1);
|
|
178
179
|
|
|
179
180
|
const ev = escalated[0]!;
|
|
180
181
|
const payload = (ev.payload ?? {}) as { confidence?: number; floor?: number; escalationKind?: string; workerId?: string };
|
|
181
|
-
expect(payload.confidence, 'payload.confidence echoes the decision').toBe(0.3);
|
|
182
|
+
expect(payload.confidence, req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte', 'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A', 'payload.confidence echoes the decision')).toBe(0.3);
|
|
182
183
|
expect(
|
|
183
184
|
typeof payload.floor === 'number' && payload.floor >= 0.5 && payload.floor <= 1.0,
|
|
184
|
-
'payload.floor is the host-advertised floor (in [0.5, 1.0])',
|
|
185
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte', 'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A', 'payload.floor is the host-advertised floor (in [0.5, 1.0])'),
|
|
185
186
|
).toBe(true);
|
|
186
187
|
expect(
|
|
187
188
|
payload.escalationKind === 'clarify' || payload.escalationKind === 'escalate',
|
|
188
|
-
'payload.escalationKind ∈ {clarify, escalate}',
|
|
189
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte', 'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A', 'payload.escalationKind ∈ {clarify, escalate}'),
|
|
189
190
|
).toBe(true);
|
|
190
191
|
|
|
191
192
|
// Causation (S32, 2026-08-17): this leg used to REQUIRE `causationId` → a
|
|
@@ -202,7 +203,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
202
203
|
const cause = events.find((e) => e.eventId === ev.causationId);
|
|
203
204
|
expect(
|
|
204
205
|
cause !== undefined,
|
|
205
|
-
|
|
206
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
206
207
|
'spec/v1/multi-agent-execution.md §"Confidence escalation"',
|
|
207
208
|
`confidence-escalated causationId (${ev.causationId}) MUST resolve to an event on this run's log when present`,
|
|
208
209
|
),
|
|
@@ -211,14 +212,14 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-confidence-escalation: behavioral
|
|
|
211
212
|
const original = (ev.payload as { originalDecision?: unknown } | undefined)?.originalDecision;
|
|
212
213
|
expect(
|
|
213
214
|
original !== null && typeof original === 'object',
|
|
214
|
-
|
|
215
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte', 'run-event-payloads.schema.json §confidence-escalated', 'payload.originalDecision carries the escalated OrchestratorDecision verbatim — the decision is on the log HERE, not on a prior decided event'),
|
|
215
216
|
).toBe(true);
|
|
216
217
|
|
|
217
218
|
// Load-bearing: NO dispatch event fired. RFC 0039 gates BEFORE the loop.
|
|
218
219
|
const chainEvents = events.filter((e) => e.type === 'core.workflowChain.event');
|
|
219
220
|
expect(
|
|
220
221
|
chainEvents.length,
|
|
221
|
-
|
|
222
|
+
req('openwop.it.multi-agent-confidence-escalation.happy-path-low-confidence-decision-confidence-escalated-event-clarification-inte',
|
|
222
223
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §A',
|
|
223
224
|
'low-confidence decision MUST NOT produce any core.workflowChain.event records — the escalation fires before any dispatch.began per the spec ordering',
|
|
224
225
|
),
|
|
@@ -37,6 +37,7 @@ import { executionModelVersionMax } from '../lib/execution-model-version.js';
|
|
|
37
37
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
38
38
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
39
39
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
40
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
41
|
|
|
41
42
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
42
43
|
|
|
@@ -69,14 +70,14 @@ describe.skipIf(HTTP_SKIP)('multi-agent-handoff-state-machine: advertisement sha
|
|
|
69
70
|
if (executionModel === undefined) return softSkip('inapplicable', 'host doesn\'t advertise — soft-skip');
|
|
70
71
|
expect(
|
|
71
72
|
typeof executionModel.supported,
|
|
72
|
-
|
|
73
|
+
req('openwop.it.multi-agent-handoff-state-machine.capabilities-multiagent-executionmodel-when-present-conforms-to-rfc-0037-c',
|
|
73
74
|
'RFCS/0037-multi-agent-execution-model.md §C',
|
|
74
75
|
'capabilities.multiAgent.executionModel.supported MUST be boolean when present',
|
|
75
76
|
),
|
|
76
77
|
).toBe('boolean');
|
|
77
78
|
expect(
|
|
78
79
|
typeof executionModel.version,
|
|
79
|
-
|
|
80
|
+
req('openwop.it.multi-agent-handoff-state-machine.capabilities-multiagent-executionmodel-when-present-conforms-to-rfc-0037-c',
|
|
80
81
|
'RFCS/0037-multi-agent-execution-model.md §C',
|
|
81
82
|
'capabilities.multiAgent.executionModel.version MUST be integer when present',
|
|
82
83
|
),
|
|
@@ -87,7 +88,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-handoff-state-machine: advertisement sha
|
|
|
87
88
|
const max = executionModelVersionMax();
|
|
88
89
|
expect(
|
|
89
90
|
Number.isInteger(v) && v >= 1 && v <= max,
|
|
90
|
-
|
|
91
|
+
req('openwop.it.multi-agent-handoff-state-machine.capabilities-multiagent-executionmodel-when-present-conforms-to-rfc-0037-c',
|
|
91
92
|
'RFCS/0037-multi-agent-execution-model.md §C',
|
|
92
93
|
`version MUST be an integer in [1, ${max}] (1 = Phase 1 only; later phases lift the ceiling additively — 5 = RFC 0061 stateful agent-loop lifecycle, 6 = RFC 0090 verifier; the ceiling is \`capabilities.schema.json\` §multiAgent.executionModel.version maximum)`,
|
|
93
94
|
),
|
|
@@ -118,7 +119,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-handoff-state-machine: behavioral
|
|
|
118
119
|
const runId = (create.json as { runId: string }).runId;
|
|
119
120
|
|
|
120
121
|
const terminal = await pollUntilTerminal(runId);
|
|
121
|
-
expect(terminal.status,
|
|
122
|
+
expect(terminal.status, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
122
123
|
'spec/v1/multi-agent-execution.md §"Execution loop"',
|
|
123
124
|
'parent run with supervisor → next-worker → terminate MUST reach terminal `completed`',
|
|
124
125
|
)).toBe('completed');
|
|
@@ -128,13 +129,13 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-handoff-state-machine: behavioral
|
|
|
128
129
|
const events = ((eventsRes.json as { events?: RunEvent[] } | undefined)?.events ?? []);
|
|
129
130
|
const chainEvents = events.filter((e) => e.type === 'core.workflowChain.event');
|
|
130
131
|
|
|
131
|
-
expect(chainEvents.length,
|
|
132
|
+
expect(chainEvents.length, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
132
133
|
'RFCS/0037-multi-agent-execution-model.md §"Conformance"',
|
|
133
134
|
'happy-path fixture MUST produce 4 core.workflowChain.event records (dispatch.began, dispatch.succeeded, child.completed, output.harvested)',
|
|
134
135
|
)).toBe(4);
|
|
135
136
|
|
|
136
137
|
const phases = chainEvents.map((e) => (e.payload as { phase?: string } | undefined)?.phase);
|
|
137
|
-
expect(phases,
|
|
138
|
+
expect(phases, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
138
139
|
'spec/v1/multi-agent-execution.md §"Transition events"',
|
|
139
140
|
'phase order MUST be dispatch.began → dispatch.succeeded → child.completed → output.harvested',
|
|
140
141
|
)).toEqual(['dispatch.began', 'dispatch.succeeded', 'child.completed', 'output.harvested']);
|
|
@@ -144,7 +145,7 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-handoff-state-machine: behavioral
|
|
|
144
145
|
for (let i = 1; i < chainEvents.length; i++) {
|
|
145
146
|
const prior = chainEvents[i - 1];
|
|
146
147
|
const cur = chainEvents[i];
|
|
147
|
-
expect(cur?.causationId,
|
|
148
|
+
expect(cur?.causationId, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
148
149
|
'spec/v1/multi-agent-execution.md §"Transition events"',
|
|
149
150
|
`core.workflowChain.event #${i} (${phases[i]}) MUST have causationId === prior event's eventId`,
|
|
150
151
|
)).toBe(prior?.eventId);
|
|
@@ -154,14 +155,14 @@ describe.skipIf(BEHAVIORAL_SKIP)('multi-agent-handoff-state-machine: behavioral
|
|
|
154
155
|
const dispatchBegan = chainEvents[0];
|
|
155
156
|
expect(dispatchBegan?.causationId).toBeDefined();
|
|
156
157
|
const decidedEvent = events.find((e) => e.eventId === dispatchBegan?.causationId);
|
|
157
|
-
expect(decidedEvent?.type,
|
|
158
|
+
expect(decidedEvent?.type, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
158
159
|
'spec/v1/multi-agent-execution.md §"Transition events"',
|
|
159
160
|
'dispatch.began causationId MUST point at the runOrchestrator.decided event that named this worker',
|
|
160
161
|
)).toBe('runOrchestrator.decided');
|
|
161
162
|
|
|
162
163
|
// output.harvested.harvestedKeys MUST list the outputMapping keys harvested.
|
|
163
164
|
const harvested = chainEvents[3]?.payload as { harvestedKeys?: string[] } | undefined;
|
|
164
|
-
expect(harvested?.harvestedKeys,
|
|
165
|
+
expect(harvested?.harvestedKeys, req('openwop.it.multi-agent-handoff-state-machine.happy-path-dispatch-began-dispatch-succeeded-child-completed-output-harvested-fi',
|
|
165
166
|
'spec/v1/multi-agent-execution.md §"Transition events"',
|
|
166
167
|
'output.harvested payload MUST list harvested parent-variable keys (the fixture\'s outputMapping is { parentResult: \'childOutcome\' })',
|
|
167
168
|
)).toEqual(['parentResult']);
|
|
@@ -50,6 +50,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
50
50
|
import { softSkip } from '../lib/soft-skip.js';
|
|
51
51
|
import { driver } from '../lib/driver.js';
|
|
52
52
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
53
|
+
import { req } from '../lib/requirement-ids.js';
|
|
53
54
|
|
|
54
55
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
55
56
|
|
|
@@ -82,17 +83,17 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: advertisement shape (R
|
|
|
82
83
|
if (d === null) {
|
|
83
84
|
softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
84
85
|
ctx.skip();
|
|
85
|
-
return;
|
|
86
|
+
return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
86
87
|
}
|
|
87
88
|
const ccmc = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.crossChildMemoryConcurrency;
|
|
88
89
|
if (ccmc === undefined) {
|
|
89
90
|
softSkip('inapplicable', 'optional advertisement — `multiAgent.executionModel.crossChildMemoryConcurrency` not advertised by this host');
|
|
90
91
|
ctx.skip(); // optional advertisement — host hasn't opted in
|
|
91
|
-
return;
|
|
92
|
+
return softSkip('blocked', 'precondition not met — `ccmc === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
92
93
|
}
|
|
93
94
|
expect(
|
|
94
95
|
ccmc === 'strict' || ccmc === 'advisory',
|
|
95
|
-
|
|
96
|
+
req('openwop.it.multi-agent-memory-lifecycle.crosschildmemoryconcurrency-when-advertised-must-be-one-of-strict-advisory',
|
|
96
97
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B',
|
|
97
98
|
'crossChildMemoryConcurrency MUST be one of {strict, advisory} when present; values outside the closed enum are non-conformant',
|
|
98
99
|
),
|
|
@@ -138,7 +139,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
138
139
|
if (d === null) {
|
|
139
140
|
softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
140
141
|
ctx.skip();
|
|
141
|
-
return;
|
|
142
|
+
return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
142
143
|
}
|
|
143
144
|
const v = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.version;
|
|
144
145
|
const memorySupported = capabilityFamily<{ supported?: unknown }>(d, 'memory')?.supported;
|
|
@@ -147,7 +148,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
147
148
|
if (!phase2OrLater || memorySupported !== true || !expiredRunId) {
|
|
148
149
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!phase2OrLater || memorySupported !== true || !expiredRunId` returned early');
|
|
149
150
|
ctx.skip();
|
|
150
|
-
return;
|
|
151
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!phase2OrLater || memorySupported !== true || !expiredRunId` returned early');
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
const fromSeq = 0;
|
|
@@ -158,7 +159,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
158
159
|
|
|
159
160
|
expect(
|
|
160
161
|
res.status,
|
|
161
|
-
|
|
162
|
+
req('openwop.it.multi-agent-memory-lifecycle.mae-3-replay-snapshot-refusal-fork-mode-replay-against-a-past-retention-runid-mu',
|
|
162
163
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B MAE-3',
|
|
163
164
|
'fork mode:replay against a past-retention runId MUST refuse with 422; silent substitution of current memory is non-conformant',
|
|
164
165
|
),
|
|
@@ -171,7 +172,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
171
172
|
|
|
172
173
|
expect(
|
|
173
174
|
body?.error,
|
|
174
|
-
|
|
175
|
+
req('openwop.it.multi-agent-memory-lifecycle.mae-3-replay-snapshot-refusal-fork-mode-replay-against-a-past-retention-runid-mu',
|
|
175
176
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B MAE-3',
|
|
176
177
|
'refusal envelope error code MUST be "replay_memory_snapshot_unavailable" (distinct from the pre-flight invalid_from_seq gate)',
|
|
177
178
|
),
|
|
@@ -179,7 +180,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
179
180
|
|
|
180
181
|
expect(
|
|
181
182
|
body?.details?.fromSeq,
|
|
182
|
-
|
|
183
|
+
req('openwop.it.multi-agent-memory-lifecycle.mae-3-replay-snapshot-refusal-fork-mode-replay-against-a-past-retention-runid-mu',
|
|
183
184
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B MAE-3',
|
|
184
185
|
'refusal envelope details.fromSeq MUST echo the requested fromSeq',
|
|
185
186
|
),
|
|
@@ -187,7 +188,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
187
188
|
|
|
188
189
|
expect(
|
|
189
190
|
body?.details?.sourceRunId,
|
|
190
|
-
|
|
191
|
+
req('openwop.it.multi-agent-memory-lifecycle.mae-3-replay-snapshot-refusal-fork-mode-replay-against-a-past-retention-runid-mu',
|
|
191
192
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B MAE-3',
|
|
192
193
|
'refusal envelope details.sourceRunId MUST echo the runId from the URL',
|
|
193
194
|
),
|
|
@@ -196,7 +197,7 @@ describe.skipIf(HTTP_SKIP)('multi-agent-memory-lifecycle: behavioral (RFC 0039
|
|
|
196
197
|
const reason = body?.details?.reason;
|
|
197
198
|
expect(
|
|
198
199
|
reason === 'retention_expired' || reason === 'event_log_unavailable',
|
|
199
|
-
|
|
200
|
+
req('openwop.it.multi-agent-memory-lifecycle.mae-3-replay-snapshot-refusal-fork-mode-replay-against-a-past-retention-runid-mu',
|
|
200
201
|
'RFCS/0039-multi-agent-confidence-and-memory-lifecycle.md §B MAE-3',
|
|
201
202
|
'refusal envelope details.reason MUST be one of {"retention_expired", "event_log_unavailable"}',
|
|
202
203
|
),
|
|
@@ -14,6 +14,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
14
14
|
import { driver } from '../lib/driver.js';
|
|
15
15
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
16
16
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
17
|
+
import { req } from '../lib/requirement-ids.js';
|
|
17
18
|
|
|
18
19
|
const WORKFLOW_ID = 'conformance-multi-node';
|
|
19
20
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
|
|
@@ -33,7 +34,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('multi-node: conformance-multi-node fixture emi
|
|
|
33
34
|
const runId = (create.json as { runId: string }).runId;
|
|
34
35
|
|
|
35
36
|
const terminal = await pollUntilTerminal(runId);
|
|
36
|
-
expect(terminal.status,
|
|
37
|
+
expect(terminal.status, req('openwop.it.multi-node-ordering.a-b-c-node-completed-events-arrive-in-dag-order-by-sequence',
|
|
37
38
|
'fixtures.md conformance-multi-node §Terminal status',
|
|
38
39
|
'fixture MUST reach terminal `completed`',
|
|
39
40
|
)).toBe('completed');
|
|
@@ -41,7 +42,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('multi-node: conformance-multi-node fixture emi
|
|
|
41
42
|
const eventsRes = await driver.get(
|
|
42
43
|
`/v1/runs/${encodeURIComponent(runId)}/events/poll?lastSequence=0&timeout=1`,
|
|
43
44
|
);
|
|
44
|
-
expect(eventsRes.status,
|
|
45
|
+
expect(eventsRes.status, req('openwop.it.multi-node-ordering.a-b-c-node-completed-events-arrive-in-dag-order-by-sequence',
|
|
45
46
|
'rest-endpoints.md GET /v1/runs/{runId}/events/poll',
|
|
46
47
|
'event-poll MUST return 200 for known runs',
|
|
47
48
|
)).toBe(200);
|
|
@@ -52,7 +53,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('multi-node: conformance-multi-node fixture emi
|
|
|
52
53
|
.sort((x, y) => x.sequence - y.sequence)
|
|
53
54
|
.map((e) => e.nodeId);
|
|
54
55
|
|
|
55
|
-
expect(nodeCompletions,
|
|
56
|
+
expect(nodeCompletions, req('openwop.it.multi-node-ordering.a-b-c-node-completed-events-arrive-in-dag-order-by-sequence',
|
|
56
57
|
'fixtures.md conformance-multi-node §Topology',
|
|
57
58
|
'all three node.completed events (a, b, c) MUST be present',
|
|
58
59
|
)).toEqual(['a', 'b', 'c']);
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
|
|
40
40
|
import { describe, it, expect } from 'vitest';
|
|
41
41
|
import { seamAbsent } from '../lib/soft-skip.js';
|
|
42
|
-
import { driver } from '../lib/driver.js';
|
|
43
42
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
44
43
|
import { isMultiPartyConversationSupported } from '../lib/multi-agent-capabilities.js';
|
|
45
44
|
import {
|
|
@@ -50,6 +49,7 @@ import {
|
|
|
50
49
|
type SeamAgentRef,
|
|
51
50
|
type SeamTurn,
|
|
52
51
|
} from '../lib/multiPartyConversation.js';
|
|
52
|
+
import { req } from '../lib/requirement-ids.js';
|
|
53
53
|
|
|
54
54
|
const PROFILE = 'openwop-multi-party-conversation';
|
|
55
55
|
|
|
@@ -84,7 +84,7 @@ describe('multi-party-conversation-behavioral (RFC 0101 §Conformance)', () => {
|
|
|
84
84
|
if (opened.unwired) return seamAbsent('host advertises multiPartyConversation but the open-conversation seam is not wired');
|
|
85
85
|
expect(
|
|
86
86
|
opened.status === 200,
|
|
87
|
-
|
|
87
|
+
req('openwop.it.multi-party-conversation-behavioral.opens-a-council-accepts-an-attributed-turn-and-rejects-missing-non-participant-o', 'RFC 0101 §Spec', 'a conforming 3-agent council MUST open (≤ maxParticipants)'),
|
|
88
88
|
).toBe(true);
|
|
89
89
|
|
|
90
90
|
// ---- MUST 1: POSITIVE — a roster-valid attributed turn is accepted ----
|
|
@@ -92,7 +92,7 @@ describe('multi-party-conversation-behavioral (RFC 0101 §Conformance)', () => {
|
|
|
92
92
|
if (ok.unwired) return seamAbsent('host advertises multiPartyConversation but the conversation seam is not wired');
|
|
93
93
|
expect(
|
|
94
94
|
ok.status === 200,
|
|
95
|
-
|
|
95
|
+
req('openwop.it.multi-party-conversation-behavioral.opens-a-council-accepts-an-attributed-turn-and-rejects-missing-non-participant-o', 'RFC 0101 §Spec', "a role:'agent' turn with an in-roster speakerId MUST be accepted"),
|
|
96
96
|
).toBe(true);
|
|
97
97
|
|
|
98
98
|
// ---- MUST 2: ATTRIBUTION — agent turn missing speakerId is rejected ---
|
|
@@ -102,7 +102,7 @@ describe('multi-party-conversation-behavioral (RFC 0101 §Conformance)', () => {
|
|
|
102
102
|
if (!missingRes.unwired) {
|
|
103
103
|
expect(
|
|
104
104
|
isValidationErrorRejection(missingRes),
|
|
105
|
-
|
|
105
|
+
req('openwop.it.multi-party-conversation-behavioral.opens-a-council-accepts-an-attributed-turn-and-rejects-missing-non-participant-o', 'RFC 0101 §Spec (attribution MUST)', "a role:'agent' turn missing speakerId MUST be rejected with validation_error"),
|
|
106
106
|
).toBe(true);
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -112,7 +112,7 @@ describe('multi-party-conversation-behavioral (RFC 0101 §Conformance)', () => {
|
|
|
112
112
|
if (!intruderRes.unwired) {
|
|
113
113
|
expect(
|
|
114
114
|
isValidationErrorRejection(intruderRes),
|
|
115
|
-
|
|
115
|
+
req('openwop.it.multi-party-conversation-behavioral.opens-a-council-accepts-an-attributed-turn-and-rejects-missing-non-participant-o', 'RFC 0101 §Spec (membership MUST) / RFC 0005 §E', 'a turn whose speakerId is not in the roster MUST be rejected with validation_error'),
|
|
116
116
|
).toBe(true);
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -130,7 +130,7 @@ describe('multi-party-conversation-behavioral (RFC 0101 §Conformance)', () => {
|
|
|
130
130
|
if (!overRes.unwired) {
|
|
131
131
|
expect(
|
|
132
132
|
isValidationErrorRejection(overRes),
|
|
133
|
-
|
|
133
|
+
req('openwop.it.multi-party-conversation-behavioral.opens-a-council-accepts-an-attributed-turn-and-rejects-missing-non-participant-o', 'RFC 0101 §Spec (maxParticipants MUST)', 'an open whose roster exceeds the advertised maxParticipants MUST be rejected with validation_error'),
|
|
134
134
|
).toBe(true);
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -44,9 +44,7 @@ import { join } from 'node:path';
|
|
|
44
44
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
45
45
|
import addFormats from 'ajv-formats';
|
|
46
46
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
47
|
-
|
|
48
|
-
/** Server-free assertion-message helper. */
|
|
49
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
47
|
+
import { req } from '../lib/requirement-ids.js';
|
|
50
48
|
|
|
51
49
|
function loadSchema(name: string): Record<string, unknown> {
|
|
52
50
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -59,7 +57,7 @@ describe('multi-party-conversation-shape: participant roster on conversation.ope
|
|
|
59
57
|
const opened = ajv.getSchema('conversation-event#/$defs/ConversationOpenedPayload');
|
|
60
58
|
|
|
61
59
|
it('the ConversationOpenedPayload $def exists and declares participants: AgentRef[]', () => {
|
|
62
|
-
expect(opened, 'the ConversationOpenedPayload $def MUST exist').toBeTruthy();
|
|
60
|
+
expect(opened, req('openwop.it.multi-party-conversation-shape.the-conversationopenedpayload-def-exists-and-declares-participants-agentref', 'RFC 0101', 'the ConversationOpenedPayload $def MUST exist')).toBeTruthy();
|
|
63
61
|
});
|
|
64
62
|
|
|
65
63
|
it('a conforming 3-agent council transcript (participant roster + user opening turn) validates', () => {
|
|
@@ -80,7 +78,7 @@ describe('multi-party-conversation-shape: participant roster on conversation.ope
|
|
|
80
78
|
turnIndex: 0,
|
|
81
79
|
},
|
|
82
80
|
};
|
|
83
|
-
expect(opened!(good),
|
|
81
|
+
expect(opened!(good), req('openwop.it.multi-party-conversation-shape.a-conforming-3-agent-council-transcript-participant-roster-user-opening-turn-val', 'RFC 0101 §Schema', 'a conversation.opened with a participant roster MUST validate')).toBe(true);
|
|
84
82
|
});
|
|
85
83
|
|
|
86
84
|
it('a participant entry that is not a valid AgentRef (no agentId) is rejected', () => {
|
|
@@ -96,7 +94,7 @@ describe('multi-party-conversation-shape: participant roster on conversation.ope
|
|
|
96
94
|
turnIndex: 0,
|
|
97
95
|
},
|
|
98
96
|
};
|
|
99
|
-
expect(opened!(bad),
|
|
97
|
+
expect(opened!(bad), req('openwop.it.multi-party-conversation-shape.a-participant-entry-that-is-not-a-valid-agentref-no-agentid-is-rejected', 'RFC 0101 §Schema', 'a participants[] item without agentId MUST be rejected')).toBe(false);
|
|
100
98
|
});
|
|
101
99
|
|
|
102
100
|
it('participants is OPTIONAL — a single-agent conversation.opened (no roster) still validates (back-compat)', () => {
|
|
@@ -112,7 +110,7 @@ describe('multi-party-conversation-shape: participant roster on conversation.ope
|
|
|
112
110
|
turnIndex: 0,
|
|
113
111
|
},
|
|
114
112
|
};
|
|
115
|
-
expect(opened!(noRoster),
|
|
113
|
+
expect(opened!(noRoster), req('openwop.it.multi-party-conversation-shape.participants-is-optional-a-single-agent-conversation-opened-no-roster-still-vali', 'RFC 0101 §Compatibility', 'participants is additive — a roster-less conversation MUST still validate')).toBe(true);
|
|
116
114
|
});
|
|
117
115
|
});
|
|
118
116
|
|
|
@@ -133,25 +131,25 @@ describe('multi-party-conversation-shape: per-turn speaker attribution (RFC 0101
|
|
|
133
131
|
it('an agent turn WITH a roster-instance speakerId validates', () => {
|
|
134
132
|
expect(
|
|
135
133
|
turn({ ...agentBase, speakerId: 'host:advisor-cfo' }),
|
|
136
|
-
|
|
134
|
+
req('openwop.it.multi-party-conversation-shape.an-agent-turn-with-a-roster-instance-speakerid-validates', 'RFC 0101 §Schema', "a role:'agent' turn carrying speakerId MUST validate"),
|
|
137
135
|
).toBe(true);
|
|
138
136
|
});
|
|
139
137
|
|
|
140
138
|
it("a role:'agent' turn MISSING speakerId MUST fail schema validation (the attribution MUST)", () => {
|
|
141
139
|
expect(
|
|
142
140
|
turn(agentBase),
|
|
143
|
-
|
|
141
|
+
req('openwop.it.multi-party-conversation-shape.a-role-agent-turn-missing-speakerid-must-fail-schema-validation-the-attribution', 'RFC 0101 §Schema', "a role:'agent' turn that omits speakerId MUST be rejected (the conditional required)"),
|
|
144
142
|
).toBe(false);
|
|
145
143
|
});
|
|
146
144
|
|
|
147
145
|
it("speakerId is OPTIONAL for role:'user' / role:'system' turns (additive — pre-RFC-0101 producers)", () => {
|
|
148
146
|
expect(
|
|
149
147
|
turn({ messageId: 'council-q1:0:user', from: 'user', content: 'Q3 or Q4?', ts: 1, role: 'user', turnIndex: 0 }),
|
|
150
|
-
|
|
148
|
+
req('openwop.it.multi-party-conversation-shape.speakerid-is-optional-for-role-user-role-system-turns-additive-pre-rfc-0101-prod', 'RFC 0101 §Compatibility', "a role:'user' turn without speakerId MUST still validate"),
|
|
151
149
|
).toBe(true);
|
|
152
150
|
expect(
|
|
153
151
|
turn({ messageId: 'council-q1:9:system', from: 'system', content: 'conversation timed out', ts: 1, role: 'system', turnIndex: 9 }),
|
|
154
|
-
|
|
152
|
+
req('openwop.it.multi-party-conversation-shape.speakerid-is-optional-for-role-user-role-system-turns-additive-pre-rfc-0101-prod', 'RFC 0101 §Compatibility', "a role:'system' turn without speakerId MUST still validate"),
|
|
155
153
|
).toBe(true);
|
|
156
154
|
});
|
|
157
155
|
});
|
|
@@ -166,13 +164,13 @@ describe('multi-party-conversation-shape: non-participant turn detection (RFC 01
|
|
|
166
164
|
const roster = new Set(['host:advisor-cfo', 'host:advisor-cmo', 'host:advisor-cto']);
|
|
167
165
|
|
|
168
166
|
it('a turn whose speakerId IS a participant is admissible', () => {
|
|
169
|
-
expect(roster.has('host:advisor-cmo'),
|
|
167
|
+
expect(roster.has('host:advisor-cmo'), req('openwop.it.multi-party-conversation-shape.a-turn-whose-speakerid-is-a-participant-is-admissible', 'RFC 0101 §Spec', 'an agent in the roster MAY speak')).toBe(true);
|
|
170
168
|
});
|
|
171
169
|
|
|
172
170
|
it('a turn whose speakerId is NOT a participant MUST be rejected by the host (roster membership)', () => {
|
|
173
171
|
expect(
|
|
174
172
|
roster.has('host:advisor-intruder'),
|
|
175
|
-
|
|
173
|
+
req('openwop.it.multi-party-conversation-shape.a-turn-whose-speakerid-is-not-a-participant-must-be-rejected-by-the-host-roster', 'RFC 0101 §Spec', 'a turn from a non-participant agent MUST be rejected'),
|
|
176
174
|
).toBe(false);
|
|
177
175
|
});
|
|
178
176
|
});
|
|
@@ -184,11 +182,11 @@ describe('multi-party-conversation-shape: capability advertisement (RFC 0101 §S
|
|
|
184
182
|
const mpc = props.multiPartyConversation as
|
|
185
183
|
| { properties?: Record<string, unknown>; required?: string[]; additionalProperties?: boolean }
|
|
186
184
|
| undefined;
|
|
187
|
-
expect(mpc,
|
|
188
|
-
expect(mpc?.properties?.supported,
|
|
189
|
-
expect(mpc?.properties?.maxParticipants,
|
|
190
|
-
expect(mpc?.required,
|
|
191
|
-
expect(mpc?.additionalProperties,
|
|
185
|
+
expect(mpc, req('openwop.it.multi-party-conversation-shape.capabilities-schema-json-declares-multipartyconversation-with-supported-optional', 'RFC 0101 §Schema', 'capabilities.multiPartyConversation MUST be declared')).toBeDefined();
|
|
186
|
+
expect(mpc?.properties?.supported, req('openwop.it.multi-party-conversation-shape.capabilities-schema-json-declares-multipartyconversation-with-supported-optional', 'RFC 0101 §Schema', 'multiPartyConversation.supported MUST be declared')).toBeDefined();
|
|
187
|
+
expect(mpc?.properties?.maxParticipants, req('openwop.it.multi-party-conversation-shape.capabilities-schema-json-declares-multipartyconversation-with-supported-optional', 'RFC 0101 §Schema', 'multiPartyConversation.maxParticipants MUST be declared (optional)')).toBeDefined();
|
|
188
|
+
expect(mpc?.required, req('openwop.it.multi-party-conversation-shape.capabilities-schema-json-declares-multipartyconversation-with-supported-optional', 'RFC 0101 §Schema', 'supported MUST be required on the block')).toContain('supported');
|
|
189
|
+
expect(mpc?.additionalProperties, req('openwop.it.multi-party-conversation-shape.capabilities-schema-json-declares-multipartyconversation-with-supported-optional', 'RFC 0101 §Schema', 'the multiPartyConversation block MUST be closed')).toBe(false);
|
|
192
190
|
});
|
|
193
191
|
|
|
194
192
|
it('the multiPartyConversation block validates a conforming advertisement and rejects extras', () => {
|
|
@@ -197,10 +195,10 @@ describe('multi-party-conversation-shape: capability advertisement (RFC 0101 §S
|
|
|
197
195
|
const ajv = new Ajv2020({ strict: false, allErrors: true });
|
|
198
196
|
addFormats(ajv);
|
|
199
197
|
const validate = ajv.compile(mpc);
|
|
200
|
-
expect(validate({ supported: true, maxParticipants: 8 }),
|
|
201
|
-
expect(validate({ supported: true }),
|
|
202
|
-
expect(validate({ maxParticipants: 8 }),
|
|
203
|
-
expect(validate({ supported: true, unexpected: 1 }),
|
|
204
|
-
expect(validate({ supported: true, maxParticipants: 1 }),
|
|
198
|
+
expect(validate({ supported: true, maxParticipants: 8 }), req('openwop.it.multi-party-conversation-shape.the-multipartyconversation-block-validates-a-conforming-advertisement-and-reject', 'RFC 0101 §Schema', 'a conforming advertisement MUST validate')).toBe(true);
|
|
199
|
+
expect(validate({ supported: true }), req('openwop.it.multi-party-conversation-shape.the-multipartyconversation-block-validates-a-conforming-advertisement-and-reject', 'RFC 0101 §Schema', 'maxParticipants is optional')).toBe(true);
|
|
200
|
+
expect(validate({ maxParticipants: 8 }), req('openwop.it.multi-party-conversation-shape.the-multipartyconversation-block-validates-a-conforming-advertisement-and-reject', 'RFC 0101 §Schema', 'supported is required')).toBe(false);
|
|
201
|
+
expect(validate({ supported: true, unexpected: 1 }), req('openwop.it.multi-party-conversation-shape.the-multipartyconversation-block-validates-a-conforming-advertisement-and-reject', 'RFC 0101 §Schema', 'an extra key MUST be rejected (closed block)')).toBe(false);
|
|
202
|
+
expect(validate({ supported: true, maxParticipants: 1 }), req('openwop.it.multi-party-conversation-shape.the-multipartyconversation-block-validates-a-conforming-advertisement-and-reject', 'RFC 0101 §Schema', 'maxParticipants minimum is 2 (a council has ≥2)')).toBe(false);
|
|
205
203
|
});
|
|
206
204
|
});
|
|
@@ -34,6 +34,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
34
34
|
import { softSkip, seamAbsent } from '../lib/soft-skip.js';
|
|
35
35
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
36
36
|
import { driver } from '../lib/driver.js';
|
|
37
|
+
import { req } from '../lib/requirement-ids.js';
|
|
37
38
|
|
|
38
39
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
39
40
|
|
|
@@ -81,18 +82,18 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
81
82
|
if (probe.status === 404) {
|
|
82
83
|
await noteSimulatorAbsent();
|
|
83
84
|
ctx.skip(); // host doesn't expose the simulator seam
|
|
84
|
-
return;
|
|
85
|
+
return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
85
86
|
}
|
|
86
87
|
expect(
|
|
87
88
|
probe.status,
|
|
88
|
-
|
|
89
|
+
req('openwop.it.multi-region-idempotency-behavior.two-region-conflict-resolves-to-the-lex-min-runid-per-annex-convergence-rule',
|
|
89
90
|
'idempotency.md §"Multi-region idempotency annex"',
|
|
90
91
|
'simulate-partition seam MUST return 200 when ≥2 conflicting claims are submitted',
|
|
91
92
|
),
|
|
92
93
|
).toBe(200);
|
|
93
94
|
expect(
|
|
94
95
|
probe.body.winner?.runId,
|
|
95
|
-
|
|
96
|
+
req('openwop.it.multi-region-idempotency-behavior.two-region-conflict-resolves-to-the-lex-min-runid-per-annex-convergence-rule',
|
|
96
97
|
'idempotency.md §"Convergence rule"',
|
|
97
98
|
'winner MUST be the lex-min runId (run-a-west < run-b-east)',
|
|
98
99
|
),
|
|
@@ -108,19 +109,19 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
108
109
|
if (probe.status === 404) {
|
|
109
110
|
await noteSimulatorAbsent();
|
|
110
111
|
ctx.skip();
|
|
111
|
-
return;
|
|
112
|
+
return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
112
113
|
}
|
|
113
114
|
expect(probe.status).toBe(200);
|
|
114
115
|
expect(
|
|
115
116
|
probe.body.winner?.runId,
|
|
116
|
-
|
|
117
|
+
req('openwop.it.multi-region-idempotency-behavior.three-region-partition-resolves-to-a-single-winner',
|
|
117
118
|
'idempotency.md §"Convergence rule"',
|
|
118
119
|
'winner MUST be the lex-min runId across all conflicting claims',
|
|
119
120
|
),
|
|
120
121
|
).toBe('aaa-1');
|
|
121
122
|
expect(
|
|
122
123
|
probe.body.losers?.length,
|
|
123
|
-
|
|
124
|
+
req('openwop.it.multi-region-idempotency-behavior.three-region-partition-resolves-to-a-single-winner',
|
|
124
125
|
'idempotency.md §"Convergence rule"',
|
|
125
126
|
'losers array MUST contain N-1 entries when N claims conflict',
|
|
126
127
|
),
|
|
@@ -135,13 +136,13 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
135
136
|
if (probe.status === 404) {
|
|
136
137
|
await noteSimulatorAbsent();
|
|
137
138
|
ctx.skip();
|
|
138
|
-
return;
|
|
139
|
+
return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
139
140
|
}
|
|
140
141
|
expect(probe.status).toBe(200);
|
|
141
142
|
const redirects = probe.body.cacheRedirects ?? [];
|
|
142
143
|
expect(
|
|
143
144
|
redirects.length,
|
|
144
|
-
|
|
145
|
+
req('openwop.it.multi-region-idempotency-behavior.every-region-gets-a-cache-redirect-entry-pointing-at-the-winner',
|
|
145
146
|
'idempotency.md §"Convergence rule"',
|
|
146
147
|
'cacheRedirects MUST contain one entry per claim (including the winner)',
|
|
147
148
|
),
|
|
@@ -149,7 +150,7 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
149
150
|
for (const redirect of redirects) {
|
|
150
151
|
expect(
|
|
151
152
|
redirect.redirectToRunId,
|
|
152
|
-
|
|
153
|
+
req('openwop.it.multi-region-idempotency-behavior.every-region-gets-a-cache-redirect-entry-pointing-at-the-winner',
|
|
153
154
|
'idempotency.md §"Convergence rule"',
|
|
154
155
|
'every cache redirect MUST point at the winner runId',
|
|
155
156
|
),
|
|
@@ -165,12 +166,12 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
165
166
|
if (probe.status === 404) {
|
|
166
167
|
await noteSimulatorAbsent();
|
|
167
168
|
ctx.skip();
|
|
168
|
-
return;
|
|
169
|
+
return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
169
170
|
}
|
|
170
171
|
expect(probe.status).toBe(200);
|
|
171
172
|
expect(
|
|
172
173
|
probe.body.loserCancelReason,
|
|
173
|
-
|
|
174
|
+
req('openwop.it.multi-region-idempotency-behavior.loser-cancel-reason-must-be-the-canonical-cross-region-dedup-loss-string',
|
|
174
175
|
'idempotency.md §"Convergence rule"',
|
|
175
176
|
'loserCancelReason MUST be the canonical `cross_region_dedup_loss` string',
|
|
176
177
|
),
|
|
@@ -187,7 +188,7 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
187
188
|
if (p1.status === 404) {
|
|
188
189
|
await noteSimulatorAbsent();
|
|
189
190
|
ctx.skip();
|
|
190
|
-
return;
|
|
191
|
+
return softSkip('blocked', 'precondition not met — `p1.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
191
192
|
}
|
|
192
193
|
expect(p1.status).toBe(200);
|
|
193
194
|
const p2 = await simulatePartition([claims[2]!, claims[0]!, claims[1]!]);
|
|
@@ -196,7 +197,7 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
196
197
|
expect(p3.status).toBe(200);
|
|
197
198
|
expect(
|
|
198
199
|
p1.body.winner?.runId,
|
|
199
|
-
|
|
200
|
+
req('openwop.it.multi-region-idempotency-behavior.resolver-is-order-invariant-shuffled-inputs-produce-the-same-winner',
|
|
200
201
|
'idempotency.md §"Convergence rule" — determinism',
|
|
201
202
|
'resolver MUST be order-invariant; all permutations MUST produce the same lex-min winner',
|
|
202
203
|
),
|
|
@@ -213,11 +214,11 @@ describe.skipIf(HTTP_SKIP)('multi-region-idempotency-behavior: convergence rule
|
|
|
213
214
|
if (probe.status === 404) {
|
|
214
215
|
await noteSimulatorAbsent();
|
|
215
216
|
ctx.skip();
|
|
216
|
-
return;
|
|
217
|
+
return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
217
218
|
}
|
|
218
219
|
expect(
|
|
219
220
|
probe.status,
|
|
220
|
-
|
|
221
|
+
req('openwop.it.multi-region-idempotency-behavior.mismatched-tuple-rejects-with-400-validation-error',
|
|
221
222
|
'idempotency.md §"Convergence rule"',
|
|
222
223
|
'claims with non-matching (tenantId, endpoint, key) MUST be rejected — it would be a programming error in the caller',
|
|
223
224
|
),
|