@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
|
@@ -17,6 +17,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
17
17
|
import { softSkip } from '../lib/soft-skip.js';
|
|
18
18
|
import { driver } from '../lib/driver.js';
|
|
19
19
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
20
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
21
|
|
|
21
22
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
22
23
|
|
|
@@ -45,7 +46,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-memory-cap: capability shape + behavioral (R
|
|
|
45
46
|
|
|
46
47
|
expect(
|
|
47
48
|
Number.isInteger(sb.memoryLimitBytes) && sb.memoryLimitBytes >= 1048576,
|
|
48
|
-
|
|
49
|
+
req('openwop.it.sandbox-memory-cap.memorylimitbytes-must-be-integer-1-mib-when-present-per-schema',
|
|
49
50
|
'RFCS/0035-sandbox-execution-contract.md §A',
|
|
50
51
|
'memoryLimitBytes MUST be integer ≥ 1 MiB (1048576)',
|
|
51
52
|
),
|
|
@@ -39,6 +39,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
39
39
|
import { softSkip } from '../lib/soft-skip.js';
|
|
40
40
|
import { driver } from '../lib/driver.js';
|
|
41
41
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
42
|
+
import { req } from '../lib/requirement-ids.js';
|
|
42
43
|
|
|
43
44
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
44
45
|
|
|
@@ -84,20 +85,20 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
84
85
|
if (!(await isSandboxAdvertised())) {
|
|
85
86
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
86
87
|
ctx.skip();
|
|
87
|
-
return;
|
|
88
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
88
89
|
}
|
|
89
90
|
const probe = await invoke('misbehave.fs-escape-read');
|
|
90
91
|
expect(probe.status).toBe(200);
|
|
91
92
|
expect(
|
|
92
93
|
probe.body.error?.code,
|
|
93
|
-
|
|
94
|
+
req('openwop.it.sandbox-mvp-behavior.host-fs-escape-fs-access-from-sandboxed-code-fails-closed',
|
|
94
95
|
'RFCS/0035-sandbox-execution-contract.md §B node-pack-sandbox-fs-gated',
|
|
95
96
|
'sandboxed `require("fs")` MUST fail closed with `sandbox_escape_attempt`',
|
|
96
97
|
),
|
|
97
98
|
).toBe('sandbox_escape_attempt');
|
|
98
99
|
expect(
|
|
99
100
|
probe.body.error?.details?.escapeKind,
|
|
100
|
-
|
|
101
|
+
req('openwop.it.sandbox-mvp-behavior.host-fs-escape-fs-access-from-sandboxed-code-fails-closed',
|
|
101
102
|
'RFCS/0035-sandbox-execution-contract.md §B',
|
|
102
103
|
'escapeKind MUST be host-fs-escape',
|
|
103
104
|
),
|
|
@@ -108,13 +109,13 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
108
109
|
if (!(await isSandboxAdvertised())) {
|
|
109
110
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
110
111
|
ctx.skip();
|
|
111
|
-
return;
|
|
112
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
112
113
|
}
|
|
113
114
|
const probe = await invoke('misbehave.env-leak');
|
|
114
115
|
expect(probe.status).toBe(200);
|
|
115
116
|
expect(
|
|
116
117
|
probe.body.error?.code,
|
|
117
|
-
|
|
118
|
+
req('openwop.it.sandbox-mvp-behavior.host-env-leak-process-env-access-from-sandboxed-code-fails-closed',
|
|
118
119
|
'RFCS/0035-sandbox-execution-contract.md §B node-pack-sandbox-no-env',
|
|
119
120
|
'sandboxed `process.env` access MUST fail closed with `sandbox_escape_attempt`',
|
|
120
121
|
),
|
|
@@ -126,13 +127,13 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
126
127
|
if (!(await isSandboxAdvertised())) {
|
|
127
128
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
128
129
|
ctx.skip();
|
|
129
|
-
return;
|
|
130
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
130
131
|
}
|
|
131
132
|
const probe = await invoke('misbehave.network-escape');
|
|
132
133
|
expect(probe.status).toBe(200);
|
|
133
134
|
expect(
|
|
134
135
|
probe.body.error?.code,
|
|
135
|
-
|
|
136
|
+
req('openwop.it.sandbox-mvp-behavior.network-escape-http-net-access-from-sandboxed-code-fails-closed',
|
|
136
137
|
'RFCS/0035-sandbox-execution-contract.md §B node-pack-sandbox-network-gated',
|
|
137
138
|
'sandboxed `require("http")` MUST fail closed with `sandbox_escape_attempt`',
|
|
138
139
|
),
|
|
@@ -144,10 +145,10 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
144
145
|
if (!(await isSandboxAdvertised())) {
|
|
145
146
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
146
147
|
ctx.skip();
|
|
147
|
-
return;
|
|
148
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
148
149
|
}
|
|
149
150
|
const probe = await invoke('misbehave.process-escape');
|
|
150
|
-
expect(probe.status).toBe(200);
|
|
151
|
+
expect(probe.status, req('openwop.it.sandbox-mvp-behavior.host-process-escape-child-process-access-from-sandboxed-code-fails-closed', 'RFC 0035 §B', 'host-process-escape — child_process access from sandboxed code fails closed')).toBe(200);
|
|
151
152
|
expect(probe.body.error?.code).toBe('sandbox_escape_attempt');
|
|
152
153
|
// The heuristic may catch this as host-fs-escape (via "require") if
|
|
153
154
|
// network/process patterns don't match first. Accept either as long
|
|
@@ -159,7 +160,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
159
160
|
if (!(await isSandboxAdvertised())) {
|
|
160
161
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
161
162
|
ctx.skip();
|
|
162
|
-
return;
|
|
163
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
163
164
|
}
|
|
164
165
|
const start = Date.now();
|
|
165
166
|
const probe = await invoke('misbehave.timeout');
|
|
@@ -167,7 +168,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
167
168
|
expect(probe.status).toBe(200);
|
|
168
169
|
expect(
|
|
169
170
|
probe.body.error?.code,
|
|
170
|
-
|
|
171
|
+
req('openwop.it.sandbox-mvp-behavior.sandbox-timeout-runaway-loop-terminated-by-wallclocklimitms',
|
|
171
172
|
'RFCS/0035-sandbox-execution-contract.md §B node-pack-sandbox-timeout',
|
|
172
173
|
'sandboxed infinite-loop MUST be terminated with `sandbox_timeout`',
|
|
173
174
|
),
|
|
@@ -175,7 +176,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
175
176
|
// Should terminate within ~2× wallClockLimitMs (1000ms config + overhead).
|
|
176
177
|
expect(
|
|
177
178
|
elapsed < 5000,
|
|
178
|
-
|
|
179
|
+
req('openwop.it.sandbox-mvp-behavior.sandbox-timeout-runaway-loop-terminated-by-wallclocklimitms',
|
|
179
180
|
'RFCS/0035-sandbox-execution-contract.md §A wallClockLimitMs',
|
|
180
181
|
`timeout MUST terminate within reasonable bound (got ${elapsed}ms; cap is 1000ms)`,
|
|
181
182
|
),
|
|
@@ -186,7 +187,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
186
187
|
if (!(await isSandboxAdvertised())) {
|
|
187
188
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
188
189
|
ctx.skip();
|
|
189
|
-
return;
|
|
190
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
190
191
|
}
|
|
191
192
|
const r1 = await invoke('misbehave.cross-pack-mutate');
|
|
192
193
|
const r2 = await invoke('misbehave.cross-pack-mutate');
|
|
@@ -202,7 +203,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
202
203
|
const shared3 = (r3.body.result as { shared?: number })?.shared;
|
|
203
204
|
expect(
|
|
204
205
|
shared1 === 1 && shared2 === 1 && shared3 === 1,
|
|
205
|
-
|
|
206
|
+
req('openwop.it.sandbox-mvp-behavior.cross-pack-mutation-fresh-vm-context-per-invocation-no-state-leaks',
|
|
206
207
|
'RFCS/0035-sandbox-execution-contract.md §B node-pack-sandbox-isolated-context',
|
|
207
208
|
`each invocation MUST see fresh state (got shared=[${shared1}, ${shared2}, ${shared3}]; expected all 1)`,
|
|
208
209
|
),
|
|
@@ -213,20 +214,20 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
213
214
|
if (!(await isSandboxAdvertised())) {
|
|
214
215
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
215
216
|
ctx.skip();
|
|
216
|
-
return;
|
|
217
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
217
218
|
}
|
|
218
219
|
const probe = await invoke('misbehave.capability-gate-violation', {}, []);
|
|
219
220
|
expect(probe.status).toBe(200);
|
|
220
221
|
expect(
|
|
221
222
|
probe.body.error?.code,
|
|
222
|
-
|
|
223
|
+
req('openwop.it.sandbox-mvp-behavior.capability-gate-respected-host-call-not-in-allowedhostcalls-fails-with-sandbox-c',
|
|
223
224
|
'spec/v1/host-capabilities.md §"Error codes" + §B node-pack-sandbox-capability-gate-respected',
|
|
224
225
|
'capability-gate violation MUST fail closed with `sandbox_capability_denied` — distinct from `sandbox_escape_attempt` which covers forbidden-syscall escapes per the spec\'s 4-code catalog',
|
|
225
226
|
),
|
|
226
227
|
).toBe('sandbox_capability_denied');
|
|
227
228
|
expect(
|
|
228
229
|
probe.body.error?.details?.requestedCapability,
|
|
229
|
-
|
|
230
|
+
req('openwop.it.sandbox-mvp-behavior.capability-gate-respected-host-call-not-in-allowedhostcalls-fails-with-sandbox-c',
|
|
230
231
|
'spec/v1/host-capabilities.md §"Error codes"',
|
|
231
232
|
'`sandbox_capability_denied` MUST carry `details.requestedCapability` identifying the host method the sandboxed code attempted to call',
|
|
232
233
|
),
|
|
@@ -237,7 +238,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
237
238
|
if (!(await isSandboxAdvertised())) {
|
|
238
239
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
239
240
|
ctx.skip();
|
|
240
|
-
return;
|
|
241
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
241
242
|
}
|
|
242
243
|
const probe = await invoke('misbehave.memory-bomb');
|
|
243
244
|
expect(probe.status).toBe(200);
|
|
@@ -254,7 +255,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
254
255
|
// legacy code.
|
|
255
256
|
expect(
|
|
256
257
|
['sandbox_memory_exceeded', 'sandbox_timeout'].includes(probe.body.error?.code ?? ''),
|
|
257
|
-
|
|
258
|
+
req('openwop.it.sandbox-mvp-behavior.memory-exceeded-runaway-allocation-fails-with-sandbox-memory-exceeded',
|
|
258
259
|
'spec/v1/host-capabilities.md §"Error codes" + §B node-pack-sandbox-memory-cap',
|
|
259
260
|
`memory-bomb MUST surface either \`sandbox_memory_exceeded\` (when memoryLimitBytes caught it) or \`sandbox_timeout\` (when wallClockLimitMs caught it first) — got code: ${probe.body.error?.code}`,
|
|
260
261
|
),
|
|
@@ -265,13 +266,13 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
265
266
|
if (!(await isSandboxAdvertised())) {
|
|
266
267
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
267
268
|
ctx.skip();
|
|
268
|
-
return;
|
|
269
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
269
270
|
}
|
|
270
271
|
const probe = await invoke('well-behaved.host-fetch', {}, ['fetch']);
|
|
271
272
|
expect(probe.status).toBe(200);
|
|
272
273
|
expect(
|
|
273
274
|
probe.body.error,
|
|
274
|
-
|
|
275
|
+
req('openwop.it.sandbox-mvp-behavior.well-behaved-host-fetch-allowedhostcalls-fetch-permits-the-host-call',
|
|
275
276
|
'RFCS/0035-sandbox-execution-contract.md §A allowedHostCalls',
|
|
276
277
|
'host call IN allowedHostCalls MUST succeed (no error envelope)',
|
|
277
278
|
),
|
|
@@ -282,10 +283,10 @@ describe.skipIf(HTTP_SKIP)('sandbox-mvp-behavior: RFC 0035 §B failure-mode inva
|
|
|
282
283
|
if (!(await isSandboxAdvertised())) {
|
|
283
284
|
softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
284
285
|
ctx.skip();
|
|
285
|
-
return;
|
|
286
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isSandboxAdvertised())` returned early');
|
|
286
287
|
}
|
|
287
288
|
const probe = await invoke('well-behaved.echo', { input: 'hello-sandbox' });
|
|
288
|
-
expect(probe.status).toBe(200);
|
|
289
|
+
expect(probe.status, req('openwop.it.sandbox-mvp-behavior.well-behaved-echo-sandboxed-code-returns-args-round-trip-when-no-escape-attempt', 'RFC 0035 §B', 'well-behaved.echo — sandboxed code returns args round-trip when no escape attempt')).toBe(200);
|
|
289
290
|
expect(probe.body.error).toBeUndefined();
|
|
290
291
|
expect((probe.body.result as { echoed?: string })?.echoed).toBe('hello-sandbox');
|
|
291
292
|
});
|
|
@@ -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
|
|
|
@@ -58,7 +59,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-no-host-fs-escape: capability shape (RFC 003
|
|
|
58
59
|
const sb = await readSandboxCaps();
|
|
59
60
|
if (sb === null) return softSkip('inapplicable', 'host omits the block — soft-skip cleanly (sb === null)');
|
|
60
61
|
|
|
61
|
-
expect(typeof sb.supported, 'capabilities.sandbox.supported MUST be boolean when present').toBe('boolean');
|
|
62
|
+
expect(typeof sb.supported, req('openwop.it.sandbox-no-host-fs-escape.capabilities-sandbox-when-present-conforms-to-rfc-0035-a', 'RFCS/0035-sandbox-execution-contract.md §A', 'capabilities.sandbox.supported MUST be boolean when present')).toBe('boolean');
|
|
62
63
|
|
|
63
64
|
if (sb.supported === true) {
|
|
64
65
|
const m = sb.isolationModel as string;
|
|
@@ -66,7 +67,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-no-host-fs-escape: capability shape (RFC 003
|
|
|
66
67
|
const isExtension = /^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$/.test(m);
|
|
67
68
|
expect(
|
|
68
69
|
isCategorical || isExtension,
|
|
69
|
-
|
|
70
|
+
req('openwop.it.sandbox-no-host-fs-escape.capabilities-sandbox-when-present-conforms-to-rfc-0035-a',
|
|
70
71
|
'RFCS/0035-sandbox-execution-contract.md §A',
|
|
71
72
|
'isolationModel MUST be one of {wasm, process, container, vm} OR match ^x-host-<host>-<key>$ pattern',
|
|
72
73
|
),
|
|
@@ -17,6 +17,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
17
17
|
import { softSkip } from '../lib/soft-skip.js';
|
|
18
18
|
import { driver } from '../lib/driver.js';
|
|
19
19
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
20
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
21
|
|
|
21
22
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
22
23
|
|
|
@@ -45,7 +46,7 @@ describe.skipIf(HTTP_SKIP)('sandbox-timeout-cap: capability shape + behavioral (
|
|
|
45
46
|
|
|
46
47
|
expect(
|
|
47
48
|
Number.isInteger(sb.wallClockLimitMs) && sb.wallClockLimitMs >= 100,
|
|
48
|
-
|
|
49
|
+
req('openwop.it.sandbox-timeout-cap.wallclocklimitms-must-be-integer-100-ms-when-present-per-schema',
|
|
49
50
|
'RFCS/0035-sandbox-execution-contract.md §A',
|
|
50
51
|
'wallClockLimitMs MUST be integer ≥ 100 ms',
|
|
51
52
|
),
|
|
@@ -31,8 +31,7 @@ import { readFileSync } from 'node:fs';
|
|
|
31
31
|
import { join } from 'node:path';
|
|
32
32
|
import { FIXTURES_DIR } from '../lib/paths.js';
|
|
33
33
|
import { probeSandboxed } from '../lib/wasm-sandbox-probe.js';
|
|
34
|
-
|
|
35
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
34
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
35
|
const dir = join(FIXTURES_DIR, 'wasm-sandbox');
|
|
37
36
|
const fix = (name: string): Uint8Array => new Uint8Array(readFileSync(join(dir, `${name}.wasm`)));
|
|
38
37
|
const BASE = { allowedHostCalls: [] as string[], memoryLimitBytes: 2 * 1024 * 1024 };
|
|
@@ -40,14 +39,14 @@ const BASE = { allowedHostCalls: [] as string[], memoryLimitBytes: 2 * 1024 * 10
|
|
|
40
39
|
describe('sandbox-wasm-isolation: positive controls (RFC 0035 §B, server-free)', () => {
|
|
41
40
|
it('a well-behaved pure module runs and returns its input', () => {
|
|
42
41
|
const r = probeSandboxed(fix('well-behaved-echo'), BASE, 'invoke', 42);
|
|
43
|
-
expect(r.ok,
|
|
44
|
-
expect(r.result).toBe(42);
|
|
42
|
+
expect(r.ok, req('openwop.it.sandbox-wasm-isolation.a-well-behaved-pure-module-runs-and-returns-its-input', 'RFC 0035 §B', 'a pure-compute module runs')).toBe(true);
|
|
43
|
+
expect(r.result, req('openwop.it.sandbox-wasm-isolation.a-well-behaved-pure-module-runs-and-returns-its-input', 'RFC 0035 §B', 'a well-behaved pure module runs and returns its input')).toBe(42);
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
it('a granted host capability is callable when in allowedHostCalls', () => {
|
|
48
47
|
const r = probeSandboxed(fix('well-behaved-host-fetch'), { ...BASE, allowedHostCalls: ['fetch'] }, 'invoke', 7);
|
|
49
|
-
expect(r.ok,
|
|
50
|
-
expect(r.result).toBe(7);
|
|
48
|
+
expect(r.ok, req('openwop.it.sandbox-wasm-isolation.a-granted-host-capability-is-callable-when-in-allowedhostcalls', 'RFC 0035 §B invariant 7', 'a granted openwop.* capability is callable')).toBe(true);
|
|
49
|
+
expect(r.result, req('openwop.it.sandbox-wasm-isolation.a-granted-host-capability-is-callable-when-in-allowedhostcalls', 'RFC 0035 §B', 'a granted host capability is callable when in allowedHostCalls')).toBe(7);
|
|
51
50
|
});
|
|
52
51
|
});
|
|
53
52
|
|
|
@@ -61,8 +60,8 @@ describe('sandbox-wasm-isolation: escape attempts fail closed (RFC 0035 §B 1–
|
|
|
61
60
|
for (const [fixture, escapeKind, invariant] of cases) {
|
|
62
61
|
it(`${invariant}: ${fixture} → sandbox_escape_attempt (${escapeKind})`, () => {
|
|
63
62
|
const r = probeSandboxed(fix(fixture), BASE);
|
|
64
|
-
expect(r.code,
|
|
65
|
-
expect(r.escapeKind).toBe(escapeKind);
|
|
63
|
+
expect(r.code, req('openwop.it.sandbox-wasm-isolation.sandbox-escape-attempt', 'RFC 0035 §B', `${invariant} fails closed before instantiation`)).toBe('sandbox_escape_attempt');
|
|
64
|
+
expect(r.escapeKind, req('openwop.it.sandbox-wasm-isolation.sandbox-escape-attempt', 'RFC 0035 §B', ': → sandbox_escape_attempt ( )')).toBe(escapeKind);
|
|
66
65
|
});
|
|
67
66
|
}
|
|
68
67
|
});
|
|
@@ -70,13 +69,13 @@ describe('sandbox-wasm-isolation: escape attempts fail closed (RFC 0035 §B 1–
|
|
|
70
69
|
describe('sandbox-wasm-isolation: capability gate (RFC 0035 §B 7, server-free)', () => {
|
|
71
70
|
it('an un-granted openwop capability is denied with its name', () => {
|
|
72
71
|
const r = probeSandboxed(fix('misbehaving-capability-gate'), BASE);
|
|
73
|
-
expect(r.code,
|
|
74
|
-
expect(r.requestedCapability).toBe('privileged');
|
|
72
|
+
expect(r.code, req('openwop.it.sandbox-wasm-isolation.an-un-granted-openwop-capability-is-denied-with-its-name', 'RFC 0035 §B invariant 7', 'undeclared host capability fails closed')).toBe('sandbox_capability_denied');
|
|
73
|
+
expect(r.requestedCapability, req('openwop.it.sandbox-wasm-isolation.an-un-granted-openwop-capability-is-denied-with-its-name', 'RFC 0035 §B', 'an un-granted openwop capability is denied with its name')).toBe('privileged');
|
|
75
74
|
});
|
|
76
75
|
|
|
77
76
|
it('host-fetch WITHOUT the grant is denied (the gate works both directions)', () => {
|
|
78
77
|
const r = probeSandboxed(fix('well-behaved-host-fetch'), BASE);
|
|
79
|
-
expect(r.code).toBe('sandbox_capability_denied');
|
|
78
|
+
expect(r.code, req('openwop.it.sandbox-wasm-isolation.host-fetch-without-the-grant-is-denied-the-gate-works-both-directions', 'RFC 0035 §B', 'host-fetch WITHOUT the grant is denied (the gate works both directions)')).toBe('sandbox_capability_denied');
|
|
80
79
|
expect(r.requestedCapability).toBe('fetch');
|
|
81
80
|
});
|
|
82
81
|
});
|
|
@@ -84,15 +83,15 @@ describe('sandbox-wasm-isolation: capability gate (RFC 0035 §B 7, server-free)'
|
|
|
84
83
|
describe('sandbox-wasm-isolation: memory cap (RFC 0035 §B 5, server-free)', () => {
|
|
85
84
|
it('node-pack-sandbox-memory-cap: access beyond the host memory bound is sandbox_memory_exceeded', () => {
|
|
86
85
|
const r = probeSandboxed(fix('misbehaving-memory'), BASE);
|
|
87
|
-
expect(r.ok,
|
|
88
|
-
expect(r.code).toBe('sandbox_memory_exceeded');
|
|
86
|
+
expect(r.ok, req('openwop.it.sandbox-wasm-isolation.node-pack-sandbox-memory-cap-access-beyond-the-host-memory-bound-is-sandbox-memo', 'RFC 0035 §B invariant 5', 'memory bound is engine-enforced')).toBe(false);
|
|
87
|
+
expect(r.code, req('openwop.it.sandbox-wasm-isolation.node-pack-sandbox-memory-cap-access-beyond-the-host-memory-bound-is-sandbox-memo', 'RFC 0035 §B', 'node-pack-sandbox-memory-cap: access beyond the host memory bound is sandbox_memory_exceeded')).toBe('sandbox_memory_exceeded');
|
|
89
88
|
});
|
|
90
89
|
});
|
|
91
90
|
|
|
92
91
|
describe('sandbox-wasm-isolation: isolated context (RFC 0035 §B 8, server-free)', () => {
|
|
93
92
|
it('node-pack-sandbox-isolated-context: each invocation gets a fresh instance (no cross-pack state)', () => {
|
|
94
93
|
const iso = fix('isolation-global');
|
|
95
|
-
expect(probeSandboxed(iso, BASE, 'bump').result,
|
|
96
|
-
expect(probeSandboxed(iso, BASE, 'read').result,
|
|
94
|
+
expect(probeSandboxed(iso, BASE, 'bump').result, req('openwop.it.sandbox-wasm-isolation.node-pack-sandbox-isolated-context-each-invocation-gets-a-fresh-instance-no-cros', 'RFC 0035 §B invariant 8', 'a fresh instance starts at 0')).toBe(1);
|
|
95
|
+
expect(probeSandboxed(iso, BASE, 'read').result, req('openwop.it.sandbox-wasm-isolation.node-pack-sandbox-isolated-context-each-invocation-gets-a-fresh-instance-no-cros', 'RFC 0035 §B invariant 8', 'no state leaks across invocations')).toBe(0);
|
|
97
96
|
});
|
|
98
97
|
});
|
|
@@ -20,21 +20,20 @@ import { readFileSync } from 'node:fs';
|
|
|
20
20
|
import { join } from 'node:path';
|
|
21
21
|
import { FIXTURES_DIR } from '../lib/paths.js';
|
|
22
22
|
import { probeTimeout } from '../lib/wasm-sandbox-probe.js';
|
|
23
|
-
|
|
24
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
23
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
24
|
const dir = join(FIXTURES_DIR, 'wasm-sandbox');
|
|
26
25
|
const fix = (name: string): Uint8Array => new Uint8Array(readFileSync(join(dir, `${name}.wasm`)));
|
|
27
26
|
|
|
28
27
|
describe('sandbox-wasm-timeout: wall-clock cap is engine/worker-enforced (RFC 0035 §B 6, server-free)', () => {
|
|
29
28
|
it('node-pack-sandbox-timeout: a non-terminating module is killed with sandbox_timeout', async () => {
|
|
30
29
|
const r = await probeTimeout(fix('misbehaving-timeout'), { memoryLimitBytes: 2 * 1024 * 1024, wallClockLimitMs: 300 });
|
|
31
|
-
expect(r.ok,
|
|
32
|
-
expect(r.code,
|
|
30
|
+
expect(r.ok, req('openwop.it.sandbox-wasm-timeout.node-pack-sandbox-timeout-a-non-terminating-module-is-killed-with-sandbox-timeou', 'RFC 0035 §B invariant 6', 'an over-budget invocation MUST fail')).toBe(false);
|
|
31
|
+
expect(r.code, req('openwop.it.sandbox-wasm-timeout.node-pack-sandbox-timeout-a-non-terminating-module-is-killed-with-sandbox-timeou', 'RFC 0035 §C', 'the failure code MUST be sandbox_timeout')).toBe('sandbox_timeout');
|
|
33
32
|
});
|
|
34
33
|
|
|
35
34
|
it('positive control: a well-behaved module completes within the budget (the kill-timer does not false-positive)', async () => {
|
|
36
35
|
const r = await probeTimeout(fix('well-behaved-echo'), { memoryLimitBytes: 2 * 1024 * 1024, wallClockLimitMs: 1000 }, 'invoke', 7);
|
|
37
|
-
expect(r.ok,
|
|
38
|
-
expect(r.result).toBe(7);
|
|
36
|
+
expect(r.ok, req('openwop.it.sandbox-wasm-timeout.positive-control-a-well-behaved-module-completes-within-the-budget-the-kill-time', 'RFC 0035 §B', 'a within-budget invocation completes before the kill-timer')).toBe(true);
|
|
37
|
+
expect(r.result, req('openwop.it.sandbox-wasm-timeout.positive-control-a-well-behaved-module-completes-within-the-budget-the-kill-time', 'RFC 0035 §B', 'positive control: a well-behaved module completes within the budget (the kill-timer does not false-positive)')).toBe(7);
|
|
39
38
|
});
|
|
40
39
|
});
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
import { describe, it, expect } from 'vitest';
|
|
22
22
|
import { driver } from '../lib/driver.js';
|
|
23
23
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
24
26
|
|
|
25
27
|
interface DiscoveryScheduling {
|
|
26
28
|
supported?: boolean;
|
|
@@ -46,10 +48,10 @@ async function readScheduling(): Promise<DiscoveryScheduling | null> {
|
|
|
46
48
|
describe('scheduling-capability-shape: advertisement shape (RFC 0052 §A)', () => {
|
|
47
49
|
it('capabilities.scheduling is either absent or well-formed', async () => {
|
|
48
50
|
const sched = await readScheduling();
|
|
49
|
-
if (sched === null) return; // host doesn't advertise scheduling at all
|
|
51
|
+
if (sched === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `sched === null` returned early (host doesn\'t advertise scheduling at all)'); // host doesn't advertise scheduling at all
|
|
50
52
|
expect(
|
|
51
53
|
typeof sched.supported,
|
|
52
|
-
|
|
54
|
+
req('openwop.it.scheduling-capability-shape.capabilities-scheduling-is-either-absent-or-well-formed',
|
|
53
55
|
'capabilities.schema.json §scheduling',
|
|
54
56
|
'capabilities.scheduling.supported MUST be a boolean when scheduling is advertised',
|
|
55
57
|
),
|
|
@@ -58,22 +60,22 @@ describe('scheduling-capability-shape: advertisement shape (RFC 0052 §A)', () =
|
|
|
58
60
|
|
|
59
61
|
it('cron/delayed/calendar are booleans when present + supported', async () => {
|
|
60
62
|
const sched = await readScheduling();
|
|
61
|
-
if (!sched?.supported) return;
|
|
63
|
+
if (!sched?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!sched?.supported` returned early');
|
|
62
64
|
for (const k of ['cron', 'delayed', 'calendar'] as const) {
|
|
63
65
|
if (sched[k] === undefined) continue;
|
|
64
66
|
expect(
|
|
65
67
|
typeof sched[k],
|
|
66
|
-
|
|
68
|
+
req('openwop.it.scheduling-capability-shape.cron-delayed-calendar-are-booleans-when-present-supported', 'RFC 0052 §A', `capabilities.scheduling.${k} MUST be a boolean when present`),
|
|
67
69
|
).toBe('boolean');
|
|
68
70
|
}
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
it('maxFutureHorizon is an ISO-8601 duration when present', async () => {
|
|
72
74
|
const sched = await readScheduling();
|
|
73
|
-
if (!sched?.supported || sched.maxFutureHorizon === undefined) return;
|
|
75
|
+
if (!sched?.supported || sched.maxFutureHorizon === undefined) return softSkip('blocked', 'precondition not met — `!sched?.supported || sched.maxFutureHorizon === undefined` returned early (seam, prior step, or fixture unavailable)');
|
|
74
76
|
expect(
|
|
75
77
|
ISO_DURATION.test(sched.maxFutureHorizon),
|
|
76
|
-
|
|
78
|
+
req('openwop.it.scheduling-capability-shape.maxfuturehorizon-is-an-iso-8601-duration-when-present',
|
|
77
79
|
'RFC 0052 §A',
|
|
78
80
|
`capabilities.scheduling.maxFutureHorizon MUST be an ISO-8601 duration, got: ${sched.maxFutureHorizon}`,
|
|
79
81
|
),
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
import { describe, it, expect } from 'vitest';
|
|
28
28
|
import { driver } from '../lib/driver.js';
|
|
29
29
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
30
|
+
import { req } from '../lib/requirement-ids.js';
|
|
31
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
30
32
|
|
|
31
33
|
interface DiscoveryDoc {
|
|
32
34
|
capabilities?: { scheduling?: { supported?: boolean; cron?: boolean } };
|
|
@@ -40,25 +42,25 @@ async function readScheduling(): Promise<{ supported?: boolean; cron?: boolean }
|
|
|
40
42
|
describe('scheduling-cron-fires-once: once-per-tick + missed-tick (RFC 0052 §B)', () => {
|
|
41
43
|
it('a single cron tick produces exactly one run', async () => {
|
|
42
44
|
const sched = await readScheduling();
|
|
43
|
-
if (!sched?.supported || sched.cron !== true) return; // capability-gated
|
|
45
|
+
if (!sched?.supported || sched.cron !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!sched?.supported || sched.cron !== true` returned early (capability-gated)'); // capability-gated
|
|
44
46
|
const res = await driver.post('/v1/host/sample/scheduling/tick', { scenario: 'single-tick' });
|
|
45
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
47
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
46
48
|
const body = res.json as { runsFired?: number } | undefined;
|
|
47
49
|
expect(
|
|
48
50
|
body?.runsFired,
|
|
49
|
-
|
|
51
|
+
req('openwop.it.scheduling-cron-fires-once.a-single-cron-tick-produces-exactly-one-run', 'RFC 0052 §B.2', 'a single cron tick MUST fire exactly one run (no duplicate concurrent firing)'),
|
|
50
52
|
).toBe(1);
|
|
51
53
|
});
|
|
52
54
|
|
|
53
55
|
it('a missed-tick window does not produce a backlog flood', async () => {
|
|
54
56
|
const sched = await readScheduling();
|
|
55
|
-
if (!sched?.supported || sched.cron !== true) return; // capability-gated
|
|
57
|
+
if (!sched?.supported || sched.cron !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!sched?.supported || sched.cron !== true` returned early (capability-gated)'); // capability-gated
|
|
56
58
|
const res = await driver.post('/v1/host/sample/scheduling/tick', { scenario: 'missed-window', missedTicks: 5 });
|
|
57
|
-
if (res.status === 404) return; // seam unwired — soft-skip
|
|
59
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
58
60
|
const body = res.json as { runsFired?: number } | undefined;
|
|
59
61
|
expect(
|
|
60
62
|
typeof body?.runsFired === 'number' && body.runsFired <= 1,
|
|
61
|
-
|
|
63
|
+
req('openwop.it.scheduling-cron-fires-once.a-missed-tick-window-does-not-produce-a-backlog-flood',
|
|
62
64
|
'RFC 0052 §B.4',
|
|
63
65
|
`a missed-tick window MUST apply the advertised policy (fire-once-on-recovery or skip), never N backlogged runs; got runsFired=${body?.runsFired}`,
|
|
64
66
|
),
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
import { describe, it, expect } from 'vitest';
|
|
17
17
|
import { driver } from '../lib/driver.js';
|
|
18
18
|
import { discoveryFamilies } from '../lib/discovery-capabilities.js';
|
|
19
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
19
21
|
|
|
20
22
|
interface DiscoveryDoc {
|
|
21
23
|
capabilities?: Record<string, unknown>;
|
|
@@ -32,10 +34,10 @@ async function readCap(): Promise<Record<string, unknown> | null> {
|
|
|
32
34
|
describe('search-bm25-roundtrip: advertisement shape (RFC 0018)', () => {
|
|
33
35
|
it('capabilities.searchIndex is either absent or a well-formed object', async () => {
|
|
34
36
|
const cap = await readCap();
|
|
35
|
-
if (cap === null) return; // host doesn't advertise — skip
|
|
37
|
+
if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early (host doesn\'t advertise — skip)'); // host doesn't advertise — skip
|
|
36
38
|
expect(
|
|
37
39
|
typeof cap.supported,
|
|
38
|
-
|
|
40
|
+
req('openwop.it.search-bm25-roundtrip.capabilities-searchindex-is-either-absent-or-a-well-formed-object',
|
|
39
41
|
'capabilities.schema.json §searchIndex',
|
|
40
42
|
'capabilities.searchIndex.supported MUST be a boolean when present',
|
|
41
43
|
),
|
|
@@ -50,7 +52,7 @@ async function call(op: string, args: Record<string, unknown>) {
|
|
|
50
52
|
describe('search-bm25-roundtrip: behavioral (RFC 0018 §A.searchIndex)', () => {
|
|
51
53
|
it('index 3 docs → query for a distinguishing keyword returns the matching doc as top hit', async () => {
|
|
52
54
|
const probe = await call('query', { index: '__probe__', q: 'hello' });
|
|
53
|
-
if (probe.status === 404) return; // seam not exposed
|
|
55
|
+
if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam not exposed) (seam, prior step, or fixture unavailable)'); // seam not exposed
|
|
54
56
|
const index = `idx-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
55
57
|
const idx = await call('index', {
|
|
56
58
|
index,
|
|
@@ -69,7 +71,7 @@ describe('search-bm25-roundtrip: behavioral (RFC 0018 §A.searchIndex)', () => {
|
|
|
69
71
|
expect(Array.isArray(body.hits) && body.hits.length > 0).toBe(true);
|
|
70
72
|
expect(
|
|
71
73
|
body.hits![0]!.id,
|
|
72
|
-
|
|
74
|
+
req('openwop.it.search-bm25-roundtrip.index-3-docs-query-for-a-distinguishing-keyword-returns-the-matching-doc-as-top', 'RFC 0018 §A.searchIndex', 'query for the doc\'s distinguishing tokens MUST return that doc as top-1'),
|
|
73
75
|
).toBe('doc-2');
|
|
74
76
|
// Top hit's score MUST be strictly greater than any tied below-rank.
|
|
75
77
|
if (body.hits!.length > 1) {
|
|
@@ -79,7 +81,7 @@ describe('search-bm25-roundtrip: behavioral (RFC 0018 §A.searchIndex)', () => {
|
|
|
79
81
|
|
|
80
82
|
it('k limit caps the result set', async () => {
|
|
81
83
|
const probe = await call('query', { index: '__probe__', q: 'hello' });
|
|
82
|
-
if (probe.status === 404) return;
|
|
84
|
+
if (probe.status === 404) return softSkip('blocked', 'precondition not met — `probe.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
83
85
|
const index = `idx-k-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
84
86
|
const docs = Array.from({ length: 5 }, (_, i) => ({ id: `d-${i}`, fields: { body: 'apple orange banana' } }));
|
|
85
87
|
await call('index', { index, docs });
|
|
@@ -87,7 +89,7 @@ describe('search-bm25-roundtrip: behavioral (RFC 0018 §A.searchIndex)', () => {
|
|
|
87
89
|
const body = q.json as { hits?: unknown[] };
|
|
88
90
|
expect(
|
|
89
91
|
Array.isArray(body.hits) && body.hits.length <= 2,
|
|
90
|
-
|
|
92
|
+
req('openwop.it.search-bm25-roundtrip.k-limit-caps-the-result-set', 'RFC 0018 §A.searchIndex', 'query MUST return at most k hits'),
|
|
91
93
|
).toBe(true);
|
|
92
94
|
});
|
|
93
95
|
});
|