@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
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
import { describe, it, expect } from 'vitest';
|
|
33
33
|
import { driver } from '../lib/driver.js';
|
|
34
34
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
35
37
|
|
|
36
38
|
interface PromptPrefixCacheCap {
|
|
37
39
|
supported?: unknown;
|
|
@@ -76,10 +78,10 @@ async function generate(args: {
|
|
|
76
78
|
describe('prompt-prefix-cache: advertisement shape (RFC 0116)', () => {
|
|
77
79
|
it('aiProviders.promptPrefixCache is either absent or a well-formed object', async () => {
|
|
78
80
|
const cap = await readCap();
|
|
79
|
-
if (cap === null) return; // not advertised — skip
|
|
81
|
+
if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early (not advertised — skip)'); // not advertised — skip
|
|
80
82
|
expect(
|
|
81
83
|
typeof cap.supported,
|
|
82
|
-
|
|
84
|
+
req('openwop.it.prompt-prefix-cache.aiproviders-promptprefixcache-is-either-absent-or-a-well-formed-object',
|
|
83
85
|
'capabilities.schema.json §aiProviders.promptPrefixCache',
|
|
84
86
|
'promptPrefixCache.supported MUST be a boolean when the block is present',
|
|
85
87
|
),
|
|
@@ -87,7 +89,7 @@ describe('prompt-prefix-cache: advertisement shape (RFC 0116)', () => {
|
|
|
87
89
|
if (cap.providers !== undefined) {
|
|
88
90
|
expect(
|
|
89
91
|
Array.isArray(cap.providers),
|
|
90
|
-
|
|
92
|
+
req('openwop.it.prompt-prefix-cache.aiproviders-promptprefixcache-is-either-absent-or-a-well-formed-object',
|
|
91
93
|
'capabilities.schema.json §aiProviders.promptPrefixCache',
|
|
92
94
|
'promptPrefixCache.providers MUST be an array of provider ids when present (provider-scoped)',
|
|
93
95
|
),
|
|
@@ -99,19 +101,19 @@ describe('prompt-prefix-cache: advertisement shape (RFC 0116)', () => {
|
|
|
99
101
|
describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")', () => {
|
|
100
102
|
it('(a) outcome-invariance — cachePrefixId vs control → same envelope + identical input/output tokens', async () => {
|
|
101
103
|
const cap = await readCap();
|
|
102
|
-
if (!cap || cap.supported !== true) return; // not advertised — skip
|
|
104
|
+
if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early (not advertised — skip)'); // not advertised — skip
|
|
103
105
|
const prefixId = `inv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
104
106
|
|
|
105
107
|
const control = await generate({ tenantId: 'tenant-a' });
|
|
106
|
-
if (control.status === 404 || control.status === 405) return; // seam not wired
|
|
107
|
-
expect(control.status,
|
|
108
|
+
if (control.status === 404 || control.status === 405) return softSkip('blocked', 'precondition not met — `control.status === 404 || control.status === 405` returned early (seam not wired) (seam, prior step, or fixture unavailable)'); // seam not wired
|
|
109
|
+
expect(control.status, req('openwop.it.prompt-prefix-cache.a-outcome-invariance-cacheprefixid-vs-control-same-envelope-identical-input-outp', 'host-sample-test-seams.md §16', 'generate seam MUST return 200')).toBe(200);
|
|
108
110
|
|
|
109
111
|
const withPrefix = await generate({ tenantId: 'tenant-a', cachePrefixId: prefixId });
|
|
110
112
|
expect(withPrefix.status).toBe(200);
|
|
111
113
|
|
|
112
114
|
expect(
|
|
113
115
|
withPrefix.body.envelope?.envelopeType,
|
|
114
|
-
|
|
116
|
+
req('openwop.it.prompt-prefix-cache.a-outcome-invariance-cacheprefixid-vs-control-same-envelope-identical-input-outp',
|
|
115
117
|
'ai-envelope.md §"Prompt-prefix cache (RFC 0116)" rule 3',
|
|
116
118
|
'cachePrefixId is a cost hint, never semantic: the accepted envelope MUST be identical hit-vs-miss',
|
|
117
119
|
),
|
|
@@ -119,7 +121,7 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
119
121
|
expect(withPrefix.body.usage?.inputTokens).toBe(control.body.usage?.inputTokens);
|
|
120
122
|
expect(
|
|
121
123
|
withPrefix.body.usage?.outputTokens,
|
|
122
|
-
|
|
124
|
+
req('openwop.it.prompt-prefix-cache.a-outcome-invariance-cacheprefixid-vs-control-same-envelope-identical-input-outp',
|
|
123
125
|
'ai-envelope.md §"Prompt-prefix cache (RFC 0116)" rule 3',
|
|
124
126
|
'provider.usage.inputTokens/outputTokens MUST be identical hit-vs-miss (replay-invariant)',
|
|
125
127
|
),
|
|
@@ -128,18 +130,18 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
128
130
|
|
|
129
131
|
it('(b) cache hit observable — a repeat generate shows cacheReadTokens > 0 while tokens stay invariant', async () => {
|
|
130
132
|
const cap = await readCap();
|
|
131
|
-
if (!cap || cap.supported !== true) return; // not advertised — skip
|
|
133
|
+
if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early (not advertised — skip)'); // not advertised — skip
|
|
132
134
|
const prefixId = `hit-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
133
135
|
|
|
134
136
|
const prime = await generate({ tenantId: 'tenant-a', cachePrefixId: prefixId });
|
|
135
|
-
if (prime.status === 404 || prime.status === 405) return; // seam not wired
|
|
137
|
+
if (prime.status === 404 || prime.status === 405) return softSkip('blocked', 'precondition not met — `prime.status === 404 || prime.status === 405` returned early (seam not wired) (seam, prior step, or fixture unavailable)'); // seam not wired
|
|
136
138
|
expect(prime.status).toBe(200);
|
|
137
139
|
|
|
138
140
|
const repeat = await generate({ tenantId: 'tenant-a', cachePrefixId: prefixId });
|
|
139
141
|
expect(repeat.status).toBe(200);
|
|
140
142
|
expect(
|
|
141
143
|
repeat.body.usage?.cacheReadTokens ?? 0,
|
|
142
|
-
|
|
144
|
+
req('openwop.it.prompt-prefix-cache.b-cache-hit-observable-a-repeat-generate-shows-cachereadtokens-0-while-tokens-st',
|
|
143
145
|
'ai-envelope.md §"Prompt-prefix cache (RFC 0116)" rule 4',
|
|
144
146
|
'a repeat generate with the same cachePrefixId for the SAME tenant MUST be an observable cache hit (cacheReadTokens > 0)',
|
|
145
147
|
),
|
|
@@ -151,12 +153,12 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
151
153
|
|
|
152
154
|
it('(c) cross-tenant isolation — tenant B first use of tenant A\'s cachePrefixId → cacheReadTokens == 0', async () => {
|
|
153
155
|
const cap = await readCap();
|
|
154
|
-
if (!cap || cap.supported !== true) return; // not advertised — skip
|
|
156
|
+
if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early (not advertised — skip)'); // not advertised — skip
|
|
155
157
|
const prefixId = `xtenant-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
156
158
|
|
|
157
159
|
// Tenant A primes the cache under a shared, predictable cachePrefixId.
|
|
158
160
|
const aPrime = await generate({ tenantId: 'tenant-a', cachePrefixId: prefixId });
|
|
159
|
-
if (aPrime.status === 404 || aPrime.status === 405) return; // seam not wired
|
|
161
|
+
if (aPrime.status === 404 || aPrime.status === 405) return softSkip('blocked', 'precondition not met — `aPrime.status === 404 || aPrime.status === 405` returned early (seam not wired) (seam, prior step, or fixture unavailable)'); // seam not wired
|
|
160
162
|
expect(aPrime.status).toBe(200);
|
|
161
163
|
|
|
162
164
|
// Tenant B's FIRST use of the SAME cachePrefixId MUST be a miss — the host
|
|
@@ -165,7 +167,7 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
165
167
|
expect(bFirst.status).toBe(200);
|
|
166
168
|
expect(
|
|
167
169
|
bFirst.body.usage?.cacheReadTokens ?? 0,
|
|
168
|
-
|
|
170
|
+
req('openwop.it.prompt-prefix-cache.c-cross-tenant-isolation-tenant-b-first-use-of-tenant-a-s-cacheprefixid-cacherea',
|
|
169
171
|
'SECURITY/invariants.yaml prompt-prefix-cache-cross-tenant-isolation',
|
|
170
172
|
'tenant B\'s first use of tenant A\'s cachePrefixId MUST be a cache MISS (cacheReadTokens == 0) — the cache MUST be keyed by (tenant, cachePrefixId), never global; cross-tenant sharing is context leakage',
|
|
171
173
|
),
|
|
@@ -174,11 +176,11 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
174
176
|
|
|
175
177
|
it('(d) secret-free — the response never echoes cachePrefixId in a SR-1-sensitive position', async () => {
|
|
176
178
|
const cap = await readCap();
|
|
177
|
-
if (!cap || cap.supported !== true) return; // not advertised — skip
|
|
179
|
+
if (!cap || cap.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!cap || cap.supported !== true` returned early (not advertised — skip)'); // not advertised — skip
|
|
178
180
|
const prefixId = `secretfree-${Date.now()}`;
|
|
179
181
|
|
|
180
182
|
const res = await generate({ tenantId: 'tenant-a', cachePrefixId: prefixId });
|
|
181
|
-
if (res.status === 404 || res.status === 405) return; // seam not wired
|
|
183
|
+
if (res.status === 404 || res.status === 405) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 405` returned early (seam not wired) (seam, prior step, or fixture unavailable)'); // seam not wired
|
|
182
184
|
expect(res.status).toBe(200);
|
|
183
185
|
// The usage block is cost-only; it MUST NOT carry prompt/response substrings
|
|
184
186
|
// (SR-1). cachePrefixId is a public cache key, but the cost witness fields
|
|
@@ -189,7 +191,7 @@ describe('prompt-prefix-cache: behavioral (RFC 0116 §"Normative requirements")'
|
|
|
189
191
|
if (v !== undefined) {
|
|
190
192
|
expect(
|
|
191
193
|
typeof v,
|
|
192
|
-
|
|
194
|
+
req('openwop.it.prompt-prefix-cache.d-secret-free-the-response-never-echoes-cacheprefixid-in-a-sr-1-sensitive-positi',
|
|
193
195
|
'run-event-payloads.schema.json §providerUsage',
|
|
194
196
|
`provider.usage.${k} MUST be a cost-only integer (no prompt substrings per SR-1)`,
|
|
195
197
|
),
|
|
@@ -68,6 +68,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
68
68
|
import { randomUUID } from 'node:crypto';
|
|
69
69
|
import { driver } from '../lib/driver.js';
|
|
70
70
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
71
|
+
import { req } from '../lib/requirement-ids.js';
|
|
72
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
71
73
|
|
|
72
74
|
const HTTP_SKIP = !process.env.OPENWOP_BASE_URL;
|
|
73
75
|
|
|
@@ -100,12 +102,12 @@ describe.skipIf(HTTP_SKIP)(
|
|
|
100
102
|
const d = await readDiscovery();
|
|
101
103
|
if (d === null) {
|
|
102
104
|
ctx.skip();
|
|
103
|
-
return;
|
|
105
|
+
return softSkip('blocked', 'precondition not met — `d === null` returned early (seam, prior step, or fixture unavailable)');
|
|
104
106
|
}
|
|
105
107
|
const promptsSupported = capabilityFamily(d, 'prompts')?.supported;
|
|
106
108
|
if (promptsSupported !== true) {
|
|
107
109
|
ctx.skip();
|
|
108
|
-
return;
|
|
110
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `promptsSupported !== true` returned early');
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
const nonMemberWorkspaceId =
|
|
@@ -125,18 +127,18 @@ describe.skipIf(HTTP_SKIP)(
|
|
|
125
127
|
const body = res.json as { error?: unknown } | null;
|
|
126
128
|
expect(
|
|
127
129
|
body?.error,
|
|
128
|
-
|
|
130
|
+
req('openwop.it.prompt-read-workspace-membership-enforced.get-v1-prompts-workspaceid-non-member-must-refuse-or-return-empty-templates-neve',
|
|
129
131
|
'spec/v1/rest-endpoints.md §Common error codes — workspace_membership_required',
|
|
130
132
|
`403 refusal of a workspace-scoped read MUST carry error: "workspace_membership_required"; got error: ${JSON.stringify(body?.error)}`,
|
|
131
133
|
),
|
|
132
134
|
).toBe('workspace_membership_required');
|
|
133
135
|
}
|
|
134
|
-
return;
|
|
136
|
+
return softSkip('blocked', 'precondition not met — `res.status >= 400 && res.status < 500` returned early (4xx — refused. Acceptable shape for the membership-required failure (and any other refusal mode the host chooses: 401, 404 for existence-d…');
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
// 5xx — refused (infrastructure failure is acceptable; envelope shape
|
|
138
140
|
// unconstrained).
|
|
139
|
-
if (res.status >= 500) return;
|
|
141
|
+
if (res.status >= 500) return softSkip('blocked', 'precondition not met — `res.status >= 500` returned early (5xx — refused (infrastructure failure is acceptable; envelope shape unconstrained).) (seam, prior step, or fixture unavailable)');
|
|
140
142
|
|
|
141
143
|
// 2xx — must inspect the response body. The failure mode this
|
|
142
144
|
// invariant guards against is a 200 response that LEAKS templates
|
|
@@ -154,13 +156,13 @@ describe.skipIf(HTTP_SKIP)(
|
|
|
154
156
|
// workspace-scoped reads, and a host without that surface is
|
|
155
157
|
// simply out of scope.
|
|
156
158
|
ctx.skip();
|
|
157
|
-
return;
|
|
159
|
+
return softSkip('blocked', 'precondition not met — `body === null || typeof body !== \'object\' || !(\'templates\' in body)` returned early (seam, prior step, or fixture unavailable)');
|
|
158
160
|
}
|
|
159
161
|
const templates = body.templates;
|
|
160
162
|
if (!Array.isArray(templates)) {
|
|
161
163
|
// Same: unrecognized shape, skip.
|
|
162
164
|
ctx.skip();
|
|
163
|
-
return;
|
|
165
|
+
return softSkip('blocked', 'precondition not met — `!Array.isArray(templates)` returned early (seam, prior step, or fixture unavailable)');
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
// A random non-member workspaceId can never legitimately contain
|
|
@@ -168,12 +170,12 @@ describe.skipIf(HTTP_SKIP)(
|
|
|
168
170
|
// is a cross-tenant data leak.
|
|
169
171
|
expect(
|
|
170
172
|
templates.length,
|
|
171
|
-
|
|
173
|
+
req('openwop.it.prompt-read-workspace-membership-enforced.get-v1-prompts-workspaceid-non-member-must-refuse-or-return-empty-templates-neve',
|
|
172
174
|
'spec/v1/prompts.md §Workspace membership on workspace-scoped reads and writes',
|
|
173
175
|
`GET /v1/prompts?workspaceId=<random-non-member> MUST NOT return any templates; got ${templates.length} templates which is a cross-tenant data leak (the random workspaceId is freshly generated per probe and cannot legitimately contain authorized content)`,
|
|
174
176
|
),
|
|
175
177
|
).toBe(0);
|
|
176
|
-
return;
|
|
178
|
+
return softSkip('blocked', 'precondition not met — `res.status >= 200 && res.status < 300` returned early (2xx — must inspect the response body. The failure mode this invariant guards against is a 200 response that LEAKS templates from a workspa…');
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
// Other status codes (1xx, 3xx) — soft-skip with note. Not a clear
|
|
@@ -24,6 +24,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
24
24
|
import { driver } from '../lib/driver.js';
|
|
25
25
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
26
26
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
27
|
+
import { req } from '../lib/requirement-ids.js';
|
|
28
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
27
29
|
|
|
28
30
|
interface DiscoveryDoc {
|
|
29
31
|
capabilities?: {
|
|
@@ -91,7 +93,7 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
91
93
|
if (!behaviorGate('prompts-endpoints', endpointsSupported(d))) return;
|
|
92
94
|
|
|
93
95
|
const template = await pickTemplateWithInputVar();
|
|
94
|
-
if (!template) return;
|
|
96
|
+
if (!template) return softSkip('blocked', 'precondition not met — `!template` returned early (seam, prior step, or fixture unavailable)');
|
|
95
97
|
|
|
96
98
|
const variableNames = (template.variables ?? [])
|
|
97
99
|
.filter((v) => v.source !== 'secret')
|
|
@@ -103,7 +105,7 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
103
105
|
|
|
104
106
|
const ref = `prompt:${template.templateId}@${template.version}`;
|
|
105
107
|
const first = await driver.post('/v1/prompts:render', { ref, variables });
|
|
106
|
-
if (first.status !== 200) return;
|
|
108
|
+
if (first.status !== 200) return softSkip('blocked', 'precondition not met — `first.status !== 200` returned early (seam, prior step, or fixture unavailable)');
|
|
107
109
|
const second = await driver.post('/v1/prompts:render', { ref, variables });
|
|
108
110
|
expect(second.status).toBe(200);
|
|
109
111
|
|
|
@@ -112,14 +114,14 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
112
114
|
|
|
113
115
|
expect(
|
|
114
116
|
a.hash,
|
|
115
|
-
|
|
117
|
+
req('openwop.it.prompt-render-deterministic.identical-ref-variables-inputs-produce-identical-hash-variablehashes',
|
|
116
118
|
'spec/v1/prompts.md §Discovery & distribution',
|
|
117
119
|
'render hash MUST be stable across identical (ref, variables) inputs',
|
|
118
120
|
),
|
|
119
121
|
).toBe(b.hash);
|
|
120
122
|
expect(
|
|
121
123
|
Object.keys(a.variableHashes).sort(),
|
|
122
|
-
|
|
124
|
+
req('openwop.it.prompt-render-deterministic.identical-ref-variables-inputs-produce-identical-hash-variablehashes',
|
|
123
125
|
'spec/v1/prompts.md §Discovery & distribution',
|
|
124
126
|
'variableHashes key set MUST be stable',
|
|
125
127
|
),
|
|
@@ -134,11 +136,11 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
134
136
|
if (!behaviorGate('prompts-endpoints', endpointsSupported(d))) return;
|
|
135
137
|
|
|
136
138
|
const template = await pickTemplateWithInputVar();
|
|
137
|
-
if (!template) return;
|
|
139
|
+
if (!template) return softSkip('blocked', 'precondition not met — `!template` returned early (seam, prior step, or fixture unavailable)');
|
|
138
140
|
const requiredVars = (template.variables ?? []).filter(
|
|
139
141
|
(v) => v.source !== 'secret' && v.required === true,
|
|
140
142
|
);
|
|
141
|
-
if (requiredVars.length === 0) return; // no required var to toggle
|
|
143
|
+
if (requiredVars.length === 0) return softSkip('blocked', 'precondition not met — `requiredVars.length === 0` returned early (no required var to toggle) (seam, prior step, or fixture unavailable)'); // no required var to toggle
|
|
142
144
|
|
|
143
145
|
const variables: Record<string, unknown> = {};
|
|
144
146
|
for (const v of template.variables ?? []) {
|
|
@@ -148,7 +150,7 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
148
150
|
|
|
149
151
|
const ref = `prompt:${template.templateId}@${template.version}`;
|
|
150
152
|
const baseline = await driver.post('/v1/prompts:render', { ref, variables });
|
|
151
|
-
if (baseline.status !== 200) return;
|
|
153
|
+
if (baseline.status !== 200) return softSkip('blocked', 'precondition not met — `baseline.status !== 200` returned early (seam, prior step, or fixture unavailable)');
|
|
152
154
|
|
|
153
155
|
// Toggle one required variable.
|
|
154
156
|
const toggled = { ...variables, [requiredVars[0]!.name]: 'conformance-toggled-value' };
|
|
@@ -160,14 +162,14 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
160
162
|
|
|
161
163
|
expect(
|
|
162
164
|
a.hash,
|
|
163
|
-
|
|
165
|
+
req('openwop.it.prompt-render-deterministic.different-variable-values-produce-different-hash-at-least-one-different-variable',
|
|
164
166
|
'spec/v1/prompts.md §Discovery & distribution',
|
|
165
167
|
'render hash MUST differ when any variable binding differs',
|
|
166
168
|
),
|
|
167
169
|
).not.toBe(b.hash);
|
|
168
170
|
expect(
|
|
169
171
|
a.variableHashes[requiredVars[0]!.name],
|
|
170
|
-
|
|
172
|
+
req('openwop.it.prompt-render-deterministic.different-variable-values-produce-different-hash-at-least-one-different-variable',
|
|
171
173
|
'spec/v1/prompts.md §Discovery & distribution',
|
|
172
174
|
'variableHashes[name] MUST differ when name binding differs',
|
|
173
175
|
),
|
|
@@ -179,7 +181,7 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
179
181
|
if (!behaviorGate('prompts-endpoints', endpointsSupported(d))) return;
|
|
180
182
|
|
|
181
183
|
const template = await pickTemplateWithInputVar();
|
|
182
|
-
if (!template) return;
|
|
184
|
+
if (!template) return softSkip('blocked', 'precondition not met — `!template` returned early (seam, prior step, or fixture unavailable)');
|
|
183
185
|
const variables: Record<string, unknown> = {};
|
|
184
186
|
for (const v of template.variables ?? []) {
|
|
185
187
|
if (v.source === 'secret') continue;
|
|
@@ -187,12 +189,12 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
187
189
|
}
|
|
188
190
|
const ref = `prompt:${template.templateId}@${template.version}`;
|
|
189
191
|
const res = await driver.post('/v1/prompts:render', { ref, variables });
|
|
190
|
-
if (res.status !== 200) return;
|
|
192
|
+
if (res.status !== 200) return softSkip('blocked', 'precondition not met — `res.status !== 200` returned early (seam, prior step, or fixture unavailable)');
|
|
191
193
|
const r = res.json as RenderResponse;
|
|
192
194
|
|
|
193
195
|
expect(
|
|
194
196
|
/^sha256:[0-9a-f]{64}$/.test(r.hash),
|
|
195
|
-
|
|
197
|
+
req('openwop.it.prompt-render-deterministic.hash-variablehashes-must-match-sha256-hex64-pattern',
|
|
196
198
|
'schemas/run-event-payloads.schema.json §promptComposed.hash',
|
|
197
199
|
'hash MUST match `^sha256:[0-9a-f]{64}$`',
|
|
198
200
|
),
|
|
@@ -200,7 +202,7 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
200
202
|
for (const [name, h] of Object.entries(r.variableHashes)) {
|
|
201
203
|
expect(
|
|
202
204
|
/^sha256:[0-9a-f]{64}$/.test(h),
|
|
203
|
-
`variableHashes[${name}] MUST match sha256:<hex64>; got ${h}
|
|
205
|
+
req('openwop.it.prompt-render-deterministic.hash-variablehashes-must-match-sha256-hex64-pattern', 'schemas/run-event-payloads.schema.json §promptComposed.hash', `variableHashes[${name}] MUST match sha256:<hex64>; got ${h}`),
|
|
204
206
|
).toBe(true);
|
|
205
207
|
}
|
|
206
208
|
});
|
|
@@ -214,12 +216,12 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
214
216
|
const d = await readDiscovery();
|
|
215
217
|
if (!behaviorGate('prompts-endpoints', endpointsSupported(d))) return;
|
|
216
218
|
const list = await driver.get('/v1/prompts?source=host&limit=200');
|
|
217
|
-
if (list.status !== 200) return;
|
|
219
|
+
if (list.status !== 200) return softSkip('blocked', 'precondition not met — `list.status !== 200` returned early (seam, prior step, or fixture unavailable)');
|
|
218
220
|
const body = list.json as ListResponse;
|
|
219
221
|
const nonSystemUser = body.items.find(
|
|
220
222
|
(t) => t.kind === 'few-shot' || t.kind === 'schema-hint',
|
|
221
223
|
);
|
|
222
|
-
if (!nonSystemUser) return; // host doesn't ship one — soft-skip
|
|
224
|
+
if (!nonSystemUser) return softSkip('blocked', 'precondition not met — `!nonSystemUser` returned early (host doesn\'t ship one — soft-skip) (seam, prior step, or fixture unavailable)'); // host doesn't ship one — soft-skip
|
|
223
225
|
|
|
224
226
|
const variables: Record<string, unknown> = {};
|
|
225
227
|
for (const v of nonSystemUser.variables ?? []) {
|
|
@@ -228,11 +230,11 @@ describe.skipIf(HTTP_SKIP)('prompt-render-deterministic: hash stable across iden
|
|
|
228
230
|
}
|
|
229
231
|
const ref = `prompt:${nonSystemUser.templateId}@${nonSystemUser.version}`;
|
|
230
232
|
const res = await driver.post('/v1/prompts:render', { ref, variables });
|
|
231
|
-
if (res.status !== 200) return;
|
|
233
|
+
if (res.status !== 200) return softSkip('blocked', 'precondition not met — `res.status !== 200` returned early (seam, prior step, or fixture unavailable)');
|
|
232
234
|
const r = res.json as RenderResponse;
|
|
233
235
|
expect(
|
|
234
236
|
typeof r.composed === 'string' && r.composed.length > 0,
|
|
235
|
-
|
|
237
|
+
req('openwop.it.prompt-render-deterministic.renders-few-shot-schema-hint-kinds-with-non-empty-composed-body',
|
|
236
238
|
'spec/v1/prompts.md §Discovery & distribution',
|
|
237
239
|
'`composed` body MUST populate for every PromptKind under observability: full',
|
|
238
240
|
),
|
|
@@ -31,6 +31,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
31
31
|
import { driver } from '../lib/driver.js';
|
|
32
32
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
33
33
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
34
|
+
import { req } from '../lib/requirement-ids.js';
|
|
35
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
34
36
|
|
|
35
37
|
interface DiscoveryDoc {
|
|
36
38
|
capabilities?: {
|
|
@@ -101,7 +103,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-agent-intrinsic: layer-2 age
|
|
|
101
103
|
system: 'prompt:host-default@1.0.0',
|
|
102
104
|
},
|
|
103
105
|
});
|
|
104
|
-
if (res.status === 404) return;
|
|
106
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
105
107
|
expect(res.status).toBe(200);
|
|
106
108
|
|
|
107
109
|
const payload = res.json as AgentPromptResolvedPayload;
|
|
@@ -109,14 +111,14 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-agent-intrinsic: layer-2 age
|
|
|
109
111
|
const appliedEntries = payload.chain.filter((c) => c.applied);
|
|
110
112
|
expect(
|
|
111
113
|
appliedEntries.length,
|
|
112
|
-
|
|
114
|
+
req('openwop.it.prompt-resolution-chain-agent-intrinsic.agent-intrinsic-systempromptref-wins-over-workflow-defaults-host-defaults-when-n',
|
|
113
115
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
114
116
|
'exactly one chain entry MUST carry applied: true',
|
|
115
117
|
),
|
|
116
118
|
).toBe(1);
|
|
117
119
|
expect(
|
|
118
120
|
appliedEntries[0]?.layer,
|
|
119
|
-
|
|
121
|
+
req('openwop.it.prompt-resolution-chain-agent-intrinsic.agent-intrinsic-systempromptref-wins-over-workflow-defaults-host-defaults-when-n',
|
|
120
122
|
'spec/v1/prompts.md §Resolution chain (normative) — Layer 2',
|
|
121
123
|
'system-kind resolution MUST prefer agent intrinsic (systemPromptRef) over agent-overrides when both are set',
|
|
122
124
|
),
|
|
@@ -124,7 +126,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-agent-intrinsic: layer-2 age
|
|
|
124
126
|
|
|
125
127
|
expect(
|
|
126
128
|
payload.resolved,
|
|
127
|
-
|
|
129
|
+
req('openwop.it.prompt-resolution-chain-agent-intrinsic.agent-intrinsic-systempromptref-wins-over-workflow-defaults-host-defaults-when-n',
|
|
128
130
|
'spec/v1/prompts.md §Resolution chain (normative) — Layer 2',
|
|
129
131
|
'resolved MUST mirror the winning chain entry source',
|
|
130
132
|
),
|
|
@@ -132,7 +134,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-agent-intrinsic: layer-2 age
|
|
|
132
134
|
|
|
133
135
|
expect(
|
|
134
136
|
payload.agentId,
|
|
135
|
-
|
|
137
|
+
req('openwop.it.prompt-resolution-chain-agent-intrinsic.agent-intrinsic-systempromptref-wins-over-workflow-defaults-host-defaults-when-n',
|
|
136
138
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
137
139
|
'agent.promptResolved.agentId MUST be set when config.agentId resolves to a known agent',
|
|
138
140
|
),
|
|
@@ -30,6 +30,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
30
30
|
import { driver } from '../lib/driver.js';
|
|
31
31
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
32
32
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
33
35
|
|
|
34
36
|
const PROMPT_FIXTURE_ID = 'conformance-prompt-end-to-end';
|
|
35
37
|
const VALID_LAYERS = new Set([
|
|
@@ -48,17 +50,17 @@ async function promptsSupported(): Promise<boolean> {
|
|
|
48
50
|
|
|
49
51
|
describe('prompt-resolution-chain-event (black-box): agent.promptResolved carries the precedence record (RFC 0029)', () => {
|
|
50
52
|
it('the production agent.promptResolved event records the full four-layer resolution chain', async () => {
|
|
51
|
-
if (!(await promptsSupported())) return; // capability not advertised — skip
|
|
53
|
+
if (!(await promptsSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await promptsSupported())` returned early (capability not advertised — skip)'); // capability not advertised — skip
|
|
52
54
|
|
|
53
55
|
const create = await driver.post('/v1/runs', { workflowId: PROMPT_FIXTURE_ID });
|
|
54
56
|
if (create.status !== 201) {
|
|
55
57
|
// Fixture not seeded / run not accepted — not a prompt-chain failure.
|
|
56
58
|
// eslint-disable-next-line no-console
|
|
57
59
|
console.warn(`[prompt-resolution-chain-event] POST /v1/runs for ${PROMPT_FIXTURE_ID} returned ${create.status}; skipping the production-path assertion`);
|
|
58
|
-
return;
|
|
60
|
+
return softSkip('blocked', 'precondition not met — `create.status !== 201` returned early ([prompt-resolution-chain-event] POST /v1/runs for … returned …; skipping the production-path assertion) (seam, prior step, or fixture unavailable)');
|
|
59
61
|
}
|
|
60
62
|
const runId = (create.json as { runId?: string }).runId;
|
|
61
|
-
if (!runId) return;
|
|
63
|
+
if (!runId) return softSkip('blocked', 'precondition not met — `!runId` returned early (seam, prior step, or fixture unavailable)');
|
|
62
64
|
await pollUntilTerminal(runId);
|
|
63
65
|
|
|
64
66
|
const poll = await driver.get(`/v1/runs/${encodeURIComponent(runId)}/events/poll`);
|
|
@@ -69,14 +71,14 @@ describe('prompt-resolution-chain-event (black-box): agent.promptResolved carrie
|
|
|
69
71
|
// (RFC 0029 emission is staged) — soft-skip the behavioral assertion.
|
|
70
72
|
// eslint-disable-next-line no-console
|
|
71
73
|
console.warn('[prompt-resolution-chain-event] host emitted no agent.promptResolved event; skipping (RFC 0029 emission staged)');
|
|
72
|
-
return;
|
|
74
|
+
return softSkip('blocked', 'precondition not met — `resolved.length === 0` returned early ([prompt-resolution-chain-event] host emitted no agent.promptResolved event; skipping (RFC 0029 emission staged)) (seam, prior step, or fixture unavailable)');
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
for (const ev of resolved) {
|
|
76
78
|
const chain = ev.payload?.chain;
|
|
77
79
|
expect(
|
|
78
80
|
Array.isArray(chain) && chain.length > 0,
|
|
79
|
-
|
|
81
|
+
req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'prompts.md §Resolution chain', 'agent.promptResolved MUST carry a non-empty chain[] of attempted layers'),
|
|
80
82
|
).toBe(true);
|
|
81
83
|
const entries = chain as ChainEntry[];
|
|
82
84
|
|
|
@@ -84,28 +86,28 @@ describe('prompt-resolution-chain-event (black-box): agent.promptResolved carrie
|
|
|
84
86
|
for (const e of entries) {
|
|
85
87
|
expect(
|
|
86
88
|
typeof e.layer === 'string' && VALID_LAYERS.has(e.layer),
|
|
87
|
-
|
|
89
|
+
req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'prompts.md §Resolution chain', `each chain entry MUST name a valid layer, got ${String(e.layer)}`),
|
|
88
90
|
).toBe(true);
|
|
89
|
-
expect(typeof e.applied,
|
|
91
|
+
expect(typeof e.applied, req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'prompts.md §Resolution chain', 'each chain entry MUST carry a boolean `applied`')).toBe('boolean');
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
// Exactly one layer wins (or none, when resolved is null).
|
|
93
95
|
const applied = entries.filter((e) => e.applied === true);
|
|
94
96
|
expect(
|
|
95
97
|
applied.length <= 1,
|
|
96
|
-
|
|
98
|
+
req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'prompts.md §Resolution chain', 'AT MOST one chain entry MAY be applied: true (the winning layer)'),
|
|
97
99
|
).toBe(true);
|
|
98
100
|
|
|
99
101
|
// resolved mirrors the applied entry's source (RFC 0029 §B).
|
|
100
102
|
if (applied.length === 1) {
|
|
101
103
|
expect(
|
|
102
104
|
ev.payload?.resolved,
|
|
103
|
-
|
|
105
|
+
req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'run-event-payloads.schema.json agentPromptResolved', '`resolved` MUST mirror the applied chain entry\'s `source`'),
|
|
104
106
|
).toBe(applied[0]?.source);
|
|
105
107
|
} else {
|
|
106
108
|
expect(
|
|
107
109
|
ev.payload?.resolved === null || ev.payload?.resolved === undefined,
|
|
108
|
-
|
|
110
|
+
req('openwop.it.prompt-resolution-chain-event.the-production-agent-promptresolved-event-records-the-full-four-layer-resolution', 'run-event-payloads.schema.json agentPromptResolved', 'with no applied layer, `resolved` MUST be null'),
|
|
109
111
|
).toBe(true);
|
|
110
112
|
}
|
|
111
113
|
}
|
|
@@ -32,6 +32,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
32
32
|
import { driver } from '../lib/driver.js';
|
|
33
33
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
34
34
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
35
37
|
|
|
36
38
|
interface DiscoveryDoc {
|
|
37
39
|
capabilities?: {
|
|
@@ -88,7 +90,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
88
90
|
system: 'prompt:host-default@1.0.0',
|
|
89
91
|
},
|
|
90
92
|
});
|
|
91
|
-
if (res.status === 404) return;
|
|
93
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
92
94
|
expect(res.status).toBe(200);
|
|
93
95
|
|
|
94
96
|
const payload = res.json as AgentPromptResolvedPayload;
|
|
@@ -96,7 +98,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
96
98
|
expect(applied?.layer).toBe('workflow-defaults');
|
|
97
99
|
expect(
|
|
98
100
|
payload.resolved,
|
|
99
|
-
|
|
101
|
+
req('openwop.it.prompt-resolution-chain-fallback-cascade.workflow-defaults-win-over-host-defaults-when-both-are-set',
|
|
100
102
|
'spec/v1/prompts.md §Resolution chain (normative) — Layer 3',
|
|
101
103
|
'workflow-defaults MUST win over host-defaults when both are set',
|
|
102
104
|
),
|
|
@@ -115,14 +117,14 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
115
117
|
system: 'prompt:host-default@1.0.0',
|
|
116
118
|
},
|
|
117
119
|
});
|
|
118
|
-
if (res.status === 404) return;
|
|
120
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
119
121
|
expect(res.status).toBe(200);
|
|
120
122
|
|
|
121
123
|
const payload = res.json as AgentPromptResolvedPayload;
|
|
122
124
|
const applied = payload.chain.find((c) => c.applied);
|
|
123
125
|
expect(
|
|
124
126
|
applied?.layer,
|
|
125
|
-
|
|
127
|
+
req('openwop.it.prompt-resolution-chain-fallback-cascade.host-defaults-win-when-workflow-defaults-are-also-absent',
|
|
126
128
|
'spec/v1/prompts.md §Resolution chain (normative) — Layer 4',
|
|
127
129
|
'host-defaults MUST apply when layers 1-3 yield null',
|
|
128
130
|
),
|
|
@@ -139,13 +141,13 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
139
141
|
node: { nodeId: 'writer', config: {} },
|
|
140
142
|
// workflowDefaults + hostDefaults intentionally omitted.
|
|
141
143
|
});
|
|
142
|
-
if (res.status === 404) return;
|
|
144
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (seam, prior step, or fixture unavailable)');
|
|
143
145
|
expect(res.status).toBe(200);
|
|
144
146
|
|
|
145
147
|
const payload = res.json as AgentPromptResolvedPayload;
|
|
146
148
|
expect(
|
|
147
149
|
payload.resolved,
|
|
148
|
-
|
|
150
|
+
req('openwop.it.prompt-resolution-chain-fallback-cascade.resolved-is-null-and-chain-still-lists-every-attempted-layer-when-all-four-yield',
|
|
149
151
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
150
152
|
'resolved MUST be null when all four layers yield null',
|
|
151
153
|
),
|
|
@@ -154,7 +156,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
154
156
|
const appliedEntries = payload.chain.filter((c) => c.applied);
|
|
155
157
|
expect(
|
|
156
158
|
appliedEntries.length,
|
|
157
|
-
|
|
159
|
+
req('openwop.it.prompt-resolution-chain-fallback-cascade.resolved-is-null-and-chain-still-lists-every-attempted-layer-when-all-four-yield',
|
|
158
160
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
159
161
|
'zero applied entries when no layer yielded a candidate',
|
|
160
162
|
),
|
|
@@ -164,7 +166,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-fallback-cascade: layers 3 +
|
|
|
164
166
|
// see why the resolution returned null.
|
|
165
167
|
expect(
|
|
166
168
|
payload.chain.length,
|
|
167
|
-
|
|
169
|
+
req('openwop.it.prompt-resolution-chain-fallback-cascade.resolved-is-null-and-chain-still-lists-every-attempted-layer-when-all-four-yield',
|
|
168
170
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
169
171
|
'chain[] MUST list every layer attempted, even when none applied',
|
|
170
172
|
),
|
|
@@ -30,6 +30,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
30
30
|
import { driver } from '../lib/driver.js';
|
|
31
31
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
32
32
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
33
35
|
|
|
34
36
|
interface DiscoveryDoc {
|
|
35
37
|
capabilities?: {
|
|
@@ -104,14 +106,14 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-node-wins: layer-1 node-conf
|
|
|
104
106
|
system: 'prompt:host-default@1.0.0',
|
|
105
107
|
},
|
|
106
108
|
});
|
|
107
|
-
if (res.status === 404) return; // host doesn't expose the seam
|
|
108
|
-
expect(res.status, 'resolve seam MUST return 200').toBe(200);
|
|
109
|
+
if (res.status === 404) return softSkip('blocked', 'precondition not met — `res.status === 404` returned early (host doesn\'t expose the seam) (seam, prior step, or fixture unavailable)'); // host doesn't expose the seam
|
|
110
|
+
expect(res.status, req('openwop.it.prompt-resolution-chain-node-wins.node-level-systempromptref-wins-over-agent-intrinsic-workflow-defaults-host-defa', 'spec/v1/prompts.md §Resolution chain (normative)', 'resolve seam MUST return 200')).toBe(200);
|
|
109
111
|
|
|
110
112
|
const payload = res.json as AgentPromptResolvedPayload;
|
|
111
113
|
|
|
112
114
|
expect(
|
|
113
115
|
payload.kind,
|
|
114
|
-
|
|
116
|
+
req('openwop.it.prompt-resolution-chain-node-wins.node-level-systempromptref-wins-over-agent-intrinsic-workflow-defaults-host-defa',
|
|
115
117
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
116
118
|
'agent.promptResolved.kind MUST match the requested kind',
|
|
117
119
|
),
|
|
@@ -119,7 +121,7 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-node-wins: layer-1 node-conf
|
|
|
119
121
|
|
|
120
122
|
expect(
|
|
121
123
|
payload.resolved,
|
|
122
|
-
|
|
124
|
+
req('openwop.it.prompt-resolution-chain-node-wins.node-level-systempromptref-wins-over-agent-intrinsic-workflow-defaults-host-defa',
|
|
123
125
|
'spec/v1/prompts.md §Resolution chain (normative) — Layer 1',
|
|
124
126
|
'node-level systemPromptRef MUST win over agent intrinsic + overrides + workflow defaults + host defaults',
|
|
125
127
|
),
|
|
@@ -128,13 +130,13 @@ describe.skipIf(HTTP_SKIP)('prompt-resolution-chain-node-wins: layer-1 node-conf
|
|
|
128
130
|
// chain[] MUST list the layers attempted in precedence order. The
|
|
129
131
|
// node layer (first entry of the resolution chain) MUST carry
|
|
130
132
|
// applied: true; every other layer applied: false.
|
|
131
|
-
expect(Array.isArray(payload.chain), 'agent.promptResolved.chain MUST be an array').toBe(true);
|
|
133
|
+
expect(Array.isArray(payload.chain), req('openwop.it.prompt-resolution-chain-node-wins.node-level-systempromptref-wins-over-agent-intrinsic-workflow-defaults-host-defa', 'spec/v1/prompts.md §Resolution chain (normative) — Layer 1', 'agent.promptResolved.chain MUST be an array')).toBe(true);
|
|
132
134
|
expect(payload.chain.length).toBeGreaterThan(0);
|
|
133
135
|
|
|
134
136
|
const appliedEntries = payload.chain.filter((c) => c.applied);
|
|
135
137
|
expect(
|
|
136
138
|
appliedEntries.length,
|
|
137
|
-
|
|
139
|
+
req('openwop.it.prompt-resolution-chain-node-wins.node-level-systempromptref-wins-over-agent-intrinsic-workflow-defaults-host-defa',
|
|
138
140
|
'spec/v1/prompts.md §Resolution chain (normative)',
|
|
139
141
|
'exactly one chain entry MUST carry applied: true',
|
|
140
142
|
),
|