@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
|
@@ -18,6 +18,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
18
18
|
import { driver } from '../lib/driver.js';
|
|
19
19
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
20
20
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
21
|
+
import { req } from '../lib/requirement-ids.js';
|
|
22
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
21
23
|
|
|
22
24
|
const CANDIDATES = ['conformance-append-ordering', 'conformance-multi-node'] as const;
|
|
23
25
|
const FIXTURE = CANDIDATES.find((id) => isFixtureAdvertised(id)) ?? null;
|
|
@@ -71,13 +73,13 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
|
|
|
71
73
|
console.warn(
|
|
72
74
|
'[append-ordering] fixture emitted no channel.written events; skipping ordering assertions',
|
|
73
75
|
);
|
|
74
|
-
return;
|
|
76
|
+
return softSkip('blocked', 'precondition not met — `byChannel.size === 0` returned early ([append-ordering] fixture emitted no channel.written events; skipping ordering assertions) (seam, prior step, or fixture unavailable)');
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
// For each channel, sequence MUST be strictly increasing within the run.
|
|
78
80
|
for (const [channel, writes] of byChannel) {
|
|
79
81
|
for (let i = 1; i < writes.length; i++) {
|
|
80
|
-
expect(writes[i].sequence,
|
|
82
|
+
expect(writes[i].sequence, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
|
|
81
83
|
'channels-and-reducers.md §"Append ordering"',
|
|
82
84
|
`channel '${channel}': channel.written events MUST appear in sequence order in the event log`,
|
|
83
85
|
)).toBeGreaterThan(writes[i - 1].sequence);
|
|
@@ -101,7 +103,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
|
|
|
101
103
|
// Property: every cross-engine event carries BOTH sourceEngineId
|
|
102
104
|
// AND sourceRunId (per channel-written-payload.schema.json).
|
|
103
105
|
for (const e of crossEngineWrites) {
|
|
104
|
-
expect(typeof e.payload?.sourceRunId,
|
|
106
|
+
expect(typeof e.payload?.sourceRunId, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
|
|
105
107
|
'channel-written-payload.schema.json',
|
|
106
108
|
'cross-engine writes MUST carry sourceRunId alongside sourceEngineId',
|
|
107
109
|
)).toBe('string');
|
|
@@ -110,7 +112,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
|
|
|
110
112
|
const seen = new Set<string>();
|
|
111
113
|
for (const e of allWrites) {
|
|
112
114
|
const key = `${e.sequence}::${e.eventId ?? ''}`;
|
|
113
|
-
expect(seen.has(key),
|
|
115
|
+
expect(seen.has(key), req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
|
|
114
116
|
'channels-and-reducers.md §"Tie-breaking when sequences collide"',
|
|
115
117
|
`(sequence, eventId) MUST be unique across the run — duplicate found: ${key}`,
|
|
116
118
|
)).toBe(false);
|
|
@@ -125,7 +127,7 @@ describe.skipIf(SKIP)('append-ordering: folded channel reflects event sequence',
|
|
|
125
127
|
for (const [channel, writes] of byChannel) {
|
|
126
128
|
const projected = (channels as Record<string, unknown>)[channel];
|
|
127
129
|
if (Array.isArray(projected)) {
|
|
128
|
-
expect(projected.length,
|
|
130
|
+
expect(projected.length, req('openwop.it.append-ordering.append-reducer-channels-project-entries-in-event-sequence-order',
|
|
129
131
|
'channels-and-reducers.md §"Append ordering"',
|
|
130
132
|
`channel '${channel}': projected array length MUST equal #channel.written events`,
|
|
131
133
|
)).toBe(writes.length);
|
|
@@ -22,6 +22,7 @@ import { readFileSync } from 'node:fs';
|
|
|
22
22
|
import { join } from 'node:path';
|
|
23
23
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
24
24
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
26
|
|
|
26
27
|
interface PayloadsSchema {
|
|
27
28
|
$schema: string;
|
|
@@ -41,7 +42,7 @@ describe('category: approval-gate governance events (RFC 0051 §B)', () => {
|
|
|
41
42
|
it('approval.granted requires gateId + principal; quorumProgress optional', () => {
|
|
42
43
|
const v = compile('approvalGranted');
|
|
43
44
|
expect(v({ gateId: 'g1', principal: 'user_1' }), JSON.stringify(v.errors)).toBe(true);
|
|
44
|
-
expect(v({ gateId: 'g1', principal: 'user_1', quorumProgress: { granted: 1, required: 2 } })).toBe(true);
|
|
45
|
+
expect(v({ gateId: 'g1', principal: 'user_1', quorumProgress: { granted: 1, required: 2 } }), req('openwop.it.approval-gate-events.approval-granted-requires-gateid-principal-quorumprogress-optional', 'RFC 0051 §B', 'approval.granted requires gateId + principal; quorumProgress optional')).toBe(true);
|
|
45
46
|
expect(v({ gateId: 'g1' })).toBe(false); // missing principal
|
|
46
47
|
expect(v({ gateId: 'g1', principal: 'user_1', role: 'admin' })).toBe(false); // unknown prop
|
|
47
48
|
});
|
|
@@ -49,13 +50,13 @@ describe('category: approval-gate governance events (RFC 0051 §B)', () => {
|
|
|
49
50
|
it('approval.rejected requires gateId + principal; reason optional', () => {
|
|
50
51
|
const v = compile('approvalRejected');
|
|
51
52
|
expect(v({ gateId: 'g1', principal: 'user_1' }), JSON.stringify(v.errors)).toBe(true);
|
|
52
|
-
expect(v({ gateId: 'g1', principal: 'user_1', reason: 'incomplete' })).toBe(true);
|
|
53
|
+
expect(v({ gateId: 'g1', principal: 'user_1', reason: 'incomplete' }), req('openwop.it.approval-gate-events.approval-rejected-requires-gateid-principal-reason-optional', 'RFC 0051 §B', 'approval.rejected requires gateId + principal; reason optional')).toBe(true);
|
|
53
54
|
expect(v({ principal: 'user_1' })).toBe(false); // missing gateId
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
it('approval.overridden requires gateId + principal + reason (audit breadcrumb)', () => {
|
|
57
58
|
const v = compile('approvalOverridden');
|
|
58
59
|
expect(v({ gateId: 'g1', principal: 'owner_1', reason: 'emergency publish' }), JSON.stringify(v.errors)).toBe(true);
|
|
59
|
-
expect(v({ gateId: 'g1', principal: 'owner_1' })).toBe(false); // reason MUST be present
|
|
60
|
+
expect(v({ gateId: 'g1', principal: 'owner_1' }), req('openwop.it.approval-gate-events.approval-overridden-requires-gateid-principal-reason-audit-breadcrumb', 'RFC 0051 §B', 'approval.overridden requires gateId + principal + reason (audit breadcrumb)')).toBe(false); // reason MUST be present
|
|
60
61
|
});
|
|
61
62
|
});
|
|
@@ -24,6 +24,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
24
24
|
import { softSkip } from '../lib/soft-skip.js';
|
|
25
25
|
import { driver } from '../lib/driver.js';
|
|
26
26
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
27
|
+
import { req } from '../lib/requirement-ids.js';
|
|
27
28
|
|
|
28
29
|
async function authorizationSupported(): Promise<boolean> {
|
|
29
30
|
// Root-first per RFC 0073 (`capabilities.authorization` is the deprecated wrapper shape).
|
|
@@ -42,7 +43,7 @@ describe('approval-gate-flow: role-gated, audited approval (RFC 0051 §A)', () =
|
|
|
42
43
|
const body = res.json as { released?: boolean } | undefined;
|
|
43
44
|
expect(
|
|
44
45
|
body?.released,
|
|
45
|
-
|
|
46
|
+
req('openwop.it.approval-gate-flow.an-unauthorized-principal-does-not-release-the-gate-fail-closed', 'RFC 0051 §A', 'an unauthorized principal MUST NOT release the gate (fail-closed)'),
|
|
46
47
|
).toBe(false);
|
|
47
48
|
});
|
|
48
49
|
|
|
@@ -57,11 +58,11 @@ describe('approval-gate-flow: role-gated, audited approval (RFC 0051 §A)', () =
|
|
|
57
58
|
const body = res.json as { event?: { type?: string; payload?: { reason?: string } } } | undefined;
|
|
58
59
|
expect(
|
|
59
60
|
body?.event?.type,
|
|
60
|
-
|
|
61
|
+
req('openwop.it.approval-gate-flow.the-override-path-emits-an-audited-approval-overridden-with-a-reason', 'RFC 0051 §B', 'taking the override path MUST emit approval.overridden'),
|
|
61
62
|
).toBe('approval.overridden');
|
|
62
63
|
expect(
|
|
63
64
|
typeof body?.event?.payload?.reason === 'string' && body.event.payload.reason.length > 0,
|
|
64
|
-
|
|
65
|
+
req('openwop.it.approval-gate-flow.the-override-path-emits-an-audited-approval-overridden-with-a-reason', 'RFC 0051 §B', 'approval.overridden MUST carry a non-empty reason (the audit breadcrumb)'),
|
|
65
66
|
).toBe(true);
|
|
66
67
|
});
|
|
67
68
|
});
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
import { describe, it, expect } from 'vitest';
|
|
45
45
|
import { driver } from '../lib/driver.js';
|
|
46
|
+
import { req } from '../lib/requirement-ids.js';
|
|
46
47
|
|
|
47
48
|
const CANONICAL_ACTIONS = ['accept', 'reject', 'refine', 'edit-accept', 'ask'] as const;
|
|
48
49
|
const CANONICAL_EVENT_ACTIONS = ['accept', 'reject', 'refine', 'edit-accept', 'timeout'] as const;
|
|
@@ -73,7 +74,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
|
|
|
73
74
|
// is distinguishable from the canonical form.
|
|
74
75
|
const legacyHits = text.match(/"edit"/g) ?? [];
|
|
75
76
|
|
|
76
|
-
expect(legacyHits.length,
|
|
77
|
+
expect(legacyHits.length, req('openwop.it.approval-payload.host-capability-declaration-does-not-regress-on-the-legacy-edit-form-7-drift-pin',
|
|
77
78
|
'interrupt.md §"`ApprovalResume`"',
|
|
78
79
|
'capability declaration MUST NOT contain the legacy `"edit"` action token (use `"edit-accept"` per spec)',
|
|
79
80
|
)).toBe(0);
|
|
@@ -84,7 +85,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
|
|
|
84
85
|
// accept/reject/refine/edit-accept/ask. Per-host advertisement is
|
|
85
86
|
// optional; this test pins the vocabulary itself for future
|
|
86
87
|
// scenarios that gate on it.
|
|
87
|
-
expect(CANONICAL_ACTIONS).toHaveLength(5);
|
|
88
|
+
expect(CANONICAL_ACTIONS, req('openwop.it.approval-payload.canonical-action-vocabulary-is-documented-in-spec-assertion-free-reference', 'capabilities.md', 'canonical action vocabulary is documented in spec (assertion-free reference)')).toHaveLength(5);
|
|
88
89
|
expect(new Set(CANONICAL_ACTIONS)).toEqual(
|
|
89
90
|
new Set(['accept', 'reject', 'refine', 'edit-accept', 'ask']),
|
|
90
91
|
);
|
|
@@ -98,7 +99,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
|
|
|
98
99
|
// but isn't a resume action (clients can't submit a timeout).
|
|
99
100
|
//
|
|
100
101
|
// Pin this asymmetry so it doesn't drift.
|
|
101
|
-
expect(CANONICAL_EVENT_ACTIONS).toHaveLength(5);
|
|
102
|
+
expect(CANONICAL_EVENT_ACTIONS, req('openwop.it.approval-payload.canonical-event-action-vocabulary-differs-from-resume-timeout-instead-of-ask', 'capabilities.md', 'canonical event action vocabulary differs from resume (timeout instead of ask)')).toHaveLength(5);
|
|
102
103
|
expect(new Set(CANONICAL_EVENT_ACTIONS)).toEqual(
|
|
103
104
|
new Set(['accept', 'reject', 'refine', 'edit-accept', 'timeout']),
|
|
104
105
|
);
|
|
@@ -112,7 +113,7 @@ describe('approval-payload: vocabulary discovery contract', () => {
|
|
|
112
113
|
// The 3 documented scopes `whole/section/items` MUST be a stable
|
|
113
114
|
// set in v1.x. Adding a scope is additive (clients tolerating
|
|
114
115
|
// unknown values) but semantic changes need a spec discussion.
|
|
115
|
-
expect(CANONICAL_REFINE_SCOPES).toHaveLength(3);
|
|
116
|
+
expect(CANONICAL_REFINE_SCOPES, req('openwop.it.approval-payload.refinefeedback-scope-vocabulary-pin-7-audit-a-5-prereq', 'capabilities.md', 'refineFeedback scope vocabulary pin (§7 audit, A.5 prereq)')).toHaveLength(3);
|
|
116
117
|
expect(new Set(CANONICAL_REFINE_SCOPES)).toEqual(
|
|
117
118
|
new Set(['whole', 'section', 'items']),
|
|
118
119
|
);
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
import { describe, it, expect } from 'vitest';
|
|
22
22
|
|
|
23
|
-
import { driver } from '../lib/driver.js';
|
|
24
23
|
import { loadEnv } from '../lib/env.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
25
26
|
|
|
26
27
|
describe('artifact-auth: unauthenticated artifact requests are rejected', () => {
|
|
27
28
|
it('GET /v1/runs/{runId}/artifacts/{artifactId} without Authorization returns 401', async () => {
|
|
@@ -31,12 +32,12 @@ describe('artifact-auth: unauthenticated artifact requests are rejected', () =>
|
|
|
31
32
|
const res = await fetch(
|
|
32
33
|
`${env.baseUrl}/v1/runs/openwop-conformance-noauth-run/artifacts/openwop-conformance-noauth-artifact`,
|
|
33
34
|
);
|
|
34
|
-
expect(res.status,
|
|
35
|
+
expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401',
|
|
35
36
|
'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}',
|
|
36
37
|
'artifact endpoint MUST reject unauthenticated requests with 401 (never 200, never redirect)',
|
|
37
38
|
)).toBe(401);
|
|
38
|
-
expect(res.status, 'redirect MUST NOT be used to handle missing auth on artifact endpoint').not.toBe(301);
|
|
39
|
-
expect(res.status, 'redirect MUST NOT be used to handle missing auth on artifact endpoint').not.toBe(302);
|
|
39
|
+
expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401', 'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}', 'redirect MUST NOT be used to handle missing auth on artifact endpoint')).not.toBe(301);
|
|
40
|
+
expect(res.status, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401', 'rest-endpoints.md GET /v1/runs/{runId}/artifacts/{artifactId}', 'redirect MUST NOT be used to handle missing auth on artifact endpoint')).not.toBe(302);
|
|
40
41
|
expect(res.status).not.toBe(200);
|
|
41
42
|
|
|
42
43
|
// Canonical error envelope: error: 'unauthenticated', message: string.
|
|
@@ -46,10 +47,10 @@ describe('artifact-auth: unauthenticated artifact requests are rejected', () =>
|
|
|
46
47
|
} catch {
|
|
47
48
|
// Some hosts return a bare 401 with no body — acceptable. Skip the
|
|
48
49
|
// envelope-shape assertion in that case.
|
|
49
|
-
return;
|
|
50
|
+
return softSkip('blocked', 'precondition not met — an earlier step threw (Some hosts return a bare 401 with no body — acceptable. Skip the envelope-shape assertion in that case.) (seam, prior step, or fixture unavailable)');
|
|
50
51
|
}
|
|
51
52
|
if (typeof body.error === 'string') {
|
|
52
|
-
expect(body.error,
|
|
53
|
+
expect(body.error, req('openwop.it.artifact-auth.get-v1-runs-runid-artifacts-artifactid-without-authorization-returns-401',
|
|
53
54
|
'auth.md §"Error envelope"',
|
|
54
55
|
'401 envelope SHOULD carry `error: "unauthenticated"` for missing-auth on artifact endpoint',
|
|
55
56
|
)).toBe('unauthenticated');
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import { describe, it, expect } from 'vitest';
|
|
29
|
-
import { driver } from '../lib/driver.js';
|
|
30
29
|
import { behaviorGate, behaviorGatePresent } from '../lib/behavior-gate.js';
|
|
31
30
|
|
|
32
31
|
const PROFILE = 'openwop-artifact-type-packs';
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
produceArtifact,
|
|
38
37
|
sampleArtifactTypePack,
|
|
39
38
|
} from '../lib/artifactTypes.js';
|
|
39
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
40
|
|
|
41
41
|
describe('artifact-type-pack-install: registered artifacts are schema-validated (RFC 0071)', () => {
|
|
42
42
|
it('a conforming payload yields artifact.created { registered: true }', async () => {
|
|
@@ -47,24 +47,24 @@ describe('artifact-type-pack-install: registered artifacts are schema-validated
|
|
|
47
47
|
if (!behaviorGatePresent(PROFILE, installed)) return; // seam absent: skip default, FAIL strict
|
|
48
48
|
expect(
|
|
49
49
|
installed.status >= 200 && installed.status < 300,
|
|
50
|
-
|
|
50
|
+
req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md §"Pack kind"', 'a valid artifact-type pack MUST install cleanly'),
|
|
51
51
|
).toBe(true);
|
|
52
52
|
|
|
53
53
|
const produced = await produceArtifact(artifactTypeId, { title: 'Hello', body: 'World' });
|
|
54
54
|
if (!behaviorGatePresent(PROFILE, produced)) return; // seam absent: skip default, FAIL strict
|
|
55
55
|
expect(
|
|
56
56
|
produced.json['registered'],
|
|
57
|
-
|
|
57
|
+
req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload matching a registered artifactTypeId MUST be marked registered'),
|
|
58
58
|
).toBe(true);
|
|
59
59
|
expect(
|
|
60
60
|
produced.json['validated'],
|
|
61
|
-
|
|
61
|
+
req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'artifact-type-packs.md', 'the host MUST validate the payload against the pack schema before emitting artifact.created'),
|
|
62
62
|
).toBe(true);
|
|
63
63
|
const evt = produced.json['artifactCreated'] as { registered?: unknown } | undefined;
|
|
64
64
|
if (evt && 'registered' in evt) {
|
|
65
65
|
expect(
|
|
66
66
|
evt.registered,
|
|
67
|
-
|
|
67
|
+
req('openwop.it.artifact-type-pack-install.a-conforming-payload-yields-artifact-created-registered-true', 'run-event-payloads.schema.json §artifactCreated', 'artifact.created.registered MUST be true for a validated registered artifact'),
|
|
68
68
|
).toBe(true);
|
|
69
69
|
}
|
|
70
70
|
});
|
|
@@ -83,7 +83,7 @@ describe('artifact-type-pack-install: registered artifacts are schema-validated
|
|
|
83
83
|
produced.json['stored'] === false;
|
|
84
84
|
expect(
|
|
85
85
|
rejected,
|
|
86
|
-
|
|
86
|
+
req('openwop.it.artifact-type-pack-install.a-schema-violating-payload-is-rejected-not-stored-as-a-validated-registered-arti', 'artifact-type-packs.md §"Binding the existing artifact surfaces"', 'a payload that fails the pack schema MUST NOT be emitted as a validated registered artifact'),
|
|
87
87
|
).toBe(true);
|
|
88
88
|
});
|
|
89
89
|
});
|
|
@@ -47,6 +47,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
47
47
|
import addFormats from 'ajv-formats';
|
|
48
48
|
import type { ErrorObject } from 'ajv';
|
|
49
49
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
50
|
+
import { req } from '../lib/requirement-ids.js';
|
|
50
51
|
|
|
51
52
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'artifact-type-pack-manifest.schema.json');
|
|
52
53
|
|
|
@@ -87,7 +88,7 @@ describe('category: artifact-type-pack manifest validation', () => {
|
|
|
87
88
|
const ok = validate(validManifest());
|
|
88
89
|
expect(
|
|
89
90
|
ok,
|
|
90
|
-
`artifact-type-packs.md §"Manifest format": a well-formed kind:"artifact-type" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
91
|
+
req('openwop.it.artifact-type-pack-manifest-validation.positive-a-valid-artifact-type-pack-manifest-validates-cleanly', 'artifact-type-packs.md', `artifact-type-packs.md §"Manifest format": a well-formed kind:"artifact-type" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
91
92
|
).toBe(true);
|
|
92
93
|
});
|
|
93
94
|
|
|
@@ -96,45 +97,45 @@ describe('category: artifact-type-pack manifest validation', () => {
|
|
|
96
97
|
const errs = failsWith(manifest, 'additionalProperties');
|
|
97
98
|
expect(
|
|
98
99
|
errs.some((e) => (e.params as { additionalProperty?: string }).additionalProperty === 'nodes'),
|
|
99
|
-
'artifact-type-packs.md §"Pack kind": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)',
|
|
100
|
+
req('openwop.it.artifact-type-pack-manifest-validation.negative-a-manifest-mixing-artifacttypes-and-nodes-is-rejected-pack-kind-invalid', 'artifact-type-packs.md', 'artifact-type-packs.md §"Pack kind": one kind per pack — a foreign `nodes[]` field MUST be rejected (additionalProperties:false)'),
|
|
100
101
|
).toBe(true);
|
|
101
102
|
});
|
|
102
103
|
|
|
103
104
|
it('negative: an empty artifactTypes[] is rejected (a pack MUST declare ≥1 type)', () => {
|
|
104
105
|
const manifest = { ...validManifest(), artifactTypes: [] };
|
|
105
106
|
const errs = failsWith(manifest, 'minItems');
|
|
106
|
-
expect(errs.length, 'artifact-type-pack-manifest.schema.json: artifactTypes minItems:1').toBeGreaterThan(0);
|
|
107
|
+
expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-empty-artifacttypes-is-rejected-a-pack-must-declare-1-type', 'artifact-type-packs.md', 'artifact-type-pack-manifest.schema.json: artifactTypes minItems:1')).toBeGreaterThan(0);
|
|
107
108
|
});
|
|
108
109
|
|
|
109
110
|
it('negative: an artifactTypeId that is not reverse-DNS scoped is rejected', () => {
|
|
110
111
|
const manifest = validManifest();
|
|
111
112
|
manifest.artifactTypes[0]!.artifactTypeId = 'Vendor.Acme.Model'; // uppercase scope
|
|
112
113
|
const errs = failsWith(manifest, 'pattern');
|
|
113
|
-
expect(errs.length, 'artifact-type-packs.md: artifactTypeId MUST match the reverse-DNS pattern').toBeGreaterThan(0);
|
|
114
|
+
expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-artifacttypeid-that-is-not-reverse-dns-scoped-is-rejected', 'artifact-type-packs.md', 'artifact-type-packs.md: artifactTypeId MUST match the reverse-DNS pattern')).toBeGreaterThan(0);
|
|
114
115
|
});
|
|
115
116
|
|
|
116
117
|
it('negative: an unknown rendering.display value is rejected (closed RFC 0055 enum, card excluded)', () => {
|
|
117
118
|
const manifest = validManifest();
|
|
118
119
|
(manifest.artifactTypes[0]!.rendering as { display: string }).display = '3d-viewport';
|
|
119
120
|
const errs = failsWith(manifest, 'enum');
|
|
120
|
-
expect(errs.length, 'artifact-type-packs.md: rendering.display reuses the closed ai-envelope §"Rendering hints" enum').toBeGreaterThan(0);
|
|
121
|
+
expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-an-unknown-rendering-display-value-is-rejected-closed-rfc-0055-enum-car', 'RFC 0055', 'artifact-type-packs.md: rendering.display reuses the closed ai-envelope §"Rendering hints" enum')).toBeGreaterThan(0);
|
|
121
122
|
});
|
|
122
123
|
|
|
123
124
|
it('negative: a non-conforming exportFormats identifier is rejected (reserved-core + vendor.*/x- only)', () => {
|
|
124
125
|
const manifest = validManifest();
|
|
125
126
|
manifest.artifactTypes[0]!.exportFormats = ['PPTX']; // uppercase, unprefixed
|
|
126
127
|
const errs = failsWith(manifest, 'pattern');
|
|
127
|
-
expect(errs.length, 'artifact-type-packs.md: exportFormats identifiers are lowercase core ids OR vendor.*/x- extensions').toBeGreaterThan(0);
|
|
128
|
+
expect(errs.length, req('openwop.it.artifact-type-pack-manifest-validation.negative-a-non-conforming-exportformats-identifier-is-rejected-reserved-core-ven', 'artifact-type-packs.md', 'artifact-type-packs.md: exportFormats identifiers are lowercase core ids OR vendor.*/x- extensions')).toBeGreaterThan(0);
|
|
128
129
|
});
|
|
129
130
|
|
|
130
131
|
it('positive: the validation field accepts "open"/"closed" and rejects other values (RFC 0075)', () => {
|
|
131
132
|
for (const v of ['open', 'closed']) {
|
|
132
133
|
const m = validManifest();
|
|
133
134
|
(m.artifactTypes[0] as Record<string, unknown>).validation = v;
|
|
134
|
-
expect(validate(m), `artifact-type-packs.md §validation: "${v}" MUST validate (RFC 0075)`).toBe(true);
|
|
135
|
+
expect(validate(m), req('openwop.it.artifact-type-pack-manifest-validation.positive-the-validation-field-accepts-open-closed-and-rejects-other-values-rfc-0', 'RFC 0075', `artifact-type-packs.md §validation: "${v}" MUST validate (RFC 0075)`)).toBe(true);
|
|
135
136
|
}
|
|
136
137
|
const bad = validManifest();
|
|
137
138
|
(bad.artifactTypes[0] as Record<string, unknown>).validation = 'lenient';
|
|
138
|
-
expect(failsWith(bad, 'enum').length, 'validation MUST be open|closed').toBeGreaterThan(0);
|
|
139
|
+
expect(failsWith(bad, 'enum').length, req('openwop.it.artifact-type-pack-manifest-validation.positive-the-validation-field-accepts-open-closed-and-rejects-other-values-rfc-0', 'RFC 0075', 'validation MUST be open|closed')).toBeGreaterThan(0);
|
|
139
140
|
});
|
|
140
141
|
});
|
|
@@ -36,8 +36,8 @@ import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
|
|
|
36
36
|
import { driver } from '../lib/driver.js';
|
|
37
37
|
import { behaviorGatePresent } from '../lib/behavior-gate.js';
|
|
38
38
|
import { readArtifactTypesCap } from '../lib/artifactTypes.js';
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
import { req } from '../lib/requirement-ids.js';
|
|
40
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
41
41
|
const CAPS = join(SCHEMAS_DIR, 'capabilities.schema.json');
|
|
42
42
|
const EVENT_PAYLOADS = join(SCHEMAS_DIR, 'run-event-payloads.schema.json');
|
|
43
43
|
const readDoc = (name: string): string => (V1_DIR ? readFileSync(join(V1_DIR, name), 'utf8') : '');
|
|
@@ -59,14 +59,14 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
|
|
|
59
59
|
const entry = perTypeEntry();
|
|
60
60
|
const props = entry.properties as Record<string, Record<string, unknown>>;
|
|
61
61
|
|
|
62
|
-
expect(props.registrationSource,
|
|
62
|
+
expect(props.registrationSource, req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'facet is declared')).toBeDefined();
|
|
63
63
|
expect(
|
|
64
64
|
props.registrationSource.enum,
|
|
65
|
-
|
|
65
|
+
req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'enum is exactly [pack, host]'),
|
|
66
66
|
).toEqual(['pack', 'host']);
|
|
67
67
|
expect(
|
|
68
68
|
(entry.required as string[] | undefined)?.includes('registrationSource') ?? false,
|
|
69
|
-
|
|
69
|
+
req('openwop.it.artifact-type-registration-source.a1-the-per-type-entry-declares-registrationsource-as-an-optional-pack-host-enum', '§artifactTypes.types', 'facet is OPTIONAL — absent ⇒ unspecified provenance, not a default'),
|
|
70
70
|
).toBe(false);
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -77,22 +77,22 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
|
|
|
77
77
|
|
|
78
78
|
expect(
|
|
79
79
|
validate({ validated: true, registrationSource: 'host', schemaVersion: 1 }),
|
|
80
|
-
|
|
80
|
+
req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `"host" validates: ${JSON.stringify(validate.errors)}`),
|
|
81
81
|
).toBe(true);
|
|
82
82
|
expect(
|
|
83
83
|
validate({ validated: true, registrationSource: 'pack' }),
|
|
84
|
-
|
|
84
|
+
req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `"pack" validates: ${JSON.stringify(validate.errors)}`),
|
|
85
85
|
).toBe(true);
|
|
86
86
|
// Absent stays legal — requirement 2.
|
|
87
87
|
expect(
|
|
88
88
|
validate({ validated: true }),
|
|
89
|
-
|
|
89
|
+
req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', `absent validates: ${JSON.stringify(validate.errors)}`),
|
|
90
90
|
).toBe(true);
|
|
91
91
|
// A third provenance is a wire error, NOT a hint to ignore. This is where the facet
|
|
92
92
|
// parts company with RFC 0136's `format`, and the reason is in the docblock.
|
|
93
93
|
expect(
|
|
94
94
|
validate({ validated: true, registrationSource: 'registry' }),
|
|
95
|
-
|
|
95
|
+
req('openwop.it.artifact-type-registration-source.a2-a-valid-provenance-validates-an-out-of-enum-value-does-not', '§artifactTypes.types', 'an undefined provenance is REJECTED'),
|
|
96
96
|
).toBe(false);
|
|
97
97
|
});
|
|
98
98
|
|
|
@@ -107,7 +107,7 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
|
|
|
107
107
|
// advertise a provenance it could never emit.
|
|
108
108
|
expect(
|
|
109
109
|
entryProps.registrationSource.enum,
|
|
110
|
-
|
|
110
|
+
req('openwop.it.artifact-type-registration-source.a3-the-facet-mirrors-the-vocabulary-artifact-created-already-carries', 'RFC 0145 req 3', 'discovery enum matches artifact.created enum'),
|
|
111
111
|
).toEqual(eventProps.registrationSource.enum);
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -118,10 +118,10 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
|
|
|
118
118
|
const facetList = readDoc(name).match(
|
|
119
119
|
/validated, validation, schemaVersion, store, render, export[^}]*}/,
|
|
120
120
|
);
|
|
121
|
-
expect(facetList,
|
|
121
|
+
expect(facetList, req('openwop.it.artifact-type-registration-source.a4-both-prose-sites-list-the-facet-so-schema-and-normative-surface-cannot-drift', `${name} §"Per-type facets"`, 'per-type facet list present')).not.toBeNull();
|
|
122
122
|
expect(
|
|
123
123
|
facetList?.[0].includes('registrationSource'),
|
|
124
|
-
|
|
124
|
+
req('openwop.it.artifact-type-registration-source.a4-both-prose-sites-list-the-facet-so-schema-and-normative-surface-cannot-drift', `${name} §"Per-type facets"`, 'facet list names registrationSource'),
|
|
125
125
|
).toBe(true);
|
|
126
126
|
}
|
|
127
127
|
});
|
|
@@ -130,11 +130,11 @@ describe('artifact-type-registration-source (RFC 0145, always-on)', () => {
|
|
|
130
130
|
const doc = readDoc('artifact-type-packs.md');
|
|
131
131
|
expect(
|
|
132
132
|
/Serving is a MUST for host-registered/.test(doc),
|
|
133
|
-
|
|
133
|
+
req('openwop.it.artifact-type-registration-source.a5-the-spec-states-the-must-should-asymmetry-the-facet-exists-to-disclose', '§Schema distribution', 'serving is a MUST for no-pack types'),
|
|
134
134
|
).toBe(true);
|
|
135
135
|
expect(
|
|
136
136
|
/serving stays a SHOULD for them/.test(doc),
|
|
137
|
-
|
|
137
|
+
req('openwop.it.artifact-type-registration-source.a5-the-spec-states-the-must-should-asymmetry-the-facet-exists-to-disclose', '§Schema distribution', 'serving stays a SHOULD for pack-backed types'),
|
|
138
138
|
).toBe(true);
|
|
139
139
|
});
|
|
140
140
|
});
|
|
@@ -179,7 +179,7 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
|
|
|
179
179
|
const target = comparableType(cap);
|
|
180
180
|
// INAPPLICABLE, not gated. `registrationSource` is OPTIONAL (requirement 2) and strict mode
|
|
181
181
|
// must not coerce a host into advertising it — the same call RFC 0142 makes for `store`.
|
|
182
|
-
if (target === null) return;
|
|
182
|
+
if (target === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `target === null` returned early (INAPPLICABLE, not gated. `registrationSource` is OPTIONAL (requirement 2) and strict mode must not coerce a host into advertis…');
|
|
183
183
|
|
|
184
184
|
const started = await driver.post('/v1/host/sample/artifacttypes/runproduce', {
|
|
185
185
|
artifactTypeId: target.id,
|
|
@@ -189,10 +189,10 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
|
|
|
189
189
|
// scenario that owns that enforcement. Gating again here would double-report one defect,
|
|
190
190
|
// and gating on the seam for a 0145 advert would coerce hosts into wiring 0142's host-sample
|
|
191
191
|
// surface in order to advertise a facet that has nothing to do with it.
|
|
192
|
-
if (started.status === 404 || started.status === 405) return; // seam absent — 0142 reports it
|
|
192
|
+
if (started.status === 404 || started.status === 405) return softSkip('blocked', 'precondition not met — `started.status === 404 || started.status === 405` returned early (seam absent — 0142 reports it) (seam, prior step, or fixture unavailable)'); // seam absent — 0142 reports it
|
|
193
193
|
expect(
|
|
194
194
|
started.status >= 200 && started.status < 300,
|
|
195
|
-
|
|
195
|
+
req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type', 'coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
|
|
196
196
|
).toBe(true);
|
|
197
197
|
const runId = (started.json as Record<string, unknown> | undefined)?.['runId'];
|
|
198
198
|
if (!behaviorGatePresent(PROFILE, typeof runId === 'string' ? runId : null)) return;
|
|
@@ -200,18 +200,18 @@ describe('artifact-type-registration-source: the advert agrees with the event (R
|
|
|
200
200
|
const events = await driver.get(`/v1/runs/${runId}/events/poll?timeout=5`);
|
|
201
201
|
expect(
|
|
202
202
|
events.status,
|
|
203
|
-
|
|
203
|
+
req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type', 'run-events surface', 'the run event log is readable over the standard poll endpoint'),
|
|
204
204
|
).toBe(200);
|
|
205
205
|
const list = ((events.json as Record<string, unknown>)?.['events'] ?? []) as Array<Record<string, unknown>>;
|
|
206
206
|
const created = list.filter((e) => e['type'] === 'artifact.created');
|
|
207
207
|
// Emission itself is RFC 0142's MUST, reported by its own leg. Reaching here without an
|
|
208
208
|
// event means that leg is already red; don't restate its finding as a 0145 failure.
|
|
209
|
-
if (created.length === 0) return;
|
|
209
|
+
if (created.length === 0) return softSkip('blocked', 'precondition not met — `created.length === 0` returned early (Emission itself is RFC 0142\'s MUST, reported by its own leg. Reaching here without an event means that leg is already red; don\'t restate its finding as a 0…');
|
|
210
210
|
|
|
211
211
|
const payload = (created[0]?.['payload'] ?? created[0]?.['data'] ?? {}) as Record<string, unknown>;
|
|
212
212
|
expect(
|
|
213
213
|
payload['registrationSource'],
|
|
214
|
-
|
|
214
|
+
req('openwop.it.artifact-type-registration-source.the-emitted-registrationsource-equals-the-advertised-one-for-that-type',
|
|
215
215
|
'RFC 0145 requirement 3',
|
|
216
216
|
`the host advertises registrationSource: "${target.advertised}" for ${target.id}, so that is the value it MUST emit — an advert of one provenance against an event carrying another (or carrying none, which asserts UNSPECIFIED provenance and therefore disagrees) is a false advertisement, not a permitted divergence`,
|
|
217
217
|
),
|
|
@@ -43,31 +43,28 @@ import { driver } from '../lib/driver.js';
|
|
|
43
43
|
import { behaviorGate, behaviorGatePresent } from '../lib/behavior-gate.js';
|
|
44
44
|
import { readArtifactTypesCap } from '../lib/artifactTypes.js';
|
|
45
45
|
import { SCHEMAS_DIR, V1_DIR } from '../lib/paths.js';
|
|
46
|
+
import { req } from '../lib/requirement-ids.js';
|
|
47
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
46
48
|
|
|
47
49
|
const PROFILE = 'openwop-artifact-type-store';
|
|
48
50
|
|
|
49
|
-
/** Server-free assertion message helper — leg A must not touch `driver`, whose
|
|
50
|
-
* describe() loads env and would make a "server-free" leg fail on a missing
|
|
51
|
-
* OPENWOP_BASE_URL instead of on its assertion (a vacuous red). */
|
|
52
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
53
|
-
|
|
54
51
|
describe('artifact-type-store-emission: the payload fact is pinned always-on (RFC 0142 leg A)', () => {
|
|
55
52
|
it('artifactCreated REQUIRES artifactType — the fact the RFC 0138 replay correction rests on', () => {
|
|
56
53
|
const schema = JSON.parse(
|
|
57
54
|
readFileSync(join(SCHEMAS_DIR, 'run-event-payloads.schema.json'), 'utf8'),
|
|
58
55
|
) as { $defs?: Record<string, { properties?: Record<string, unknown>; required?: string[] }> };
|
|
59
56
|
const ac = schema.$defs?.['artifactCreated'];
|
|
60
|
-
expect(ac !== undefined, 'run-event-payloads.schema.json — $defs/artifactCreated exists').toBe(true);
|
|
57
|
+
expect(ac !== undefined, req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re', 'RFC 0138', 'run-event-payloads.schema.json — $defs/artifactCreated exists')).toBe(true);
|
|
61
58
|
expect(
|
|
62
59
|
ac?.required?.includes('artifactType'),
|
|
63
|
-
|
|
60
|
+
req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re',
|
|
64
61
|
'run-event-payloads.schema.json §artifactCreated',
|
|
65
62
|
'artifactType is REQUIRED on the artifact.created payload — artifactTypeId values ride in the fixed event log, which is why identifier migrations MUST NOT rewrite history (RFC 0141) and why this fact must be pinned by an always-on leg rather than a gated one (RFC 0138 G8)',
|
|
66
63
|
),
|
|
67
64
|
).toBe(true);
|
|
68
65
|
expect(
|
|
69
66
|
Object.keys(ac?.properties ?? {}).includes('registered'),
|
|
70
|
-
|
|
67
|
+
req('openwop.it.artifact-type-store-emission.artifactcreated-requires-artifacttype-the-fact-the-rfc-0138-replay-correction-re', 'run-event-payloads.schema.json §artifactCreated', 'the registered flag the store-tier validation promise is reported through is present'),
|
|
71
68
|
).toBe(true);
|
|
72
69
|
});
|
|
73
70
|
});
|
|
@@ -83,21 +80,21 @@ describe('artifact-type-store-emission: what `store: true` claims is stated norm
|
|
|
83
80
|
it.skipIf(V1_DIR === null)('the claim is quantified over artifacts of the type, not over the host\'s paths', () => {
|
|
84
81
|
expect(
|
|
85
82
|
/\*\*every\*\* path by which the host persists an artifact carrying that registered `artifactTypeId` MUST emit `artifact\.created`/.test(doc),
|
|
86
|
-
|
|
83
|
+
req('openwop.it.artifact-type-store-emission.the-claim-is-quantified-over-artifacts-of-the-type-not-over-the-host-s-paths',
|
|
87
84
|
'artifact-type-packs.md §"Sub-flags"',
|
|
88
85
|
'EVERY production path emits, not at least one — the permissive reading lets a host wire the leg-B seam through its single emitting path and pass while most of its production stays silent',
|
|
89
86
|
),
|
|
90
87
|
).toBe(true);
|
|
91
88
|
expect(
|
|
92
89
|
/MUST NOT advertise `store: true` for that type/.test(doc),
|
|
93
|
-
|
|
90
|
+
req('openwop.it.artifact-type-store-emission.the-claim-is-quantified-over-artifacts-of-the-type-not-over-the-host-s-paths', 'artifact-type-packs.md §"Sub-flags"', 'a host with a silent persistence path for the type is forbidden from advertising it, rather than merely discouraged'),
|
|
94
91
|
).toBe(true);
|
|
95
92
|
});
|
|
96
93
|
|
|
97
94
|
it.skipIf(V1_DIR === null)('the obligation is scoped to REGISTERED types, so the unregistered tier does not falsify an advert', () => {
|
|
98
95
|
expect(
|
|
99
96
|
/a path that persists only unregistered artifacts[^.]*is outside this facet and does not falsify the advert/.test(doc),
|
|
100
|
-
|
|
97
|
+
req('openwop.it.artifact-type-store-emission.the-obligation-is-scoped-to-registered-types-so-the-unregistered-tier-does-not-f',
|
|
101
98
|
'artifact-type-packs.md §"Sub-flags"',
|
|
102
99
|
'the narrowing is normative, not a courtesy — without it a host holds back an honest advert on account of a path the facet never bound',
|
|
103
100
|
),
|
|
@@ -107,7 +104,7 @@ describe('artifact-type-store-emission: what `store: true` claims is stated norm
|
|
|
107
104
|
it.skipIf(V1_DIR === null)('per-type is named as the instrument, including the case it cannot rescue', () => {
|
|
108
105
|
expect(
|
|
109
106
|
/cannot be advertised `store: true` at all until one of those two facts changes/.test(doc),
|
|
110
|
-
|
|
107
|
+
req('openwop.it.artifact-type-store-emission.per-type-is-named-as-the-instrument-including-the-case-it-cannot-rescue',
|
|
111
108
|
'artifact-type-packs.md §"Sub-flags"',
|
|
112
109
|
'a single type produced through both an emitting and a non-emitting path is not advertisable — per-type resolves a heterogeneous fleet, not a heterogeneous type',
|
|
113
110
|
),
|
|
@@ -144,7 +141,7 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
|
|
|
144
141
|
const cap = await readArtifactTypesCap();
|
|
145
142
|
// `store` is OPTIONAL. A host that does not advertise it is INAPPLICABLE —
|
|
146
143
|
// not gated: strict mode must not coerce hosts into an advertisement.
|
|
147
|
-
if (!storeAdvertised(cap)) return; // scenario inapplicable
|
|
144
|
+
if (!storeAdvertised(cap)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!storeAdvertised(cap)` returned early (scenario inapplicable)'); // scenario inapplicable
|
|
148
145
|
|
|
149
146
|
const requested = storeTypeId(cap) ?? 'vendor.conformance.note';
|
|
150
147
|
const started = await driver.post('/v1/host/sample/artifacttypes/runproduce', {
|
|
@@ -155,7 +152,7 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
|
|
|
155
152
|
|
|
156
153
|
expect(
|
|
157
154
|
started.status >= 200 && started.status < 300,
|
|
158
|
-
|
|
155
|
+
req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist', 'coverage.md §"Open seams"', 'runproduce starts a real run producing one artifact of the requested registered type'),
|
|
159
156
|
).toBe(true);
|
|
160
157
|
const runId = (started.json as Record<string, unknown> | undefined)?.['runId'];
|
|
161
158
|
if (!behaviorGatePresent(PROFILE, typeof runId === 'string' ? runId : null)) return;
|
|
@@ -163,14 +160,14 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
|
|
|
163
160
|
const events = await driver.get(`/v1/runs/${runId}/events/poll?timeout=5`);
|
|
164
161
|
expect(
|
|
165
162
|
events.status,
|
|
166
|
-
|
|
163
|
+
req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist', 'run-events surface', 'the run event log is readable over the standard poll endpoint — the same wire any consumer uses'),
|
|
167
164
|
).toBe(200);
|
|
168
165
|
const list = ((events.json as Record<string, unknown>)?.['events'] ?? []) as Array<Record<string, unknown>>;
|
|
169
166
|
const created = list.filter((e) => e['type'] === 'artifact.created');
|
|
170
167
|
|
|
171
168
|
expect(
|
|
172
169
|
created.length > 0,
|
|
173
|
-
|
|
170
|
+
req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
|
|
174
171
|
'artifact-type-packs.md §"Host capability", store row',
|
|
175
172
|
'a host advertising store:true MUST emit artifact.created — persistence without emission is the exact posture the advertisement forbids',
|
|
176
173
|
),
|
|
@@ -179,14 +176,14 @@ describe('artifact-type-store-emission: a store:true host MUST emit, witnessed f
|
|
|
179
176
|
const payload = (created[0]?.['payload'] ?? created[0]?.['data'] ?? {}) as Record<string, unknown>;
|
|
180
177
|
expect(
|
|
181
178
|
payload['artifactType'],
|
|
182
|
-
|
|
179
|
+
req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
|
|
183
180
|
'run-event-payloads.schema.json §artifactCreated',
|
|
184
181
|
'the emitted artifactType is the bound id — an event present but carrying the wrong type would let a mis-wired emitter pass a presence-only check',
|
|
185
182
|
),
|
|
186
183
|
).toBe(requested);
|
|
187
184
|
expect(
|
|
188
185
|
payload['registered'],
|
|
189
|
-
|
|
186
|
+
req('openwop.it.artifact-type-store-emission.artifact-created-appears-in-the-event-log-with-the-bound-artifacttype-and-regist',
|
|
190
187
|
'artifact-type-packs.md §"Binding the existing artifact surfaces"',
|
|
191
188
|
'a store-tier host validates before emitting and reports registered:true for a registered type',
|
|
192
189
|
),
|