@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
|
@@ -48,6 +48,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
48
48
|
import { softSkip } from '../lib/soft-skip.js';
|
|
49
49
|
import { driver } from '../lib/driver.js';
|
|
50
50
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
51
|
+
import { req } from '../lib/requirement-ids.js';
|
|
51
52
|
|
|
52
53
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
53
54
|
|
|
@@ -80,18 +81,18 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: advertisement shape (R
|
|
|
80
81
|
if (d === null) {
|
|
81
82
|
softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
82
83
|
ctx.skip();
|
|
83
|
-
return;
|
|
84
|
+
return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
84
85
|
}
|
|
85
86
|
const rd = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.replayDeterminism;
|
|
86
87
|
if (rd === undefined) {
|
|
87
88
|
softSkip('inapplicable', 'optional advertisement — `multiAgent.executionModel.replayDeterminism` not advertised by this host (RFC 0041 §D)');
|
|
88
89
|
ctx.skip(); // optional advertisement — host hasn't opted in
|
|
89
|
-
return;
|
|
90
|
+
return softSkip('blocked', 'precondition not met — `rd === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
expect(
|
|
93
94
|
typeof rd.supported,
|
|
94
|
-
|
|
95
|
+
req('openwop.it.replay-divergence-at-refusal.replaydeterminism-when-present-conforms-to-rfc-0041-d',
|
|
95
96
|
'RFCS/0041-multi-agent-replay-under-nondeterminism.md §D',
|
|
96
97
|
'replayDeterminism.supported MUST be boolean when present',
|
|
97
98
|
),
|
|
@@ -101,7 +102,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: advertisement shape (R
|
|
|
101
102
|
const version = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.version as number | undefined;
|
|
102
103
|
expect(
|
|
103
104
|
typeof version === 'number' && version >= 4,
|
|
104
|
-
|
|
105
|
+
req('openwop.it.replay-divergence-at-refusal.replaydeterminism-when-present-conforms-to-rfc-0041-d',
|
|
105
106
|
'RFCS/0041-multi-agent-replay-under-nondeterminism.md §D',
|
|
106
107
|
'when replayDeterminism.supported: true, multiAgent.executionModel.version MUST be >= 4',
|
|
107
108
|
),
|
|
@@ -114,7 +115,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: advertisement shape (R
|
|
|
114
115
|
// assertion closes the conformance-enforcement gap.
|
|
115
116
|
expect(
|
|
116
117
|
rd.refusalDivergenceEmission,
|
|
117
|
-
|
|
118
|
+
req('openwop.it.replay-divergence-at-refusal.replaydeterminism-when-present-conforms-to-rfc-0041-d',
|
|
118
119
|
'schemas/capabilities.schema.json §replayDeterminism.refusalDivergenceEmission',
|
|
119
120
|
'hosts advertising version: 4 MUST set replayDeterminism.refusalDivergenceEmission to true',
|
|
120
121
|
),
|
|
@@ -196,7 +197,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
196
197
|
if (programStatus === 404) {
|
|
197
198
|
softSkip('blocked', 'precondition not met — `programStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
198
199
|
ctx.skip(); // mock-AI program seam not exposed — soft-skip
|
|
199
|
-
return;
|
|
200
|
+
return softSkip('blocked', 'precondition not met — `programStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
200
201
|
}
|
|
201
202
|
expect(programStatus).toBe(200);
|
|
202
203
|
|
|
@@ -206,7 +207,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
206
207
|
if (createRes.status === 404 || createRes.status === 422) {
|
|
207
208
|
softSkip('blocked', 'precondition not met — `createRes.status === 404 || createRes.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
208
209
|
ctx.skip(); // fixture not advertised
|
|
209
|
-
return;
|
|
210
|
+
return softSkip('blocked', 'precondition not met — `createRes.status === 404 || createRes.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
210
211
|
}
|
|
211
212
|
expect(createRes.status).toBe(201);
|
|
212
213
|
const sourceRunId = (createRes.json as { runId: string }).runId;
|
|
@@ -228,14 +229,14 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
228
229
|
|
|
229
230
|
expect(
|
|
230
231
|
replayTerminal.status,
|
|
231
|
-
|
|
232
|
+
req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref',
|
|
232
233
|
'RFCS/0041-multi-agent-replay-under-nondeterminism.md §B + spec/v1/rest-endpoints.md §"Common error codes"',
|
|
233
234
|
'replay MUST terminate `failed` when refusal-divergence is detected (silent substitution is non-conformant)',
|
|
234
235
|
),
|
|
235
236
|
).toBe('failed');
|
|
236
237
|
expect(
|
|
237
238
|
replayTerminal.error?.code,
|
|
238
|
-
|
|
239
|
+
req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref',
|
|
239
240
|
'spec/v1/rest-endpoints.md §"Common error codes" — replay_diverged_at_refusal',
|
|
240
241
|
'error.code MUST be `replay_diverged_at_refusal` per the canonical catalog',
|
|
241
242
|
),
|
|
@@ -245,7 +246,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
245
246
|
const divergenceEvent = replayEvents.find((e) => e.type === 'replay.divergedAtRefusal');
|
|
246
247
|
expect(
|
|
247
248
|
divergenceEvent,
|
|
248
|
-
|
|
249
|
+
req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref',
|
|
249
250
|
'schemas/run-event-payloads.schema.json §replayDivergedAtRefusal',
|
|
250
251
|
'replay event log MUST contain exactly one `replay.divergedAtRefusal` event identifying the divergence',
|
|
251
252
|
),
|
|
@@ -254,14 +255,14 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
254
255
|
expect(divergenceEvent?.payload?.nodeId).toBe(NODE_ID);
|
|
255
256
|
expect(
|
|
256
257
|
divergenceEvent?.payload?.originalEnvelopeKind,
|
|
257
|
-
|
|
258
|
+
req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref',
|
|
258
259
|
'schemas/run-event-payloads.schema.json §replayDivergedAtRefusal.originalEnvelopeKind',
|
|
259
260
|
'originalEnvelopeKind MUST be `valid` (source run completed normally)',
|
|
260
261
|
),
|
|
261
262
|
).toBe('valid');
|
|
262
263
|
expect(
|
|
263
264
|
divergenceEvent?.payload?.replayEnvelopeKind,
|
|
264
|
-
|
|
265
|
+
req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref',
|
|
265
266
|
'schemas/run-event-payloads.schema.json §replayDivergedAtRefusal.replayEnvelopeKind',
|
|
266
267
|
'replayEnvelopeKind MUST be `refusal` (replay hit the refusal entry of the mock program)',
|
|
267
268
|
),
|
|
@@ -279,9 +280,9 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
279
280
|
if (programStatus === 404) {
|
|
280
281
|
softSkip('blocked', 'precondition not met — `programStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
281
282
|
ctx.skip();
|
|
282
|
-
return;
|
|
283
|
+
return softSkip('blocked', 'precondition not met — `programStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
283
284
|
}
|
|
284
|
-
expect(programStatus).toBe(200);
|
|
285
|
+
expect(programStatus, req('openwop.it.replay-divergence-at-refusal.phase-4-host-must-emit-replay-divergedatrefusal-fail-with-replay-diverged-at-ref~2', 'RFC 0041 §B', 'Phase 4 host MUST emit replay.divergedAtRefusal + fail with replay_diverged_at_refusal when original=refusal + replay=valid (symmetric case)')).toBe(200);
|
|
285
286
|
|
|
286
287
|
const createRes = await driver.post('/v1/runs', {
|
|
287
288
|
workflowId: 'conformance-phase4-replay-divergence',
|
|
@@ -289,7 +290,7 @@ describe.skipIf(HTTP_SKIP)('replay-divergence-at-refusal: behavioral (RFC 0041
|
|
|
289
290
|
if (createRes.status === 404 || createRes.status === 422) {
|
|
290
291
|
softSkip('blocked', 'precondition not met — `createRes.status === 404 || createRes.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
291
292
|
ctx.skip();
|
|
292
|
-
return;
|
|
293
|
+
return softSkip('blocked', 'precondition not met — `createRes.status === 404 || createRes.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
293
294
|
}
|
|
294
295
|
expect(createRes.status).toBe(201);
|
|
295
296
|
const sourceRunId = (createRes.json as { runId: string }).runId;
|
|
@@ -79,6 +79,7 @@ import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
|
79
79
|
import { discoverOwnedTenant } from '../lib/webhook-receiver.js';
|
|
80
80
|
import { recordRequirement } from '../lib/requirement-ledger.js';
|
|
81
81
|
import { requirementIdForFile } from '../lib/scenario-disposition.js';
|
|
82
|
+
import { req } from '../lib/requirement-ids.js';
|
|
82
83
|
|
|
83
84
|
/**
|
|
84
85
|
* RFC 0148 §A — the MUST NOT gets its OWN disposition, separate from the file's.
|
|
@@ -108,10 +109,10 @@ interface Delivered {
|
|
|
108
109
|
|
|
109
110
|
async function startReceiver(): Promise<{ server: Server; url: string; received: Delivered[] }> {
|
|
110
111
|
const received: Delivered[] = [];
|
|
111
|
-
const server = createServer((
|
|
112
|
+
const server = createServer((reqBody: IncomingMessage, res: ServerResponse) => {
|
|
112
113
|
const chunks: Buffer[] = [];
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
reqBody.on('data', (c: Buffer) => chunks.push(c));
|
|
115
|
+
reqBody.on('end', () => {
|
|
115
116
|
received.push({ body: Buffer.concat(chunks).toString('utf8') });
|
|
116
117
|
res.writeHead(204);
|
|
117
118
|
res.end();
|
|
@@ -193,21 +194,21 @@ describe('replay-fanout-suppression: a replay fork MUST NOT fan out re-emitted e
|
|
|
193
194
|
+ 'set OPENWOP_WEBHOOK_ALLOW_PRIVATE=true on the host (or equivalent) to run',
|
|
194
195
|
);
|
|
195
196
|
}
|
|
196
|
-
expect(reg.status,
|
|
197
|
+
expect(reg.status, req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br',
|
|
197
198
|
'webhooks.md §"Register"',
|
|
198
199
|
'POST /v1/webhooks MUST return 201 on success',
|
|
199
200
|
)).toBe(201);
|
|
200
201
|
|
|
201
202
|
// ── LEG 1 — POSITIVE CONTROL. Prove this wiring delivers at all. ─────────
|
|
202
203
|
const create = await driver.post('/v1/runs', { workflowId: 'conformance-noop' });
|
|
203
|
-
expect(create.status, 'failed to start conformance-noop').toBe(201);
|
|
204
|
+
expect(create.status, req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br', 'webhooks.md §"Register"', 'failed to start conformance-noop')).toBe(201);
|
|
204
205
|
const sourceRunId = (create.json as { runId: string }).runId;
|
|
205
206
|
await pollUntilTerminal(sourceRunId, { timeoutMs: 10_000 });
|
|
206
207
|
await quietWindow(DELIVERY_GRACE_MS);
|
|
207
208
|
|
|
208
209
|
expect(
|
|
209
210
|
forRun(receiver.received, sourceRunId).length,
|
|
210
|
-
|
|
211
|
+
req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br',
|
|
211
212
|
'webhooks.md §"Register"',
|
|
212
213
|
'POSITIVE CONTROL: the host must deliver the source run\'s events to this receiver — '
|
|
213
214
|
+ 'without this, every "no delivery" assertion below is vacuous',
|
|
@@ -236,7 +237,7 @@ describe('replay-fanout-suppression: a replay fork MUST NOT fan out re-emitted e
|
|
|
236
237
|
+ 'has nothing to constrain on this host',
|
|
237
238
|
);
|
|
238
239
|
ctx.skip();
|
|
239
|
-
return;
|
|
240
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `replayCap?.supported !== true` returned early');
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
// ── LEG 2 — THE MUST NOT. A replay fork re-emits; it must not deliver. ───
|
|
@@ -261,16 +262,16 @@ describe('replay-fanout-suppression: a replay fork MUST NOT fan out re-emitted e
|
|
|
261
262
|
+ 'so the absence of deliveries below would prove nothing',
|
|
262
263
|
);
|
|
263
264
|
ctx.skip();
|
|
264
|
-
return;
|
|
265
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(replay.status, \'fanout-suppression replay fork\')` returned early (seam, prior step, or fixture unavailable)');
|
|
265
266
|
}
|
|
266
|
-
expect(replay.status, 'replay fork should be accepted').toBe(201);
|
|
267
|
+
expect(replay.status, req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br', 'webhooks.md §"Register"', 'replay fork should be accepted')).toBe(201);
|
|
267
268
|
const replayRunId = (replay.json as { runId: string }).runId;
|
|
268
269
|
await pollUntilTerminal(replayRunId, { timeoutMs: 30_000 });
|
|
269
270
|
await quietWindow(SUPPRESSION_WINDOW_MS);
|
|
270
271
|
|
|
271
272
|
expect(
|
|
272
273
|
forRun(receiver.received, replayRunId).map((d) => d.body.slice(0, 200)),
|
|
273
|
-
|
|
274
|
+
req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br',
|
|
274
275
|
'replay.md §"Host-initiated fan-out is an external effect"',
|
|
275
276
|
'a mode:"replay" fork MUST NOT emit outbound deliveries for the events it re-emits as fixed history — '
|
|
276
277
|
+ 'delivering one asserts to a subscriber that something happened in this run which did not',
|
|
@@ -283,11 +284,11 @@ describe('replay-fanout-suppression: a replay fork MUST NOT fan out re-emitted e
|
|
|
283
284
|
// still carries them). Without this, a host that simply failed the fork
|
|
284
285
|
// would pass leg 2.
|
|
285
286
|
const forkEvents = await driver.get(`/v1/runs/${encodeURIComponent(replayRunId)}/events`);
|
|
286
|
-
expect(forkEvents.status, 'fork events must be readable').toBe(200);
|
|
287
|
+
expect(forkEvents.status, req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br', 'replay.md §"Host-initiated fan-out is an external effect"', 'fork events must be readable')).toBe(200);
|
|
287
288
|
const forkEventList = (forkEvents.json as { events?: { type?: string }[] }).events ?? [];
|
|
288
289
|
expect(
|
|
289
290
|
forkEventList.length,
|
|
290
|
-
|
|
291
|
+
req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br',
|
|
291
292
|
'replay.md §"Host-initiated fan-out is an external effect"',
|
|
292
293
|
'suppression is OUTBOUND ONLY — the fork\'s own event log MUST still carry the re-emitted events, '
|
|
293
294
|
+ 'so an empty fork log means leg 2 proved nothing',
|
|
@@ -309,16 +310,16 @@ describe('replay-fanout-suppression: a replay fork MUST NOT fan out re-emitted e
|
|
|
309
310
|
});
|
|
310
311
|
if (branch.status === 501 || branch.status === 400) {
|
|
311
312
|
// branch not offered on this range — leg 2 still stands on its own.
|
|
312
|
-
return;
|
|
313
|
+
return softSkip('blocked', 'precondition not met — `branch.status === 501 || branch.status === 400` returned early (branch not offered on this range — leg 2 still stands on its own.) (seam, prior step, or fixture unavailable)');
|
|
313
314
|
}
|
|
314
|
-
expect(branch.status, 'branch fork should be accepted').toBe(201);
|
|
315
|
+
expect(branch.status, req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br', 'replay.md §"Host-initiated fan-out is an external effect"', 'branch fork should be accepted')).toBe(201);
|
|
315
316
|
const branchRunId = (branch.json as { runId: string }).runId;
|
|
316
317
|
await pollUntilTerminal(branchRunId, { timeoutMs: 30_000 });
|
|
317
318
|
await quietWindow(DELIVERY_GRACE_MS);
|
|
318
319
|
|
|
319
320
|
expect(
|
|
320
321
|
forRun(receiver.received, branchRunId).length,
|
|
321
|
-
|
|
322
|
+
req('openwop.it.replay-fanout-suppression.delivers-for-a-live-run-suppresses-for-a-replay-fork-and-delivers-again-for-a-br',
|
|
322
323
|
'replay.md §"Host-initiated fan-out is an external effect"',
|
|
323
324
|
'a branch fork is deliberately OUT of scope — its events are new facts, so suppressing them '
|
|
324
325
|
+ 'means the host keyed on "is a fork" rather than on replay-ness read from the run',
|
|
@@ -34,6 +34,7 @@ import { softSkip } from '../lib/soft-skip.js';
|
|
|
34
34
|
import { forkDeclined } from '../lib/fork-availability.js';
|
|
35
35
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
36
36
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
37
|
+
import { req } from '../lib/requirement-ids.js';
|
|
37
38
|
|
|
38
39
|
const MULTI_NODE_WORKFLOW_ID = 'conformance-multi-node';
|
|
39
40
|
const SKIP_NO_MULTI = !isFixtureAdvertised(MULTI_NODE_WORKFLOW_ID);
|
|
@@ -126,7 +127,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
126
127
|
if (replay?.supported !== true) {
|
|
127
128
|
softSkip('inapplicable', "host does not advertise `replay.supported: true` — the replay contract does not apply to it");
|
|
128
129
|
ctx.skip();
|
|
129
|
-
return;
|
|
130
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `replay?.supported !== true` returned early');
|
|
130
131
|
}
|
|
131
132
|
const modes = Array.isArray(replay.modes)
|
|
132
133
|
? replay.modes.filter((m): m is string => typeof m === 'string')
|
|
@@ -134,7 +135,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
134
135
|
if (!modes.includes('replay')) {
|
|
135
136
|
softSkip('inapplicable', "host does not advertise the `replay` fork mode — this leg's rule has no path to apply");
|
|
136
137
|
ctx.skip();
|
|
137
|
-
return;
|
|
138
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'replay\')` returned early');
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
const sourceRunId = await startAndFinishMultiNode();
|
|
@@ -146,7 +147,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
146
147
|
// with the standard event shape will hit the assertions below.
|
|
147
148
|
softSkip('blocked', "the advertised fixture's wire shape exposes no numeric sequence for node.completed(b), so there is no mid-run point to fork from");
|
|
148
149
|
ctx.skip();
|
|
149
|
-
return;
|
|
150
|
+
return softSkip('blocked', 'precondition not met — `fromSeq === null` returned early (seam, prior step, or fixture unavailable)');
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
const fork = await driver.post(
|
|
@@ -156,11 +157,11 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
156
157
|
|
|
157
158
|
if (forkDeclined(fork.status, 'arbitrary-event fork')) {
|
|
158
159
|
ctx.skip();
|
|
159
|
-
return;
|
|
160
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(fork.status, \'arbitrary-event fork\')` returned early (seam, prior step, or fixture unavailable)');
|
|
160
161
|
}
|
|
161
162
|
expect(
|
|
162
163
|
fork.status,
|
|
163
|
-
|
|
164
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed',
|
|
164
165
|
'spec/v1/replay.md §"Replay-from-event-log internals"',
|
|
165
166
|
`mid-range fromSeq=${fromSeq} replay fork MUST return 201`,
|
|
166
167
|
),
|
|
@@ -171,23 +172,23 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
171
172
|
sourceRunId?: unknown;
|
|
172
173
|
mode?: unknown;
|
|
173
174
|
};
|
|
174
|
-
expect(typeof body.runId, 'fork response MUST include a new runId').toBe(
|
|
175
|
+
expect(typeof body.runId, req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed', 'spec/v1/replay.md §"Replay-from-event-log internals"', 'fork response MUST include a new runId')).toBe(
|
|
175
176
|
'string',
|
|
176
177
|
);
|
|
177
178
|
expect(
|
|
178
179
|
body.runId,
|
|
179
|
-
'forked runId MUST differ from source',
|
|
180
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed', 'spec/v1/replay.md §"Replay-from-event-log internals"', 'forked runId MUST differ from source'),
|
|
180
181
|
).not.toBe(sourceRunId);
|
|
181
|
-
expect(body.sourceRunId, 'fork response MUST echo sourceRunId').toBe(
|
|
182
|
+
expect(body.sourceRunId, req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed', 'spec/v1/replay.md §"Replay-from-event-log internals"', 'fork response MUST echo sourceRunId')).toBe(
|
|
182
183
|
sourceRunId,
|
|
183
184
|
);
|
|
184
|
-
expect(body.mode, 'fork response MUST echo mode').toBe('replay');
|
|
185
|
+
expect(body.mode, req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed', 'spec/v1/replay.md §"Replay-from-event-log internals"', 'fork response MUST echo mode')).toBe('replay');
|
|
185
186
|
|
|
186
187
|
const newRunId = body.runId as string;
|
|
187
188
|
const terminal = await pollUntilTerminal(newRunId, { timeoutMs: 15_000 });
|
|
188
189
|
expect(
|
|
189
190
|
terminal.status,
|
|
190
|
-
|
|
191
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-replay-fork-produces-a-new-run-that-reaches-completed',
|
|
191
192
|
'spec/v1/replay.md §"Replay determinism"',
|
|
192
193
|
`replay fork from mid-range fromSeq=${fromSeq} MUST reach the same terminal status as the source`,
|
|
193
194
|
),
|
|
@@ -205,14 +206,14 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
205
206
|
const replay = await fetchReplayCapability();
|
|
206
207
|
if (replay?.supported !== true) {
|
|
207
208
|
ctx.skip();
|
|
208
|
-
return;
|
|
209
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `replay?.supported !== true` returned early');
|
|
209
210
|
}
|
|
210
211
|
const modes = Array.isArray(replay.modes)
|
|
211
212
|
? replay.modes.filter((m): m is string => typeof m === 'string')
|
|
212
213
|
: [];
|
|
213
214
|
if (!modes.includes('replay')) {
|
|
214
215
|
ctx.skip();
|
|
215
|
-
return;
|
|
216
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'replay\')` returned early');
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
const sourceRunId = await startAndFinishMultiNode();
|
|
@@ -220,7 +221,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
220
221
|
const fromSeq = pickMidRangeFromSeq(sourceEvents);
|
|
221
222
|
if (fromSeq === null) {
|
|
222
223
|
ctx.skip();
|
|
223
|
-
return;
|
|
224
|
+
return softSkip('blocked', 'precondition not met — `fromSeq === null` returned early (seam, prior step, or fixture unavailable)');
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
// Fork twice at the same mid-range point. Per replay.md, both
|
|
@@ -233,7 +234,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
233
234
|
);
|
|
234
235
|
if (forkDeclined(fork1.status, 'arbitrary-event fork 1')) {
|
|
235
236
|
ctx.skip();
|
|
236
|
-
return;
|
|
237
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(fork1.status, \'arbitrary-event fork 1\')` returned early (seam, prior step, or fixture unavailable)');
|
|
237
238
|
}
|
|
238
239
|
expect(fork1.status).toBe(201);
|
|
239
240
|
const fork1Id = (fork1.json as { runId: string }).runId;
|
|
@@ -245,7 +246,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
245
246
|
);
|
|
246
247
|
if (forkDeclined(fork2.status, 'arbitrary-event fork 2')) {
|
|
247
248
|
ctx.skip();
|
|
248
|
-
return;
|
|
249
|
+
return softSkip('blocked', 'precondition not met — `forkDeclined(fork2.status, \'arbitrary-event fork 2\')` returned early (seam, prior step, or fixture unavailable)');
|
|
249
250
|
}
|
|
250
251
|
expect(fork2.status).toBe(201);
|
|
251
252
|
const fork2Id = (fork2.json as { runId: string }).runId;
|
|
@@ -274,7 +275,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
274
275
|
|
|
275
276
|
expect(
|
|
276
277
|
tail1.length,
|
|
277
|
-
|
|
278
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-determinism-same-source-same-fromseq-identical-post-fork-events-modu',
|
|
278
279
|
'spec/v1/replay.md §"Replay determinism"',
|
|
279
280
|
`two replay forks at fromSeq=${fromSeq} MUST produce the same number of re-executed events`,
|
|
280
281
|
),
|
|
@@ -282,7 +283,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
282
283
|
|
|
283
284
|
expect(
|
|
284
285
|
structuralShape(tail1),
|
|
285
|
-
|
|
286
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-determinism-same-source-same-fromseq-identical-post-fork-events-modu',
|
|
286
287
|
'spec/v1/replay.md §"Replay determinism"',
|
|
287
288
|
`event sequence (type/nodeId/data) post-fromSeq=${fromSeq} MUST be identical across two replay forks`,
|
|
288
289
|
),
|
|
@@ -301,14 +302,14 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
301
302
|
if (replay?.supported !== true) {
|
|
302
303
|
softSkip('inapplicable', "host does not advertise `replay.supported: true` — the replay contract does not apply to it");
|
|
303
304
|
ctx.skip();
|
|
304
|
-
return;
|
|
305
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `replay?.supported !== true` returned early');
|
|
305
306
|
}
|
|
306
307
|
const modes = Array.isArray(replay.modes)
|
|
307
308
|
? replay.modes.filter((m): m is string => typeof m === 'string')
|
|
308
309
|
: [];
|
|
309
310
|
if (!modes.includes('branch')) {
|
|
310
311
|
ctx.skip();
|
|
311
|
-
return;
|
|
312
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'branch\')` returned early');
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
const sourceRunId = await startAndFinishMultiNode();
|
|
@@ -316,7 +317,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
316
317
|
const fromSeq = pickMidRangeFromSeq(sourceEvents);
|
|
317
318
|
if (fromSeq === null) {
|
|
318
319
|
ctx.skip();
|
|
319
|
-
return;
|
|
320
|
+
return softSkip('blocked', 'precondition not met — `fromSeq === null` returned early (seam, prior step, or fixture unavailable)');
|
|
320
321
|
}
|
|
321
322
|
|
|
322
323
|
// Branch mode with an empty overlay is the boundary case: the
|
|
@@ -331,11 +332,11 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
331
332
|
|
|
332
333
|
if (fork.status === 501) {
|
|
333
334
|
ctx.skip();
|
|
334
|
-
return;
|
|
335
|
+
return softSkip('blocked', 'precondition not met — `fork.status === 501` returned early (seam, prior step, or fixture unavailable)');
|
|
335
336
|
}
|
|
336
337
|
expect(
|
|
337
338
|
fork.status,
|
|
338
|
-
|
|
339
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-branch-fork-with-empty-overlay-produces-a-new-run-that-reaches-compl',
|
|
339
340
|
'spec/v1/replay.md §"branch mode"',
|
|
340
341
|
`mid-range fromSeq=${fromSeq} branch fork with empty overlay MUST return 201`,
|
|
341
342
|
),
|
|
@@ -345,7 +346,7 @@ describe.skipIf(SKIP_NO_MULTI)(
|
|
|
345
346
|
const terminal = await pollUntilTerminal(newRunId, { timeoutMs: 15_000 });
|
|
346
347
|
expect(
|
|
347
348
|
terminal.status,
|
|
348
|
-
|
|
349
|
+
req('openwop.it.replay-fork-arbitrary.mid-fromseq-branch-fork-with-empty-overlay-produces-a-new-run-that-reaches-compl',
|
|
349
350
|
'spec/v1/replay.md',
|
|
350
351
|
`branch fork from mid-range fromSeq=${fromSeq} MUST reach terminal status`,
|
|
351
352
|
),
|
|
@@ -29,6 +29,7 @@ import { softSkip } from '../lib/soft-skip.js';
|
|
|
29
29
|
import { forkDeclined } from '../lib/fork-availability.js';
|
|
30
30
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
31
31
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
33
|
|
|
33
34
|
const SOURCE_WORKFLOW_ID = 'conformance-noop';
|
|
34
35
|
const SKIP_NO_NOOP = !isFixtureAdvertised(SOURCE_WORKFLOW_ID);
|
|
@@ -64,7 +65,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: fork from fromSeq=0 in replay mode', () =
|
|
|
64
65
|
// unexercised tests apart from honest passes.
|
|
65
66
|
softSkip('inapplicable', "host does not advertise the `replay` fork mode — this leg's rule has no path to apply");
|
|
66
67
|
ctx.skip();
|
|
67
|
-
return;
|
|
68
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'replay\')` returned early');
|
|
68
69
|
}
|
|
69
70
|
const sourceRunId = await startAndFinishNoop();
|
|
70
71
|
|
|
@@ -73,27 +74,27 @@ describe.skipIf(SKIP_NO_NOOP)('replay: fork from fromSeq=0 in replay mode', () =
|
|
|
73
74
|
{ fromSeq: 0, mode: 'replay' },
|
|
74
75
|
);
|
|
75
76
|
|
|
76
|
-
if (forkDeclined(fork.status, 'replay fork')) return;
|
|
77
|
-
expect(fork.status,
|
|
77
|
+
if (forkDeclined(fork.status, 'replay fork')) return softSkip('blocked', 'precondition not met — `forkDeclined(fork.status, \'replay fork\')` returned early (seam, prior step, or fixture unavailable)');
|
|
78
|
+
expect(fork.status, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed',
|
|
78
79
|
'rest-endpoints.md POST /v1/runs/{runId}:fork',
|
|
79
80
|
'fork MUST return 201 on accepted replay',
|
|
80
81
|
)).toBe(201);
|
|
81
82
|
|
|
82
83
|
const body = fork.json as { runId?: unknown; sourceRunId?: unknown; mode?: unknown };
|
|
83
|
-
expect(typeof body.runId,
|
|
84
|
+
expect(typeof body.runId, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed',
|
|
84
85
|
'replay.md',
|
|
85
86
|
'fork response MUST include a new runId',
|
|
86
87
|
)).toBe('string');
|
|
87
|
-
expect(body.runId, 'forked runId MUST differ from source').not.toBe(sourceRunId);
|
|
88
|
-
expect(body.sourceRunId,
|
|
88
|
+
expect(body.runId, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed', 'replay.md', 'forked runId MUST differ from source')).not.toBe(sourceRunId);
|
|
89
|
+
expect(body.sourceRunId, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed',
|
|
89
90
|
'replay.md',
|
|
90
91
|
'fork response MUST echo sourceRunId',
|
|
91
92
|
)).toBe(sourceRunId);
|
|
92
|
-
expect(body.mode, 'fork response MUST echo mode').toBe('replay');
|
|
93
|
+
expect(body.mode, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed', 'replay.md', 'fork response MUST echo mode')).toBe('replay');
|
|
93
94
|
|
|
94
95
|
const newRunId = body.runId as string;
|
|
95
96
|
const terminal = await pollUntilTerminal(newRunId, { timeoutMs: 15_000 });
|
|
96
|
-
expect(terminal.status,
|
|
97
|
+
expect(terminal.status, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed',
|
|
97
98
|
'replay.md',
|
|
98
99
|
'replay of a successful run MUST reach the same terminal status',
|
|
99
100
|
)).toBe('completed');
|
|
@@ -106,7 +107,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: fork from fromSeq=0 in branch mode with e
|
|
|
106
107
|
if (!modes.includes('branch')) {
|
|
107
108
|
softSkip('inapplicable', "host does not advertise the `branch` fork mode — this leg's rule has no path to apply");
|
|
108
109
|
ctx.skip();
|
|
109
|
-
return;
|
|
110
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'branch\')` returned early');
|
|
110
111
|
}
|
|
111
112
|
const sourceRunId = await startAndFinishNoop();
|
|
112
113
|
|
|
@@ -115,8 +116,8 @@ describe.skipIf(SKIP_NO_NOOP)('replay: fork from fromSeq=0 in branch mode with e
|
|
|
115
116
|
{ fromSeq: 0, mode: 'branch', runOptionsOverlay: {} },
|
|
116
117
|
);
|
|
117
118
|
|
|
118
|
-
if (forkDeclined(fork.status, 'branch fork')) return;
|
|
119
|
-
expect(fork.status,
|
|
119
|
+
if (forkDeclined(fork.status, 'branch fork')) return softSkip('blocked', 'precondition not met — `forkDeclined(fork.status, \'branch fork\')` returned early (seam, prior step, or fixture unavailable)');
|
|
120
|
+
expect(fork.status, req('openwop.it.replay-fork.produces-a-new-run-that-reaches-terminal-completed~2',
|
|
120
121
|
'rest-endpoints.md POST /v1/runs/{runId}:fork',
|
|
121
122
|
'branch fork MUST return 201',
|
|
122
123
|
)).toBe(201);
|
|
@@ -143,7 +144,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
143
144
|
if (modes.length === 0) {
|
|
144
145
|
softSkip('inapplicable', "host advertises no usable fork mode for this leg");
|
|
145
146
|
ctx.skip();
|
|
146
|
-
return;
|
|
147
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `modes.length === 0` returned early');
|
|
147
148
|
}
|
|
148
149
|
const mode = modes.includes('branch') ? 'branch' : 'replay';
|
|
149
150
|
const sourceRunId = await startAndFinishNoop();
|
|
@@ -151,7 +152,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
151
152
|
`/v1/runs/${encodeURIComponent(sourceRunId)}:fork`,
|
|
152
153
|
{ fromSeq: -1, mode },
|
|
153
154
|
);
|
|
154
|
-
expect(res.status,
|
|
155
|
+
expect(res.status, req('openwop.it.replay-fork.rejects-negative-fromseq-with-400',
|
|
155
156
|
'rest-endpoints.md',
|
|
156
157
|
'negative fromSeq MUST return 400',
|
|
157
158
|
)).toBe(400);
|
|
@@ -162,7 +163,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
162
163
|
if (modes.length === 0) {
|
|
163
164
|
softSkip('inapplicable', "host advertises no usable fork mode for this leg");
|
|
164
165
|
ctx.skip();
|
|
165
|
-
return;
|
|
166
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `modes.length === 0` returned early');
|
|
166
167
|
}
|
|
167
168
|
const mode = modes.includes('branch') ? 'branch' : 'replay';
|
|
168
169
|
const sourceRunId = await startAndFinishNoop();
|
|
@@ -172,7 +173,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
172
173
|
`/v1/runs/${encodeURIComponent(sourceRunId)}:fork`,
|
|
173
174
|
{ fromSeq: 99999, mode },
|
|
174
175
|
);
|
|
175
|
-
expect(res.status,
|
|
176
|
+
expect(res.status, req('openwop.it.replay-fork.rejects-fromseq-beyond-source-event-log-length-with-422',
|
|
176
177
|
'rest-endpoints.md POST /v1/runs/{runId}:fork',
|
|
177
178
|
'fromSeq beyond source event log MUST return 422',
|
|
178
179
|
)).toBe(422);
|
|
@@ -187,7 +188,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
187
188
|
// Visible skip rather than silent vacuous pass.
|
|
188
189
|
softSkip('inapplicable', "host does not advertise the `replay` fork mode — the runOptionsOverlay rejection rule only applies to hosts that do");
|
|
189
190
|
ctx.skip();
|
|
190
|
-
return;
|
|
191
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!modes.includes(\'replay\')` returned early');
|
|
191
192
|
}
|
|
192
193
|
const sourceRunId = await startAndFinishNoop();
|
|
193
194
|
const res = await driver.post(
|
|
@@ -198,7 +199,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
198
199
|
runOptionsOverlay: { configurable: { recursionLimit: 50 } },
|
|
199
200
|
},
|
|
200
201
|
);
|
|
201
|
-
expect(res.status,
|
|
202
|
+
expect(res.status, req('openwop.it.replay-fork.rejects-replay-mode-with-non-empty-runoptionsoverlay-overlay-is-branch-only',
|
|
202
203
|
'rest-endpoints.md POST /v1/runs/{runId}:fork',
|
|
203
204
|
'replay mode + non-empty overlay MUST return 400 (overlay is branch-only)',
|
|
204
205
|
)).toBe(400);
|
|
@@ -209,7 +210,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
209
210
|
if (modes.length === 0) {
|
|
210
211
|
softSkip('inapplicable', "host advertises no usable fork mode for this leg");
|
|
211
212
|
ctx.skip();
|
|
212
|
-
return;
|
|
213
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `modes.length === 0` returned early');
|
|
213
214
|
}
|
|
214
215
|
const mode = modes.includes('branch') ? 'branch' : 'replay';
|
|
215
216
|
const res = await driver.post(
|
|
@@ -218,7 +219,7 @@ describe.skipIf(SKIP_NO_NOOP)('replay: validation errors', () => {
|
|
|
218
219
|
);
|
|
219
220
|
expect(
|
|
220
221
|
[403, 404].includes(res.status),
|
|
221
|
-
|
|
222
|
+
req('openwop.it.replay-fork.rejects-fork-on-a-non-existent-run-with-404', 'rest-endpoints.md', 'fork on unknown run MUST return 404 or 403'),
|
|
222
223
|
).toBe(true);
|
|
223
224
|
});
|
|
224
225
|
});
|