@openwop/openwop-conformance 1.163.0 → 2.0.0-rc.1
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 +262 -14
- package/dist/lib/certification-bundle-v3.js +142 -0
- package/dist/lib/paths.js +25 -3
- package/dist/lib/requirement-ids.js +57 -4
- package/dist/lib/requirement-ledger.js +1 -0
- package/dist/lib/scenario-disposition.js +6 -1
- package/dist/lib/spec-coherence.js +13 -32
- package/dist/spec-artifacts.lock.json +5 -0
- package/package.json +11 -33
- package/requirements.json +22892 -11701
- package/scenario-majors.json +1493 -0
- package/schemas/CORPUS-STAMP.json +137 -5
- package/src/cli.ts +236 -19
- package/src/global-setup.ts +3 -2
- package/src/lib/certification-bundle-v3.ts +175 -0
- package/src/lib/corpus-stamp.ts +29 -1
- package/src/lib/driver.ts +9 -1
- package/src/lib/era2-seed.ts +197 -0
- package/src/lib/paths.ts +25 -3
- package/src/lib/requirement-ids.ts +54 -4
- package/src/lib/requirement-ledger.ts +7 -1
- package/src/lib/scenario-disposition.ts +6 -1
- package/src/lib/seams.ts +45 -0
- package/src/lib/spec-coherence.ts +15 -32
- package/src/lib/v2.ts +62 -0
- 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/v2-approver-enforced.test.ts +97 -0
- package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
- package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
- package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
- package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
- package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
- package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
- package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
- package/src/scenarios/v2-configurable-closed.test.ts +67 -0
- package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
- package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
- package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
- package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
- package/src/scenarios/v2-era-key.test.ts +86 -0
- package/src/scenarios/v2-error-registry.test.ts +89 -0
- package/src/scenarios/v2-event-type-closed.test.ts +97 -0
- package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
- package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
- package/src/scenarios/v2-header-scheme.test.ts +67 -0
- package/src/scenarios/v2-id-grammar.test.ts +77 -0
- package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
- package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
- package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
- package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
- package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
- package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
- package/src/scenarios/v2-min-client-version.test.ts +48 -0
- package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
- package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
- package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
- package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
- package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
- package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
- package/src/scenarios/v2-pack-isolation.test.ts +147 -0
- package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
- package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
- package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
- package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
- package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
- package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
- package/src/scenarios/v2-provider-conflict.test.ts +115 -0
- package/src/scenarios/v2-refresh-sla.test.ts +78 -0
- package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
- package/src/scenarios/v2-revocation-honored.test.ts +66 -0
- package/src/scenarios/v2-subject-link-record.test.ts +102 -0
- package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
- package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
- package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
- package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
- package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
- 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 +44 -6
- 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 -4160
- 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
|
@@ -29,8 +29,7 @@ import { readFileSync } from 'node:fs';
|
|
|
29
29
|
import { join } from 'node:path';
|
|
30
30
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
31
31
|
import { isAgentPlatformPartial, isAgentPlatformFull, agentPlatformStatus, agentPlatformSatisfiedTerms } from '../lib/profiles.js';
|
|
32
|
-
|
|
33
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
34
33
|
|
|
35
34
|
const CORE = {
|
|
36
35
|
protocolVersion: '1.0',
|
|
@@ -59,24 +58,24 @@ function floorPayload(extra: Record<string, unknown> = {}): Record<string, unkno
|
|
|
59
58
|
describe('agent-platform-profile: floor (partial) predicate (RFC 0085 §B, server-free)', () => {
|
|
60
59
|
it('a host meeting all floor flags is partial', () => {
|
|
61
60
|
const c = floorPayload();
|
|
62
|
-
expect(isAgentPlatformPartial(c),
|
|
63
|
-
expect(agentPlatformStatus(c)).toBe('partial');
|
|
61
|
+
expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.a-host-meeting-all-floor-flags-is-partial', 'agent-platform-profile.md §B', 'all floor flags ⇒ partial')).toBe(true);
|
|
62
|
+
expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-meeting-all-floor-flags-is-partial', 'RFC 0085', 'a host meeting all floor flags is partial')).toBe('partial');
|
|
64
63
|
});
|
|
65
64
|
|
|
66
65
|
it('missing a single floor flag (feedback) ⇒ none', () => {
|
|
67
66
|
const c = floorPayload({ feedback: { supported: false } });
|
|
68
|
-
expect(isAgentPlatformPartial(c),
|
|
69
|
-
expect(agentPlatformStatus(c)).toBe('none');
|
|
67
|
+
expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.missing-a-single-floor-flag-feedback-none', 'agent-platform-profile.md §B', 'a missing floor flag ⇒ not partial')).toBe(false);
|
|
68
|
+
expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.missing-a-single-floor-flag-feedback-none', 'RFC 0085', 'missing a single floor flag (feedback) ⇒ none')).toBe('none');
|
|
70
69
|
});
|
|
71
70
|
|
|
72
71
|
it('replay-OR-nondeterminism: no replay but declared nondeterminism still meets the floor', () => {
|
|
73
72
|
const c = floorPayload({ replay: { supported: false }, nondeterminismPolicy: { declared: true } });
|
|
74
|
-
expect(isAgentPlatformPartial(c),
|
|
73
|
+
expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.replay-or-nondeterminism-no-replay-but-declared-nondeterminism-still-meets-the-f', 'agent-platform-profile.md §B', 'declared nondeterminism satisfies the replay-OR term')).toBe(true);
|
|
75
74
|
});
|
|
76
75
|
|
|
77
76
|
it('neither replay nor declared nondeterminism ⇒ floor unmet', () => {
|
|
78
77
|
const c = floorPayload({ replay: { supported: false } });
|
|
79
|
-
expect(isAgentPlatformPartial(c),
|
|
78
|
+
expect(isAgentPlatformPartial(c), req('openwop.it.agent-platform-profile.neither-replay-nor-declared-nondeterminism-floor-unmet', 'agent-platform-profile.md §B', 'neither replay nor declared policy ⇒ not partial')).toBe(false);
|
|
80
79
|
});
|
|
81
80
|
});
|
|
82
81
|
|
|
@@ -92,8 +91,8 @@ describe('agent-platform-profile: full predicate + honest-advertisement (RFC 008
|
|
|
92
91
|
|
|
93
92
|
it('a host meeting floor + all governance terms is full', () => {
|
|
94
93
|
const c = floorPayload(fullExtra);
|
|
95
|
-
expect(isAgentPlatformFull(c),
|
|
96
|
-
expect(agentPlatformStatus(c)).toBe('full');
|
|
94
|
+
expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.a-host-meeting-floor-all-governance-terms-is-full', 'agent-platform-profile.md §B', 'floor + governance ⇒ full')).toBe(true);
|
|
95
|
+
expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-meeting-floor-all-governance-terms-is-full', 'RFC 0085', 'a host meeting floor + all governance terms is full')).toBe('full');
|
|
97
96
|
});
|
|
98
97
|
|
|
99
98
|
it('a host advertising governance flags but missing tenant installScope reports partial, not full', () => {
|
|
@@ -101,13 +100,13 @@ describe('agent-platform-profile: full predicate + honest-advertisement (RFC 008
|
|
|
101
100
|
...fullExtra,
|
|
102
101
|
agents: { manifestRuntime: { supported: true, installScope: 'host' }, liveRuntime: { supported: true } },
|
|
103
102
|
});
|
|
104
|
-
expect(isAgentPlatformFull(c),
|
|
105
|
-
expect(agentPlatformStatus(c)).toBe('partial');
|
|
103
|
+
expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.a-host-advertising-governance-flags-but-missing-tenant-installscope-reports-part', 'agent-platform-profile.md §D', 'missing a governance term ⇒ MUST NOT be full')).toBe(false);
|
|
104
|
+
expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-advertising-governance-flags-but-missing-tenant-installscope-reports-part', 'RFC 0085', 'a host advertising governance flags but missing tenant installScope reports partial, not full')).toBe('partial');
|
|
106
105
|
});
|
|
107
106
|
|
|
108
107
|
it('eval/deploy/budget are NOT hard full terms (a full host without them is still full)', () => {
|
|
109
108
|
const c = floorPayload(fullExtra); // no agents.evalSuite / agents.deployment / budget
|
|
110
|
-
expect(isAgentPlatformFull(c),
|
|
109
|
+
expect(isAgentPlatformFull(c), req('openwop.it.agent-platform-profile.eval-deploy-budget-are-not-hard-full-terms-a-full-host-without-them-is-still-ful', 'agent-platform-profile.md §B', 'platform-plus tier is advisory, not a hard full term')).toBe(true);
|
|
111
110
|
});
|
|
112
111
|
});
|
|
113
112
|
|
|
@@ -126,12 +125,12 @@ describe('agent-platform-profile: satisfiedTerms[] non-contiguous adoption (RFC
|
|
|
126
125
|
feedback: { supported: true },
|
|
127
126
|
replay: { supported: true },
|
|
128
127
|
} as Record<string, unknown>;
|
|
129
|
-
expect(agentPlatformStatus(c),
|
|
128
|
+
expect(agentPlatformStatus(c), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', 'agent-platform-profile.md §D', 'floor unmet ⇒ none')).toBe('none');
|
|
130
129
|
const terms = agentPlatformSatisfiedTerms(c);
|
|
131
|
-
expect(terms.includes('full:authorization'),
|
|
132
|
-
expect(terms.includes('full:memory.attribution')).toBe(true);
|
|
130
|
+
expect(terms.includes('full:authorization'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', '§D', 'a satisfied full term is reported even at none')).toBe(true);
|
|
131
|
+
expect(terms.includes('full:memory.attribution'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', 'RFC 0085', 'a host honoring full-tier terms but failing floor terms is status none yet has a non-empty satisfiedTerms[]')).toBe(true);
|
|
133
132
|
expect(terms.includes('full:tenant-installScope')).toBe(true);
|
|
134
|
-
expect(terms.includes('floor:agents.liveRuntime'),
|
|
133
|
+
expect(terms.includes('floor:agents.liveRuntime'), req('openwop.it.agent-platform-profile.a-host-honoring-full-tier-terms-but-failing-floor-terms-is-status-none-yet-has-a', '§D', 'an unmet floor term is NOT reported')).toBe(false);
|
|
135
134
|
expect(terms.length).toBeGreaterThan(0); // distinguishable from a 0/16 do-nothing host
|
|
136
135
|
});
|
|
137
136
|
|
|
@@ -144,7 +143,7 @@ describe('agent-platform-profile: satisfiedTerms[] non-contiguous adoption (RFC
|
|
|
144
143
|
triggerBridge: { supported: true },
|
|
145
144
|
httpClient: { safeFetch: { supported: true }, egressPolicy: { supported: true } },
|
|
146
145
|
});
|
|
147
|
-
expect(agentPlatformSatisfiedTerms(c).length,
|
|
146
|
+
expect(agentPlatformSatisfiedTerms(c).length, req('openwop.it.agent-platform-profile.a-full-host-reports-all-sixteen-terms-satisfied', '§D', 'a full host satisfies all 16 terms')).toBe(16);
|
|
148
147
|
});
|
|
149
148
|
});
|
|
150
149
|
|
|
@@ -153,7 +152,7 @@ describe('agent-platform-profile: capability shape (RFC 0085, server-free)', ()
|
|
|
153
152
|
const caps = JSON.parse(readFileSync(join(SCHEMAS_DIR, 'capabilities.schema.json'), 'utf8')) as { properties?: Record<string, { properties?: Record<string, unknown> }> };
|
|
154
153
|
expect(
|
|
155
154
|
caps.properties?.nondeterminismPolicy?.properties?.declared,
|
|
156
|
-
|
|
155
|
+
req('openwop.it.agent-platform-profile.capabilities-nondeterminismpolicy-declared-is-declared', 'agent-platform-profile.md §B', 'capabilities.nondeterminismPolicy.declared MUST be declared'),
|
|
157
156
|
).toBeDefined();
|
|
158
157
|
});
|
|
159
158
|
});
|
|
@@ -21,9 +21,9 @@ import { join } from 'node:path';
|
|
|
21
21
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
22
22
|
import addFormats from 'ajv-formats';
|
|
23
23
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
24
25
|
|
|
25
26
|
const BASE = 'https://openwop.dev/spec/v1/';
|
|
26
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
27
27
|
function loadSchema(name: string): Record<string, unknown> {
|
|
28
28
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
29
29
|
}
|
|
@@ -47,18 +47,18 @@ describe('agent-requires-capabilities-shape: AgentManifest.requiresCapabilities
|
|
|
47
47
|
it('a manifest WITH requiresCapabilities validates', () => {
|
|
48
48
|
expect(
|
|
49
49
|
manifest({ ...base, requiresCapabilities: ['host.workspace', 'aiProviders.toolCalling'] }),
|
|
50
|
-
|
|
50
|
+
req('openwop.it.agent-requires-capabilities-shape.a-manifest-with-requirescapabilities-validates', 'RFC 0092 §A', 'a manifest declaring requiresCapabilities MUST validate'),
|
|
51
51
|
).toBe(true);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it('a manifest WITHOUT it still validates (absent ⇒ no requirements)', () => {
|
|
55
|
-
expect(manifest(base),
|
|
55
|
+
expect(manifest(base), req('openwop.it.agent-requires-capabilities-shape.a-manifest-without-it-still-validates-absent-no-requirements', 'RFC 0092 §A', 'requiresCapabilities is optional')).toBe(true);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it('rejects a non-string-array value', () => {
|
|
59
59
|
expect(
|
|
60
60
|
manifest({ ...base, requiresCapabilities: [123] }),
|
|
61
|
-
|
|
61
|
+
req('openwop.it.agent-requires-capabilities-shape.rejects-a-non-string-array-value', 'RFC 0092 §A', 'requiresCapabilities items MUST be non-empty strings'),
|
|
62
62
|
).toBe(false);
|
|
63
63
|
});
|
|
64
64
|
});
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
import { describe, it, expect } from 'vitest';
|
|
37
|
-
import { driver } from '../lib/driver.js';
|
|
38
37
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
39
38
|
import { readRosterCap, listRoster, getRosterEntry, fireRosterPortfolio } from '../lib/agentRoster.js';
|
|
40
39
|
import {
|
|
@@ -43,6 +42,8 @@ import {
|
|
|
43
42
|
resetTestSeam,
|
|
44
43
|
type TestEvent,
|
|
45
44
|
} from '../lib/event-log-query.js';
|
|
45
|
+
import { req } from '../lib/requirement-ids.js';
|
|
46
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
46
47
|
|
|
47
48
|
const ROSTER_ID_RE = /^host:[a-z0-9][a-z0-9._-]*$/;
|
|
48
49
|
|
|
@@ -62,42 +63,42 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
62
63
|
const installScope = typeof cap?.installScope === 'string' ? cap.installScope : 'host';
|
|
63
64
|
expect(
|
|
64
65
|
installScope === 'host' || installScope === 'tenant',
|
|
65
|
-
|
|
66
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'RFC 0086 §F / RFC 0074 §B', "agents.roster.installScope (when present) MUST be 'host' or 'tenant'"),
|
|
66
67
|
).toBe(true);
|
|
67
68
|
|
|
68
69
|
// ---- Leg 1: normative read (black-box on any roster host) -------------
|
|
69
70
|
const body = await listRoster();
|
|
70
|
-
if (body === null) return; // host advertises roster but doesn't serve the read yet — soft-skip
|
|
71
|
+
if (body === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `body === null` returned early (host advertises roster but doesn\'t serve the read yet — soft-skip)'); // host advertises roster but doesn't serve the read yet — soft-skip
|
|
71
72
|
const roster = body.roster ?? [];
|
|
72
73
|
expect(
|
|
73
74
|
Array.isArray(roster),
|
|
74
|
-
|
|
75
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B', 'GET /v1/agents/roster MUST return a roster[] array'),
|
|
75
76
|
).toBe(true);
|
|
76
77
|
expect(
|
|
77
78
|
body.total === roster.length,
|
|
78
|
-
|
|
79
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster-response.schema.json', 'total MUST equal roster.length'),
|
|
79
80
|
).toBe(true);
|
|
80
81
|
for (const entry of roster) {
|
|
81
82
|
expect(
|
|
82
83
|
typeof entry.rosterId === 'string' && ROSTER_ID_RE.test(entry.rosterId),
|
|
83
|
-
|
|
84
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster-entry.schema.json', 'each entry MUST carry a host:<id> rosterId'),
|
|
84
85
|
).toBe(true);
|
|
85
86
|
expect(
|
|
86
87
|
typeof entry.persona === 'string' && entry.persona.length > 0,
|
|
87
|
-
|
|
88
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §A', 'each entry MUST carry a non-empty persona'),
|
|
88
89
|
).toBe(true);
|
|
89
90
|
expect(
|
|
90
91
|
typeof entry.agentRef?.agentId === 'string',
|
|
91
|
-
|
|
92
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §A', 'each entry MUST reference an agentRef.agentId'),
|
|
92
93
|
).toBe(true);
|
|
93
94
|
expect(
|
|
94
95
|
typeof entry.owner?.tenantId === 'string',
|
|
95
|
-
|
|
96
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B / RFC 0074', 'each entry MUST carry an owner.tenantId scope'),
|
|
96
97
|
).toBe(true);
|
|
97
98
|
// RFC 0082 §A XOR: an agentRef MUST NOT pin both version and channel.
|
|
98
99
|
expect(
|
|
99
100
|
!(entry.agentRef?.version !== undefined && entry.agentRef?.channel !== undefined),
|
|
100
|
-
|
|
101
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'RFC 0082 §A', 'agentRef MUST NOT carry both version and channel'),
|
|
101
102
|
).toBe(true);
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -111,7 +112,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
111
112
|
const init = firstOf(q.events, ['roster.run.initiated']);
|
|
112
113
|
expect(
|
|
113
114
|
init !== undefined,
|
|
114
|
-
|
|
115
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'a portfolio fire MUST emit roster.run.initiated'),
|
|
115
116
|
).toBe(true);
|
|
116
117
|
|
|
117
118
|
if (init) {
|
|
@@ -124,7 +125,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
124
125
|
if (firstAgent) {
|
|
125
126
|
expect(
|
|
126
127
|
init.sequence < firstAgent.sequence,
|
|
127
|
-
|
|
128
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'roster.run.initiated MUST precede any agent.* event in the run'),
|
|
128
129
|
).toBe(true);
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -133,18 +134,18 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
133
134
|
for (const key of ['rosterId', 'persona', 'agentId', 'workflowId', 'triggerSource']) {
|
|
134
135
|
expect(
|
|
135
136
|
typeof p[key] === 'string' && (p[key] as string).length > 0,
|
|
136
|
-
|
|
137
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'run-event-payloads.schema.json#rosterRunInitiated', `roster.run.initiated MUST carry ${key}`),
|
|
137
138
|
).toBe(true);
|
|
138
139
|
}
|
|
139
140
|
for (const forbidden of ['body', 'prompt', 'input', 'payload', 'apiKey', 'secret', 'credentials', 'token']) {
|
|
140
141
|
expect(
|
|
141
142
|
!(forbidden in p),
|
|
142
|
-
|
|
143
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'SECURITY roster-attribution-no-content', `roster.run.initiated MUST be content-free (no ${forbidden})`),
|
|
143
144
|
).toBe(true);
|
|
144
145
|
}
|
|
145
146
|
expect(
|
|
146
147
|
typeof p.rosterId === 'string' && ROSTER_ID_RE.test(p.rosterId),
|
|
147
|
-
|
|
148
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §C', 'roster.run.initiated.rosterId MUST be a host:<id> AgentRef id'),
|
|
148
149
|
).toBe(true);
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -158,7 +159,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
158
159
|
const p = q.events[0].payload;
|
|
159
160
|
expect(
|
|
160
161
|
typeof p.triggerSubscriptionId === 'string' && (p.triggerSubscriptionId as string).length > 0,
|
|
161
|
-
|
|
162
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §D / RFC 0083', 'a durable work-item fire MUST carry triggerSubscriptionId for trigger→run→roster ancestry'),
|
|
162
163
|
).toBe(true);
|
|
163
164
|
}
|
|
164
165
|
}
|
|
@@ -172,7 +173,7 @@ describe('agent-roster-attribution (RFC 0086 §B/§C)', () => {
|
|
|
172
173
|
const probe = await getRosterEntry(crossTenantId);
|
|
173
174
|
expect(
|
|
174
175
|
probe.status === 404,
|
|
175
|
-
|
|
176
|
+
req('openwop.it.agent-roster-attribution.serves-the-normative-roster-attributes-a-portfolio-fire-content-free-ordered-and', 'agent-roster.md §B / RFC 0074', "GET /v1/agents/roster/{id} for a cross-tenant id MUST 404 (no cross-tenant disclosure)"),
|
|
176
177
|
).toBe(true);
|
|
177
178
|
}
|
|
178
179
|
});
|
|
@@ -35,9 +35,7 @@ import { join } from 'node:path';
|
|
|
35
35
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
36
36
|
import addFormats from 'ajv-formats';
|
|
37
37
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
38
|
-
|
|
39
|
-
/** Server-free assertion-message helper. */
|
|
40
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
38
|
+
import { req } from '../lib/requirement-ids.js';
|
|
41
39
|
|
|
42
40
|
function loadSchema(name: string): Record<string, unknown> {
|
|
43
41
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -48,9 +46,9 @@ describe('agent-roster-shape: capability advertisement (RFC 0086, server-free)',
|
|
|
48
46
|
const caps = loadSchema('capabilities.schema.json');
|
|
49
47
|
const agents = (caps.properties as Record<string, { properties?: Record<string, { properties?: Record<string, unknown> }> }>).agents;
|
|
50
48
|
const roster = agents?.properties?.roster;
|
|
51
|
-
expect(roster,
|
|
49
|
+
expect(roster, req('openwop.it.agent-roster-shape.the-capabilities-schema-declares-agents-roster-with-its-sub-flags', 'capabilities.md §agents', 'agents.roster MUST be declared')).toBeDefined();
|
|
52
50
|
for (const flag of ['supported', 'installScope', 'portfolioTriggerSources']) {
|
|
53
|
-
expect(roster?.properties?.[flag],
|
|
51
|
+
expect(roster?.properties?.[flag], req('openwop.it.agent-roster-shape.the-capabilities-schema-declares-agents-roster-with-its-sub-flags', 'agent-roster.md §F', `agents.roster.${flag} MUST be declared`)).toBeDefined();
|
|
54
52
|
}
|
|
55
53
|
});
|
|
56
54
|
});
|
|
@@ -69,7 +67,7 @@ describe('agent-roster-shape: roster entry (RFC 0086 §A, server-free)', () => {
|
|
|
69
67
|
owner: { tenantId: 'acme', workspaceId: 'growth' },
|
|
70
68
|
enabled: true,
|
|
71
69
|
};
|
|
72
|
-
expect(entry(good),
|
|
70
|
+
expect(entry(good), req('openwop.it.agent-roster-shape.agentrosterentry-validates-a-conforming-entry', 'RFC 0086 §A', 'a conforming roster entry MUST validate')).toBe(true);
|
|
73
71
|
});
|
|
74
72
|
|
|
75
73
|
it('rejects a non-host: rosterId and an agentRef carrying both version and channel', () => {
|
|
@@ -79,12 +77,12 @@ describe('agent-roster-shape: roster entry (RFC 0086 §A, server-free)', () => {
|
|
|
79
77
|
agentRef: { agentId: 'core.openwop.agents.brief-writer' },
|
|
80
78
|
owner: { tenantId: 'acme' },
|
|
81
79
|
};
|
|
82
|
-
expect(entry({ ...base, rosterId: 'core.openwop.agents.sally' }),
|
|
80
|
+
expect(entry({ ...base, rosterId: 'core.openwop.agents.sally' }), req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0086 §A', 'a non-`host:` rosterId MUST be rejected')).toBe(false);
|
|
83
81
|
expect(
|
|
84
82
|
entry({ ...base, agentRef: { agentId: 'core.x.y.z', version: '1.0.0', channel: 'stable' } }),
|
|
85
|
-
|
|
83
|
+
req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0082 §A', 'an agentRef with BOTH version and channel MUST be rejected'),
|
|
86
84
|
).toBe(false);
|
|
87
|
-
expect(entry({ persona: 'x', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }),
|
|
85
|
+
expect(entry({ persona: 'x', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }), req('openwop.it.agent-roster-shape.rejects-a-non-host-rosterid-and-an-agentref-carrying-both-version-and-channel', 'RFC 0086 §A', 'a roster entry without rosterId MUST be rejected')).toBe(false);
|
|
88
86
|
});
|
|
89
87
|
});
|
|
90
88
|
|
|
@@ -96,23 +94,23 @@ describe('agent-roster-shape: roster.run.initiated event (RFC 0086 §C, server-f
|
|
|
96
94
|
const initiated = ajv.getSchema('payloads#/$defs/rosterRunInitiated');
|
|
97
95
|
|
|
98
96
|
it('roster.run.initiated validates a content-free attribution record and requires its ids', () => {
|
|
99
|
-
expect(initiated, 'the rosterRunInitiated $def MUST exist').toBeTruthy();
|
|
97
|
+
expect(initiated, req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086', 'the rosterRunInitiated $def MUST exist')).toBeTruthy();
|
|
100
98
|
expect(
|
|
101
99
|
initiated!({ rosterId: 'host:sally-marketing', persona: 'Sally', agentId: 'core.openwop.agents.brief-writer', workflowId: 'marketing-email-campaign', triggerSource: 'schedule' }),
|
|
102
|
-
|
|
100
|
+
req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086 §C', 'a conforming roster.run.initiated payload MUST validate'),
|
|
103
101
|
).toBe(true);
|
|
104
|
-
expect(initiated!({ rosterId: 'host:s', persona: 'S' }),
|
|
102
|
+
expect(initiated!({ rosterId: 'host:s', persona: 'S' }), req('openwop.it.agent-roster-shape.roster-run-initiated-validates-a-content-free-attribution-record-and-requires-it', 'RFC 0086 §C', 'roster.run.initiated without agentId/workflowId/triggerSource MUST be rejected')).toBe(false);
|
|
105
103
|
});
|
|
106
104
|
|
|
107
105
|
it('roster.run.initiated is content-free — a work-item body and a prompt are rejected (roster-attribution-no-content)', () => {
|
|
108
106
|
const base = { rosterId: 'host:s', persona: 'S', agentId: 'a.b.c.d', workflowId: 'wf', triggerSource: 'queue' };
|
|
109
107
|
expect(
|
|
110
108
|
initiated!({ ...base, body: 'the card description' }),
|
|
111
|
-
|
|
109
|
+
req('openwop.it.agent-roster-shape.roster-run-initiated-is-content-free-a-work-item-body-and-a-prompt-are-rejected', 'SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry the work-item body'),
|
|
112
110
|
).toBe(false);
|
|
113
111
|
expect(
|
|
114
112
|
initiated!({ ...base, prompt: 'system: …' }),
|
|
115
|
-
|
|
113
|
+
req('openwop.it.agent-roster-shape.roster-run-initiated-is-content-free-a-work-item-body-and-a-prompt-are-rejected', 'SECURITY invariant roster-attribution-no-content', 'roster.run.initiated MUST NOT carry prompt content'),
|
|
116
114
|
).toBe(false);
|
|
117
115
|
});
|
|
118
116
|
});
|
|
@@ -121,13 +119,13 @@ describe('agent-roster-shape: inventory projection + enum (RFC 0086 §B, server-
|
|
|
121
119
|
it('AgentInventoryEntry carries the additive optional roster portfolio projection', () => {
|
|
122
120
|
const inv = loadSchema('agent-inventory-response.schema.json');
|
|
123
121
|
const entry = (inv.$defs as Record<string, { properties?: Record<string, unknown> }>).AgentInventoryEntry?.properties ?? {};
|
|
124
|
-
expect(entry.roster,
|
|
122
|
+
expect(entry.roster, req('openwop.it.agent-roster-shape.agentinventoryentry-carries-the-additive-optional-roster-portfolio-projection', 'RFC 0086 §B', 'AgentInventoryEntry.roster (the portfolio projection) MUST be declared')).toBeDefined();
|
|
125
123
|
});
|
|
126
124
|
|
|
127
125
|
it('roster.run.initiated appears in the RunEventType enum', () => {
|
|
128
126
|
const runEvent = loadSchema('run-event.schema.json');
|
|
129
127
|
const enumVals = (runEvent.$defs as Record<string, { enum?: string[] }>).RunEventType?.enum ?? [];
|
|
130
|
-
expect(enumVals).toContain('roster.run.initiated');
|
|
128
|
+
expect(enumVals, req('openwop.it.agent-roster-shape.roster-run-initiated-appears-in-the-runeventtype-enum', 'RFC 0086', 'roster.run.initiated appears in the RunEventType enum')).toContain('roster.run.initiated');
|
|
131
129
|
});
|
|
132
130
|
|
|
133
131
|
it('the GET /v1/agents/roster response schema validates + rejects extras (RFC 0086 §B)', () => {
|
|
@@ -139,8 +137,8 @@ describe('agent-roster-shape: inventory projection + enum (RFC 0086 §B, server-
|
|
|
139
137
|
roster: [{ rosterId: 'host:sally', persona: 'Sally', agentRef: { agentId: 'core.x.y.z' }, owner: { tenantId: 'acme' } }],
|
|
140
138
|
total: 1,
|
|
141
139
|
};
|
|
142
|
-
expect(resp(good),
|
|
143
|
-
expect(resp({ ...good, unexpected: true }),
|
|
144
|
-
expect(resp({ roster: [] }),
|
|
140
|
+
expect(resp(good), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'a conforming GET /v1/agents/roster response MUST validate')).toBe(true);
|
|
141
|
+
expect(resp({ ...good, unexpected: true }), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'an extra top-level property MUST be rejected')).toBe(false);
|
|
142
|
+
expect(resp({ roster: [] }), req('openwop.it.agent-roster-shape.the-get-v1-agents-roster-response-schema-validates-rejects-extras-rfc-0086-b', 'RFC 0086 §B', 'the response MUST require `total`')).toBe(false);
|
|
145
143
|
});
|
|
146
144
|
});
|
|
@@ -25,9 +25,9 @@ import { join } from 'node:path';
|
|
|
25
25
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
26
26
|
import addFormats from 'ajv-formats';
|
|
27
27
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
28
|
+
import { req } from '../lib/requirement-ids.js';
|
|
28
29
|
|
|
29
30
|
const BASE = 'https://openwop.dev/spec/v1/';
|
|
30
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
31
31
|
function loadSchema(name: string): Record<string, unknown> {
|
|
32
32
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
33
33
|
}
|
|
@@ -52,21 +52,21 @@ describe('agent-verifier-shape: agent.verified payload (RFC 0090 §A, server-fre
|
|
|
52
52
|
const verified = ajv.getSchema(`${BASE}run-event-payloads.schema.json#/$defs/agentVerified`);
|
|
53
53
|
|
|
54
54
|
it('a conforming content-free verdict validates', () => {
|
|
55
|
-
expect(verified, 'the agentVerified $def MUST exist').toBeTruthy();
|
|
55
|
+
expect(verified, req('openwop.it.agent-verifier-shape.a-conforming-content-free-verdict-validates', 'RFC 0090', 'the agentVerified $def MUST exist')).toBeTruthy();
|
|
56
56
|
expect(
|
|
57
57
|
verified!({ agentId: 'core.openwop.verifier', target: 'evt-42', verdict: 'pass', criteria: ['grounded'], confidence: 0.9 }),
|
|
58
|
-
|
|
58
|
+
req('openwop.it.agent-verifier-shape.a-conforming-content-free-verdict-validates', 'RFC 0090 §A', 'a conforming agent.verified payload MUST validate'),
|
|
59
59
|
).toBe(true);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
it('rejects an out-of-enum verdict', () => {
|
|
63
|
-
expect(verified!({ agentId: 'c', target: 'e', verdict: 'ok' }),
|
|
63
|
+
expect(verified!({ agentId: 'c', target: 'e', verdict: 'ok' }), req('openwop.it.agent-verifier-shape.rejects-an-out-of-enum-verdict', 'RFC 0090 §A', 'verdict MUST be pass|fail|revise')).toBe(false);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
it('rejects a content-carrying payload (verifier-no-content-leak)', () => {
|
|
67
67
|
expect(
|
|
68
68
|
verified!({ agentId: 'c', target: 'e', verdict: 'fail', result: 'the secret answer' }),
|
|
69
|
-
|
|
69
|
+
req('openwop.it.agent-verifier-shape.rejects-a-content-carrying-payload-verifier-no-content-leak', 'RFC 0090 §SECURITY', 'agent.verified MUST be content-free (additionalProperties:false)'),
|
|
70
70
|
).toBe(false);
|
|
71
71
|
});
|
|
72
72
|
});
|
|
@@ -78,7 +78,7 @@ describe('agent-verifier-shape: RunEventType + terminate + capability (RFC 0090)
|
|
|
78
78
|
const runEvent = loadSchema('run-event.schema.json') as { $defs?: { RunEventType?: { enum?: string[] } } };
|
|
79
79
|
expect(
|
|
80
80
|
runEvent.$defs?.RunEventType?.enum?.includes('agent.verified'),
|
|
81
|
-
|
|
81
|
+
req('openwop.it.agent-verifier-shape.agent-verified-is-registered-in-the-runeventtype-enum', 'RFC 0090 §A', 'agent.verified MUST appear in the RunEventType enum'),
|
|
82
82
|
).toBe(true);
|
|
83
83
|
});
|
|
84
84
|
|
|
@@ -86,21 +86,21 @@ describe('agent-verifier-shape: RunEventType + terminate + capability (RFC 0090)
|
|
|
86
86
|
const decision = ajv.getSchema(`${BASE}orchestrator-decision.schema.json`)!;
|
|
87
87
|
expect(
|
|
88
88
|
decision({ kind: 'terminate', reason: 'goal-reached', successCriteria: [{ key: 'goal-answered', met: true }] }),
|
|
89
|
-
|
|
89
|
+
req('openwop.it.agent-verifier-shape.the-terminate-decision-accepts-the-additive-successcriteria', 'RFC 0090 §C', 'terminate MUST accept successCriteria[{key,met}]'),
|
|
90
90
|
).toBe(true);
|
|
91
91
|
expect(
|
|
92
92
|
decision({ kind: 'terminate', successCriteria: [{ key: 'x' }] }),
|
|
93
|
-
|
|
93
|
+
req('openwop.it.agent-verifier-shape.the-terminate-decision-accepts-the-additive-successcriteria', 'RFC 0090 §C', 'a successCriteria entry MUST require both key and met'),
|
|
94
94
|
).toBe(false);
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('capabilities accepts executionModel.version 6 + verifier sub-block', () => {
|
|
98
98
|
const execModel = ajv.getSchema(`${BASE}capabilities.schema.json#/properties/multiAgent/properties/executionModel`);
|
|
99
|
-
expect(execModel, 'the executionModel sub-schema MUST exist').toBeTruthy();
|
|
99
|
+
expect(execModel, req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090', 'the executionModel sub-schema MUST exist')).toBeTruthy();
|
|
100
100
|
expect(
|
|
101
101
|
execModel!({ supported: true, version: 6, verifier: { supported: true, gating: true } }),
|
|
102
|
-
|
|
102
|
+
req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090 §D', 'version:6 + verifier{supported,gating} MUST validate'),
|
|
103
103
|
).toBe(true);
|
|
104
|
-
expect(execModel!({ supported: true, version: 7 }),
|
|
104
|
+
expect(execModel!({ supported: true, version: 7 }), req('openwop.it.agent-verifier-shape.capabilities-accepts-executionmodel-version-6-verifier-sub-block', 'RFC 0090 §D', 'version above the ceiling MUST be rejected')).toBe(false);
|
|
105
105
|
});
|
|
106
106
|
});
|
|
@@ -21,6 +21,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
21
21
|
import { driver } from '../lib/driver.js';
|
|
22
22
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
23
23
|
import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
|
|
24
|
+
import { req } from '../lib/requirement-ids.js';
|
|
24
25
|
|
|
25
26
|
const FIXTURE = 'conformance-agent-low-confidence';
|
|
26
27
|
const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -51,7 +52,7 @@ describe.skipIf(SKIP)('agentConfidenceEscalation: confidence < threshold → low
|
|
|
51
52
|
const lowConfSuspend = list.find(
|
|
52
53
|
(e) => e.type === 'node.suspended' && e.payload?.reason === 'low-confidence',
|
|
53
54
|
);
|
|
54
|
-
expect(lowConfSuspend, 'CP-1: low-confidence agent.decided MUST emit node.suspended { reason: low-confidence }').toBeDefined();
|
|
55
|
+
expect(lowConfSuspend, req('openwop.it.agentConfidenceEscalation.low-confidence-agent-decided-suspends-with-reason-low-confidence-and-run-reaches', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'CP-1: low-confidence agent.decided MUST emit node.suspended { reason: low-confidence }')).toBeDefined();
|
|
55
56
|
|
|
56
57
|
const payload = lowConfSuspend!.payload as Record<string, unknown>;
|
|
57
58
|
expect(typeof payload.agentId).toBe('string');
|
|
@@ -20,6 +20,7 @@ import { driver } from '../lib/driver.js';
|
|
|
20
20
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
21
21
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
22
22
|
import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
|
|
23
|
+
import { req } from '../lib/requirement-ids.js';
|
|
23
24
|
|
|
24
25
|
const FIXTURE = 'conformance-agent-memory-cross-tenant';
|
|
25
26
|
const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -50,13 +51,13 @@ describe.skipIf(SKIP)('agentMemoryCrossTenantIsolation: CTI-1 invariant', () =>
|
|
|
50
51
|
const ownerProbe = vars.ownerProbe;
|
|
51
52
|
expect(
|
|
52
53
|
Array.isArray(ownerProbe) && ownerProbe.length > 0,
|
|
53
|
-
|
|
54
|
+
req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1 / fixtures.md conformance-agent-memory-cross-tenant', 'ownerProbe MUST be a NON-EMPTY array — the run\'s own tenant can read the entry it just wrote (positive control; an unset or empty ownerProbe means the probe never ran)'),
|
|
54
55
|
).toBe(true);
|
|
55
56
|
const ownerEntryId = vars.ownerEntryId;
|
|
56
57
|
if (typeof ownerEntryId === 'string' && ownerEntryId.length > 0) {
|
|
57
58
|
expect(
|
|
58
59
|
(ownerProbe as Array<{ id?: unknown }>).some((e) => e && typeof e === 'object' && e.id === ownerEntryId),
|
|
59
|
-
|
|
60
|
+
req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', `ownerProbe MUST contain the entry the host reports writing (ownerEntryId=${ownerEntryId})`),
|
|
60
61
|
).toBe(true);
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -65,12 +66,12 @@ describe.skipIf(SKIP)('agentMemoryCrossTenantIsolation: CTI-1 invariant', () =>
|
|
|
65
66
|
const crossTenantResult = vars.crossTenantProbe;
|
|
66
67
|
expect(
|
|
67
68
|
crossTenantResult !== undefined,
|
|
68
|
-
|
|
69
|
+
req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'crossTenantProbe MUST be set — an unset variable means the cross-tenant probe was never issued, which proves nothing'),
|
|
69
70
|
).toBe(true);
|
|
70
71
|
if (Array.isArray(crossTenantResult)) {
|
|
71
|
-
expect(crossTenantResult.length,
|
|
72
|
+
expect(crossTenantResult.length, req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'a cross-tenant memoryRef probe MUST return [] — no entries of another tenant')).toBe(0);
|
|
72
73
|
} else {
|
|
73
|
-
expect(crossTenantResult,
|
|
74
|
+
expect(crossTenantResult, req('openwop.it.agentMemoryCrossTenantIsolation.cross-tenant-memoryref-returns-empty-null-no-leak-across-tenant-boundary', 'agent-memory.md §CTI-1', 'a non-array cross-tenant probe result MUST be null')).toBeNull();
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
});
|
|
@@ -20,6 +20,7 @@ import { driver } from '../lib/driver.js';
|
|
|
20
20
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
21
21
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
22
22
|
import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
|
|
23
|
+
import { req } from '../lib/requirement-ids.js';
|
|
23
24
|
|
|
24
25
|
const FIXTURE = 'conformance-agent-memory-redaction';
|
|
25
26
|
const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -27,7 +28,7 @@ const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
|
27
28
|
describe.skipIf(SKIP)('agentMemoryRedactionContract: SR-1 invariant', () => {
|
|
28
29
|
it('BYOK plaintext is redacted to [REDACTED:<secretId>] at the read surface', async () => {
|
|
29
30
|
const create = await driver.post('/v1/runs', { workflowId: FIXTURE });
|
|
30
|
-
expect(create.status).toBe(201);
|
|
31
|
+
expect(create.status, req('openwop.it.agentMemoryRedactionContract.byok-plaintext-is-redacted-to-redacted-secretid-at-the-read-surface', 'RFCS/0004-memory-layer.md', 'BYOK plaintext is redacted to [REDACTED:<secretId>] at the read surface')).toBe(201);
|
|
31
32
|
const runId = (create.json as { runId: string }).runId;
|
|
32
33
|
|
|
33
34
|
const terminal = await pollUntilTerminal(runId);
|
|
@@ -19,6 +19,7 @@ import { driver } from '../lib/driver.js';
|
|
|
19
19
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
20
20
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
21
21
|
import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
|
|
22
|
+
import { req } from '../lib/requirement-ids.js';
|
|
22
23
|
|
|
23
24
|
const FIXTURE = 'conformance-agent-memory-roundtrip';
|
|
24
25
|
const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -26,7 +27,7 @@ const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
|
26
27
|
describe.skipIf(SKIP)('agentMemoryRoundTrip: write → read via MemoryAdapter', () => {
|
|
27
28
|
it('memory entries written during a run are readable via the resolved memoryRef', async () => {
|
|
28
29
|
const create = await driver.post('/v1/runs', { workflowId: FIXTURE });
|
|
29
|
-
expect(create.status).toBe(201);
|
|
30
|
+
expect(create.status, req('openwop.it.agentMemoryRoundTrip.memory-entries-written-during-a-run-are-readable-via-the-resolved-memoryref', 'RFCS/0004-memory-layer.md', 'memory entries written during a run are readable via the resolved memoryRef')).toBe(201);
|
|
30
31
|
const runId = (create.json as { runId: string }).runId;
|
|
31
32
|
|
|
32
33
|
const terminal = await pollUntilTerminal(runId);
|
|
@@ -18,6 +18,7 @@ import { driver } from '../lib/driver.js';
|
|
|
18
18
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
19
19
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
20
20
|
import { hasLongTermMemory } from '../lib/multi-agent-capabilities.js';
|
|
21
|
+
import { req } from '../lib/requirement-ids.js';
|
|
21
22
|
|
|
22
23
|
const FIXTURE = 'conformance-agent-memory-ttl';
|
|
23
24
|
const SKIP = !hasLongTermMemory() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -52,15 +53,15 @@ describe.skipIf(SKIP)('agentMemoryTtlExpiry: expired entries are excluded from l
|
|
|
52
53
|
const expiredId = body.variables?.expiredId;
|
|
53
54
|
expect(
|
|
54
55
|
typeof freshId === 'string' && freshId.length > 0 && typeof expiredId === 'string' && expiredId.length > 0,
|
|
55
|
-
|
|
56
|
+
req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'fixtures.md conformance-agent-memory-ttl', 'the host MUST land freshId and expiredId (the ids of the two entries it wrote) so the list can be checked on both sides'),
|
|
56
57
|
).toBe(true);
|
|
57
58
|
expect(
|
|
58
59
|
listResult!.some((e) => e.id === freshId),
|
|
59
|
-
|
|
60
|
+
req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'agent-memory.md §TTL', `list() MUST include the fresh entry (freshId=${String(freshId)})`),
|
|
60
61
|
).toBe(true);
|
|
61
62
|
expect(
|
|
62
63
|
listResult!.some((e) => e.id === expiredId),
|
|
63
|
-
|
|
64
|
+
req('openwop.it.agentMemoryTtlExpiry.list-excludes-entries-whose-expiresat-is-in-the-past', 'agent-memory.md §TTL', `list() MUST NOT include the expired entry (expiredId=${String(expiredId)})`),
|
|
64
65
|
).toBe(false);
|
|
65
66
|
});
|
|
66
67
|
});
|
|
@@ -23,6 +23,7 @@ import { driver } from '../lib/driver.js';
|
|
|
23
23
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
24
24
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
25
25
|
import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
27
|
|
|
27
28
|
const FIXTURE = 'conformance-message-reducer';
|
|
28
29
|
const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -44,7 +45,7 @@ describe.skipIf(SKIP)('agentMessageReducer: message reducer idempotency + append
|
|
|
44
45
|
// fixture convention is `conversation` or `messages`).
|
|
45
46
|
const channelEntries = Object.entries(body.channels ?? {});
|
|
46
47
|
const messageChannel = channelEntries.find(([, val]) => Array.isArray(val));
|
|
47
|
-
expect(messageChannel, 'fixture MUST expose at least one message-reducer channel').toBeDefined();
|
|
48
|
+
expect(messageChannel, req('openwop.it.agentMessageReducer.duplicate-messageid-emissions-fold-to-a-single-channel-entry', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'fixture MUST expose at least one message-reducer channel')).toBeDefined();
|
|
48
49
|
|
|
49
50
|
const messages = messageChannel![1] as Array<{ messageId?: string }>;
|
|
50
51
|
const messageIds = messages
|
|
@@ -23,6 +23,7 @@ import { driver } from '../lib/driver.js';
|
|
|
23
23
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
24
24
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
25
25
|
import { isAgentSupported } from '../lib/multi-agent-capabilities.js';
|
|
26
|
+
import { req } from '../lib/requirement-ids.js';
|
|
26
27
|
|
|
27
28
|
const FIXTURE = 'conformance-agent-identity';
|
|
28
29
|
const SKIP = !isAgentSupported() || !isFixtureAdvertised(FIXTURE);
|
|
@@ -44,7 +45,7 @@ describe.skipIf(SKIP)('agentMetadata: RunSnapshot.agent + runOrchestrator wire-s
|
|
|
44
45
|
const hasOrch = body.runOrchestrator && typeof body.runOrchestrator.agentId === 'string';
|
|
45
46
|
expect(
|
|
46
47
|
hasAgent || hasOrch,
|
|
47
|
-
'fixture-runs MUST populate at least one of RunSnapshot.agent / runOrchestrator',
|
|
48
|
+
req('openwop.it.agentMetadata.host-populates-agentref-shaped-agent-identity-on-runsnapshot', 'RFCS/0002-agent-identity-and-reasoning-events.md', 'fixture-runs MUST populate at least one of RunSnapshot.agent / runOrchestrator'),
|
|
48
49
|
).toBe(true);
|
|
49
50
|
|
|
50
51
|
if (hasAgent) {
|