@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
|
@@ -11,6 +11,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
11
11
|
import addFormats from 'ajv-formats';
|
|
12
12
|
import type { ErrorObject } from 'ajv';
|
|
13
13
|
import { FIXTURES_DIR, SCHEMAS_DIR } from '../lib/paths.js';
|
|
14
|
+
import { req } from '../lib/requirement-ids.js';
|
|
14
15
|
|
|
15
16
|
// Layout-aware paths — `lib/paths.ts` resolves these for both repo
|
|
16
17
|
// checkouts (schemas one level above the conformance package) and the
|
|
@@ -46,7 +47,7 @@ describe('fixtures: workflow-definition schema validity', () => {
|
|
|
46
47
|
.sort();
|
|
47
48
|
|
|
48
49
|
it('finds at least one fixture file', () => {
|
|
49
|
-
expect(files.length).toBeGreaterThan(0);
|
|
50
|
+
expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-fixture-file', 'fixtures-valid.test.ts (no spec citation in file)', 'finds at least one fixture file')).toBeGreaterThan(0);
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
for (const file of files) {
|
|
@@ -56,7 +57,7 @@ describe('fixtures: workflow-definition schema validity', () => {
|
|
|
56
57
|
const errors = (validate.errors ?? [])
|
|
57
58
|
.map((e: ErrorObject) => `${e.instancePath || '/'}: ${e.message}`)
|
|
58
59
|
.join('\n');
|
|
59
|
-
expect(ok, `Fixture ${file} fails workflow-definition schema:\n${errors}`).toBe(true);
|
|
60
|
+
expect(ok, req('openwop.it.fixtures-valid.validates-against-workflow-definition-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture ${file} fails workflow-definition schema:\n${errors}`)).toBe(true);
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -66,7 +67,7 @@ describe('fixtures: workflow-definition schema validity', () => {
|
|
|
66
67
|
const expected = file.replace(/\.json$/, '');
|
|
67
68
|
expect(
|
|
68
69
|
data.id,
|
|
69
|
-
`Fixture file ${file} declares id "${data.id}" — MUST match filename
|
|
70
|
+
req('openwop.it.fixtures-valid.every-fixture-id-matches-its-filename', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture file ${file} declares id "${data.id}" — MUST match filename`),
|
|
70
71
|
).toBe(expected);
|
|
71
72
|
}
|
|
72
73
|
});
|
|
@@ -80,7 +81,7 @@ describe('fixtures: workflow-definition schema validity', () => {
|
|
|
80
81
|
const hasManual = data.triggers.some((t) => t.type === 'manual');
|
|
81
82
|
expect(
|
|
82
83
|
hasManual,
|
|
83
|
-
`Fixture ${data.id} MUST include a manual trigger per fixtures.md §Seeding contract
|
|
84
|
+
req('openwop.it.fixtures-valid.every-fixture-has-a-manual-trigger-so-the-conformance-driver-can-start-it', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture ${data.id} MUST include a manual trigger per fixtures.md §Seeding contract`),
|
|
84
85
|
).toBe(true);
|
|
85
86
|
}
|
|
86
87
|
});
|
|
@@ -120,7 +121,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
|
|
|
120
121
|
.sort();
|
|
121
122
|
|
|
122
123
|
it('finds at least one pack-manifest fixture (private-scope coverage)', () => {
|
|
123
|
-
expect(files.length).toBeGreaterThan(0);
|
|
124
|
+
expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-pack-manifest-fixture-private-scope-coverage', 'fixtures-valid.test.ts (no spec citation in file)', 'finds at least one pack-manifest fixture (private-scope coverage)')).toBeGreaterThan(0);
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
for (const file of files) {
|
|
@@ -139,7 +140,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
|
|
|
139
140
|
.join('\n');
|
|
140
141
|
expect(
|
|
141
142
|
ok,
|
|
142
|
-
`Fixture pack-manifests/${file} fails ${schemaName}:\n${errors}
|
|
143
|
+
req('openwop.it.fixtures-valid.pack-manifests-validates-against-its-kind-s-manifest-schema', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture pack-manifests/${file} fails ${schemaName}:\n${errors}`),
|
|
143
144
|
).toBe(true);
|
|
144
145
|
});
|
|
145
146
|
}
|
|
@@ -158,7 +159,7 @@ describe('fixtures: node-pack-manifest schema validity', () => {
|
|
|
158
159
|
});
|
|
159
160
|
expect(
|
|
160
161
|
privateFixtures.length,
|
|
161
|
-
'Expected at least one pack-manifest fixture under the `private.<host>.*` scope to assert v1.0 private-scope pattern coverage',
|
|
162
|
+
req('openwop.it.fixtures-valid.the-private-scope-fixture-exercises-the-v1-0-private-pack-pattern', 'fixtures-valid.test.ts (no spec citation in file)', 'Expected at least one pack-manifest fixture under the `private.<host>.*` scope to assert v1.0 private-scope pattern coverage'),
|
|
162
163
|
).toBeGreaterThan(0);
|
|
163
164
|
});
|
|
164
165
|
});
|
|
@@ -179,7 +180,7 @@ describe('fixtures: connection-pack-manifest schema validity', () => {
|
|
|
179
180
|
.sort();
|
|
180
181
|
|
|
181
182
|
it('finds at least one connection-pack fixture (RFC 0095 coverage)', () => {
|
|
182
|
-
expect(files.length).toBeGreaterThan(0);
|
|
183
|
+
expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-connection-pack-fixture-rfc-0095-coverage', 'RFC 0095', 'finds at least one connection-pack fixture (RFC 0095 coverage)')).toBeGreaterThan(0);
|
|
183
184
|
});
|
|
184
185
|
|
|
185
186
|
for (const file of files) {
|
|
@@ -191,7 +192,7 @@ describe('fixtures: connection-pack-manifest schema validity', () => {
|
|
|
191
192
|
.join('\n');
|
|
192
193
|
expect(
|
|
193
194
|
ok,
|
|
194
|
-
`Fixture connection-packs/${file} fails connection-pack-manifest schema:\n${errors}
|
|
195
|
+
req('openwop.it.fixtures-valid.connection-packs-validates-against-connection-pack-manifest-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture connection-packs/${file} fails connection-pack-manifest schema:\n${errors}`),
|
|
195
196
|
).toBe(true);
|
|
196
197
|
});
|
|
197
198
|
}
|
|
@@ -219,7 +220,7 @@ describe('fixtures: trigger-event + registration schema validity', () => {
|
|
|
219
220
|
.sort();
|
|
220
221
|
|
|
221
222
|
it('finds at least one trigger-event fixture (RFC 0099 coverage)', () => {
|
|
222
|
-
expect(files.length).toBeGreaterThan(0);
|
|
223
|
+
expect(files.length, req('openwop.it.fixtures-valid.finds-at-least-one-trigger-event-fixture-rfc-0099-coverage', 'RFC 0099', 'finds at least one trigger-event fixture (RFC 0099 coverage)')).toBeGreaterThan(0);
|
|
223
224
|
});
|
|
224
225
|
|
|
225
226
|
for (const file of files) {
|
|
@@ -230,7 +231,7 @@ describe('fixtures: trigger-event + registration schema validity', () => {
|
|
|
230
231
|
const errors = (validate.errors ?? [])
|
|
231
232
|
.map((e: ErrorObject) => `${e.instancePath || '/'}: ${e.message}`)
|
|
232
233
|
.join('\n');
|
|
233
|
-
expect(ok, `Fixture trigger-events/${file} fails its schema:\n${errors}`).toBe(true);
|
|
234
|
+
expect(ok, req('openwop.it.fixtures-valid.trigger-events-validates-against-its-schema', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture trigger-events/${file} fails its schema:\n${errors}`)).toBe(true);
|
|
234
235
|
});
|
|
235
236
|
}
|
|
236
237
|
});
|
|
@@ -264,7 +265,7 @@ describe('fixtures: prompt-template schema validity', () => {
|
|
|
264
265
|
it('finds at least one prompt-template fixture', () => {
|
|
265
266
|
expect(
|
|
266
267
|
files.length,
|
|
267
|
-
'Expected at least one PromptTemplate fixture under fixtures/prompt-templates/',
|
|
268
|
+
req('openwop.it.fixtures-valid.finds-at-least-one-prompt-template-fixture', 'fixtures-valid.test.ts (no spec citation in file)', 'Expected at least one PromptTemplate fixture under fixtures/prompt-templates/'),
|
|
268
269
|
).toBeGreaterThan(0);
|
|
269
270
|
});
|
|
270
271
|
|
|
@@ -279,7 +280,7 @@ describe('fixtures: prompt-template schema validity', () => {
|
|
|
279
280
|
.join('\n');
|
|
280
281
|
expect(
|
|
281
282
|
ok,
|
|
282
|
-
`Fixture prompt-templates/${file} fails prompt-template schema:\n${errors}
|
|
283
|
+
req('openwop.it.fixtures-valid.prompt-templates-validates-against-prompt-template-schema-json', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} fails prompt-template schema:\n${errors}`),
|
|
283
284
|
).toBe(true);
|
|
284
285
|
});
|
|
285
286
|
}
|
|
@@ -297,7 +298,7 @@ describe('fixtures: prompt-template schema validity', () => {
|
|
|
297
298
|
) as { templateId: string };
|
|
298
299
|
expect(
|
|
299
300
|
typeof data.templateId,
|
|
300
|
-
`Fixture prompt-templates/${file} MUST declare a templateId
|
|
301
|
+
req('openwop.it.fixtures-valid.every-fixture-templateid-matches-its-filename', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} MUST declare a templateId`),
|
|
301
302
|
).toBe('string');
|
|
302
303
|
expect(data.templateId.length).toBeGreaterThan(0);
|
|
303
304
|
}
|
|
@@ -321,7 +322,7 @@ describe('fixtures: prompt-template schema validity', () => {
|
|
|
321
322
|
if (hasSecretSource) {
|
|
322
323
|
expect(
|
|
323
324
|
(data.tags ?? []).includes('secret-redaction'),
|
|
324
|
-
`Fixture prompt-templates/${file} declares a secret-source variable but lacks the 'secret-redaction' tag
|
|
325
|
+
req('openwop.it.fixtures-valid.every-secret-source-variable-lives-in-a-fixture-tagged-for-the-secret-redaction', 'fixtures-valid.test.ts (no spec citation in file)', `Fixture prompt-templates/${file} declares a secret-source variable but lacks the 'secret-redaction' tag`),
|
|
325
326
|
).toBe(true);
|
|
326
327
|
}
|
|
327
328
|
}
|
|
@@ -55,7 +55,6 @@
|
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
57
|
import { describe, it, expect } from 'vitest';
|
|
58
|
-
import { driver } from '../lib/driver.js';
|
|
59
58
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
60
59
|
import {
|
|
61
60
|
readFormContentCap,
|
|
@@ -65,6 +64,8 @@ import {
|
|
|
65
64
|
isEditable,
|
|
66
65
|
PLAIN_TEXT_CONTROLS,
|
|
67
66
|
} from '../lib/formContentPacks.js';
|
|
67
|
+
import { req } from '../lib/requirement-ids.js';
|
|
68
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* Conformance fixture templates a host wires the seam against.
|
|
@@ -82,17 +83,17 @@ describe('form-content-instantiation: a host instantiates a registered template
|
|
|
82
83
|
it('#1 instantiation goes through the host NORMAL create path', async () => {
|
|
83
84
|
if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
|
|
84
85
|
const res = await instantiateTemplate(BASIC_TEMPLATE);
|
|
85
|
-
if (res === null) return; // seam absent — soft-skip
|
|
86
|
+
if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
|
|
86
87
|
|
|
87
88
|
expect(
|
|
88
89
|
res.status >= 200 && res.status < 300,
|
|
89
|
-
|
|
90
|
+
req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path', 'form-content-packs.md §Instantiation', 'a registered template MUST instantiate'),
|
|
90
91
|
).toBe(true);
|
|
91
92
|
|
|
92
93
|
if (res.json['viaCreatePath'] !== undefined) {
|
|
93
94
|
expect(
|
|
94
95
|
res.json['viaCreatePath'],
|
|
95
|
-
|
|
96
|
+
req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path',
|
|
96
97
|
'form-content-packs.md §Instantiation #1',
|
|
97
98
|
'the host MUST create the form through the SAME path that serves a hand-authored form',
|
|
98
99
|
),
|
|
@@ -101,14 +102,14 @@ describe('form-content-instantiation: a host instantiates a registered template
|
|
|
101
102
|
|
|
102
103
|
expect(
|
|
103
104
|
res.fields.length,
|
|
104
|
-
|
|
105
|
+
req('openwop.it.form-content-instantiation.1-instantiation-goes-through-the-host-normal-create-path', 'form-content-packs.md §Instantiation', 'the instantiated form MUST carry the template fields'),
|
|
105
106
|
).toBeGreaterThan(0);
|
|
106
107
|
});
|
|
107
108
|
|
|
108
109
|
it('#1/F2 the instantiated form carries NO pack-bound submission destination', async () => {
|
|
109
110
|
if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
|
|
110
111
|
const res = await instantiateTemplate(BASIC_TEMPLATE);
|
|
111
|
-
if (res === null) return;
|
|
112
|
+
if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
|
|
112
113
|
|
|
113
114
|
const routing = res.json['routing'];
|
|
114
115
|
const bound =
|
|
@@ -118,7 +119,7 @@ describe('form-content-instantiation: a host instantiates a registered template
|
|
|
118
119
|
|
|
119
120
|
expect(
|
|
120
121
|
bound,
|
|
121
|
-
|
|
122
|
+
req('openwop.it.form-content-instantiation.1-f2-the-instantiated-form-carries-no-pack-bound-submission-destination',
|
|
122
123
|
'form-content-packs.md §No submission routing (F2)',
|
|
123
124
|
'a template MUST NOT bind a submission destination — the operator configures routing afterward, as for any hand-authored form',
|
|
124
125
|
),
|
|
@@ -128,21 +129,21 @@ describe('form-content-instantiation: a host instantiates a registered template
|
|
|
128
129
|
it('#2 an unrecognized vendor.* field type DEGRADES to plain text, and does NOT fail the instantiation', async () => {
|
|
129
130
|
if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
|
|
130
131
|
const res = await instantiateTemplate(EXTENDED_TEMPLATE);
|
|
131
|
-
if (res === null) return;
|
|
132
|
+
if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
|
|
132
133
|
|
|
133
134
|
expect(
|
|
134
135
|
res.status >= 200 && res.status < 300 && res.json['refused'] !== true,
|
|
135
|
-
|
|
136
|
+
req('openwop.it.form-content-instantiation.2-an-unrecognized-vendor-field-type-degrades-to-plain-text-and-does-not-fail-the',
|
|
136
137
|
'form-content-packs.md §Instantiation #2',
|
|
137
138
|
'a well-formed but unrecognized vendor.*/x- type MUST degrade, NOT fail the instantiation — refusing a valid extension breaks forward compatibility',
|
|
138
139
|
),
|
|
139
140
|
).toBe(true);
|
|
140
141
|
|
|
141
142
|
const field = fieldById(res.fields, VENDOR_FIELD_ID);
|
|
142
|
-
if (field === undefined) return; // host doesn't report per-field controls on the seam — soft-skip
|
|
143
|
+
if (field === undefined) return softSkip('blocked', 'precondition not met — `field === undefined` returned early (host doesn\'t report per-field controls on the seam — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't report per-field controls on the seam — soft-skip
|
|
143
144
|
expect(
|
|
144
145
|
field.control !== undefined && PLAIN_TEXT_CONTROLS.has(field.control),
|
|
145
|
-
|
|
146
|
+
req('openwop.it.form-content-instantiation.2-an-unrecognized-vendor-field-type-degrades-to-plain-text-and-does-not-fail-the',
|
|
146
147
|
'form-content-packs.md §Instantiation #2',
|
|
147
148
|
`an unrecognized field type MUST render as a plain text input (got control ${JSON.stringify(field.control)})`,
|
|
148
149
|
),
|
|
@@ -152,14 +153,14 @@ describe('form-content-instantiation: a host instantiates a registered template
|
|
|
152
153
|
it('#3 pack-authored fields are FULLY EDITABLE — no privilege over a hand-added field', async () => {
|
|
153
154
|
if (!behaviorGate(PROFILE, formContentSupported(await readFormContentCap()))) return;
|
|
154
155
|
const res = await instantiateTemplate(BASIC_TEMPLATE);
|
|
155
|
-
if (res === null) return;
|
|
156
|
+
if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam, prior step, or fixture unavailable)');
|
|
156
157
|
|
|
157
158
|
const reporting = res.fields.filter((f) => f.editable !== undefined || f.locked !== undefined);
|
|
158
|
-
if (reporting.length === 0) return; // host doesn't report editability — soft-skip
|
|
159
|
+
if (reporting.length === 0) return softSkip('blocked', 'precondition not met — `reporting.length === 0` returned early (host doesn\'t report editability — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't report editability — soft-skip
|
|
159
160
|
|
|
160
161
|
expect(
|
|
161
162
|
reporting.every((f) => isEditable(f)),
|
|
162
|
-
|
|
163
|
+
req('openwop.it.form-content-instantiation.3-pack-authored-fields-are-fully-editable-no-privilege-over-a-hand-added-field',
|
|
163
164
|
'form-content-packs.md §Instantiation #3',
|
|
164
165
|
'the host MUST NOT treat a pack-authored field as immutable or privileged relative to a hand-added one',
|
|
165
166
|
),
|
|
@@ -39,6 +39,8 @@ import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
|
39
39
|
import { driver } from '../lib/driver.js';
|
|
40
40
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
41
41
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
42
|
+
import { req } from '../lib/requirement-ids.js';
|
|
43
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
42
44
|
|
|
43
45
|
const MANIFEST_SCHEMA = join(SCHEMAS_DIR, 'frontend-plugin-manifest.schema.json');
|
|
44
46
|
const MESSAGE_SCHEMA = join(SCHEMAS_DIR, 'ui-plugin-message.schema.json');
|
|
@@ -68,7 +70,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
|
|
|
68
70
|
it('a well-formed frontend-plugin manifest validates', () => {
|
|
69
71
|
expect(
|
|
70
72
|
validate(validManifest()),
|
|
71
|
-
`frontend-plugin-packs.md §The pack — a valid manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
73
|
+
req('openwop.it.frontend-plugin-packs.a-well-formed-frontend-plugin-manifest-validates', 'frontend-plugin-packs.md', `frontend-plugin-packs.md §The pack — a valid manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
72
74
|
).toBe(true);
|
|
73
75
|
});
|
|
74
76
|
|
|
@@ -76,20 +78,20 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
|
|
|
76
78
|
const m = { ...validManifest(), runtime: { language: 'javascript', entry: 'index.mjs' } };
|
|
77
79
|
expect(
|
|
78
80
|
validate(m),
|
|
79
|
-
'node-packs.md §Pack kinds — a kind:"frontend-plugin" manifest carrying `runtime` MUST be rejected (pack_kind_invalid)',
|
|
81
|
+
req('openwop.it.frontend-plugin-packs.a-backend-runtime-member-is-rejected-a-plugin-is-sandboxed-ui-not-a-node-entry', 'frontend-plugin-packs.md', 'node-packs.md §Pack kinds — a kind:"frontend-plugin" manifest carrying `runtime` MUST be rejected (pack_kind_invalid)'),
|
|
80
82
|
).toBe(false);
|
|
81
83
|
});
|
|
82
84
|
|
|
83
85
|
it('a uiPlugins[] entry missing `entry` is rejected', () => {
|
|
84
86
|
const m = validManifest();
|
|
85
87
|
delete (m.uiPlugins as Array<Record<string, unknown>>)[0].entry;
|
|
86
|
-
expect(validate(m), 'a uiPlugins[] entry missing `entry` MUST NOT validate').toBe(false);
|
|
88
|
+
expect(validate(m), req('openwop.it.frontend-plugin-packs.a-uiplugins-entry-missing-entry-is-rejected', 'frontend-plugin-packs.md', 'a uiPlugins[] entry missing `entry` MUST NOT validate')).toBe(false);
|
|
87
89
|
});
|
|
88
90
|
|
|
89
91
|
it('an `entry` path with `..` traversal is rejected', () => {
|
|
90
92
|
const m = validManifest();
|
|
91
93
|
(m.uiPlugins as Array<Record<string, unknown>>)[0].entry = '../escape.mjs';
|
|
92
|
-
expect(validate(m), 'an `entry` path MUST NOT contain `..` (path-traversal)').toBe(false);
|
|
94
|
+
expect(validate(m), req('openwop.it.frontend-plugin-packs.an-entry-path-with-traversal-is-rejected', 'frontend-plugin-packs.md', 'an `entry` path MUST NOT contain `..` (path-traversal)')).toBe(false);
|
|
93
95
|
});
|
|
94
96
|
|
|
95
97
|
it('a hostApi method outside the closed allowlist is rejected (frontend-plugin-rpc-allowlist)', () => {
|
|
@@ -97,13 +99,13 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
|
|
|
97
99
|
(m.uiPlugins as Array<Record<string, unknown>>)[0].hostApi = ['artifact.read', 'host.exec'];
|
|
98
100
|
expect(
|
|
99
101
|
validate(m),
|
|
100
|
-
'frontend-plugin-packs.md §Host-RPC — only the closed allowlist methods are permitted; `host.exec` MUST NOT validate',
|
|
102
|
+
req('openwop.it.frontend-plugin-packs.a-hostapi-method-outside-the-closed-allowlist-is-rejected-frontend-plugin-rpc-al', 'frontend-plugin-packs.md', 'frontend-plugin-packs.md §Host-RPC — only the closed allowlist methods are permitted; `host.exec` MUST NOT validate'),
|
|
101
103
|
).toBe(false);
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
it('an empty uiPlugins[] is rejected (a pack MUST declare at least one plugin)', () => {
|
|
105
107
|
const m = { ...validManifest(), uiPlugins: [] };
|
|
106
|
-
expect(validate(m), 'a frontend-plugin pack MUST declare at least one uiPlugins[] entry').toBe(false);
|
|
108
|
+
expect(validate(m), req('openwop.it.frontend-plugin-packs.an-empty-uiplugins-is-rejected-a-pack-must-declare-at-least-one-plugin', 'frontend-plugin-packs.md', 'a frontend-plugin pack MUST declare at least one uiPlugins[] entry')).toBe(false);
|
|
107
109
|
});
|
|
108
110
|
|
|
109
111
|
it('a canvas-preview entry with canvasTypes + host.announce validates (RFC 0130)', () => {
|
|
@@ -117,7 +119,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
|
|
|
117
119
|
};
|
|
118
120
|
expect(
|
|
119
121
|
validate(m),
|
|
120
|
-
`frontend-plugin-packs.md §The pack (RFC 0130) — a canvas-preview entry MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
122
|
+
req('openwop.it.frontend-plugin-packs.a-canvas-preview-entry-with-canvastypes-host-announce-validates-rfc-0130', 'RFC 0130', `frontend-plugin-packs.md §The pack (RFC 0130) — a canvas-preview entry MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
121
123
|
).toBe(true);
|
|
122
124
|
});
|
|
123
125
|
|
|
@@ -126,7 +128,7 @@ describe('frontend-plugin manifest: schema layer (always-on, server-free)', () =
|
|
|
126
128
|
(m.uiPlugins as Array<Record<string, unknown>>)[0].surface = 'omni-panel';
|
|
127
129
|
expect(
|
|
128
130
|
validate(m),
|
|
129
|
-
'frontend-plugin-packs.md §The pack — the surface enum stays closed; an unknown surface MUST NOT validate',
|
|
131
|
+
req('openwop.it.frontend-plugin-packs.a-surface-outside-the-closed-set-is-still-rejected-rfc-0130-keeps-the-enum-close', 'RFC 0130', 'frontend-plugin-packs.md §The pack — the surface enum stays closed; an unknown surface MUST NOT validate'),
|
|
130
132
|
).toBe(false);
|
|
131
133
|
});
|
|
132
134
|
});
|
|
@@ -137,14 +139,14 @@ describe('ui-plugin/1 message: schema layer (always-on, server-free)', () => {
|
|
|
137
139
|
const validate = ajv.compile(JSON.parse(readFileSync(MESSAGE_SCHEMA, 'utf8')));
|
|
138
140
|
|
|
139
141
|
it('a valid artifact.write request carrying a version token validates', () => {
|
|
140
|
-
const
|
|
142
|
+
const reqBody = {
|
|
141
143
|
openwop: 'ui-plugin/1',
|
|
142
144
|
type: 'request',
|
|
143
145
|
id: 7,
|
|
144
146
|
method: 'artifact.write',
|
|
145
147
|
params: { artifactId: 'a-1', version: 'opaque-v1', payload: {} },
|
|
146
148
|
};
|
|
147
|
-
expect(validate(
|
|
149
|
+
expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-valid-artifact-write-request-carrying-a-version-token-validates', 'frontend-plugin-packs.md', `a valid artifact.write request MUST validate. Errors: ${JSON.stringify(validate.errors)}`)).toBe(true);
|
|
148
150
|
});
|
|
149
151
|
|
|
150
152
|
it('an artifact_conflict response carries currentVersion (version-token concurrency)', () => {
|
|
@@ -157,28 +159,28 @@ describe('ui-plugin/1 message: schema layer (always-on, server-free)', () => {
|
|
|
157
159
|
};
|
|
158
160
|
expect(
|
|
159
161
|
validate(res),
|
|
160
|
-
`frontend-plugin-packs.md §Concurrency — a stale write surfaces artifact_conflict + currentVersion. Errors: ${JSON.stringify(validate.errors)}
|
|
162
|
+
req('openwop.it.frontend-plugin-packs.an-artifact-conflict-response-carries-currentversion-version-token-concurrency', 'frontend-plugin-packs.md', `frontend-plugin-packs.md §Concurrency — a stale write surfaces artifact_conflict + currentVersion. Errors: ${JSON.stringify(validate.errors)}`),
|
|
161
163
|
).toBe(true);
|
|
162
164
|
});
|
|
163
165
|
|
|
164
166
|
it('a request with a method outside the allowlist is schema-rejected', () => {
|
|
165
|
-
const
|
|
166
|
-
expect(validate(
|
|
167
|
+
const reqBody = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'host.exec' };
|
|
168
|
+
expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-request-with-a-method-outside-the-allowlist-is-schema-rejected', 'frontend-plugin-packs.md', 'a method outside the ui-plugin/1 allowlist MUST NOT validate')).toBe(false);
|
|
167
169
|
});
|
|
168
170
|
|
|
169
171
|
it('a message without the ui-plugin/1 protocol tag is rejected', () => {
|
|
170
|
-
const
|
|
171
|
-
expect(validate(
|
|
172
|
+
const reqBody = { openwop: 'ui-plugin/2', type: 'request', id: 1, method: 'artifact.read' };
|
|
173
|
+
expect(validate(reqBody), req('openwop.it.frontend-plugin-packs.a-message-without-the-ui-plugin-1-protocol-tag-is-rejected', 'frontend-plugin-packs.md', 'a host MUST ignore messages whose ui-plugin tag it does not recognize')).toBe(false);
|
|
172
174
|
});
|
|
173
175
|
|
|
174
176
|
it('no credential-bearing field is admitted on the envelope (frontend-plugin-no-byok)', () => {
|
|
175
177
|
// additionalProperties:false on every envelope variant — a stray apiKey/token at the
|
|
176
178
|
// envelope root cannot ride the boundary.
|
|
177
179
|
for (const leak of ['apiKey', 'token', 'clientSecret', 'authorization']) {
|
|
178
|
-
const
|
|
180
|
+
const reqBody = { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'artifact.read', [leak]: 'xxx' };
|
|
179
181
|
expect(
|
|
180
|
-
validate(
|
|
181
|
-
`frontend-plugin-no-byok — a credential-named envelope field ("${leak}") MUST NOT validate (additionalProperties:false)
|
|
182
|
+
validate(reqBody),
|
|
183
|
+
req('openwop.it.frontend-plugin-packs.no-credential-bearing-field-is-admitted-on-the-envelope-frontend-plugin-no-byok', 'frontend-plugin-packs.md', `frontend-plugin-no-byok — a credential-named envelope field ("${leak}") MUST NOT validate (additionalProperties:false)`),
|
|
182
184
|
).toBe(false);
|
|
183
185
|
}
|
|
184
186
|
});
|
|
@@ -194,11 +196,11 @@ describe('frontend-plugin: isolation advertisement (always-on, capability shape)
|
|
|
194
196
|
const X_HOST = /^x-host-[a-z0-9-]+-[a-z0-9-]+$/;
|
|
195
197
|
it('a host advertising uiPlugins MUST advertise a conformant isolation model', async () => {
|
|
196
198
|
const uiPlugins = await readCapabilityFamily<{ supported?: boolean; isolation?: string }>('uiPlugins');
|
|
197
|
-
if (!uiPlugins?.supported) return; // unadvertised → out of scope (graceful degradation)
|
|
199
|
+
if (!uiPlugins?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!uiPlugins?.supported` returned early (unadvertised → out of scope (graceful degradation))'); // unadvertised → out of scope (graceful degradation)
|
|
198
200
|
const iso = uiPlugins.isolation;
|
|
199
201
|
expect(
|
|
200
202
|
iso !== undefined && (CONFORMANT_ISOLATION.includes(iso) || X_HOST.test(iso)),
|
|
201
|
-
|
|
203
|
+
req('openwop.it.frontend-plugin-packs.a-host-advertising-uiplugins-must-advertise-a-conformant-isolation-model',
|
|
202
204
|
'frontend-plugin-packs.md §Isolation (RFC 0119)',
|
|
203
205
|
'frontend-plugin-isolation — isolation MUST be a conformant model (cross-origin-iframe default | wasm | process | container | vm | x-host-*); every value denotes the same property, in-process loading is a protocol-tier MUST NOT regardless of mechanism',
|
|
204
206
|
),
|
|
@@ -214,16 +216,16 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
|
|
|
214
216
|
const res = await driver.post('/v1/host/sample/ui-plugin/rpc', {
|
|
215
217
|
message: { openwop: 'ui-plugin/1', type: 'request', id: 1, method: 'host.exec' },
|
|
216
218
|
});
|
|
217
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
219
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
218
220
|
|
|
219
221
|
const body = res.json as { ok?: boolean; error?: { code?: string } } | undefined;
|
|
220
222
|
expect(
|
|
221
223
|
body?.ok,
|
|
222
|
-
|
|
224
|
+
req('openwop.it.frontend-plugin-packs.an-undeclared-host-rpc-method-is-refused-with-method-not-allowed', 'frontend-plugin-packs.md §Host-RPC', 'an undeclared method MUST NOT execute'),
|
|
223
225
|
).toBe(false);
|
|
224
226
|
expect(
|
|
225
227
|
body?.error?.code,
|
|
226
|
-
|
|
228
|
+
req('openwop.it.frontend-plugin-packs.an-undeclared-host-rpc-method-is-refused-with-method-not-allowed',
|
|
227
229
|
'frontend-plugin-packs.md §Host-RPC',
|
|
228
230
|
'frontend-plugin-rpc-allowlist — an undeclared method surfaces method_not_allowed',
|
|
229
231
|
),
|
|
@@ -233,7 +235,7 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
|
|
|
233
235
|
it('a stale artifact.write is refused with artifact_conflict + currentVersion (no persist)', async () => {
|
|
234
236
|
const uiPlugins = await readCapabilityFamily<{ supported?: boolean; hostApi?: string[] }>('uiPlugins');
|
|
235
237
|
if (!behaviorGate('uiPlugins.supported', uiPlugins?.supported === true)) return;
|
|
236
|
-
if (!(uiPlugins?.hostApi ?? []).includes('artifact.write')) return; // write unsupported → out of scope
|
|
238
|
+
if (!(uiPlugins?.hostApi ?? []).includes('artifact.write')) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(uiPlugins?.hostApi ?? []).includes(\'artifact.write\')` returned early (write unsupported → out of scope)'); // write unsupported → out of scope
|
|
237
239
|
|
|
238
240
|
const res = await driver.post('/v1/host/sample/ui-plugin/rpc', {
|
|
239
241
|
message: {
|
|
@@ -244,19 +246,19 @@ describe('frontend-plugin: host-RPC behavior (capability-gated)', () => {
|
|
|
244
246
|
params: { artifactId: 'conformance-canary', version: 'stale-token', payload: {} },
|
|
245
247
|
},
|
|
246
248
|
});
|
|
247
|
-
if (res.status === 404 || res.status === 403) return; // seam unwired — soft-skip
|
|
249
|
+
if (res.status === 404 || res.status === 403) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 403` returned early (seam unwired — soft-skip) (seam, prior step, or fixture unavailable)'); // seam unwired — soft-skip
|
|
248
250
|
|
|
249
251
|
const body = res.json as { ok?: boolean; error?: { code?: string; currentVersion?: string } } | undefined;
|
|
250
252
|
expect(
|
|
251
253
|
body?.error?.code,
|
|
252
|
-
|
|
254
|
+
req('openwop.it.frontend-plugin-packs.a-stale-artifact-write-is-refused-with-artifact-conflict-currentversion-no-persi',
|
|
253
255
|
'frontend-plugin-packs.md §Concurrency',
|
|
254
256
|
'a stale artifact.write version surfaces artifact_conflict (host MUST NOT persist)',
|
|
255
257
|
),
|
|
256
258
|
).toBe('artifact_conflict');
|
|
257
259
|
expect(
|
|
258
260
|
typeof body?.error?.currentVersion,
|
|
259
|
-
|
|
261
|
+
req('openwop.it.frontend-plugin-packs.a-stale-artifact-write-is-refused-with-artifact-conflict-currentversion-no-persi', 'frontend-plugin-packs.md §Concurrency', 'artifact_conflict carries the host currentVersion for re-read/merge'),
|
|
260
262
|
).toBe('string');
|
|
261
263
|
});
|
|
262
264
|
});
|
|
@@ -29,6 +29,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
29
29
|
import { readErrorCode } from '../lib/error-envelope.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';
|
|
33
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
32
34
|
|
|
33
35
|
interface DiscoveryFs {
|
|
34
36
|
supported?: boolean;
|
|
@@ -57,10 +59,10 @@ const PATH_REJECTION_CODES: ReadonlySet<string> = new Set([
|
|
|
57
59
|
describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
|
|
58
60
|
it('capabilities.fs is either absent or well-formed', async () => {
|
|
59
61
|
const fs = await readFs();
|
|
60
|
-
if (fs === null) return; // host doesn't advertise fs at all
|
|
62
|
+
if (fs === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `fs === null` returned early (host doesn\'t advertise fs at all)'); // host doesn't advertise fs at all
|
|
61
63
|
expect(
|
|
62
64
|
typeof fs.supported,
|
|
63
|
-
|
|
65
|
+
req('openwop.it.fs-path-traversal.capabilities-fs-is-either-absent-or-well-formed',
|
|
64
66
|
'capabilities.schema.json §fs',
|
|
65
67
|
'capabilities.fs.supported MUST be a boolean when fs is advertised',
|
|
66
68
|
),
|
|
@@ -69,17 +71,17 @@ describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
|
|
|
69
71
|
|
|
70
72
|
it('fs.sandboxRoot is set + non-empty when fs.supported=true', async () => {
|
|
71
73
|
const fs = await readFs();
|
|
72
|
-
if (!fs?.supported) return;
|
|
74
|
+
if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
|
|
73
75
|
expect(
|
|
74
76
|
typeof fs.sandboxRoot,
|
|
75
|
-
|
|
77
|
+
req('openwop.it.fs-path-traversal.fs-sandboxroot-is-set-non-empty-when-fs-supported-true',
|
|
76
78
|
'RFC 0014 §A',
|
|
77
79
|
'capabilities.fs.sandboxRoot MUST be present when fs.supported=true',
|
|
78
80
|
),
|
|
79
81
|
).toBe('string');
|
|
80
82
|
expect(
|
|
81
83
|
(fs.sandboxRoot ?? '').length,
|
|
82
|
-
|
|
84
|
+
req('openwop.it.fs-path-traversal.fs-sandboxroot-is-set-non-empty-when-fs-supported-true', 'RFC 0014 §A', 'capabilities.fs.sandboxRoot MUST NOT be empty'),
|
|
83
85
|
).toBeGreaterThan(0);
|
|
84
86
|
});
|
|
85
87
|
});
|
|
@@ -87,13 +89,13 @@ describe('fs-path-traversal: advertisement shape (RFC 0014 §A)', () => {
|
|
|
87
89
|
describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () => {
|
|
88
90
|
it('absolute path outside sandbox is rejected', async () => {
|
|
89
91
|
const fs = await readFs();
|
|
90
|
-
if (!fs?.supported) return;
|
|
92
|
+
if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
|
|
91
93
|
const res = await driver.post('/v1/host/sample/fs/read', { path: '/etc/passwd' });
|
|
92
94
|
// 404 from a host that hasn't wired the test seam is a soft-skip.
|
|
93
|
-
if (res.status === 404) return;
|
|
95
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (404 from a host that hasn\'t wired the test seam is a soft-skip.) (seam, prior step, or fixture unavailable)');
|
|
94
96
|
expect(
|
|
95
97
|
res.status,
|
|
96
|
-
|
|
98
|
+
req('openwop.it.fs-path-traversal.absolute-path-outside-sandbox-is-rejected',
|
|
97
99
|
'SECURITY/invariants.yaml fs-path-traversal',
|
|
98
100
|
'absolute paths outside sandboxRoot MUST be rejected with a 4xx envelope',
|
|
99
101
|
),
|
|
@@ -101,7 +103,7 @@ describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () =>
|
|
|
101
103
|
const code = readErrorCode(res.json);
|
|
102
104
|
expect(
|
|
103
105
|
code !== undefined && PATH_REJECTION_CODES.has(code),
|
|
104
|
-
|
|
106
|
+
req('openwop.it.fs-path-traversal.absolute-path-outside-sandbox-is-rejected',
|
|
105
107
|
'SECURITY/invariants.yaml fs-path-traversal',
|
|
106
108
|
`error.code MUST be one of {${[...PATH_REJECTION_CODES].join(', ')}}, got: ${code ?? '(absent)'}`,
|
|
107
109
|
),
|
|
@@ -110,14 +112,14 @@ describe('fs-path-traversal: MUST-NOT escape sandboxRoot (RFC 0014 §C)', () =>
|
|
|
110
112
|
|
|
111
113
|
it('relative ../ path escape is rejected', async () => {
|
|
112
114
|
const fs = await readFs();
|
|
113
|
-
if (!fs?.supported) return;
|
|
115
|
+
if (!fs?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!fs?.supported` returned early');
|
|
114
116
|
const res = await driver.post('/v1/host/sample/fs/read', { path: '../../etc/passwd' });
|
|
115
|
-
if (res.status === 404) return;
|
|
117
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
116
118
|
expect(res.status).toBeGreaterThanOrEqual(400);
|
|
117
119
|
const code = readErrorCode(res.json);
|
|
118
120
|
expect(
|
|
119
121
|
code !== undefined && PATH_REJECTION_CODES.has(code),
|
|
120
|
-
|
|
122
|
+
req('openwop.it.fs-path-traversal.relative-path-escape-is-rejected',
|
|
121
123
|
'SECURITY/invariants.yaml fs-path-traversal',
|
|
122
124
|
`error.code MUST be one of {${[...PATH_REJECTION_CODES].join(', ')}}, got: ${code ?? '(absent)'}`,
|
|
123
125
|
),
|