@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
|
@@ -30,8 +30,7 @@ import {
|
|
|
30
30
|
ProducedVarProducerUnknownError,
|
|
31
31
|
type WorkflowChain,
|
|
32
32
|
} from '../lib/workflow-chain-expansion.js';
|
|
33
|
-
|
|
34
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
35
34
|
const SPEC = 'workflow-chain-packs.md §"Produced (run-scoped) variables (RFC 0133)"';
|
|
36
35
|
|
|
37
36
|
/** `generate` writes `plan`; `decompose` reads it via a variable binding. */
|
|
@@ -56,19 +55,19 @@ const PLAN_GEN: WorkflowChain = {
|
|
|
56
55
|
describe('chain-produced-var-roundtrip: run-scoped variables (RFC 0133 §2, server-free)', () => {
|
|
57
56
|
it('emits declared producedVariables into variables[] (name + type, NO value)', () => {
|
|
58
57
|
const vars = emitProducedVariables(PLAN_GEN);
|
|
59
|
-
expect(vars,
|
|
58
|
+
expect(vars, req('openwop.it.chain-produced-var-roundtrip.emits-declared-producedvariables-into-variables-name-type-no-value', SPEC, '§2.3 — one run-scoped variable emitted')).toEqual([{ name: 'plan', type: 'object' }]);
|
|
60
59
|
// Run-scoped: NO author-time value rides the emitted entry.
|
|
61
|
-
expect('value' in (vars[0] as object),
|
|
60
|
+
expect('value' in (vars[0] as object), req('openwop.it.chain-produced-var-roundtrip.emits-declared-producedvariables-into-variables-name-type-no-value', SPEC, '§2.3 — no author-time value (distinct from parameters)')).toBe(
|
|
62
61
|
false,
|
|
63
62
|
);
|
|
64
63
|
expect(
|
|
65
64
|
'defaultValue' in (vars[0] as object),
|
|
66
|
-
|
|
65
|
+
req('openwop.it.chain-produced-var-roundtrip.emits-declared-producedvariables-into-variables-name-type-no-value', SPEC, '§2.3 — no default value (a produced var is written during the run)'),
|
|
67
66
|
).toBe(false);
|
|
68
67
|
});
|
|
69
68
|
|
|
70
69
|
it('validates a variable read of a DECLARED producedVariables name', () => {
|
|
71
|
-
expect(() => validateVariableReads(PLAN_GEN),
|
|
70
|
+
expect(() => validateVariableReads(PLAN_GEN), req('openwop.it.chain-produced-var-roundtrip.validates-a-variable-read-of-a-declared-producedvariables-name', SPEC, '§2.2 — declared read is closed-world valid')).not.toThrow();
|
|
72
71
|
});
|
|
73
72
|
|
|
74
73
|
it('rejects a variable read of an UNDECLARED name (variable_undeclared)', () => {
|
|
@@ -86,14 +85,14 @@ describe('chain-produced-var-roundtrip: run-scoped variables (RFC 0133 §2, serv
|
|
|
86
85
|
],
|
|
87
86
|
},
|
|
88
87
|
};
|
|
89
|
-
expect(() => validateVariableReads(undeclared),
|
|
88
|
+
expect(() => validateVariableReads(undeclared), req('openwop.it.chain-produced-var-roundtrip.rejects-a-variable-read-of-an-undeclared-name-variable-undeclared', SPEC, '§2.2 — undeclared read MUST reject')).toThrow(
|
|
90
89
|
VariableUndeclaredError,
|
|
91
90
|
);
|
|
92
91
|
try {
|
|
93
92
|
validateVariableReads(undeclared);
|
|
94
93
|
} catch (e) {
|
|
95
|
-
expect((e as VariableUndeclaredError).code,
|
|
96
|
-
expect((e as VariableUndeclaredError).variableName,
|
|
94
|
+
expect((e as VariableUndeclaredError).code, req('openwop.it.chain-produced-var-roundtrip.rejects-a-variable-read-of-an-undeclared-name-variable-undeclared', SPEC, 'wire code variable_undeclared')).toBe('variable_undeclared');
|
|
95
|
+
expect((e as VariableUndeclaredError).variableName, req('openwop.it.chain-produced-var-roundtrip.rejects-a-variable-read-of-an-undeclared-name-variable-undeclared', SPEC, 'names the offending variable')).toBe('plan');
|
|
97
96
|
}
|
|
98
97
|
});
|
|
99
98
|
|
|
@@ -104,12 +103,12 @@ describe('chain-produced-var-roundtrip: run-scoped variables (RFC 0133 §2, serv
|
|
|
104
103
|
};
|
|
105
104
|
expect(
|
|
106
105
|
() => validateVariableReads(badProducer),
|
|
107
|
-
|
|
106
|
+
req('openwop.it.chain-produced-var-roundtrip.rejects-a-producedvariables-whose-producedby-names-a-non-existent-node-produced', SPEC, '§2.2 — producedBy MUST be a real fragment node'),
|
|
108
107
|
).toThrow(ProducedVarProducerUnknownError);
|
|
109
108
|
try {
|
|
110
109
|
validateVariableReads(badProducer);
|
|
111
110
|
} catch (e) {
|
|
112
|
-
expect((e as ProducedVarProducerUnknownError).code,
|
|
111
|
+
expect((e as ProducedVarProducerUnknownError).code, req('openwop.it.chain-produced-var-roundtrip.rejects-a-producedvariables-whose-producedby-names-a-non-existent-node-produced', SPEC, 'distinct wire code')).toBe(
|
|
113
112
|
'produced_var_producer_unknown',
|
|
114
113
|
);
|
|
115
114
|
}
|
|
@@ -123,7 +122,7 @@ describe('chain-produced-var-roundtrip: run-scoped variables (RFC 0133 §2, serv
|
|
|
123
122
|
};
|
|
124
123
|
expect(
|
|
125
124
|
() => validateVariableReads(collide),
|
|
126
|
-
|
|
125
|
+
req('openwop.it.chain-produced-var-roundtrip.rejects-a-producedvariables-name-that-collides-with-a-parameter-channels-must-be', SPEC, '§2.2 — a produced var colliding with a parameter name MUST reject'),
|
|
127
126
|
).toThrow(VariableUndeclaredError);
|
|
128
127
|
});
|
|
129
128
|
|
|
@@ -141,12 +140,12 @@ describe('chain-produced-var-roundtrip: run-scoped variables (RFC 0133 §2, serv
|
|
|
141
140
|
};
|
|
142
141
|
expect(
|
|
143
142
|
() => validateVariableReads(paramRead, new Set(['seed'])),
|
|
144
|
-
|
|
143
|
+
req('openwop.it.chain-produced-var-roundtrip.validates-a-read-of-a-materialized-parameter-name-params-produced-vars-compose', SPEC, '§2.2 — a materialized-parameter read validates'),
|
|
145
144
|
).not.toThrow();
|
|
146
145
|
// …but still rejects when the name is neither a produced var nor a param.
|
|
147
146
|
expect(
|
|
148
147
|
() => validateVariableReads(paramRead, new Set()),
|
|
149
|
-
|
|
148
|
+
req('openwop.it.chain-produced-var-roundtrip.validates-a-read-of-a-materialized-parameter-name-params-produced-vars-compose', SPEC, '§2.2 — same read with no matching param still rejects'),
|
|
150
149
|
).toThrow(VariableUndeclaredError);
|
|
151
150
|
});
|
|
152
151
|
});
|
|
@@ -30,8 +30,7 @@ import {
|
|
|
30
30
|
DEFAULT_MAX_SUB_CHAIN_DEPTH,
|
|
31
31
|
type WorkflowChain,
|
|
32
32
|
} from '../lib/workflow-chain-expansion.js';
|
|
33
|
-
|
|
34
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
35
34
|
const SPEC = 'workflow-chain-packs.md §"Sub-chain composition (RFC 0133)"';
|
|
36
35
|
|
|
37
36
|
/** A chain node that dispatches a named sub-chain ref. */
|
|
@@ -88,14 +87,14 @@ const ctxFor = (siblings: Map<string, WorkflowChain>, maxDepth?: number) => ({
|
|
|
88
87
|
describe('chain-subchain-cycle-rejected: bounded recursion (RFC 0133, server-free)', () => {
|
|
89
88
|
it('rejects a chain that transitively composes itself (sub_chain_cycle)', () => {
|
|
90
89
|
const siblings = new Map([[selfRef.chainId, selfRef]]);
|
|
91
|
-
expect(() => expandChainTree(selfRef, ctxFor(siblings)),
|
|
90
|
+
expect(() => expandChainTree(selfRef, ctxFor(siblings)), req('openwop.it.chain-subchain-cycle-rejected.rejects-a-chain-that-transitively-composes-itself-sub-chain-cycle', SPEC, 'self-composition MUST reject')).toThrow(
|
|
92
91
|
SubChainCycleError,
|
|
93
92
|
);
|
|
94
93
|
try {
|
|
95
94
|
expandChainTree(selfRef, ctxFor(siblings));
|
|
96
95
|
} catch (e) {
|
|
97
|
-
expect((e as SubChainCycleError).code,
|
|
98
|
-
expect((e as SubChainCycleError).httpStatus,
|
|
96
|
+
expect((e as SubChainCycleError).code, req('openwop.it.chain-subchain-cycle-rejected.rejects-a-chain-that-transitively-composes-itself-sub-chain-cycle', SPEC, 'wire code sub_chain_cycle')).toBe('sub_chain_cycle');
|
|
97
|
+
expect((e as SubChainCycleError).httpStatus, req('openwop.it.chain-subchain-cycle-rejected.rejects-a-chain-that-transitively-composes-itself-sub-chain-cycle', SPEC, 'HTTP 400')).toBe(400);
|
|
99
98
|
}
|
|
100
99
|
});
|
|
101
100
|
|
|
@@ -105,13 +104,13 @@ describe('chain-subchain-cycle-rejected: bounded recursion (RFC 0133, server-fre
|
|
|
105
104
|
const { root, siblings } = linearChain(5);
|
|
106
105
|
expect(
|
|
107
106
|
() => expandChainTree(root, ctxFor(siblings, 2)),
|
|
108
|
-
|
|
107
|
+
req('openwop.it.chain-subchain-cycle-rejected.rejects-nesting-past-maxsubchaindepth-with-a-distinct-sub-chain-max-depth-exceed', SPEC, 'depth breach MUST reject (bounded recursion)'),
|
|
109
108
|
).toThrow(SubChainDepthExceededError);
|
|
110
109
|
try {
|
|
111
110
|
expandChainTree(root, ctxFor(siblings, 2));
|
|
112
111
|
} catch (e) {
|
|
113
|
-
expect((e as SubChainDepthExceededError).code,
|
|
114
|
-
expect(e instanceof SubChainCycleError,
|
|
112
|
+
expect((e as SubChainDepthExceededError).code, req('openwop.it.chain-subchain-cycle-rejected.rejects-nesting-past-maxsubchaindepth-with-a-distinct-sub-chain-max-depth-exceed', SPEC, 'distinct wire code')).toBe('sub_chain_max_depth_exceeded');
|
|
113
|
+
expect(e instanceof SubChainCycleError, req('openwop.it.chain-subchain-cycle-rejected.rejects-nesting-past-maxsubchaindepth-with-a-distinct-sub-chain-max-depth-exceed', SPEC, 'a depth breach is NOT a cycle')).toBe(false);
|
|
115
114
|
}
|
|
116
115
|
});
|
|
117
116
|
|
|
@@ -119,7 +118,7 @@ describe('chain-subchain-cycle-rejected: bounded recursion (RFC 0133, server-fre
|
|
|
119
118
|
const { root, siblings } = linearChain(3);
|
|
120
119
|
const { children } = expandChainTree(root, ctxFor(siblings, DEFAULT_MAX_SUB_CHAIN_DEPTH));
|
|
121
120
|
// 3 composing links (link.0..link.2 each compose their successor) ⇒ 3 co-registered children.
|
|
122
|
-
expect(children.length,
|
|
121
|
+
expect(children.length, req('openwop.it.chain-subchain-cycle-rejected.expands-an-acyclic-tree-within-the-bound-cleanly-guard-rejects-bombs-not-benign', SPEC, 'benign acyclic tree within the bound expands')).toBe(3);
|
|
123
122
|
});
|
|
124
123
|
|
|
125
124
|
it('rejects a subChainRef that resolves to no sibling chain (sub_chain_unresolved)', () => {
|
|
@@ -135,7 +134,7 @@ describe('chain-subchain-cycle-rejected: bounded recursion (RFC 0133, server-fre
|
|
|
135
134
|
const siblings = new Map([[orphan.chainId, orphan]]);
|
|
136
135
|
expect(
|
|
137
136
|
() => expandChainTree(orphan, ctxFor(siblings)),
|
|
138
|
-
|
|
137
|
+
req('openwop.it.chain-subchain-cycle-rejected.rejects-a-subchainref-that-resolves-to-no-sibling-chain-sub-chain-unresolved', SPEC, '§1.1 — unresolvable ref rejects distinctly'),
|
|
139
138
|
).toThrow(SubChainUnresolvedError);
|
|
140
139
|
});
|
|
141
140
|
});
|
|
@@ -28,8 +28,7 @@ import addFormats from 'ajv-formats';
|
|
|
28
28
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
29
29
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
30
30
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
31
|
-
|
|
32
|
-
const cite = (section: string, requirement: string): string => `${section} — ${requirement}`;
|
|
31
|
+
import { req } from '../lib/requirement-ids.js';
|
|
33
32
|
const CAPS = join(SCHEMAS_DIR, 'capabilities.schema.json');
|
|
34
33
|
const MANIFEST = join(SCHEMAS_DIR, 'workflow-chain-pack-manifest.schema.json');
|
|
35
34
|
|
|
@@ -40,20 +39,20 @@ function loadSchema(path: string): Record<string, unknown> {
|
|
|
40
39
|
describe('chain-subchain-fanout §A: capability + manifest shape (RFC 0133, always-on)', () => {
|
|
41
40
|
it('capabilities.schema.json §workflowChainPacks.subChains requires supported:boolean + maxDepth default 8', () => {
|
|
42
41
|
const raw = readFileSync(CAPS, 'utf8');
|
|
43
|
-
expect(raw.includes('"subChains"'),
|
|
42
|
+
expect(raw.includes('"subChains"'), req('openwop.it.chain-subchain-fanout.capabilities-schema-json-workflowchainpacks-subchains-requires-supported-boolean', 'capabilities §workflowChainPacks', 'the subChains block MUST exist')).toBe(
|
|
44
43
|
true,
|
|
45
44
|
);
|
|
46
45
|
const schema = loadSchema(CAPS);
|
|
47
46
|
// The subChains sub-block MUST be present somewhere in the workflowChainPacks family.
|
|
48
47
|
expect(
|
|
49
48
|
JSON.stringify(schema).includes('"subChains"'),
|
|
50
|
-
|
|
49
|
+
req('openwop.it.chain-subchain-fanout.capabilities-schema-json-workflowchainpacks-subchains-requires-supported-boolean', 'capabilities §subChains', 'declared in the capabilities schema'),
|
|
51
50
|
).toBe(true);
|
|
52
51
|
expect(
|
|
53
52
|
raw.includes('sub_chain_unsupported'),
|
|
54
|
-
|
|
53
|
+
req('openwop.it.chain-subchain-fanout.capabilities-schema-json-workflowchainpacks-subchains-requires-supported-boolean', 'capabilities §subChains', 'the description MUST cite the sub_chain_unsupported refusal'),
|
|
55
54
|
).toBe(true);
|
|
56
|
-
expect(raw.includes('"default": 8'),
|
|
55
|
+
expect(raw.includes('"default": 8'), req('openwop.it.chain-subchain-fanout.capabilities-schema-json-workflowchainpacks-subchains-requires-supported-boolean', 'capabilities §subChains.maxDepth', 'RECOMMENDED default 8')).toBe(true);
|
|
57
56
|
});
|
|
58
57
|
|
|
59
58
|
it('manifest schema accepts a core.dispatch fan-out over a subChainRef worker', () => {
|
|
@@ -93,7 +92,7 @@ describe('chain-subchain-fanout §A: capability + manifest shape (RFC 0133, alwa
|
|
|
93
92
|
},
|
|
94
93
|
],
|
|
95
94
|
};
|
|
96
|
-
expect(validate(pack),
|
|
95
|
+
expect(validate(pack), req('openwop.it.chain-subchain-fanout.manifest-schema-accepts-a-core-dispatch-fan-out-over-a-subchainref-worker', 'manifest §subChains', `a subChainRef fan-out validates: ${ajv.errorsText(validate.errors)}`)).toBe(
|
|
97
96
|
true,
|
|
98
97
|
);
|
|
99
98
|
});
|
|
@@ -120,7 +119,7 @@ describe('chain-subchain-fanout §A: capability + manifest shape (RFC 0133, alwa
|
|
|
120
119
|
};
|
|
121
120
|
expect(
|
|
122
121
|
validate(pack),
|
|
123
|
-
|
|
122
|
+
req('openwop.it.chain-subchain-fanout.manifest-schema-rejects-a-concrete-config-workflowid-inside-a-fragment-the-1-2-n', 'manifest §config not-guard', 'a chain MUST NOT pin a concrete config.workflowId'),
|
|
124
123
|
).toBe(false);
|
|
125
124
|
});
|
|
126
125
|
});
|
|
@@ -134,6 +133,6 @@ describe('chain-subchain-fanout §B: host child fan-out (RFC 0133, capability-ga
|
|
|
134
133
|
// invariant `sub-chain-child-tenant-scoped` (child owned by parent's tenant).
|
|
135
134
|
// The from-chain response MUST carry the §1.3 contract: { workflowId,
|
|
136
135
|
// subChainWorkflowIds[] (tenant-scoped, deduped), nodeCount }.
|
|
137
|
-
expect(wcp?.subChains?.supported, 'host advertising subChains.supported implements child fan-out').toBe(true);
|
|
136
|
+
expect(wcp?.subChains?.supported, req('openwop.it.chain-subchain-fanout.fans-out-n-child-runs-over-a-subchainref-worker-returns-the-from-chain-contract', 'RFC 0133 §1.2', 'host advertising subChains.supported implements child fan-out')).toBe(true);
|
|
138
137
|
});
|
|
139
138
|
});
|
|
@@ -30,9 +30,7 @@ import {
|
|
|
30
30
|
mintChildWorkflowId,
|
|
31
31
|
type WorkflowChain,
|
|
32
32
|
} from '../lib/workflow-chain-expansion.js';
|
|
33
|
-
|
|
34
|
-
/** Server-free assertion-message helper (mirrors driver.describe without OPENWOP_BASE_URL). */
|
|
35
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
36
34
|
const SPEC = 'workflow-chain-packs.md §"Sub-chain composition (RFC 0133)"';
|
|
37
35
|
|
|
38
36
|
/** A leaf child chain — one plain node, no further composition. */
|
|
@@ -83,53 +81,53 @@ const ctx = (tenantId = 'tenant-a') => ({
|
|
|
83
81
|
describe('chain-subchain-sibling: co-registration (RFC 0133 §1, server-free)', () => {
|
|
84
82
|
it('co-registers the referenced sibling as its own workflow', () => {
|
|
85
83
|
const { children } = expandChainTree(PARENT, ctx());
|
|
86
|
-
expect(children.length,
|
|
87
|
-
expect(children[0]?.chainId,
|
|
84
|
+
expect(children.length, req('openwop.it.chain-subchain-sibling.co-registers-the-referenced-sibling-as-its-own-workflow', SPEC, '§1.3 step 2 — one distinct sibling ref ⇒ one co-registered child')).toBe(1);
|
|
85
|
+
expect(children[0]?.chainId, req('openwop.it.chain-subchain-sibling.co-registers-the-referenced-sibling-as-its-own-workflow', SPEC, 'child carries the composed chainId')).toBe('lesson-batch');
|
|
88
86
|
expect(
|
|
89
87
|
children[0]?.fragment.nodes.length,
|
|
90
|
-
|
|
88
|
+
req('openwop.it.chain-subchain-sibling.co-registers-the-referenced-sibling-as-its-own-workflow', SPEC, 'child is a fully expanded fragment (its own registered workflow)'),
|
|
91
89
|
).toBe(1);
|
|
92
90
|
});
|
|
93
91
|
|
|
94
92
|
it('mints a DETERMINISTIC, TENANT-SCOPED, version-pinned child id', () => {
|
|
95
93
|
const { children } = expandChainTree(PARENT, ctx());
|
|
96
94
|
const expected = mintChildWorkflowId('tenant-a', 'lesson-batch', '1.0.0');
|
|
97
|
-
expect(children[0]?.childWorkflowId,
|
|
95
|
+
expect(children[0]?.childWorkflowId, req('openwop.it.chain-subchain-sibling.mints-a-deterministic-tenant-scoped-version-pinned-child-id', SPEC, '§1.3 step 2 — deterministic (tenantId, childChainId, version) id')).toBe(
|
|
98
96
|
expected,
|
|
99
97
|
);
|
|
100
98
|
// Re-instantiating in the same tenant converges on the same id.
|
|
101
99
|
const again = expandChainTree(PARENT, ctx());
|
|
102
|
-
expect(again.children[0]?.childWorkflowId,
|
|
100
|
+
expect(again.children[0]?.childWorkflowId, req('openwop.it.chain-subchain-sibling.mints-a-deterministic-tenant-scoped-version-pinned-child-id', SPEC, 'repeat instantiation in-tenant converges')).toBe(expected);
|
|
103
101
|
});
|
|
104
102
|
|
|
105
103
|
it('scopes the child id per TENANT — two tenants NEVER collide on the global registry (isolation)', () => {
|
|
106
104
|
const a = expandChainTree(PARENT, ctx('tenant-a')).children[0]?.childWorkflowId;
|
|
107
105
|
const b = expandChainTree(PARENT, ctx('tenant-b')).children[0]?.childWorkflowId;
|
|
108
|
-
expect(a,
|
|
106
|
+
expect(a, req('openwop.it.chain-subchain-sibling.scopes-the-child-id-per-tenant-two-tenants-never-collide-on-the-global-registry', SPEC, 'tenant-a mints an id')).toBeTruthy();
|
|
109
107
|
expect(
|
|
110
108
|
a !== b,
|
|
111
|
-
|
|
109
|
+
req('openwop.it.chain-subchain-sibling.scopes-the-child-id-per-tenant-two-tenants-never-collide-on-the-global-registry', SPEC, '§1.3 SECURITY sub-chain-child-tenant-scoped — distinct tenants ⇒ distinct child ids, no cross-tenant collision'),
|
|
112
110
|
).toBe(true);
|
|
113
111
|
});
|
|
114
112
|
|
|
115
113
|
it('registers a child referenced twice exactly ONCE (dedup by deterministic id)', () => {
|
|
116
114
|
const { children } = expandChainTree(PARENT, ctx());
|
|
117
115
|
const ids = children.map((c) => c.childWorkflowId);
|
|
118
|
-
expect(new Set(ids).size,
|
|
119
|
-
expect(ids.length,
|
|
116
|
+
expect(new Set(ids).size, req('openwop.it.chain-subchain-sibling.registers-a-child-referenced-twice-exactly-once-dedup-by-deterministic-id', SPEC, '§1.3 step 2 — a shared child registers once')).toBe(ids.length);
|
|
117
|
+
expect(ids.length, req('openwop.it.chain-subchain-sibling.registers-a-child-referenced-twice-exactly-once-dedup-by-deterministic-id', SPEC, 'both build-0 + build-1 collapse to one child')).toBe(1);
|
|
120
118
|
});
|
|
121
119
|
|
|
122
120
|
it('rewrites config.subChainRef → the minted child config.workflowId', () => {
|
|
123
121
|
const { parent } = expandChainTree(PARENT, ctx());
|
|
124
122
|
const expected = mintChildWorkflowId('tenant-a', 'lesson-batch', '1.0.0');
|
|
125
123
|
const dispatchNodes = parent.nodes.filter((n) => n.typeId === 'core.subWorkflow');
|
|
126
|
-
expect(dispatchNodes.length,
|
|
124
|
+
expect(dispatchNodes.length, req('openwop.it.chain-subchain-sibling.rewrites-config-subchainref-the-minted-child-config-workflowid', SPEC, 'both dispatch nodes present')).toBe(2);
|
|
127
125
|
for (const n of dispatchNodes) {
|
|
128
126
|
const config = n.config as Record<string, unknown>;
|
|
129
|
-
expect(config['workflowId'],
|
|
127
|
+
expect(config['workflowId'], req('openwop.it.chain-subchain-sibling.rewrites-config-subchainref-the-minted-child-config-workflowid', SPEC, '§1.3 step 3 — subChainRef rewritten to minted child id')).toBe(expected);
|
|
130
128
|
expect(
|
|
131
129
|
'subChainRef' in config,
|
|
132
|
-
|
|
130
|
+
req('openwop.it.chain-subchain-sibling.rewrites-config-subchainref-the-minted-child-config-workflowid', SPEC, '§1.3 step 3 — transient subChainRef key dropped from the runtime config'),
|
|
133
131
|
).toBe(false);
|
|
134
132
|
}
|
|
135
133
|
});
|
|
@@ -140,7 +138,7 @@ describe('chain-subchain-sibling: co-registration (RFC 0133 §1, server-free)',
|
|
|
140
138
|
const referenced = parent.nodes
|
|
141
139
|
.filter((n) => n.typeId === 'core.subWorkflow')
|
|
142
140
|
.map((n) => (n.config as Record<string, unknown>)['workflowId']);
|
|
143
|
-
expect(referenced.every((id) => id === childId),
|
|
141
|
+
expect(referenced.every((id) => id === childId), req('openwop.it.chain-subchain-sibling.preserves-the-child-reference-at-runtime-concrete-workflowid-unlike-inline-mode', SPEC, 'parent HOLDS the co-registered child at runtime')).toBe(
|
|
144
142
|
true,
|
|
145
143
|
);
|
|
146
144
|
});
|
|
@@ -33,6 +33,8 @@ import { describe, it, expect } from 'vitest';
|
|
|
33
33
|
import { driver } from '../lib/driver.js';
|
|
34
34
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
35
35
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
36
|
+
import { req } from '../lib/requirement-ids.js';
|
|
37
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
36
38
|
|
|
37
39
|
const PROFILE = 'openwop-channel-presence';
|
|
38
40
|
const SUBJECT_REF = /^(user|agent):.+/;
|
|
@@ -47,37 +49,37 @@ describe('channel-presence-behavioral (RFC 0110 §Conformance)', () => {
|
|
|
47
49
|
|
|
48
50
|
const conversationId = 'conf:channel-presence:c1';
|
|
49
51
|
const res = await driver.post('/v1/host/sample/channel-presence/snapshot', { conversationId, member: 'user:conformance-runner' });
|
|
50
|
-
if (res.status === 404 || res.status === 405) return; // seam unwired — host witnesses via its own route test (dual-staging)
|
|
52
|
+
if (res.status === 404 || res.status === 405) return softSkip('blocked', 'precondition not met — `res.status === 404 || res.status === 405` returned early (seam unwired — host witnesses via its own route test (dual-staging)) (seam, prior step, or fixture unavailable)'); // seam unwired — host witnesses via its own route test (dual-staging)
|
|
51
53
|
|
|
52
54
|
expect(
|
|
53
55
|
res.status === 200,
|
|
54
|
-
|
|
56
|
+
req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal', 'the presence snapshot seam MUST return 200 for a member'),
|
|
55
57
|
).toBe(true);
|
|
56
58
|
const snap = res.json as PresenceSnapshot;
|
|
57
59
|
|
|
58
60
|
// MUST 1 — CLOSED shape: exactly conversationId / present / typing (no PII field rides).
|
|
59
61
|
expect(
|
|
60
62
|
Object.keys(snap).sort().join(','),
|
|
61
|
-
|
|
63
|
+
req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal', 'channel.presence carries ONLY conversationId/present/typing (no PII)'),
|
|
62
64
|
).toBe('conversationId,present,typing');
|
|
63
|
-
expect(snap.conversationId,
|
|
65
|
+
expect(snap.conversationId, req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal', 'the snapshot echoes the conversationId')).toBe(conversationId);
|
|
64
66
|
|
|
65
67
|
// MUST 2 — every ref is an opaque RFC 0041 subject ref (no PII).
|
|
66
68
|
for (const ref of [...snap.present, ...snap.typing]) {
|
|
67
69
|
expect(
|
|
68
70
|
SUBJECT_REF.test(ref),
|
|
69
|
-
|
|
71
|
+
req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal / RFC 0041', `present/typing ref "${ref}" MUST be an opaque user:/agent: subject ref`),
|
|
70
72
|
).toBe(true);
|
|
71
73
|
}
|
|
72
74
|
// typing is a subset of present.
|
|
73
75
|
for (const ref of snap.typing) {
|
|
74
|
-
expect(snap.present.includes(ref),
|
|
76
|
+
expect(snap.present.includes(ref), req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal', 'every typing ref MUST also be present')).toBe(true);
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
// MUST 3 — NON-VACUOUS: the snapshotting member is present.
|
|
78
80
|
expect(
|
|
79
81
|
snap.present.includes('user:conformance-runner'),
|
|
80
|
-
|
|
82
|
+
req('openwop.it.channel-presence-behavioral.a-presence-snapshot-is-the-closed-members-only-non-vacuous-channel-presence-shap', 'RFC 0110 §Proposal', 'the snapshotting member MUST appear in present (members-only, real)'),
|
|
81
83
|
).toBe(true);
|
|
82
84
|
});
|
|
83
85
|
});
|
|
@@ -34,8 +34,7 @@ import { join } from 'node:path';
|
|
|
34
34
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
35
35
|
import addFormats from 'ajv-formats';
|
|
36
36
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
37
|
-
|
|
38
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
37
|
+
import { req } from '../lib/requirement-ids.js';
|
|
39
38
|
|
|
40
39
|
function loadSchema(name: string): Record<string, unknown> {
|
|
41
40
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -49,26 +48,26 @@ describe('channel-presence-shape: the channel.presence payload (RFC 0110 §Propo
|
|
|
49
48
|
it('a conforming presence snapshot (present + typing) validates', () => {
|
|
50
49
|
expect(
|
|
51
50
|
presence({ conversationId: 'chan-eng', present: ['user:alice', 'agent:iris'], typing: ['user:alice'] }),
|
|
52
|
-
|
|
51
|
+
req('openwop.it.channel-presence-shape.a-conforming-presence-snapshot-present-typing-validates', 'RFC 0110 §Proposal', 'a conforming channel.presence payload MUST validate'),
|
|
53
52
|
).toBe(true);
|
|
54
53
|
});
|
|
55
54
|
|
|
56
55
|
it('typing is OPTIONAL — a snapshot with nobody typing validates', () => {
|
|
57
56
|
expect(
|
|
58
57
|
presence({ conversationId: 'chan-eng', present: ['user:alice'] }),
|
|
59
|
-
|
|
58
|
+
req('openwop.it.channel-presence-shape.typing-is-optional-a-snapshot-with-nobody-typing-validates', 'RFC 0110 §Proposal', 'typing is optional'),
|
|
60
59
|
).toBe(true);
|
|
61
60
|
});
|
|
62
61
|
|
|
63
62
|
it('conversationId and present are REQUIRED', () => {
|
|
64
|
-
expect(presence({ present: ['user:a'] }),
|
|
65
|
-
expect(presence({ conversationId: 'c' }),
|
|
63
|
+
expect(presence({ present: ['user:a'] }), req('openwop.it.channel-presence-shape.conversationid-and-present-are-required', 'RFC 0110 §Proposal', 'conversationId is required')).toBe(false);
|
|
64
|
+
expect(presence({ conversationId: 'c' }), req('openwop.it.channel-presence-shape.conversationid-and-present-are-required', 'RFC 0110 §Proposal', 'present is required')).toBe(false);
|
|
66
65
|
});
|
|
67
66
|
|
|
68
67
|
it('the payload is CLOSED — a non-subject-ref field (ip/location) MUST be rejected (the no-PII guard)', () => {
|
|
69
68
|
expect(
|
|
70
69
|
presence({ conversationId: 'c', present: ['user:a'], ip: '10.0.0.1' }),
|
|
71
|
-
|
|
70
|
+
req('openwop.it.channel-presence-shape.the-payload-is-closed-a-non-subject-ref-field-ip-location-must-be-rejected-the-n', 'RFC 0110 §Proposal', 'channel.presence MUST forbid extra keys — no PII rides the payload'),
|
|
72
71
|
).toBe(false);
|
|
73
72
|
});
|
|
74
73
|
});
|
|
@@ -77,7 +76,7 @@ describe('channel-presence-shape: event type + capability advertisement (RFC 011
|
|
|
77
76
|
it('run-event.schema.json enumerates `channel.presence` as a RunEvent type', () => {
|
|
78
77
|
const re = loadSchema('run-event.schema.json');
|
|
79
78
|
const enumVals = JSON.stringify(re);
|
|
80
|
-
expect(enumVals.includes('"channel.presence"'),
|
|
79
|
+
expect(enumVals.includes('"channel.presence"'), req('openwop.it.channel-presence-shape.run-event-schema-json-enumerates-channel-presence-as-a-runevent-type', 'RFC 0110 §Proposal', 'channel.presence MUST be a declared RunEvent type')).toBe(true);
|
|
81
80
|
});
|
|
82
81
|
|
|
83
82
|
it('capabilities.schema.json declares channelPresence with supported, closed', () => {
|
|
@@ -85,9 +84,9 @@ describe('channel-presence-shape: event type + capability advertisement (RFC 011
|
|
|
85
84
|
const block = (caps.properties as Record<string, Record<string, unknown>>).channelPresence as
|
|
86
85
|
| { properties?: Record<string, unknown>; required?: string[]; additionalProperties?: boolean }
|
|
87
86
|
| undefined;
|
|
88
|
-
expect(block,
|
|
89
|
-
expect(block?.properties?.supported,
|
|
90
|
-
expect(block?.required,
|
|
91
|
-
expect(block?.additionalProperties,
|
|
87
|
+
expect(block, req('openwop.it.channel-presence-shape.capabilities-schema-json-declares-channelpresence-with-supported-closed', 'RFC 0110 §Conformance', 'capabilities.channelPresence MUST be declared')).toBeDefined();
|
|
88
|
+
expect(block?.properties?.supported, req('openwop.it.channel-presence-shape.capabilities-schema-json-declares-channelpresence-with-supported-closed', 'RFC 0110 §Conformance', 'channelPresence.supported MUST be declared')).toBeDefined();
|
|
89
|
+
expect(block?.required, req('openwop.it.channel-presence-shape.capabilities-schema-json-declares-channelpresence-with-supported-closed', 'RFC 0110 §Conformance', 'supported MUST be required on the block')).toContain('supported');
|
|
90
|
+
expect(block?.additionalProperties, req('openwop.it.channel-presence-shape.capabilities-schema-json-declares-channelpresence-with-supported-closed', 'RFC 0110 §Conformance', 'the block MUST be closed')).toBe(false);
|
|
92
91
|
});
|
|
93
92
|
});
|
|
@@ -22,6 +22,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
22
22
|
import { driver } from '../lib/driver.js';
|
|
23
23
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
24
24
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
25
|
+
import { req } from '../lib/requirement-ids.js';
|
|
25
26
|
|
|
26
27
|
const WORKFLOW_ID = 'conformance-channel-ttl';
|
|
27
28
|
const SKIP_NO_FIXTURE = !isFixtureAdvertised(WORKFLOW_ID);
|
|
@@ -38,7 +39,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('channel-ttl: conformance-channel-ttl drops ent
|
|
|
38
39
|
const runId = (create.json as { runId: string }).runId;
|
|
39
40
|
|
|
40
41
|
const terminal = await pollUntilTerminal(runId);
|
|
41
|
-
expect(terminal.status,
|
|
42
|
+
expect(terminal.status, req('openwop.it.channel-ttl.after-the-post-ttl-write-the-channel-contains-exactly-one-entry-with-value-d',
|
|
42
43
|
'fixtures.md conformance-channel-ttl §Terminal status',
|
|
43
44
|
'fixture MUST reach terminal `completed`',
|
|
44
45
|
)).toBe('completed');
|
|
@@ -46,22 +47,22 @@ describe.skipIf(SKIP_NO_FIXTURE)('channel-ttl: conformance-channel-ttl drops ent
|
|
|
46
47
|
const variables = terminal.variables ?? {};
|
|
47
48
|
const events = variables.events as ChannelEntry[] | undefined;
|
|
48
49
|
|
|
49
|
-
expect(Array.isArray(events),
|
|
50
|
+
expect(Array.isArray(events), req('openwop.it.channel-ttl.after-the-post-ttl-write-the-channel-contains-exactly-one-entry-with-value-d',
|
|
50
51
|
'channels-and-reducers.md §append',
|
|
51
52
|
'channel state MUST be stored as an array of {value, _ts} entries',
|
|
52
53
|
)).toBe(true);
|
|
53
54
|
|
|
54
|
-
expect(events!.length,
|
|
55
|
+
expect(events!.length, req('openwop.it.channel-ttl.after-the-post-ttl-write-the-channel-contains-exactly-one-entry-with-value-d',
|
|
55
56
|
'channels-and-reducers.md §TTL — write-time filter',
|
|
56
57
|
'after the post-TTL write, exactly 1 entry MUST remain (the 3 priors aged out)',
|
|
57
58
|
)).toBe(1);
|
|
58
59
|
|
|
59
|
-
expect(events![0].value,
|
|
60
|
+
expect(events![0].value, req('openwop.it.channel-ttl.after-the-post-ttl-write-the-channel-contains-exactly-one-entry-with-value-d',
|
|
60
61
|
'fixtures.md conformance-channel-ttl §Topology',
|
|
61
62
|
'the surviving entry MUST be the post-delay write (value "d")',
|
|
62
63
|
)).toBe('d');
|
|
63
64
|
|
|
64
|
-
expect(typeof events![0]._ts,
|
|
65
|
+
expect(typeof events![0]._ts, req('openwop.it.channel-ttl.after-the-post-ttl-write-the-channel-contains-exactly-one-entry-with-value-d',
|
|
65
66
|
'channels-and-reducers.md §append entry shape',
|
|
66
67
|
'each channel entry MUST carry a numeric `_ts` write timestamp',
|
|
67
68
|
)).toBe('number');
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
import { describe, it, expect } from 'vitest';
|
|
30
|
-
import { driver } from '../lib/driver.js';
|
|
31
30
|
import { behaviorGate, behaviorGatePresent } from '../lib/behavior-gate.js';
|
|
32
31
|
import { readCardPacksCap, cardPacksSupported, executeCard } from '../lib/cardPacks.js';
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
33
33
|
|
|
34
34
|
const PROFILE = 'openwop-chat-card-packs';
|
|
35
35
|
|
|
@@ -40,13 +40,13 @@ describe('chat-card-pack-execution: prompt -> envelope -> typed artifact (RFC 00
|
|
|
40
40
|
if (!behaviorGatePresent(PROFILE, res)) return; // seam absent: skip default, FAIL strict
|
|
41
41
|
expect(
|
|
42
42
|
res.json['validated'],
|
|
43
|
-
|
|
43
|
+
req('openwop.it.chat-card-pack-execution.a-registered-card-produces-a-schema-validated-artifact', 'chat-card-packs.md "Card execution"', 'the host MUST validate the LLM output against the linked outputArtifactType schema'),
|
|
44
44
|
).toBe(true);
|
|
45
45
|
const evt = res.json['artifactCreated'] as { registered?: unknown } | undefined;
|
|
46
46
|
if (evt && 'registered' in evt) {
|
|
47
47
|
expect(
|
|
48
48
|
evt.registered,
|
|
49
|
-
|
|
49
|
+
req('openwop.it.chat-card-pack-execution.a-registered-card-produces-a-schema-validated-artifact', 'run-event-payloads.schema.json artifactCreated', 'a validated card output MUST emit artifact.created with registered:true'),
|
|
50
50
|
).toBe(true);
|
|
51
51
|
}
|
|
52
52
|
});
|
|
@@ -62,7 +62,7 @@ describe('chat-card-pack-execution: prompt -> envelope -> typed artifact (RFC 00
|
|
|
62
62
|
if (!behaviorGatePresent(PROFILE, res.json['contentTrust'])) return; // FAIL strict
|
|
63
63
|
expect(
|
|
64
64
|
res.json['contentTrust'],
|
|
65
|
-
|
|
65
|
+
req('openwop.it.chat-card-pack-execution.card-input-derived-prompt-content-propagates-contenttrust-untrusted-r2', 'chat-card-packs.md "Trust boundary" (R2)', 'a prompt segment derived from a card input MUST carry contentTrust:"untrusted"'),
|
|
66
66
|
).toBe('untrusted');
|
|
67
67
|
});
|
|
68
68
|
});
|
|
@@ -30,6 +30,7 @@ import Ajv2020 from 'ajv/dist/2020.js';
|
|
|
30
30
|
import addFormats from 'ajv-formats';
|
|
31
31
|
import type { ErrorObject } from 'ajv';
|
|
32
32
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
33
|
+
import { req } from '../lib/requirement-ids.js';
|
|
33
34
|
|
|
34
35
|
const SCHEMA_PATH = join(SCHEMAS_DIR, 'chat-card-pack-manifest.schema.json');
|
|
35
36
|
|
|
@@ -68,7 +69,7 @@ describe('category: chat-card-pack manifest validation', () => {
|
|
|
68
69
|
it('positive: a valid chat card pack manifest validates cleanly', () => {
|
|
69
70
|
expect(
|
|
70
71
|
validate(validManifest()),
|
|
71
|
-
`chat-card-packs.md §"Manifest format": a well-formed kind:"card" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}
|
|
72
|
+
req('openwop.it.chat-card-pack-manifest-validation.positive-a-valid-chat-card-pack-manifest-validates-cleanly', 'chat-card-packs.md', `chat-card-packs.md §"Manifest format": a well-formed kind:"card" manifest MUST validate. Errors: ${JSON.stringify(validate.errors)}`),
|
|
72
73
|
).toBe(true);
|
|
73
74
|
});
|
|
74
75
|
|
|
@@ -77,24 +78,24 @@ describe('category: chat-card-pack manifest validation', () => {
|
|
|
77
78
|
const errs = failsWith(manifest, 'additionalProperties');
|
|
78
79
|
expect(
|
|
79
80
|
errs.some((e) => (e.params as { additionalProperty?: string }).additionalProperty === 'artifactTypes'),
|
|
80
|
-
'chat-card-packs.md §"Pack kind": one kind per pack (additionalProperties:false)',
|
|
81
|
+
req('openwop.it.chat-card-pack-manifest-validation.negative-a-manifest-mixing-cards-and-artifacttypes-is-rejected', 'chat-card-packs.md', 'chat-card-packs.md §"Pack kind": one kind per pack (additionalProperties:false)'),
|
|
81
82
|
).toBe(true);
|
|
82
83
|
});
|
|
83
84
|
|
|
84
85
|
it('negative: an empty cards[] is rejected', () => {
|
|
85
|
-
expect(failsWith({ ...validManifest(), cards: [] }, 'minItems').length).toBeGreaterThan(0);
|
|
86
|
+
expect(failsWith({ ...validManifest(), cards: [] }, 'minItems').length, req('openwop.it.chat-card-pack-manifest-validation.negative-an-empty-cards-is-rejected', 'chat-card-packs.md', 'negative: an empty cards[] is rejected')).toBeGreaterThan(0);
|
|
86
87
|
});
|
|
87
88
|
|
|
88
89
|
it('negative: an uppercase-scope cardTypeId is rejected', () => {
|
|
89
90
|
const m = validManifest();
|
|
90
91
|
m.cards[0]!.cardTypeId = 'Vendor.Acme.Card';
|
|
91
|
-
expect(failsWith(m, 'pattern').length).toBeGreaterThan(0);
|
|
92
|
+
expect(failsWith(m, 'pattern').length, req('openwop.it.chat-card-pack-manifest-validation.negative-an-uppercase-scope-cardtypeid-is-rejected', 'chat-card-packs.md', 'negative: an uppercase-scope cardTypeId is rejected')).toBeGreaterThan(0);
|
|
92
93
|
});
|
|
93
94
|
|
|
94
95
|
it('negative: a card missing prompt is rejected', () => {
|
|
95
96
|
const m = validManifest();
|
|
96
97
|
delete (m.cards[0] as { prompt?: unknown }).prompt;
|
|
97
|
-
expect(failsWith(m, 'required').length).toBeGreaterThan(0);
|
|
98
|
+
expect(failsWith(m, 'required').length, req('openwop.it.chat-card-pack-manifest-validation.negative-a-card-missing-prompt-is-rejected', 'chat-card-packs.md', 'negative: a card missing prompt is rejected')).toBeGreaterThan(0);
|
|
98
99
|
});
|
|
99
100
|
|
|
100
101
|
it('negative: a non-portable inputs[].type (canvas-reference) is rejected', () => {
|
|
@@ -102,7 +103,7 @@ describe('category: chat-card-pack manifest validation', () => {
|
|
|
102
103
|
m.cards[0]!.inputs[0]!.type = 'canvas-reference';
|
|
103
104
|
expect(
|
|
104
105
|
failsWith(m, 'pattern').length,
|
|
105
|
-
'chat-card-packs.md §"Input fields": type is the closed portable enum OR a vendor.*/x- extension',
|
|
106
|
+
req('openwop.it.chat-card-pack-manifest-validation.negative-a-non-portable-inputs-type-canvas-reference-is-rejected', 'chat-card-packs.md', 'chat-card-packs.md §"Input fields": type is the closed portable enum OR a vendor.*/x- extension'),
|
|
106
107
|
).toBeGreaterThan(0);
|
|
107
108
|
});
|
|
108
109
|
|
|
@@ -111,7 +112,7 @@ describe('category: chat-card-pack manifest validation', () => {
|
|
|
111
112
|
m.cards[0]!.inputs[0]!.type = 'vendor.myndhyve.canvas-ref';
|
|
112
113
|
expect(
|
|
113
114
|
validate(m),
|
|
114
|
-
'chat-card-packs.md §"Input fields": a vendor.<org>.<kind> input type extension MUST validate (other hosts ignore it)',
|
|
115
|
+
req('openwop.it.chat-card-pack-manifest-validation.positive-a-vendor-prefixed-inputs-type-extension-is-tolerated', 'chat-card-packs.md', 'chat-card-packs.md §"Input fields": a vendor.<org>.<kind> input type extension MUST validate (other hosts ignore it)'),
|
|
115
116
|
).toBe(true);
|
|
116
117
|
});
|
|
117
118
|
|
|
@@ -121,7 +122,7 @@ describe('category: chat-card-pack manifest validation', () => {
|
|
|
121
122
|
m.cards[0]!.inputs[0]!.type = t;
|
|
122
123
|
expect(
|
|
123
124
|
validate(m),
|
|
124
|
-
`chat-card-packs.md §"Input fields": portable inputs[].type "${t}" MUST validate (G9 resolved 2026-05-27)
|
|
125
|
+
req('openwop.it.chat-card-pack-manifest-validation.positive-the-full-portable-inputs-type-subset-validates-g9-incl-multiselect-file', 'chat-card-packs.md', `chat-card-packs.md §"Input fields": portable inputs[].type "${t}" MUST validate (G9 resolved 2026-05-27)`),
|
|
125
126
|
).toBe(true);
|
|
126
127
|
}
|
|
127
128
|
});
|