@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
|
@@ -37,6 +37,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
|
37
37
|
import { driver } from '../lib/driver.js';
|
|
38
38
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
39
39
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
40
|
+
import { req } from '../lib/requirement-ids.js';
|
|
41
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
40
42
|
|
|
41
43
|
const DISPATCH_CONFIG = join(SCHEMAS_DIR, 'dispatch-config.schema.json');
|
|
42
44
|
const EVENT_PAYLOADS = join(SCHEMAS_DIR, 'run-event-payloads.schema.json');
|
|
@@ -58,7 +60,7 @@ describe('dispatch-fanout: DispatchConfig schema (always-on, server-free)', () =
|
|
|
58
60
|
maxConcurrency: 5,
|
|
59
61
|
joinPolicy: { mode: 'wait-all', onChildFailure: 'collect' },
|
|
60
62
|
};
|
|
61
|
-
expect(validate(cfg), `node-packs.md §parallel fan-out — a valid parallel config MUST validate. Errors: ${JSON.stringify(validate.errors)}`).toBe(true);
|
|
63
|
+
expect(validate(cfg), req('openwop.it.dispatch-fanout-parallel.accepts-fanoutpolicy-parallel-with-a-wait-all-collect-joinpolicy-maxconcurrency', 'node-packs.md', `node-packs.md §parallel fan-out — a valid parallel config MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
|
|
62
64
|
});
|
|
63
65
|
|
|
64
66
|
it('accepts each joinPolicy.mode (wait-all/quorum/first/race)', () => {
|
|
@@ -68,26 +70,26 @@ describe('dispatch-fanout: DispatchConfig schema (always-on, server-free)', () =
|
|
|
68
70
|
{ mode: 'first' },
|
|
69
71
|
{ mode: 'race' },
|
|
70
72
|
]) {
|
|
71
|
-
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: jp }), `joinPolicy ${JSON.stringify(jp)} MUST validate`).toBe(true);
|
|
73
|
+
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: jp }), req('openwop.it.dispatch-fanout-parallel.accepts-each-joinpolicy-mode-wait-all-quorum-first-race', 'node-packs.md', `joinPolicy ${JSON.stringify(jp)} MUST validate`)).toBe(true);
|
|
72
74
|
}
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
it('rejects an unknown fanOutPolicy and an unknown joinPolicy.mode', () => {
|
|
76
|
-
expect(validate({ fanOutPolicy: 'broadcast' }), "fanOutPolicy MUST be one of sequential/reject/parallel").toBe(false);
|
|
77
|
-
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { mode: 'any' } }), 'joinPolicy.mode MUST be in the closed enum').toBe(false);
|
|
78
|
+
expect(validate({ fanOutPolicy: 'broadcast' }), req('openwop.it.dispatch-fanout-parallel.rejects-an-unknown-fanoutpolicy-and-an-unknown-joinpolicy-mode', 'node-packs.md', "fanOutPolicy MUST be one of sequential/reject/parallel")).toBe(false);
|
|
79
|
+
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { mode: 'any' } }), req('openwop.it.dispatch-fanout-parallel.rejects-an-unknown-fanoutpolicy-and-an-unknown-joinpolicy-mode', 'node-packs.md', 'joinPolicy.mode MUST be in the closed enum')).toBe(false);
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
it('rejects an unknown onChildFailure and additionalProperties on joinPolicy', () => {
|
|
81
|
-
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { onChildFailure: 'explode' } }), 'onChildFailure MUST be collect/fail-fast/absorb').toBe(false);
|
|
82
|
-
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { mode: 'wait-all', extra: 1 } }), 'joinPolicy is additionalProperties:false').toBe(false);
|
|
83
|
+
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { onChildFailure: 'explode' } }), req('openwop.it.dispatch-fanout-parallel.rejects-an-unknown-onchildfailure-and-additionalproperties-on-joinpolicy', 'node-packs.md', 'onChildFailure MUST be collect/fail-fast/absorb')).toBe(false);
|
|
84
|
+
expect(validate({ fanOutPolicy: 'parallel', joinPolicy: { mode: 'wait-all', extra: 1 } }), req('openwop.it.dispatch-fanout-parallel.rejects-an-unknown-onchildfailure-and-additionalproperties-on-joinpolicy', 'node-packs.md', 'joinPolicy is additionalProperties:false')).toBe(false);
|
|
83
85
|
});
|
|
84
86
|
|
|
85
87
|
it('rejects a non-positive maxConcurrency', () => {
|
|
86
|
-
expect(validate({ fanOutPolicy: 'parallel', maxConcurrency: 0 }), 'maxConcurrency minimum is 1').toBe(false);
|
|
88
|
+
expect(validate({ fanOutPolicy: 'parallel', maxConcurrency: 0 }), req('openwop.it.dispatch-fanout-parallel.rejects-a-non-positive-maxconcurrency', 'node-packs.md', 'maxConcurrency minimum is 1')).toBe(false);
|
|
87
89
|
});
|
|
88
90
|
|
|
89
91
|
it('the default config (no fanOutPolicy) stays valid — additive, default sequential', () => {
|
|
90
|
-
expect(validate({ workerDispatchModel: 'child-run' }), 'a pre-RFC-0118 config MUST stay valid').toBe(true);
|
|
92
|
+
expect(validate({ workerDispatchModel: 'child-run' }), req('openwop.it.dispatch-fanout-parallel.the-default-config-no-fanoutpolicy-stays-valid-additive-default-sequential', 'node-packs.md', 'a pre-RFC-0118 config MUST stay valid')).toBe(true);
|
|
91
93
|
});
|
|
92
94
|
});
|
|
93
95
|
|
|
@@ -99,8 +101,8 @@ describe('dispatch-fanout: event $defs (always-on, server-free)', () => {
|
|
|
99
101
|
|
|
100
102
|
it('a well-formed core.dispatch.fanOut payload validates; fanOutPolicy is const "parallel"', () => {
|
|
101
103
|
expect(validateFanOut({ fanOutPolicy: 'parallel', childCount: 5, maxConcurrency: 5, joinMode: 'wait-all' })).toBe(true);
|
|
102
|
-
expect(validateFanOut({ fanOutPolicy: 'sequential', childCount: 5 }), 'fanOut is emitted only on the parallel path (const)').toBe(false);
|
|
103
|
-
expect(validateFanOut({ fanOutPolicy: 'parallel', childCount: 1 }), 'childCount minimum is 2 (> 1 by construction)').toBe(false);
|
|
104
|
+
expect(validateFanOut({ fanOutPolicy: 'sequential', childCount: 5 }), req('openwop.it.dispatch-fanout-parallel.a-well-formed-core-dispatch-fanout-payload-validates-fanoutpolicy-is-const-paral', 'node-packs.md', 'fanOut is emitted only on the parallel path (const)')).toBe(false);
|
|
105
|
+
expect(validateFanOut({ fanOutPolicy: 'parallel', childCount: 1 }), req('openwop.it.dispatch-fanout-parallel.a-well-formed-core-dispatch-fanout-payload-validates-fanoutpolicy-is-const-paral', 'node-packs.md', 'childCount minimum is 2 (> 1 by construction)')).toBe(false);
|
|
104
106
|
});
|
|
105
107
|
|
|
106
108
|
it('a well-formed core.dispatch.join payload carries mergeOrder (replay tiebreak)', () => {
|
|
@@ -111,9 +113,9 @@ describe('dispatch-fanout: event $defs (always-on, server-free)', () => {
|
|
|
111
113
|
cancelledCount: 0,
|
|
112
114
|
mergeOrder: ['run-a', 'run-b', 'run-c'],
|
|
113
115
|
};
|
|
114
|
-
expect(validateJoin(ok), `node-packs.md §parallel — join carries mergeOrder. Errors: ${JSON.stringify(validateJoin.errors)}`).toBe(true);
|
|
115
|
-
expect(validateJoin({ joinOutcome: 'satisfied', completedCount: 3, failedCount: 0 }), 'mergeOrder is required (replay determinism)').toBe(false);
|
|
116
|
-
expect(validateJoin({ ...ok, joinOutcome: 'aborted' }), 'joinOutcome MUST be satisfied/failed/partial').toBe(false);
|
|
116
|
+
expect(validateJoin(ok), req('openwop.it.dispatch-fanout-parallel.a-well-formed-core-dispatch-join-payload-carries-mergeorder-replay-tiebreak', 'node-packs.md', `node-packs.md §parallel — join carries mergeOrder. Errors: ${JSON.stringify(validateJoin.errors)}`)).toBe(true);
|
|
117
|
+
expect(validateJoin({ joinOutcome: 'satisfied', completedCount: 3, failedCount: 0 }), req('openwop.it.dispatch-fanout-parallel.a-well-formed-core-dispatch-join-payload-carries-mergeorder-replay-tiebreak', 'node-packs.md', 'mergeOrder is required (replay determinism)')).toBe(false);
|
|
118
|
+
expect(validateJoin({ ...ok, joinOutcome: 'aborted' }), req('openwop.it.dispatch-fanout-parallel.a-well-formed-core-dispatch-join-payload-carries-mergeorder-replay-tiebreak', 'node-packs.md', 'joinOutcome MUST be satisfied/failed/partial')).toBe(false);
|
|
117
119
|
});
|
|
118
120
|
});
|
|
119
121
|
|
|
@@ -121,43 +123,43 @@ describe('dispatch-fanout: parallel behavior (capability-gated, RFC 0118)', () =
|
|
|
121
123
|
it('a wait-all/collect parallel fan-out joins on all children with joinOutcome satisfied', async () => {
|
|
122
124
|
const dispatch = await readCapabilityFamily<{ fanOutSupported?: boolean; fanOutPolicies?: string[] }>('dispatch');
|
|
123
125
|
if (!behaviorGate('dispatch.fanOutSupported', dispatch?.fanOutSupported === true)) return;
|
|
124
|
-
if (!(dispatch?.fanOutPolicies ?? []).includes('parallel')) return; // parallel unsupported → out of scope
|
|
126
|
+
if (!(dispatch?.fanOutPolicies ?? []).includes('parallel')) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(dispatch?.fanOutPolicies ?? []).includes(\'parallel\')` returned early (parallel unsupported → out of scope)'); // parallel unsupported → out of scope
|
|
125
127
|
|
|
126
128
|
const res = await driver.post('/v1/host/sample/dispatch/fanout', {
|
|
127
129
|
nextWorkerIds: ['conformance.child.a', 'conformance.child.b', 'conformance.child.c'],
|
|
128
130
|
config: { fanOutPolicy: 'parallel', joinPolicy: { mode: 'wait-all', onChildFailure: 'collect' } },
|
|
129
131
|
});
|
|
130
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
132
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
131
133
|
|
|
132
134
|
const body = res.json as { joinOutcome?: string; children?: unknown[]; mergeOrder?: string[] } | undefined;
|
|
133
135
|
expect(
|
|
134
136
|
body?.joinOutcome,
|
|
135
|
-
|
|
137
|
+
req('openwop.it.dispatch-fanout-parallel.a-wait-all-collect-parallel-fan-out-joins-on-all-children-with-joinoutcome-satis', 'node-packs.md §parallel fan-out', 'wait-all + collect over all-completing children → joinOutcome satisfied'),
|
|
136
138
|
).toBe('satisfied');
|
|
137
139
|
expect(
|
|
138
140
|
body?.children?.length,
|
|
139
|
-
|
|
141
|
+
req('openwop.it.dispatch-fanout-parallel.a-wait-all-collect-parallel-fan-out-joins-on-all-children-with-joinoutcome-satis', 'node-packs.md §parallel fan-out', 'the output children[] reports every dispatched child'),
|
|
140
142
|
).toBe(3);
|
|
141
143
|
expect(
|
|
142
144
|
Array.isArray(body?.mergeOrder),
|
|
143
|
-
|
|
145
|
+
req('openwop.it.dispatch-fanout-parallel.a-wait-all-collect-parallel-fan-out-joins-on-all-children-with-joinoutcome-satis', 'node-packs.md §parallel fan-out', 'the join records mergeOrder for replay-deterministic output merge'),
|
|
144
146
|
).toBe(true);
|
|
145
147
|
});
|
|
146
148
|
|
|
147
149
|
it('parallel fan-out is rejected at registration on a host advertising fanOutSupported:false', async () => {
|
|
148
150
|
const dispatch = await readCapabilityFamily<{ supported?: boolean; fanOutSupported?: boolean }>('dispatch');
|
|
149
|
-
if (!dispatch?.supported) return; // no dispatch surface → out of scope
|
|
150
|
-
if (dispatch.fanOutSupported === true) return; // this leg targets non-supporting hosts
|
|
151
|
+
if (!dispatch?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!dispatch?.supported` returned early (no dispatch surface → out of scope)'); // no dispatch surface → out of scope
|
|
152
|
+
if (dispatch.fanOutSupported === true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `dispatch.fanOutSupported === true` returned early (this leg targets non-supporting hosts)'); // this leg targets non-supporting hosts
|
|
151
153
|
|
|
152
154
|
const res = await driver.post('/v1/workflows', {
|
|
153
155
|
id: 'conformance.dispatch.parallel-unsupported',
|
|
154
156
|
nodes: [{ nodeId: 'd', typeId: 'core.dispatch', config: { fanOutPolicy: 'parallel', joinPolicy: { mode: 'wait-all' } } }],
|
|
155
157
|
});
|
|
156
|
-
if (res.status === 404) return; // registration surface not exposed here — soft-skip
|
|
158
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (registration surface not exposed here — soft-skip) (seam, prior step, or fixture unavailable)'); // registration surface not exposed here — soft-skip
|
|
157
159
|
|
|
158
160
|
expect(
|
|
159
161
|
res.status >= 400 && res.status < 500,
|
|
160
|
-
|
|
162
|
+
req('openwop.it.dispatch-fanout-parallel.parallel-fan-out-is-rejected-at-registration-on-a-host-advertising-fanoutsupport', 'node-packs.md §parallel fan-out', "a host advertising fanOutSupported:false MUST reject fanOutPolicy:'parallel' with a validation_error (4xx), never accept it"),
|
|
161
163
|
).toBe(true);
|
|
162
164
|
});
|
|
163
165
|
});
|
|
@@ -25,6 +25,8 @@ import { driver } from '../lib/driver.js';
|
|
|
25
25
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
26
26
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
27
27
|
import { setHostCapability, resetHostCapabilities, isToggleAvailable } from '../lib/host-toggle.js';
|
|
28
|
+
import { req } from '../lib/requirement-ids.js';
|
|
29
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
28
30
|
|
|
29
31
|
const PARENT = 'conformance-dispatch-input-mapping';
|
|
30
32
|
const CHILD = 'conformance-dispatch-input-mapping-child';
|
|
@@ -49,7 +51,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
49
51
|
const parentRunId = (create.json as { runId: string }).runId;
|
|
50
52
|
|
|
51
53
|
const parentTerminal = (await pollUntilTerminal(parentRunId)) as RunSnapshot;
|
|
52
|
-
expect(parentTerminal.status,
|
|
54
|
+
expect(parentTerminal.status, req('openwop.it.dispatch-input-mapping.hvmap-1a-inputmapping-projects-parent-variables-into-child-inputs',
|
|
53
55
|
'RFCS/0022-dispatch-input-output-mapping.md §A',
|
|
54
56
|
'parent run MUST reach terminal `completed` once the dispatch loop terminates',
|
|
55
57
|
)).toBe('completed');
|
|
@@ -61,7 +63,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
61
63
|
const dispatched = events.find(
|
|
62
64
|
(e) => e.type === 'node.dispatched' && e.payload?.childWorkflowId === CHILD,
|
|
63
65
|
);
|
|
64
|
-
expect(dispatched,
|
|
66
|
+
expect(dispatched, req('openwop.it.dispatch-input-mapping.hvmap-1a-inputmapping-projects-parent-variables-into-child-inputs',
|
|
65
67
|
'RFCS/0007-dispatch.md §D',
|
|
66
68
|
'parent event log MUST contain a `node.dispatched` event naming the child workflow',
|
|
67
69
|
)).toBeDefined();
|
|
@@ -74,12 +76,12 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
74
76
|
const childSnapshotRes = await driver.get(`/v1/runs/${encodeURIComponent(childRunId!)}`);
|
|
75
77
|
expect(childSnapshotRes.status).toBe(200);
|
|
76
78
|
const childSnapshot = childSnapshotRes.json as RunSnapshot;
|
|
77
|
-
expect(childSnapshot.status,
|
|
79
|
+
expect(childSnapshot.status, req('openwop.it.dispatch-input-mapping.hvmap-1a-inputmapping-projects-parent-variables-into-child-inputs',
|
|
78
80
|
'RFCS/0007-dispatch.md',
|
|
79
81
|
'child run MUST reach terminal `completed`',
|
|
80
82
|
)).toBe('completed');
|
|
81
83
|
const childInputs = childSnapshot.inputs ?? {};
|
|
82
|
-
expect(childInputs.childGreeting,
|
|
84
|
+
expect(childInputs.childGreeting, req('openwop.it.dispatch-input-mapping.hvmap-1a-inputmapping-projects-parent-variables-into-child-inputs',
|
|
83
85
|
'RFCS/0022-dispatch-input-output-mapping.md §A',
|
|
84
86
|
'child `inputs.childGreeting` MUST be parent\'s `parentName` projection ("Alice") per inputMapping',
|
|
85
87
|
)).toBe('Alice');
|
|
@@ -87,7 +89,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
87
89
|
|
|
88
90
|
it('HVMAP-1a-null: parent variable unset → child input surfaces as `undefined` per §A', async () => {
|
|
89
91
|
const PARENT_NO_DEFAULT = 'conformance-dispatch-input-mapping-no-default';
|
|
90
|
-
if (!isFixtureAdvertised(PARENT_NO_DEFAULT) || !isFixtureAdvertised(CHILD)) return; // fixture not seeded — soft-skip
|
|
92
|
+
if (!isFixtureAdvertised(PARENT_NO_DEFAULT) || !isFixtureAdvertised(CHILD)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(PARENT_NO_DEFAULT) || !isFixtureAdvertised(CHILD)` returned early (fixture not seeded — soft-skip)'); // fixture not seeded — soft-skip
|
|
91
93
|
const create = await driver.post('/v1/runs', { workflowId: PARENT_NO_DEFAULT });
|
|
92
94
|
expect(create.status).toBe(201);
|
|
93
95
|
const parentRunId = (create.json as { runId: string }).runId;
|
|
@@ -98,7 +100,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
98
100
|
const dispatched = events.find(
|
|
99
101
|
(e) => e.type === 'node.dispatched' && e.payload?.childWorkflowId === CHILD,
|
|
100
102
|
);
|
|
101
|
-
if (!dispatched) return; // host doesn't emit node.dispatched — soft-skip
|
|
103
|
+
if (!dispatched) return softSkip('blocked', 'precondition not met — `!dispatched` returned early (host doesn\'t emit node.dispatched — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't emit node.dispatched — soft-skip
|
|
102
104
|
const childRunId = dispatched.payload?.childRunId;
|
|
103
105
|
|
|
104
106
|
const childRes = await driver.get(`/v1/runs/${encodeURIComponent(childRunId!)}`);
|
|
@@ -111,7 +113,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
111
113
|
const v = inputs.childGreeting;
|
|
112
114
|
expect(
|
|
113
115
|
v === undefined || !('childGreeting' in inputs),
|
|
114
|
-
|
|
116
|
+
req('openwop.it.dispatch-input-mapping.hvmap-1a-null-parent-variable-unset-child-input-surfaces-as-undefined-per-a',
|
|
115
117
|
'RFCS/0022-dispatch-input-output-mapping.md §A',
|
|
116
118
|
'unset parent variable projection MUST surface as undefined (NOT null, NOT a default placeholder)',
|
|
117
119
|
),
|
|
@@ -123,7 +125,7 @@ describe.skipIf(SKIP)('dispatch-input-mapping: parent → child variable project
|
|
|
123
125
|
|
|
124
126
|
describe('dispatch-input-mapping: registration refusal (RFC 0022 §C HVMAP-1a-refusal)', () => {
|
|
125
127
|
it('host with agents.dispatchMapping toggled OFF MUST refuse non-empty inputMapping at registration', async () => {
|
|
126
|
-
if (!(await isToggleAvailable())) return; // seam not exposed — soft-skip
|
|
128
|
+
if (!(await isToggleAvailable())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isToggleAvailable())` returned early (seam not exposed — soft-skip)'); // seam not exposed — soft-skip
|
|
127
129
|
await setHostCapability('agents.dispatchMapping', false);
|
|
128
130
|
try {
|
|
129
131
|
const workflow = {
|
|
@@ -142,7 +144,7 @@ describe('dispatch-input-mapping: registration refusal (RFC 0022 §C HVMAP-1a-re
|
|
|
142
144
|
const res = await driver.post('/v1/host/sample/workflows', workflow);
|
|
143
145
|
expect(
|
|
144
146
|
res.status,
|
|
145
|
-
|
|
147
|
+
req('openwop.it.dispatch-input-mapping.host-with-agents-dispatchmapping-toggled-off-must-refuse-non-empty-inputmapping',
|
|
146
148
|
'RFCS/0022-dispatch-input-output-mapping.md §C',
|
|
147
149
|
'workflow with non-empty inputMapping MUST be refused when capabilities.agents.dispatchMapping is not advertised',
|
|
148
150
|
),
|
|
@@ -151,7 +153,7 @@ describe('dispatch-input-mapping: registration refusal (RFC 0022 §C HVMAP-1a-re
|
|
|
151
153
|
expect(body.error).toBe('validation_error');
|
|
152
154
|
expect(
|
|
153
155
|
body.details?.requiredCapability,
|
|
154
|
-
|
|
156
|
+
req('openwop.it.dispatch-input-mapping.host-with-agents-dispatchmapping-toggled-off-must-refuse-non-empty-inputmapping',
|
|
155
157
|
'RFCS/0022-dispatch-input-output-mapping.md §C',
|
|
156
158
|
'refusal MUST surface requiredCapability: "agents.dispatchMapping"',
|
|
157
159
|
),
|
|
@@ -22,6 +22,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
22
22
|
import { driver } from '../lib/driver.js';
|
|
23
23
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
24
24
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
25
27
|
|
|
26
28
|
const PARENT = 'conformance-dispatch-output-mapping';
|
|
27
29
|
const CHILD = 'conformance-dispatch-output-mapping-child';
|
|
@@ -39,7 +41,7 @@ describe.skipIf(SKIP)('dispatch-output-mapping: child → parent variable harves
|
|
|
39
41
|
const parentRunId = (create.json as { runId: string }).runId;
|
|
40
42
|
|
|
41
43
|
const parentTerminal = (await pollUntilTerminal(parentRunId)) as RunSnapshot;
|
|
42
|
-
expect(parentTerminal.status,
|
|
44
|
+
expect(parentTerminal.status, req('openwop.it.dispatch-output-mapping.hvmap-1b-outputmapping-harvests-child-variables-into-parent-variables-on-termina',
|
|
43
45
|
'RFCS/0022-dispatch-input-output-mapping.md §A',
|
|
44
46
|
'parent run MUST reach terminal `completed` once the dispatch loop terminates',
|
|
45
47
|
)).toBe('completed');
|
|
@@ -49,7 +51,7 @@ describe.skipIf(SKIP)('dispatch-output-mapping: child → parent variable harves
|
|
|
49
51
|
// Child declares childOutcome.defaultValue='done' so the value is
|
|
50
52
|
// present in the child's variables_json at terminal time.
|
|
51
53
|
const parentVars = parentTerminal.variables ?? {};
|
|
52
|
-
expect(parentVars.parentResult,
|
|
54
|
+
expect(parentVars.parentResult, req('openwop.it.dispatch-output-mapping.hvmap-1b-outputmapping-harvests-child-variables-into-parent-variables-on-termina',
|
|
53
55
|
'RFCS/0022-dispatch-input-output-mapping.md §A',
|
|
54
56
|
'parent `parentResult` MUST be child\'s `childOutcome` projection ("done") per outputMapping',
|
|
55
57
|
)).toBe('done');
|
|
@@ -99,7 +101,7 @@ async function registerParent(childFixtureId: string): Promise<string | null> {
|
|
|
99
101
|
describe.skipIf(!isFixtureAdvertised('conformance-dispatch-deterministic-fail-child'))('dispatch-output-mapping: HVMAP-1b-failed (RFC 0022 §B)', () => {
|
|
100
102
|
it('child terminates `failed` → outputMapping MUST be skipped; parent.parentResult stays at sentinel', async () => {
|
|
101
103
|
const parentId = await registerParent('conformance-dispatch-deterministic-fail-child');
|
|
102
|
-
if (!parentId) return; // workflow-register seam not exposed — soft-skip
|
|
104
|
+
if (!parentId) return softSkip('blocked', 'precondition not met — `!parentId` returned early (workflow-register seam not exposed — soft-skip) (seam, prior step, or fixture unavailable)'); // workflow-register seam not exposed — soft-skip
|
|
103
105
|
const create = await driver.post('/v1/runs', { workflowId: parentId });
|
|
104
106
|
expect(create.status).toBe(201);
|
|
105
107
|
const parentRunId = (create.json as { runId: string }).runId;
|
|
@@ -109,7 +111,7 @@ describe.skipIf(!isFixtureAdvertised('conformance-dispatch-deterministic-fail-ch
|
|
|
109
111
|
const parentVars = terminal.variables ?? {};
|
|
110
112
|
expect(
|
|
111
113
|
parentVars.parentResult,
|
|
112
|
-
|
|
114
|
+
req('openwop.it.dispatch-output-mapping.child-terminates-failed-outputmapping-must-be-skipped-parent-parentresult-stays',
|
|
113
115
|
'RFCS/0022-dispatch-input-output-mapping.md §B',
|
|
114
116
|
'outputMapping MUST be SKIPPED when child terminates failed; parent variable MUST NOT be overwritten',
|
|
115
117
|
),
|
|
@@ -120,7 +122,7 @@ describe.skipIf(!isFixtureAdvertised('conformance-dispatch-deterministic-fail-ch
|
|
|
120
122
|
describe.skipIf(!isFixtureAdvertised('conformance-dispatch-cancellable-child'))('dispatch-output-mapping: HVMAP-1b-cancelled (RFC 0022 §B)', () => {
|
|
121
123
|
it('child terminates `cancelled` → outputMapping MUST be skipped; parent.parentResult stays at sentinel', async () => {
|
|
122
124
|
const parentId = await registerParent('conformance-dispatch-cancellable-child');
|
|
123
|
-
if (!parentId) return; // soft-skip
|
|
125
|
+
if (!parentId) return softSkip('blocked', 'precondition not met — `!parentId` returned early (soft-skip) (seam, prior step, or fixture unavailable)'); // soft-skip
|
|
124
126
|
const create = await driver.post('/v1/runs', { workflowId: parentId });
|
|
125
127
|
expect(create.status).toBe(201);
|
|
126
128
|
const parentRunId = (create.json as { runId: string }).runId;
|
|
@@ -138,7 +140,7 @@ describe.skipIf(!isFixtureAdvertised('conformance-dispatch-cancellable-child'))(
|
|
|
138
140
|
}
|
|
139
141
|
await new Promise((r) => setTimeout(r, 250));
|
|
140
142
|
}
|
|
141
|
-
if (!childRunId) return; // dispatch didn't surface child run id — soft-skip
|
|
143
|
+
if (!childRunId) return softSkip('blocked', 'precondition not met — `!childRunId` returned early (dispatch didn\'t surface child run id — soft-skip) (seam, prior step, or fixture unavailable)'); // dispatch didn't surface child run id — soft-skip
|
|
142
144
|
const cancelRes = await driver.post(`/v1/runs/${encodeURIComponent(childRunId)}/cancel`, { reason: 'hvmap-1b-cancelled test' });
|
|
143
145
|
expect(cancelRes.status === 200 || cancelRes.status === 202).toBe(true);
|
|
144
146
|
|
|
@@ -146,7 +148,7 @@ describe.skipIf(!isFixtureAdvertised('conformance-dispatch-cancellable-child'))(
|
|
|
146
148
|
const parentVars = terminal.variables ?? {};
|
|
147
149
|
expect(
|
|
148
150
|
parentVars.parentResult,
|
|
149
|
-
|
|
151
|
+
req('openwop.it.dispatch-output-mapping.child-terminates-cancelled-outputmapping-must-be-skipped-parent-parentresult-sta',
|
|
150
152
|
'RFCS/0022-dispatch-input-output-mapping.md §B',
|
|
151
153
|
'outputMapping MUST be SKIPPED when child terminates cancelled; parent variable MUST NOT be overwritten',
|
|
152
154
|
),
|
|
@@ -44,6 +44,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
|
44
44
|
import { driver } from '../lib/driver.js';
|
|
45
45
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
46
46
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
47
|
+
import { req } from '../lib/requirement-ids.js';
|
|
48
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
47
49
|
|
|
48
50
|
const DECISION = join(SCHEMAS_DIR, 'orchestrator-decision.schema.json');
|
|
49
51
|
|
|
@@ -60,39 +62,39 @@ describe('dispatch-per-item: NextWorkerDecision.nextWorkerInputs schema (always-
|
|
|
60
62
|
};
|
|
61
63
|
expect(
|
|
62
64
|
validate(decision),
|
|
63
|
-
`orchestrator-decision.schema.json §NextWorkerDecision — a well-formed nextWorkerInputs MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
65
|
+
req('openwop.it.dispatch-per-item-input.accepts-a-next-worker-decision-carrying-a-well-formed-index-aligned-nextworkerin', 'node-packs.md', `orchestrator-decision.schema.json §NextWorkerDecision — a well-formed nextWorkerInputs MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
64
66
|
).toBe(true);
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
it('still accepts a next-worker decision that omits nextWorkerInputs (additive / back-compat)', () => {
|
|
68
70
|
expect(
|
|
69
71
|
validate({ kind: 'next-worker', nextWorkerIds: ['pack.child'] }),
|
|
70
|
-
'a pre-RFC-0126 next-worker decision MUST stay valid — the field is OPTIONAL',
|
|
72
|
+
req('openwop.it.dispatch-per-item-input.still-accepts-a-next-worker-decision-that-omits-nextworkerinputs-additive-back-c', 'node-packs.md', 'a pre-RFC-0126 next-worker decision MUST stay valid — the field is OPTIONAL'),
|
|
71
73
|
).toBe(true);
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
it('rejects a non-object nextWorkerInputs item', () => {
|
|
75
77
|
expect(
|
|
76
78
|
validate({ kind: 'next-worker', nextWorkerIds: ['a'], nextWorkerInputs: ['not-an-object'] }),
|
|
77
|
-
'each nextWorkerInputs entry MUST be a per-child input object',
|
|
79
|
+
req('openwop.it.dispatch-per-item-input.rejects-a-non-object-nextworkerinputs-item', 'node-packs.md', 'each nextWorkerInputs entry MUST be a per-child input object'),
|
|
78
80
|
).toBe(false);
|
|
79
81
|
expect(
|
|
80
82
|
validate({ kind: 'next-worker', nextWorkerIds: ['a'], nextWorkerInputs: 'nope' }),
|
|
81
|
-
'nextWorkerInputs MUST be an array',
|
|
83
|
+
req('openwop.it.dispatch-per-item-input.rejects-a-non-object-nextworkerinputs-item', 'node-packs.md', 'nextWorkerInputs MUST be an array'),
|
|
82
84
|
).toBe(false);
|
|
83
85
|
});
|
|
84
86
|
|
|
85
87
|
it('still rejects an unknown property (additionalProperties:false) — the fail-closed gate', () => {
|
|
86
88
|
expect(
|
|
87
89
|
validate({ kind: 'next-worker', nextWorkerIds: ['a'], perItemInputs: [{ x: 1 }] }),
|
|
88
|
-
'NextWorkerDecision is additionalProperties:false — a mis-named field MUST be rejected, so old strict validators fail closed on unknown per-item shapes',
|
|
90
|
+
req('openwop.it.dispatch-per-item-input.still-rejects-an-unknown-property-additionalproperties-false-the-fail-closed-gat', 'node-packs.md', 'NextWorkerDecision is additionalProperties:false — a mis-named field MUST be rejected, so old strict validators fail closed on unknown per-item shapes'),
|
|
89
91
|
).toBe(false);
|
|
90
92
|
});
|
|
91
93
|
|
|
92
94
|
it('ADMITS a length-mismatch — array-length equality is a runtime MUST, not schema-expressible', () => {
|
|
93
95
|
expect(
|
|
94
96
|
validate({ kind: 'next-worker', nextWorkerIds: ['a', 'b'], nextWorkerInputs: [{ x: 1 }] }),
|
|
95
|
-
'the wire schema cannot express nextWorkerInputs.length == nextWorkerIds.length; the host enforces it at decision time (layer B)',
|
|
97
|
+
req('openwop.it.dispatch-per-item-input.admits-a-length-mismatch-array-length-equality-is-a-runtime-must-not-schema-expr', 'node-packs.md', 'the wire schema cannot express nextWorkerInputs.length == nextWorkerIds.length; the host enforces it at decision time (layer B)'),
|
|
96
98
|
).toBe(true);
|
|
97
99
|
});
|
|
98
100
|
});
|
|
@@ -106,16 +108,16 @@ describe('dispatch-per-item: per-item input behavior (capability-gated, RFC 0126
|
|
|
106
108
|
nextWorkerIds: ['conformance.child', 'conformance.child'],
|
|
107
109
|
nextWorkerInputs: [{ contactId: 'c-1' }, { contactId: 'c-2' }],
|
|
108
110
|
});
|
|
109
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
111
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
110
112
|
|
|
111
113
|
const body = res.json as { children?: Array<{ inputs?: Record<string, unknown> }> } | undefined;
|
|
112
114
|
expect(
|
|
113
115
|
body?.children?.length,
|
|
114
|
-
|
|
116
|
+
req('openwop.it.dispatch-per-item-input.a-host-advertising-periteminput-projects-nextworkerinputs-i-into-child-i', 'node-packs.md §core.dispatch per-item input', 'one child dispatched per nextWorkerIds entry'),
|
|
115
117
|
).toBe(2);
|
|
116
118
|
expect(
|
|
117
119
|
body?.children?.map((c) => c.inputs?.contactId),
|
|
118
|
-
|
|
120
|
+
req('openwop.it.dispatch-per-item-input.a-host-advertising-periteminput-projects-nextworkerinputs-i-into-child-i', 'node-packs.md §core.dispatch per-item input', 'each child receives its own nextWorkerInputs[i] (per-item value wins over inputMapping)'),
|
|
119
121
|
).toEqual(['c-1', 'c-2']);
|
|
120
122
|
});
|
|
121
123
|
|
|
@@ -127,11 +129,11 @@ describe('dispatch-per-item: per-item input behavior (capability-gated, RFC 0126
|
|
|
127
129
|
nextWorkerIds: ['conformance.child', 'conformance.child'],
|
|
128
130
|
nextWorkerInputs: [{ contactId: 'c-1' }],
|
|
129
131
|
});
|
|
130
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
132
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
131
133
|
|
|
132
134
|
expect(
|
|
133
135
|
res.status >= 400 && res.status < 500,
|
|
134
|
-
|
|
136
|
+
req('openwop.it.dispatch-per-item-input.a-length-mismatched-nextworkerinputs-fails-with-a-validation-error-and-dispatche', 'node-packs.md §core.dispatch per-item input', 'nextWorkerInputs.length != nextWorkerIds.length MUST fail the dispatch node (4xx validation_error), dispatching no child'),
|
|
135
137
|
).toBe(true);
|
|
136
138
|
});
|
|
137
139
|
|
|
@@ -146,16 +148,16 @@ describe('dispatch-per-item: per-item input behavior (capability-gated, RFC 0126
|
|
|
146
148
|
inputMapping: { contactId: 'from-mapping', region: 'us' },
|
|
147
149
|
nextWorkerInputs: [{ contactId: 'c-1' }, { contactId: 'c-2' }],
|
|
148
150
|
});
|
|
149
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
151
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
150
152
|
|
|
151
153
|
const body = res.json as { children?: Array<{ inputs?: Record<string, unknown> }> } | undefined;
|
|
152
154
|
expect(
|
|
153
155
|
body?.children?.map((c) => c.inputs?.contactId),
|
|
154
|
-
|
|
156
|
+
req('openwop.it.dispatch-per-item-input.nextworkerinputs-i-overrides-the-inputmapping-projection-on-key-collision-g1-pre', 'node-packs.md §core.dispatch per-item input', 'on key collision the per-item value wins over inputMapping (G1)'),
|
|
155
157
|
).toEqual(['c-1', 'c-2']);
|
|
156
158
|
expect(
|
|
157
159
|
body?.children?.every((c) => c.inputs?.region === 'us'),
|
|
158
|
-
|
|
160
|
+
req('openwop.it.dispatch-per-item-input.nextworkerinputs-i-overrides-the-inputmapping-projection-on-key-collision-g1-pre', 'node-packs.md §core.dispatch per-item input', 'non-colliding inputMapping keys still project (per-item merges OVER, does not replace)'),
|
|
159
161
|
).toBe(true);
|
|
160
162
|
});
|
|
161
163
|
|
|
@@ -170,29 +172,29 @@ describe('dispatch-per-item: per-item input behavior (capability-gated, RFC 0126
|
|
|
170
172
|
nextWorkerInputs: [{ contactId: 'c-1' }, { contactId: 'c-2' }],
|
|
171
173
|
replay: true,
|
|
172
174
|
});
|
|
173
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
175
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
174
176
|
|
|
175
177
|
const body = res.json as { children?: Array<{ inputs?: Record<string, unknown> }>; replayed?: boolean } | undefined;
|
|
176
178
|
expect(
|
|
177
179
|
body?.children?.map((c) => c.inputs?.contactId),
|
|
178
|
-
|
|
180
|
+
req('openwop.it.dispatch-per-item-input.replay-re-reads-the-recorded-nextworkerinputs-verbatim-no-recomputation-r5-repla', 'node-packs.md §core.dispatch per-item input', 'replay/:fork reproduces the recorded per-item children verbatim (frozen at decision time)'),
|
|
179
181
|
).toEqual(['c-1', 'c-2']);
|
|
180
182
|
});
|
|
181
183
|
|
|
182
184
|
it('a host NOT advertising perItemInput MUST fail closed on a non-empty nextWorkerInputs', async () => {
|
|
183
185
|
const dispatch = await readCapabilityFamily<{ supported?: boolean; perItemInput?: boolean }>('dispatch');
|
|
184
|
-
if (!dispatch?.supported) return; // no dispatch surface → out of scope
|
|
185
|
-
if (dispatch.perItemInput === true) return; // this leg targets non-supporting hosts
|
|
186
|
+
if (!dispatch?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!dispatch?.supported` returned early (no dispatch surface → out of scope)'); // no dispatch surface → out of scope
|
|
187
|
+
if (dispatch.perItemInput === true) return softSkip('blocked', 'precondition not met — `dispatch.perItemInput === true` returned early (this leg targets non-supporting hosts) (seam, prior step, or fixture unavailable)'); // this leg targets non-supporting hosts
|
|
186
188
|
|
|
187
189
|
const res = await driver.post('/v1/host/sample/dispatch/per-item', {
|
|
188
190
|
nextWorkerIds: ['conformance.child', 'conformance.child'],
|
|
189
191
|
nextWorkerInputs: [{ contactId: 'c-1' }, { contactId: 'c-2' }],
|
|
190
192
|
});
|
|
191
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
193
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
192
194
|
|
|
193
195
|
expect(
|
|
194
196
|
res.status >= 400 && res.status < 500,
|
|
195
|
-
|
|
197
|
+
req('openwop.it.dispatch-per-item-input.a-host-not-advertising-periteminput-must-fail-closed-on-a-non-empty-nextworkerin', 'node-packs.md §core.dispatch per-item input', 'a host not advertising perItemInput MUST fail closed (4xx) on a non-empty nextWorkerInputs — never silently drop it and dispatch N identical children'),
|
|
196
198
|
).toBe(true);
|
|
197
199
|
});
|
|
198
200
|
});
|
|
@@ -15,6 +15,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
15
15
|
import { driver } from '../lib/driver.js';
|
|
16
16
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
17
17
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
18
|
+
import { req } from '../lib/requirement-ids.js';
|
|
18
19
|
|
|
19
20
|
const DISPATCH_LOOP_WORKFLOW_ID = 'conformance-dispatch-loop';
|
|
20
21
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(DISPATCH_LOOP_WORKFLOW_ID);
|
|
@@ -30,7 +31,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('dispatchLoop: core.dispatch consumes Orchestra
|
|
|
30
31
|
// mock. The black-box contract here is terminal completion.
|
|
31
32
|
|
|
32
33
|
const terminal = await pollUntilTerminal(runId);
|
|
33
|
-
expect(terminal.status,
|
|
34
|
+
expect(terminal.status, req('openwop.it.dispatchLoop.host-correctly-processes-orchestrator-decisions-and-terminates',
|
|
34
35
|
'RFCS/0007-dispatch-loop.md §H',
|
|
35
36
|
'run MUST reach terminal `completed` after dispatch processes terminate decision',
|
|
36
37
|
)).toBe('completed');
|
|
@@ -44,7 +45,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('dispatchLoop: core.dispatch consumes Orchestra
|
|
|
44
45
|
.filter((e) => e.type === 'runOrchestrator.decided')
|
|
45
46
|
.map((e) => e.payload?.decision?.kind);
|
|
46
47
|
|
|
47
|
-
expect(decisions,
|
|
48
|
+
expect(decisions, req('openwop.it.dispatchLoop.host-correctly-processes-orchestrator-decisions-and-terminates',
|
|
48
49
|
'RFCS/0007-dispatch-loop.md §D',
|
|
49
50
|
'host MUST emit next-worker then terminate in a loop topology'
|
|
50
51
|
)).toEqual(['next-worker', 'terminate']);
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from 'vitest';
|
|
17
17
|
import { softSkip } from '../lib/soft-skip.js';
|
|
18
|
-
import { driver } from '../lib/driver.js';
|
|
19
18
|
import { readDistillationCap, invokeDistill } from '../lib/distillation.js';
|
|
19
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
20
|
|
|
21
21
|
describe('distillation-index-roundtrip (RFC 0062 §B)', () => {
|
|
22
22
|
it('an indexEmitted run updates a retrievable memory-index manifest', async () => {
|
|
@@ -26,11 +26,11 @@ describe('distillation-index-roundtrip (RFC 0062 §B)', () => {
|
|
|
26
26
|
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
27
27
|
expect(
|
|
28
28
|
res.body.indexUpdated === true || res.body.event?.distillation?.indexUpdated === true,
|
|
29
|
-
|
|
29
|
+
req('openwop.it.distillation-index-roundtrip.an-indexemitted-run-updates-a-retrievable-memory-index-manifest', 'RFC 0062 §B', 'an indexEmitted distillation MUST report updating the memory index'),
|
|
30
30
|
).toBe(true);
|
|
31
31
|
expect(
|
|
32
32
|
res.body.indexFile !== undefined && res.body.indexFile !== null,
|
|
33
|
-
|
|
33
|
+
req('openwop.it.distillation-index-roundtrip.an-indexemitted-run-updates-a-retrievable-memory-index-manifest', 'RFC 0062 §B', 'the MEMORY-INDEX.json manifest MUST be retrievable after distillation'),
|
|
34
34
|
).toBe(true);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { describe, it, expect } from 'vitest';
|
|
15
15
|
import { softSkip } from '../lib/soft-skip.js';
|
|
16
|
-
import { driver } from '../lib/driver.js';
|
|
17
16
|
import { readDistillationCap, invokeDistill } from '../lib/distillation.js';
|
|
17
|
+
import { req } from '../lib/requirement-ids.js';
|
|
18
18
|
|
|
19
19
|
const CANARY = 'sk-canary-rfc0062-do-not-leak-qrs456';
|
|
20
20
|
|
|
@@ -30,7 +30,7 @@ describe('distillation-secret-carryforward (RFC 0062 §B)', () => {
|
|
|
30
30
|
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
31
31
|
expect(
|
|
32
32
|
JSON.stringify(res.body).includes(CANARY),
|
|
33
|
-
|
|
33
|
+
req('openwop.it.distillation-secret-carryforward.a-redacted-secret-in-source-memory-never-appears-in-the-distilled-output', 'RFC 0062 §B', 'SR-1 carry-forward: a redacted secret MUST NOT re-appear in the archive or memory.compacted event'),
|
|
34
34
|
).toBe(false);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { describe, it, expect } from 'vitest';
|
|
15
15
|
import { softSkip } from '../lib/soft-skip.js';
|
|
16
|
-
import { driver } from '../lib/driver.js';
|
|
17
16
|
import { readDistillationCap } from '../lib/distillation.js';
|
|
17
|
+
import { req } from '../lib/requirement-ids.js';
|
|
18
18
|
|
|
19
19
|
describe('distillation-shape: advertisement (RFC 0062 §A)', () => {
|
|
20
20
|
it('capabilities.memory.distillation is absent or a well-formed object', async () => {
|
|
@@ -22,19 +22,19 @@ describe('distillation-shape: advertisement (RFC 0062 §A)', () => {
|
|
|
22
22
|
if (cap === null) return softSkip('inapplicable', 'not advertised — valid');
|
|
23
23
|
expect(
|
|
24
24
|
typeof cap.supported,
|
|
25
|
-
|
|
25
|
+
req('openwop.it.distillation-shape.capabilities-memory-distillation-is-absent-or-a-well-formed-object', 'capabilities.schema.json §memory.distillation', 'distillation.supported MUST be a boolean when the block is present'),
|
|
26
26
|
).toBe('boolean');
|
|
27
27
|
if (cap.maxTokenBudget !== undefined) {
|
|
28
28
|
expect(
|
|
29
29
|
typeof cap.maxTokenBudget === 'number' && (cap.maxTokenBudget as number) >= 1,
|
|
30
|
-
|
|
30
|
+
req('openwop.it.distillation-shape.capabilities-memory-distillation-is-absent-or-a-well-formed-object', 'capabilities.schema.json §memory.distillation', 'maxTokenBudget MUST be a positive integer when present'),
|
|
31
31
|
).toBe(true);
|
|
32
32
|
}
|
|
33
33
|
for (const k of ['scheduled', 'indexEmitted'] as const) {
|
|
34
34
|
if (cap[k] !== undefined) {
|
|
35
35
|
expect(
|
|
36
36
|
typeof cap[k],
|
|
37
|
-
|
|
37
|
+
req('openwop.it.distillation-shape.capabilities-memory-distillation-is-absent-or-a-well-formed-object', 'capabilities.schema.json §memory.distillation', `distillation.${k} MUST be a boolean when present`),
|
|
38
38
|
).toBe('boolean');
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -11,28 +11,28 @@
|
|
|
11
11
|
|
|
12
12
|
import { describe, it, expect } from 'vitest';
|
|
13
13
|
import { softSkip } from '../lib/soft-skip.js';
|
|
14
|
-
import { driver } from '../lib/driver.js';
|
|
15
14
|
import { readDistillationCap, invokeDistill } from '../lib/distillation.js';
|
|
15
|
+
import { req } from '../lib/requirement-ids.js';
|
|
16
16
|
|
|
17
17
|
describe('distillation-stable-archive (RFC 0062 §B)', () => {
|
|
18
18
|
it('identical sources + budget produce an identical archive checksum', async () => {
|
|
19
19
|
if ((await readDistillationCap())?.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `(await readDistillationCap())?.supported !== true` returned early');
|
|
20
|
-
const
|
|
20
|
+
const reqBody = {
|
|
21
21
|
memoryRef: 'conformance-distill',
|
|
22
22
|
tokenBudget: 8000,
|
|
23
23
|
sources: ['s1', 's2', 's3'],
|
|
24
24
|
};
|
|
25
|
-
const a = await invokeDistill(
|
|
25
|
+
const a = await invokeDistill(reqBody);
|
|
26
26
|
if (a === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
27
|
-
const b = await invokeDistill(
|
|
27
|
+
const b = await invokeDistill(reqBody);
|
|
28
28
|
if (b === null) return softSkip('blocked', 'precondition not met — `b === null` returned early (seam, prior step, or fixture unavailable)');
|
|
29
29
|
expect(
|
|
30
30
|
typeof a.body.archiveChecksum === 'string' && (a.body.archiveChecksum as string).length > 0,
|
|
31
|
-
|
|
31
|
+
req('openwop.it.distillation-stable-archive.identical-sources-budget-produce-an-identical-archive-checksum', 'RFC 0062 §B', 'a distillation run MUST produce a non-empty archive checksum'),
|
|
32
32
|
).toBe(true);
|
|
33
33
|
expect(
|
|
34
34
|
b.body.archiveChecksum,
|
|
35
|
-
|
|
35
|
+
req('openwop.it.distillation-stable-archive.identical-sources-budget-produce-an-identical-archive-checksum', 'RFC 0062 §B', 'the same source set + budget MUST yield a byte-stable archive'),
|
|
36
36
|
).toBe(a.body.archiveChecksum);
|
|
37
37
|
});
|
|
38
38
|
});
|