@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
|
@@ -36,6 +36,8 @@ import { driver } from '../lib/driver.js';
|
|
|
36
36
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
37
37
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
38
38
|
import { getCollector, waitForRunSpans } from '../lib/otel-collector.js';
|
|
39
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* Callback-shaped: the host exports OTLP metrics to the suite's collector.
|
|
@@ -91,14 +93,14 @@ describe.skipIf(SKIP_NO_NOOP)('cost-attribution: metrics.openwopCost forward-com
|
|
|
91
93
|
// passes trivially; don't force a value on a workflow that produces
|
|
92
94
|
// no cost.
|
|
93
95
|
expect(openwopCost).toBeUndefined();
|
|
94
|
-
return;
|
|
96
|
+
return softSkip('blocked', 'precondition not met — `openwopCost === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
// When present, validate the canonical shape per
|
|
98
100
|
// run-snapshot.schema.json §metrics.openwopCost.
|
|
99
101
|
if ('usd' in openwopCost) {
|
|
100
|
-
expect(typeof openwopCost.usd, 'metrics.openwopCost.usd MUST be a number').toBe('number');
|
|
101
|
-
expect(openwopCost.usd!, 'metrics.openwopCost.usd MUST be >= 0').toBeGreaterThanOrEqual(0);
|
|
102
|
+
expect(typeof openwopCost.usd, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.usd MUST be a number')).toBe('number');
|
|
103
|
+
expect(openwopCost.usd!, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.usd MUST be >= 0')).toBeGreaterThanOrEqual(0);
|
|
102
104
|
}
|
|
103
105
|
if ('tokens' in openwopCost && openwopCost.tokens) {
|
|
104
106
|
if ('input' in openwopCost.tokens) {
|
|
@@ -115,10 +117,10 @@ describe.skipIf(SKIP_NO_NOOP)('cost-attribution: metrics.openwopCost forward-com
|
|
|
115
117
|
expect(openwopCost.duration_ms!).toBeGreaterThanOrEqual(0);
|
|
116
118
|
}
|
|
117
119
|
if ('model' in openwopCost) {
|
|
118
|
-
expect(typeof openwopCost.model, 'metrics.openwopCost.model MUST be a string').toBe('string');
|
|
120
|
+
expect(typeof openwopCost.model, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.model MUST be a string')).toBe('string');
|
|
119
121
|
}
|
|
120
122
|
if ('provider' in openwopCost) {
|
|
121
|
-
expect(typeof openwopCost.provider, 'metrics.openwopCost.provider MUST be a string').toBe('string');
|
|
123
|
+
expect(typeof openwopCost.provider, req('openwop.it.cost-attribution.on-any-run-if-metrics-openwopcost-is-present-its-shape-must-match-the-spec', 'spec/v1/observability.md §"AI cost', 'metrics.openwopCost.provider MUST be a string')).toBe('string');
|
|
122
124
|
}
|
|
123
125
|
});
|
|
124
126
|
});
|
|
@@ -140,23 +142,23 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
|
|
|
140
142
|
// Fixture absent — host does not opt into OPENWOP_CONFORMANCE_FIXTURES.
|
|
141
143
|
// That's spec-allowed; the scenario passes trivially.
|
|
142
144
|
if (create.status === 404 || create.status === 422) {
|
|
143
|
-
return;
|
|
145
|
+
return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (Fixture absent — host does not opt into OPENWOP_CONFORMANCE_FIXTURES. That\'s spec-allowed; the scenario passes trivially.) (seam,…');
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
expect(create.status,
|
|
148
|
+
expect(create.status, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
147
149
|
'rest-endpoints.md POST /v1/runs',
|
|
148
150
|
'starting openwop-smoke-cost-emit MUST succeed when OPENWOP_CONFORMANCE_FIXTURES=1 is advertised',
|
|
149
151
|
)).toBe(201);
|
|
150
152
|
const runId = (create.json as { runId: string }).runId;
|
|
151
153
|
|
|
152
154
|
const terminal = await pollUntilTerminal(runId);
|
|
153
|
-
expect(terminal.status,
|
|
155
|
+
expect(terminal.status, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
154
156
|
'observability.md §AI cost',
|
|
155
157
|
'cost-emit fixture run MUST reach terminal completed',
|
|
156
158
|
)).toBe('completed');
|
|
157
159
|
|
|
158
160
|
const openwopCost = terminal.metrics?.openwopCost;
|
|
159
|
-
expect(openwopCost,
|
|
161
|
+
expect(openwopCost, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
160
162
|
'run-snapshot.schema.json §metrics.openwopCost',
|
|
161
163
|
'metrics.openwopCost MUST be populated after a node calls ctx.recordCost()',
|
|
162
164
|
)).toBeDefined();
|
|
@@ -176,14 +178,14 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
|
|
|
176
178
|
// Tokens — MUST be non-negative integers when present.
|
|
177
179
|
if ('tokens' in openwopCost! && openwopCost!.tokens) {
|
|
178
180
|
if ('input' in openwopCost!.tokens) {
|
|
179
|
-
expect(Number.isInteger(openwopCost!.tokens.input),
|
|
181
|
+
expect(Number.isInteger(openwopCost!.tokens.input), req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
180
182
|
'observability.md §openwop.cost.tokens.input',
|
|
181
183
|
'tokens.input MUST be a non-negative integer',
|
|
182
184
|
)).toBe(true);
|
|
183
185
|
expect(openwopCost!.tokens.input!).toBeGreaterThanOrEqual(0);
|
|
184
186
|
}
|
|
185
187
|
if ('output' in openwopCost!.tokens) {
|
|
186
|
-
expect(Number.isInteger(openwopCost!.tokens.output),
|
|
188
|
+
expect(Number.isInteger(openwopCost!.tokens.output), req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
187
189
|
'observability.md §openwop.cost.tokens.output',
|
|
188
190
|
'tokens.output MUST be a non-negative integer',
|
|
189
191
|
)).toBe(true);
|
|
@@ -193,11 +195,11 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
|
|
|
193
195
|
|
|
194
196
|
// USD — MUST be non-negative number (fractional allowed).
|
|
195
197
|
if ('usd' in openwopCost!) {
|
|
196
|
-
expect(typeof openwopCost!.usd,
|
|
198
|
+
expect(typeof openwopCost!.usd, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
197
199
|
'observability.md §openwop.cost.usd',
|
|
198
200
|
'usd MUST be a number',
|
|
199
201
|
)).toBe('number');
|
|
200
|
-
expect(openwopCost!.usd!,
|
|
202
|
+
expect(openwopCost!.usd!, req('openwop.it.cost-attribution.metrics-openwopcost-must-carry-the-canary-cost-shape-after-the-fixture-node-runs',
|
|
201
203
|
'observability.md §openwop.cost.usd',
|
|
202
204
|
'usd MUST be >= 0',
|
|
203
205
|
)).toBeGreaterThanOrEqual(0);
|
|
@@ -209,7 +211,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
|
|
|
209
211
|
workflowId: 'openwop-smoke-cost-emit',
|
|
210
212
|
});
|
|
211
213
|
if (create.status === 404 || create.status === 422) {
|
|
212
|
-
return;
|
|
214
|
+
return softSkip('blocked', 'precondition not met — `create.status === 404 || create.status === 422` returned early (seam, prior step, or fixture unavailable)');
|
|
213
215
|
}
|
|
214
216
|
expect(create.status).toBe(201);
|
|
215
217
|
const runId = (create.json as { runId: string }).runId;
|
|
@@ -224,7 +226,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: end-to-end roundtrip via c
|
|
|
224
226
|
const completed = events.filter(
|
|
225
227
|
(e) => e.type === 'node.completed' && e.nodeId === 'emit-cost',
|
|
226
228
|
);
|
|
227
|
-
expect(completed.length,
|
|
229
|
+
expect(completed.length, req('openwop.it.cost-attribution.cost-emit-fixture-run-must-emit-a-node-completed-event-for-the-cost-emitting-nod',
|
|
228
230
|
'event-log.md §node.completed',
|
|
229
231
|
'cost-emit fixture node MUST emit exactly one node.completed event',
|
|
230
232
|
)).toBe(1);
|
|
@@ -247,7 +249,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
247
249
|
if (!getCollector()) {
|
|
248
250
|
// eslint-disable-next-line no-console
|
|
249
251
|
console.warn('[cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run');
|
|
250
|
-
return;
|
|
252
|
+
return softSkip('blocked', 'precondition not met — `!getCollector()` returned early ([cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run) (seam, prior step, or fixture unavailable)');
|
|
251
253
|
}
|
|
252
254
|
const collector = getCollector()!;
|
|
253
255
|
collector.reset();
|
|
@@ -258,7 +260,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
258
260
|
await pollUntilTerminal(runId, { timeoutMs: 15_000 });
|
|
259
261
|
|
|
260
262
|
const runSpans = await waitForRunSpans(runId, { timeoutMs: 5_000, minCount: 1 });
|
|
261
|
-
expect(runSpans.length,
|
|
263
|
+
expect(runSpans.length, req('openwop.it.cost-attribution.only-allowlisted-openwop-cost-attributes-reach-the-otel-span-g6-close-criteria-a',
|
|
262
264
|
'observability.md §"Span attributes"',
|
|
263
265
|
'host MUST emit at least one span for the cost-emit run',
|
|
264
266
|
)).toBeGreaterThan(0);
|
|
@@ -276,7 +278,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
276
278
|
}
|
|
277
279
|
}
|
|
278
280
|
}
|
|
279
|
-
expect(stray,
|
|
281
|
+
expect(stray, req('openwop.it.cost-attribution.only-allowlisted-openwop-cost-attributes-reach-the-otel-span-g6-close-criteria-a',
|
|
280
282
|
'observability.md §"Cost attribution attributes" (allowlist enforcement)',
|
|
281
283
|
'host MUST NOT emit any openwop.cost.* attribute outside OPENWOP_COST_ATTRIBUTE_NAMES; defense-in-depth against accidental leakage of upstream provider fields under unfamiliar key names',
|
|
282
284
|
)).toEqual([]);
|
|
@@ -286,7 +288,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
286
288
|
if (!getCollector()) {
|
|
287
289
|
// eslint-disable-next-line no-console
|
|
288
290
|
console.warn('[cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run');
|
|
289
|
-
return;
|
|
291
|
+
return softSkip('blocked', 'precondition not met — `!getCollector()` returned early ([cost-attribution] OTel collector not started; set OPENWOP_OTEL_COLLECTOR=true to run) (seam, prior step, or fixture unavailable)');
|
|
290
292
|
}
|
|
291
293
|
const collector = getCollector()!;
|
|
292
294
|
collector.reset();
|
|
@@ -309,7 +311,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
309
311
|
|
|
310
312
|
expect(
|
|
311
313
|
corpus.includes('CANARY-openwop-CONFORMANCE-NEVER-SECRET'),
|
|
312
|
-
|
|
314
|
+
req('openwop.it.cost-attribution.credential-shaped-canaries-do-not-leak-to-any-otel-attribute-g6-close-criteria-r',
|
|
313
315
|
'SECURITY/invariants.yaml cost-attribution-allowlist-redaction',
|
|
314
316
|
'no canary plaintext substring may survive the allowlist sanitizer on its way to OTel spans',
|
|
315
317
|
),
|
|
@@ -320,7 +322,7 @@ describe.skipIf(SKIP_NO_COST_EMIT)('cost-attribution: G6 / O4 allowlist + redact
|
|
|
320
322
|
// through non-canary keys that the allowlist still happens to let
|
|
321
323
|
// through (none today, but the regression test is cheap).
|
|
322
324
|
const byokMatches = corpus.match(CREDENTIAL_SHAPE_RE) ?? [];
|
|
323
|
-
expect(byokMatches,
|
|
325
|
+
expect(byokMatches, req('openwop.it.cost-attribution.credential-shaped-canaries-do-not-leak-to-any-otel-attribute-g6-close-criteria-r',
|
|
324
326
|
'SECURITY/invariants.yaml cost-attribution-allowlist-redaction',
|
|
325
327
|
'no credential-shape substring may appear in cost-attribute span values',
|
|
326
328
|
)).toEqual([]);
|
|
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
28
28
|
import { softSkip } from '../lib/soft-skip.js';
|
|
29
29
|
import { driver } from '../lib/driver.js';
|
|
30
30
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
31
32
|
|
|
32
33
|
interface DiscoveryCredentials {
|
|
33
34
|
supported?: boolean;
|
|
@@ -54,7 +55,7 @@ describe('credential-payload-redaction: advertisement shape (RFC 0046 §A)', ()
|
|
|
54
55
|
if (cred === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cred === null` returned early');
|
|
55
56
|
expect(
|
|
56
57
|
typeof cred.supported,
|
|
57
|
-
|
|
58
|
+
req('openwop.it.credential-payload-redaction.capabilities-credentials-supported-is-a-boolean-when-advertised',
|
|
58
59
|
'capabilities.schema.json §credentials',
|
|
59
60
|
'capabilities.credentials.supported MUST be a boolean when credentials is advertised',
|
|
60
61
|
),
|
|
@@ -75,7 +76,7 @@ describe('credential-payload-redaction: resolved material MUST NOT cross the wir
|
|
|
75
76
|
|
|
76
77
|
expect(
|
|
77
78
|
res.status,
|
|
78
|
-
|
|
79
|
+
req('openwop.it.credential-payload-redaction.canary-plaintext-is-absent-from-every-observable-run-surface',
|
|
79
80
|
'SECURITY/invariants.yaml credential-payload-redaction',
|
|
80
81
|
'the credentials echo seam MUST resolve the seeded credential and return its observable surfaces',
|
|
81
82
|
),
|
|
@@ -86,7 +87,7 @@ describe('credential-payload-redaction: resolved material MUST NOT cross the wir
|
|
|
86
87
|
const serialized = JSON.stringify(res.json ?? {});
|
|
87
88
|
expect(
|
|
88
89
|
serialized.includes(CANARY),
|
|
89
|
-
|
|
90
|
+
req('openwop.it.credential-payload-redaction.canary-plaintext-is-absent-from-every-observable-run-surface',
|
|
90
91
|
'SECURITY/invariants.yaml credential-payload-redaction',
|
|
91
92
|
'resolved credential material MUST NOT appear in inputs, variables, channels, events, snapshot, or debug bundle — only the reference may cross the wire',
|
|
92
93
|
),
|
|
@@ -23,6 +23,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
23
23
|
import { softSkip } from '../lib/soft-skip.js';
|
|
24
24
|
import { driver } from '../lib/driver.js';
|
|
25
25
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
27
|
|
|
27
28
|
interface DiscoveryCredentials {
|
|
28
29
|
supported?: boolean;
|
|
@@ -53,7 +54,7 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
|
|
|
53
54
|
if (cred === null) return softSkip('inapplicable', 'host doesn\'t advertise host.credentials at all');
|
|
54
55
|
expect(
|
|
55
56
|
typeof cred.supported,
|
|
56
|
-
|
|
57
|
+
req('openwop.it.credentials-capability-shape.capabilities-credentials-is-either-absent-or-well-formed',
|
|
57
58
|
'capabilities.schema.json §credentials',
|
|
58
59
|
'capabilities.credentials.supported MUST be a boolean when credentials is advertised',
|
|
59
60
|
),
|
|
@@ -65,12 +66,12 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
|
|
|
65
66
|
if (!cred?.supported || cred.scopes === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cred?.supported || cred.scopes === undefined` returned early');
|
|
66
67
|
expect(
|
|
67
68
|
Array.isArray(cred.scopes),
|
|
68
|
-
|
|
69
|
+
req('openwop.it.credentials-capability-shape.scopes-is-a-subset-of-user-workspace-tenant-when-supported', 'RFC 0046 §A', 'capabilities.credentials.scopes MUST be an array'),
|
|
69
70
|
).toBe(true);
|
|
70
71
|
for (const scope of cred.scopes) {
|
|
71
72
|
expect(
|
|
72
73
|
VALID_SCOPES.has(scope),
|
|
73
|
-
|
|
74
|
+
req('openwop.it.credentials-capability-shape.scopes-is-a-subset-of-user-workspace-tenant-when-supported',
|
|
74
75
|
'RFC 0046 §A',
|
|
75
76
|
`capabilities.credentials.scopes entries MUST be one of {${[...VALID_SCOPES].join(', ')}}, got: ${scope}`,
|
|
76
77
|
),
|
|
@@ -83,7 +84,7 @@ describe('credentials-capability-shape: advertisement shape (RFC 0046 §A)', ()
|
|
|
83
84
|
if (!cred?.supported || cred.rotation === undefined) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cred?.supported || cred.rotation === undefined` returned early');
|
|
84
85
|
expect(
|
|
85
86
|
VALID_ROTATION.has(cred.rotation),
|
|
86
|
-
|
|
87
|
+
req('openwop.it.credentials-capability-shape.rotation-is-one-of-none-two-key-overlap-when-present',
|
|
87
88
|
'RFC 0046 §A',
|
|
88
89
|
`capabilities.credentials.rotation MUST be one of {${[...VALID_ROTATION].join(', ')}}, got: ${cred.rotation}`,
|
|
89
90
|
),
|
|
@@ -32,6 +32,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
32
32
|
import { softSkip, seamAbsent } from '../lib/soft-skip.js';
|
|
33
33
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
34
34
|
import { driver } from '../lib/driver.js';
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
35
36
|
|
|
36
37
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
37
38
|
|
|
@@ -92,7 +93,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
92
93
|
if (resetStatus === 404) {
|
|
93
94
|
await noteHarnessAbsent();
|
|
94
95
|
ctx.skip(); // host doesn't expose the cross-engine harness seam
|
|
95
|
-
return;
|
|
96
|
+
return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
96
97
|
}
|
|
97
98
|
expect(resetStatus).toBe(200);
|
|
98
99
|
|
|
@@ -115,7 +116,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
115
116
|
|
|
116
117
|
expect(
|
|
117
118
|
read.entries.length,
|
|
118
|
-
|
|
119
|
+
req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
|
|
119
120
|
'channels-and-reducers.md §"Cross-engine ordering"',
|
|
120
121
|
'all appends across all engines MUST appear in the linearized read',
|
|
121
122
|
),
|
|
@@ -126,14 +127,14 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
126
127
|
const engineBEntries = read.entries.filter((e) => e.engineId === 'engine-B').map((e) => e.value);
|
|
127
128
|
expect(
|
|
128
129
|
engineAEntries,
|
|
129
|
-
|
|
130
|
+
req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
|
|
130
131
|
'channels-and-reducers.md §"Cross-engine ordering"',
|
|
131
132
|
'engine-A submissions MUST appear in submission order within the linearization',
|
|
132
133
|
),
|
|
133
134
|
).toEqual(['a-1', 'a-2', 'a-3']);
|
|
134
135
|
expect(
|
|
135
136
|
engineBEntries,
|
|
136
|
-
|
|
137
|
+
req('openwop.it.cross-engine-append-behavior.interleaved-appends-from-two-engines-converge-to-a-single-globally-ordered-seque',
|
|
137
138
|
'channels-and-reducers.md §"Cross-engine ordering"',
|
|
138
139
|
'engine-B submissions MUST appear in submission order within the linearization',
|
|
139
140
|
),
|
|
@@ -145,7 +146,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
145
146
|
if (resetStatus === 404) {
|
|
146
147
|
await noteHarnessAbsent();
|
|
147
148
|
ctx.skip();
|
|
148
|
-
return;
|
|
149
|
+
return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
149
150
|
}
|
|
150
151
|
expect(resetStatus).toBe(200);
|
|
151
152
|
|
|
@@ -162,7 +163,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
162
163
|
// channel MUST have strictly-higher clock than the previous.
|
|
163
164
|
expect(
|
|
164
165
|
a2.entry!.lamport > b1.entry!.lamport && b1.entry!.lamport > a1.entry!.lamport,
|
|
165
|
-
|
|
166
|
+
req('openwop.it.cross-engine-append-behavior.lamport-clocks-monotonically-advance-across-engines',
|
|
166
167
|
'channels-and-reducers.md §"Cross-engine ordering" — Lamport',
|
|
167
168
|
'lamport clocks MUST be strictly monotonic on the shared channel',
|
|
168
169
|
),
|
|
@@ -174,7 +175,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
174
175
|
if (resetStatus === 404) {
|
|
175
176
|
await noteHarnessAbsent();
|
|
176
177
|
ctx.skip();
|
|
177
|
-
return;
|
|
178
|
+
return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
178
179
|
}
|
|
179
180
|
expect(resetStatus).toBe(200);
|
|
180
181
|
|
|
@@ -190,7 +191,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
190
191
|
expect(b1.status).toBe(200);
|
|
191
192
|
expect(
|
|
192
193
|
b1.entry!.lamport > seen,
|
|
193
|
-
|
|
194
|
+
req('openwop.it.cross-engine-append-behavior.lamport-hint-from-engine-a-advances-engine-b-past-it',
|
|
194
195
|
'channels-and-reducers.md §"Cross-engine ordering" — Lamport receive rule',
|
|
195
196
|
'when engine B sees engine A\'s clock at L, B\'s next append MUST have clock > L',
|
|
196
197
|
),
|
|
@@ -202,7 +203,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
202
203
|
if (resetStatus === 404) {
|
|
203
204
|
await noteHarnessAbsent();
|
|
204
205
|
ctx.skip();
|
|
205
|
-
return;
|
|
206
|
+
return softSkip('blocked', 'precondition not met — `resetStatus === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
206
207
|
}
|
|
207
208
|
expect(resetStatus).toBe(200);
|
|
208
209
|
|
|
@@ -217,7 +218,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-behavior: §B cross-engine order
|
|
|
217
218
|
expect(r2.status).toBe(200);
|
|
218
219
|
expect(
|
|
219
220
|
r1.entries.map((e) => `${e.engineId}:${String(e.value)}`),
|
|
220
|
-
|
|
221
|
+
req('openwop.it.cross-engine-append-behavior.linearization-is-deterministic-same-appends-same-total-order',
|
|
221
222
|
'channels-and-reducers.md §"Cross-engine ordering" — determinism',
|
|
222
223
|
'two reads MUST produce the same linearization (deterministic merge)',
|
|
223
224
|
),
|
|
@@ -28,6 +28,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
28
28
|
import { softSkip } from '../lib/soft-skip.js';
|
|
29
29
|
import { driver } from '../lib/driver.js';
|
|
30
30
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
31
32
|
|
|
32
33
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
33
34
|
const ORDERING_MODELS = new Set(['lamport', 'vector-clock', 'global-sequencer']);
|
|
@@ -62,7 +63,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
|
|
|
62
63
|
|
|
63
64
|
expect(
|
|
64
65
|
typeof ceo.supported,
|
|
65
|
-
|
|
66
|
+
req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
|
|
66
67
|
'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
|
|
67
68
|
'capabilities.eventLog.crossEngineOrdering.supported MUST be boolean when present',
|
|
68
69
|
),
|
|
@@ -71,7 +72,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
|
|
|
71
72
|
if (ceo.orderingModel !== undefined) {
|
|
72
73
|
expect(
|
|
73
74
|
ORDERING_MODELS.has(ceo.orderingModel as string),
|
|
74
|
-
|
|
75
|
+
req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
|
|
75
76
|
'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
|
|
76
77
|
'orderingModel MUST be one of {lamport, vector-clock, global-sequencer}',
|
|
77
78
|
),
|
|
@@ -81,7 +82,7 @@ describe.skipIf(HTTP_SKIP)('cross-engine-append-ordering: advertisement shape (R
|
|
|
81
82
|
if (ceo.supported === true) {
|
|
82
83
|
expect(
|
|
83
84
|
ceo.orderingModel,
|
|
84
|
-
|
|
85
|
+
req('openwop.it.cross-engine-append-ordering.capabilities-eventlog-crossengineordering-when-present-conforms-to-rfc-0036-b',
|
|
85
86
|
'RFCS/0036-multi-region-and-cross-engine-guarantees.md §B',
|
|
86
87
|
'when supported: true, orderingModel MUST be present (the categorical claim has no operational meaning without an advertised mechanism)',
|
|
87
88
|
),
|
|
@@ -37,6 +37,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
37
37
|
import { softSkip } from '../lib/soft-skip.js';
|
|
38
38
|
import { driver } from '../lib/driver.js';
|
|
39
39
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
40
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
41
|
|
|
41
42
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
42
43
|
|
|
@@ -71,7 +72,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
|
|
|
71
72
|
if (chc?.ancestryEndpointSupported !== true) {
|
|
72
73
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.ancestryEndpointSupported !== true` returned early');
|
|
73
74
|
ctx.skip();
|
|
74
|
-
return;
|
|
75
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.ancestryEndpointSupported !== true` returned early');
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
// Create a fresh top-level run via the host's conformance-dispatch-loop
|
|
@@ -81,33 +82,33 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
|
|
|
81
82
|
if (create.status !== 201) {
|
|
82
83
|
softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
|
|
83
84
|
ctx.skip();
|
|
84
|
-
return;
|
|
85
|
+
return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early (seam, prior step, or fixture unavailable)');
|
|
85
86
|
}
|
|
86
87
|
const runId = (create.json as { runId: string }).runId;
|
|
87
88
|
|
|
88
89
|
const ancestryRes = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/ancestry`);
|
|
89
|
-
expect(ancestryRes.status,
|
|
90
|
+
expect(ancestryRes.status, req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr',
|
|
90
91
|
'RFCS/0040-multi-agent-cross-host-causation.md §C',
|
|
91
92
|
'host advertising ancestryEndpointSupported MUST serve the endpoint (200) — 404 is non-conformant',
|
|
92
93
|
)).toBe(200);
|
|
93
94
|
|
|
94
95
|
const body = ancestryRes.json as { runId?: string; hostId?: string; parent?: unknown };
|
|
95
|
-
expect(body.runId, 'runId in response MUST match the request path').toBe(runId);
|
|
96
|
+
expect(body.runId, req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'runId in response MUST match the request path')).toBe(runId);
|
|
96
97
|
expect(
|
|
97
98
|
typeof body.hostId === 'string' && (body.hostId as string).length >= 1,
|
|
98
|
-
'hostId MUST be present + non-empty',
|
|
99
|
+
req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'hostId MUST be present + non-empty'),
|
|
99
100
|
).toBe(true);
|
|
100
101
|
if (chc.hostId !== undefined) {
|
|
101
102
|
expect(
|
|
102
103
|
body.hostId,
|
|
103
|
-
'hostId in response MUST equal the host\'s advertised crossHostCausation.hostId',
|
|
104
|
+
req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr', 'RFCS/0040-multi-agent-cross-host-causation.md §C', 'hostId in response MUST equal the host\'s advertised crossHostCausation.hostId'),
|
|
104
105
|
).toBe(chc.hostId);
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
// Top-level run: parent is null.
|
|
108
109
|
expect(
|
|
109
110
|
body.parent,
|
|
110
|
-
|
|
111
|
+
req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-ancestryendpointsupported-must-serve-get-v1-runs-runid-ancestr',
|
|
111
112
|
'RFCS/0040-multi-agent-cross-host-causation.md §C + schemas/run-ancestry-response.schema.json',
|
|
112
113
|
'a top-level run (not dispatched from any other run) MUST return parent: null',
|
|
113
114
|
),
|
|
@@ -120,12 +121,12 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
|
|
|
120
121
|
if (chc?.supported !== true) {
|
|
121
122
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.supported !== true` returned early');
|
|
122
123
|
ctx.skip();
|
|
123
|
-
return;
|
|
124
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc?.supported !== true` returned early');
|
|
124
125
|
}
|
|
125
126
|
if (chc.ancestryEndpointSupported === true) {
|
|
126
127
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc.ancestryEndpointSupported === true` returned early');
|
|
127
128
|
ctx.skip(); // covered by the test above
|
|
128
|
-
return;
|
|
129
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chc.ancestryEndpointSupported === true` returned early');
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
// Use any runId — even a synthetic non-existent one. The endpoint should
|
|
@@ -133,7 +134,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-ancestry-endpoint: behavioral (RFC 0040
|
|
|
133
134
|
const ancestryRes = await driver.get('/v1/runs/synthetic-test-run-id/ancestry');
|
|
134
135
|
expect(
|
|
135
136
|
ancestryRes.status,
|
|
136
|
-
|
|
137
|
+
req('openwop.it.cross-host-ancestry-endpoint.hosts-advertising-crosshostcausation-supported-but-not-ancestryendpointsupported',
|
|
137
138
|
'spec/v1/multi-agent-execution.md §"GET /v1/runs/{runId}/ancestry endpoint"',
|
|
138
139
|
'hosts that advertise crossHostCausation.supported: true but NOT ancestryEndpointSupported MUST return 404 — the endpoint is opt-in even within Phase 3',
|
|
139
140
|
),
|
|
@@ -29,6 +29,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
29
29
|
import { softSkip } from '../lib/soft-skip.js';
|
|
30
30
|
import { driver } from '../lib/driver.js';
|
|
31
31
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
33
|
|
|
33
34
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
34
35
|
|
|
@@ -64,18 +65,18 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
|
|
|
64
65
|
if (d === null) {
|
|
65
66
|
softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
66
67
|
ctx.skip();
|
|
67
|
-
return;
|
|
68
|
+
return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
68
69
|
}
|
|
69
70
|
const chc = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.crossHostCausation;
|
|
70
71
|
if (chc === undefined) {
|
|
71
72
|
softSkip('inapplicable', 'optional advertisement — `multiAgent.executionModel.crossHostCausation` not advertised by this host (RFC 0040 §D)');
|
|
72
73
|
ctx.skip(); // host doesn't advertise — soft-skip
|
|
73
|
-
return;
|
|
74
|
+
return softSkip('blocked', 'precondition not met — `chc === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
expect(
|
|
77
78
|
typeof chc.supported,
|
|
78
|
-
|
|
79
|
+
req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
|
|
79
80
|
'RFCS/0040-multi-agent-cross-host-causation.md §D',
|
|
80
81
|
'crossHostCausation.supported MUST be boolean when present',
|
|
81
82
|
),
|
|
@@ -85,7 +86,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
|
|
|
85
86
|
const version = capabilityFamily<{ executionModel?: { [k: string]: unknown; crossHostCausation?: Record<string, unknown>; replayDeterminism?: Record<string, unknown> } }>(d, 'multiAgent')?.executionModel?.version as number | undefined;
|
|
86
87
|
expect(
|
|
87
88
|
typeof version === 'number' && version >= 3,
|
|
88
|
-
|
|
89
|
+
req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
|
|
89
90
|
'RFCS/0040-multi-agent-cross-host-causation.md §D',
|
|
90
91
|
'when crossHostCausation.supported: true, multiAgent.executionModel.version MUST be >= 3',
|
|
91
92
|
),
|
|
@@ -93,7 +94,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
|
|
|
93
94
|
|
|
94
95
|
expect(
|
|
95
96
|
typeof chc.hostId === 'string' && (chc.hostId as string).length >= 1,
|
|
96
|
-
|
|
97
|
+
req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
|
|
97
98
|
'RFCS/0040-multi-agent-cross-host-causation.md §D',
|
|
98
99
|
'when crossHostCausation.supported: true, hostId MUST be present + non-empty',
|
|
99
100
|
),
|
|
@@ -103,7 +104,7 @@ describe.skipIf(HTTP_SKIP)('cross-host-causation-shape: advertisement shape (RFC
|
|
|
103
104
|
if (chc.ancestryEndpointSupported !== undefined) {
|
|
104
105
|
expect(
|
|
105
106
|
typeof chc.ancestryEndpointSupported,
|
|
106
|
-
|
|
107
|
+
req('openwop.it.cross-host-causation-shape.crosshostcausation-when-present-conforms-to-rfc-0040-d',
|
|
107
108
|
'RFCS/0040-multi-agent-cross-host-causation.md §D',
|
|
108
109
|
'ancestryEndpointSupported MUST be boolean when present',
|
|
109
110
|
),
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { describe, it, expect } from 'vitest';
|
|
24
24
|
import { softSkip } from '../lib/soft-skip.js';
|
|
25
25
|
import { driver } from '../lib/driver.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
27
|
|
|
27
28
|
const ISOLATION_CODES: ReadonlySet<string> = new Set(['run_forbidden', 'not_found']);
|
|
28
29
|
|
|
@@ -41,7 +42,7 @@ describe('cross-workspace-isolation: run-ownership echo shape (RFC 0048 §C)', (
|
|
|
41
42
|
if (owner === undefined) return softSkip('blocked', 'single-tenant host — owner omitted (owner === undefined)');
|
|
42
43
|
expect(
|
|
43
44
|
typeof owner.tenant === 'string' && owner.tenant.length > 0,
|
|
44
|
-
|
|
45
|
+
req('openwop.it.cross-workspace-isolation.owner-when-present-on-a-run-snapshot-carries-a-non-empty-tenant', 'RFC 0048 §C', 'RunSnapshot.owner MUST carry a non-empty tenant when present'),
|
|
45
46
|
).toBe(true);
|
|
46
47
|
});
|
|
47
48
|
});
|
|
@@ -55,7 +56,7 @@ describe('cross-workspace-isolation: a principal MUST NOT read another workspace
|
|
|
55
56
|
|
|
56
57
|
expect(
|
|
57
58
|
res.status,
|
|
58
|
-
|
|
59
|
+
req('openwop.it.cross-workspace-isolation.cross-workspace-read-fails-closed-with-run-forbidden',
|
|
59
60
|
'spec/v1/auth.md §Identity claims',
|
|
60
61
|
'a cross-workspace read MUST fail closed (4xx), never return the other workspace\'s run',
|
|
61
62
|
),
|
|
@@ -64,7 +65,7 @@ describe('cross-workspace-isolation: a principal MUST NOT read another workspace
|
|
|
64
65
|
const code = (res.json as { error?: string } | undefined)?.error;
|
|
65
66
|
expect(
|
|
66
67
|
code !== undefined && ISOLATION_CODES.has(code),
|
|
67
|
-
|
|
68
|
+
req('openwop.it.cross-workspace-isolation.cross-workspace-read-fails-closed-with-run-forbidden',
|
|
68
69
|
'spec/v1/rest-endpoints.md run_forbidden',
|
|
69
70
|
`error MUST be one of {${[...ISOLATION_CODES].join(', ')}} (fail-closed, no existence leak), got: ${code ?? '(absent)'}`,
|
|
70
71
|
),
|
|
@@ -45,6 +45,7 @@ import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
|
|
|
45
45
|
import { driver } from '../lib/driver.js';
|
|
46
46
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
47
47
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
48
|
+
import { req } from '../lib/requirement-ids.js';
|
|
48
49
|
|
|
49
50
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
50
51
|
|
|
@@ -52,31 +53,31 @@ describe('data-residency: schema + error registration (always-on, server-free)',
|
|
|
52
53
|
it('capabilities.dataResidency requires `supported` (const true) + `regions`, closed', () => {
|
|
53
54
|
const caps = JSON.parse(readFileSync(join(SCHEMAS_DIR, 'capabilities.schema.json'), 'utf8'));
|
|
54
55
|
const fam = caps.properties?.dataResidency;
|
|
55
|
-
expect(fam, 'capabilities.schema.json MUST define the dataResidency family (RFC 0129 §1)').toBeDefined();
|
|
56
|
-
expect(fam.additionalProperties, 'dataResidency MUST close its shape').toBe(false);
|
|
56
|
+
expect(fam, req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'capabilities.schema.json MUST define the dataResidency family (RFC 0129 §1)')).toBeDefined();
|
|
57
|
+
expect(fam.additionalProperties, req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'dataResidency MUST close its shape')).toBe(false);
|
|
57
58
|
expect(fam.required?.sort()).toEqual(['regions', 'supported']);
|
|
58
59
|
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
59
60
|
const vf = ajv.compile(fam);
|
|
60
|
-
expect(vf({ supported: true, regions: ['eu', 'us'] }), 'the canonical advert MUST validate').toBe(true);
|
|
61
|
-
expect(vf({ supported: true }), 'an advert without `regions` MUST fail').toBe(false);
|
|
62
|
-
expect(vf({ regions: ['eu'] }), 'an advert without `supported` MUST fail').toBe(false);
|
|
63
|
-
expect(vf({ supported: false, regions: ['eu'] }), 'dataResidency.supported is const true — false MUST fail').toBe(false);
|
|
61
|
+
expect(vf({ supported: true, regions: ['eu', 'us'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'the canonical advert MUST validate')).toBe(true);
|
|
62
|
+
expect(vf({ supported: true }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'an advert without `regions` MUST fail')).toBe(false);
|
|
63
|
+
expect(vf({ regions: ['eu'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'an advert without `supported` MUST fail')).toBe(false);
|
|
64
|
+
expect(vf({ supported: false, regions: ['eu'] }), req('openwop.it.data-residency-admission.capabilities-dataresidency-requires-supported-const-true-regions-closed', 'RFC 0129', 'dataResidency.supported is const true — false MUST fail')).toBe(false);
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
it('residency.schema.json requires `region` and closes its shape', () => {
|
|
67
68
|
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
68
69
|
addFormats(ajv);
|
|
69
70
|
const validate = ajv.compile(JSON.parse(readFileSync(join(SCHEMAS_DIR, 'residency.schema.json'), 'utf8')));
|
|
70
|
-
expect(validate({ region: 'eu' }), 'RFC 0129 §2 — a `{region}` residency constraint MUST validate').toBe(true);
|
|
71
|
-
expect(validate({}), 'RFC 0129 §2 — `region` is REQUIRED').toBe(false);
|
|
72
|
-
expect(validate({ region: 'eu', extra: 1 }), 'residency MUST be closed (additionalProperties:false)').toBe(false);
|
|
71
|
+
expect(validate({ region: 'eu' }), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'RFC 0129 §2 — a `{region}` residency constraint MUST validate')).toBe(true);
|
|
72
|
+
expect(validate({}), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'RFC 0129 §2 — `region` is REQUIRED')).toBe(false);
|
|
73
|
+
expect(validate({ region: 'eu', extra: 1 }), req('openwop.it.data-residency-admission.residency-schema-json-requires-region-and-closes-its-shape', 'RFC 0129', 'residency MUST be closed (additionalProperties:false)')).toBe(false);
|
|
73
74
|
});
|
|
74
75
|
|
|
75
76
|
it.skipIf(V1_DIR === null)('residency_unavailable is registered in the rest-endpoints error prose', () => {
|
|
76
77
|
const rest = readFileSync(join(V1_DIR as string, 'rest-endpoints.md'), 'utf8');
|
|
77
78
|
expect(
|
|
78
79
|
rest.includes('`residency_unavailable`'),
|
|
79
|
-
'rest-endpoints.md §"Common error codes" MUST register `residency_unavailable` (RFC 0129 §3)',
|
|
80
|
+
req('openwop.it.data-residency-admission.residency-unavailable-is-registered-in-the-rest-endpoints-error-prose', 'RFC 0129', 'rest-endpoints.md §"Common error codes" MUST register `residency_unavailable` (RFC 0129 §3)'),
|
|
80
81
|
).toBe(true);
|
|
81
82
|
});
|
|
82
83
|
});
|
|
@@ -99,7 +100,7 @@ describe.skipIf(HTTP_SKIP)('data-residency: admission control (capability-gated,
|
|
|
99
100
|
// region with residency_unavailable. That specific pairing is the violation.
|
|
100
101
|
expect(
|
|
101
102
|
readErrorCode(ok.json) !== 'residency_unavailable',
|
|
102
|
-
|
|
103
|
+
req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
|
|
103
104
|
'capabilities.md §dataResidency / RFC 0129 §3',
|
|
104
105
|
`an ADVERTISED region ("${advertised}") MUST NOT be rejected with residency_unavailable (accept iff advertised) — got ${ok.status} ${JSON.stringify(ok.json).slice(0, 200)}`,
|
|
105
106
|
),
|
|
@@ -118,21 +119,21 @@ describe.skipIf(HTTP_SKIP)('data-residency: admission control (capability-gated,
|
|
|
118
119
|
|
|
119
120
|
expect(
|
|
120
121
|
rej.status === 400 || rej.status === 404 || rej.status === 422,
|
|
121
|
-
|
|
122
|
+
req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
|
|
122
123
|
'rest-endpoints.md §residency_unavailable',
|
|
123
124
|
`an unadvertised region MUST be rejected at HTTP one-of 400/404/422 (envelope-not-status, #815) — got ${rej.status}`,
|
|
124
125
|
),
|
|
125
126
|
).toBe(true);
|
|
126
127
|
expect(
|
|
127
128
|
readErrorCode(rej.json) === 'residency_unavailable',
|
|
128
|
-
|
|
129
|
+
req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav',
|
|
129
130
|
'RFC 0129 §3',
|
|
130
131
|
`an unadvertised region MUST be rejected with error code "residency_unavailable" (MUST NOT silently accept-and-ignore) — got ${JSON.stringify(rej.json).slice(0, 200)}`,
|
|
131
132
|
),
|
|
132
133
|
).toBe(true);
|
|
133
134
|
expect(
|
|
134
135
|
rejBody?.runId === undefined,
|
|
135
|
-
|
|
136
|
+
req('openwop.it.data-residency-admission.accepts-an-advertised-region-and-rejects-an-unadvertised-one-with-residency-unav', 'RFC 0129 §3', 'a rejected residency request MUST create NO run (no runId in the response)'),
|
|
136
137
|
).toBe(true);
|
|
137
138
|
});
|
|
138
139
|
});
|