@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
|
@@ -15,34 +15,35 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { describe, it, expect } from 'vitest';
|
|
18
|
-
import { driver } from '../lib/driver.js';
|
|
19
18
|
import { readManifestRuntimeCap, listManifestAgents, dispatchAgent } from '../lib/agentRuntime.js';
|
|
19
|
+
import { req } from '../lib/requirement-ids.js';
|
|
20
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
20
21
|
|
|
21
22
|
describe('agent-manifest-runtime (RFC 0070)', () => {
|
|
22
23
|
it('lists installed manifest agents and dispatches one with attributed events', async () => {
|
|
23
24
|
const cap = await readManifestRuntimeCap();
|
|
24
|
-
if (cap?.supported !== true) return; // unadvertised — soft-skip
|
|
25
|
+
if (cap?.supported !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.supported !== true` returned early (unadvertised — soft-skip)'); // unadvertised — soft-skip
|
|
25
26
|
|
|
26
27
|
// RFC 0074 §B — installScope governs how GET /v1/agents is scoped.
|
|
27
28
|
const installScope = typeof cap.installScope === 'string' ? cap.installScope : 'host';
|
|
28
29
|
expect(
|
|
29
30
|
installScope === 'host' || installScope === 'tenant',
|
|
30
|
-
|
|
31
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0074 §B', "agents.manifestRuntime.installScope (when present) MUST be 'host' or 'tenant'"),
|
|
31
32
|
).toBe(true);
|
|
32
33
|
|
|
33
34
|
const inv = await listManifestAgents();
|
|
34
|
-
if (inv === null) return; // seam absent — soft-skip
|
|
35
|
+
if (inv === null) return softSkip('blocked', 'precondition not met — `inv === null` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
|
|
35
36
|
const agents = inv.agents ?? [];
|
|
36
37
|
expect(
|
|
37
38
|
Array.isArray(agents),
|
|
38
|
-
|
|
39
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0072 §A', 'GET /v1/agents MUST return an agents[] array'),
|
|
39
40
|
).toBe(true);
|
|
40
41
|
|
|
41
42
|
if (installScope === 'host') {
|
|
42
43
|
// Host-global inventory (RFC 0072 §A): a manifestRuntime host MUST surface ≥1 agent.
|
|
43
44
|
expect(
|
|
44
45
|
agents.length > 0,
|
|
45
|
-
|
|
46
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0070 §A', 'a host-scoped manifestRuntime host MUST surface ≥1 installed manifest agent'),
|
|
46
47
|
).toBe(true);
|
|
47
48
|
} else if (agents.length === 0) {
|
|
48
49
|
// RFC 0074 §A + Unresolved Q3 — tenant-scoped: GET /v1/agents is the
|
|
@@ -51,28 +52,28 @@ describe('agent-manifest-runtime (RFC 0070)', () => {
|
|
|
51
52
|
// Empty is conformant; the cross-tenant no-disclosure 404 is covered by the
|
|
52
53
|
// owner-triple isolation harness (RFC 0048/0059), not re-probed here. Nothing
|
|
53
54
|
// to dispatch.
|
|
54
|
-
return;
|
|
55
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `agents.length === 0` returned early (RFC 0074 §A + Unresolved Q3 — tenant-scoped: GET /v1/agents is the authenticated principal\'s workspace set, which MAY be e…');
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
const agentId = agents[0]?.agentId;
|
|
58
|
-
if (typeof agentId !== 'string') return;
|
|
59
|
+
if (typeof agentId !== 'string') return softSkip('blocked', 'precondition not met — `typeof agentId !== \'string\'` returned early (seam, prior step, or fixture unavailable)');
|
|
59
60
|
|
|
60
61
|
// Opaque-payload dispatch (validateHandoff:false) so the assertion is
|
|
61
62
|
// independent of the chosen agent's handoff schema.
|
|
62
63
|
const res = await dispatchAgent(agentId, { task: {}, validateHandoff: false, availableTools: [] });
|
|
63
|
-
if (res === null) return; // seam absent — soft-skip
|
|
64
|
+
if (res === null) return softSkip('blocked', 'precondition not met — `res === null` returned early (seam absent — soft-skip) (seam, prior step, or fixture unavailable)'); // seam absent — soft-skip
|
|
64
65
|
expect(
|
|
65
66
|
res.status === 'completed' || res.status === 'escalated',
|
|
66
|
-
|
|
67
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0070', 'dispatch MUST resolve to a terminal status (completed | escalated)'),
|
|
67
68
|
).toBe(true);
|
|
68
69
|
const types = (res.events ?? []).map((e) => e.type);
|
|
69
70
|
expect(
|
|
70
71
|
types.includes('agent.reasoned') && types.includes('agent.decided'),
|
|
71
|
-
|
|
72
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0002 §A', 'dispatch MUST emit attributed agent.reasoned + agent.decided events'),
|
|
72
73
|
).toBe(true);
|
|
73
74
|
expect(
|
|
74
75
|
(res.events ?? []).every((e) => e.agentId === agentId),
|
|
75
|
-
|
|
76
|
+
req('openwop.it.agent-manifest-runtime.lists-installed-manifest-agents-and-dispatches-one-with-attributed-events', 'RFC 0002 §A', 'every emitted agent.* event MUST carry the dispatched agentId'),
|
|
76
77
|
).toBe(true);
|
|
77
78
|
});
|
|
78
79
|
|
|
@@ -29,9 +29,10 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import { describe, it, expect } from 'vitest';
|
|
32
|
-
import { driver } from '../lib/driver.js';
|
|
33
32
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
34
33
|
import { readOrgChartCap, getOrgChart, getDepartmentView } from '../lib/agentOrgChart.js';
|
|
34
|
+
import { req } from '../lib/requirement-ids.js';
|
|
35
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
35
36
|
|
|
36
37
|
const ROSTER_ID_RE = /^host:[a-z0-9][a-z0-9._-]*$/;
|
|
37
38
|
|
|
@@ -43,17 +44,17 @@ describe('agent-org-chart-scoping (RFC 0087 §A/§C/§D)', () => {
|
|
|
43
44
|
const installScope = typeof cap?.installScope === 'string' ? cap.installScope : 'tenant';
|
|
44
45
|
expect(
|
|
45
46
|
installScope === 'host' || installScope === 'tenant',
|
|
46
|
-
|
|
47
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'RFC 0087 §E / RFC 0074', "agents.orgChart.installScope (when present) MUST be 'host' or 'tenant'"),
|
|
47
48
|
).toBe(true);
|
|
48
49
|
|
|
49
50
|
// ---- Leg 1: normative read (black-box) -------------------------------
|
|
50
51
|
const chart = await getOrgChart();
|
|
51
|
-
if (chart === null) return; // advertised but read not served yet — soft-skip
|
|
52
|
+
if (chart === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `chart === null` returned early (advertised but read not served yet — soft-skip)'); // advertised but read not served yet — soft-skip
|
|
52
53
|
const departments = chart.departments ?? [];
|
|
53
54
|
const members = chart.members ?? [];
|
|
54
55
|
expect(
|
|
55
56
|
Array.isArray(departments) && Array.isArray(members),
|
|
56
|
-
|
|
57
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.schema.json', 'GET /v1/agents/org-chart MUST return departments[] + members[]'),
|
|
57
58
|
).toBe(true);
|
|
58
59
|
|
|
59
60
|
const deptIds = new Set(departments.map((d) => d.departmentId).filter((x): x is string => typeof x === 'string'));
|
|
@@ -62,7 +63,7 @@ describe('agent-org-chart-scoping (RFC 0087 §A/§C/§D)', () => {
|
|
|
62
63
|
if (parent !== undefined && parent !== null) {
|
|
63
64
|
expect(
|
|
64
65
|
deptIds.has(parent),
|
|
65
|
-
|
|
66
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §A', 'every parentDepartmentId MUST resolve to a department in the chart (a tree)'),
|
|
66
67
|
).toBe(true);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -79,18 +80,18 @@ describe('agent-org-chart-scoping (RFC 0087 §A/§C/§D)', () => {
|
|
|
79
80
|
}
|
|
80
81
|
expect(
|
|
81
82
|
steps <= departments.length,
|
|
82
|
-
|
|
83
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §A', 'the department parent graph MUST be acyclic'),
|
|
83
84
|
).toBe(true);
|
|
84
85
|
}
|
|
85
86
|
for (const m of members) {
|
|
86
87
|
expect(
|
|
87
88
|
typeof m.rosterId === 'string' && ROSTER_ID_RE.test(m.rosterId),
|
|
88
|
-
|
|
89
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §A', 'each member MUST reference a roster entry (host:<id> rosterId)'),
|
|
89
90
|
).toBe(true);
|
|
90
91
|
if (typeof m.departmentId === 'string') {
|
|
91
92
|
expect(
|
|
92
93
|
deptIds.size === 0 || deptIds.has(m.departmentId),
|
|
93
|
-
|
|
94
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §A', "a member's departmentId MUST be a department in the chart"),
|
|
94
95
|
).toBe(true);
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -102,23 +103,23 @@ describe('agent-org-chart-scoping (RFC 0087 §A/§C/§D)', () => {
|
|
|
102
103
|
if (status === 200 && view) {
|
|
103
104
|
expect(
|
|
104
105
|
Array.isArray(view.responsibilities),
|
|
105
|
-
|
|
106
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §D', 'the responsibility view MUST carry a responsibilities[] roll-up'),
|
|
106
107
|
).toBe(true);
|
|
107
108
|
const r = view.responsibilities ?? [];
|
|
108
109
|
expect(
|
|
109
110
|
r.length === new Set(r).size,
|
|
110
|
-
|
|
111
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §D', 'responsibilities MUST be a deduped union (no duplicate workflow ids)'),
|
|
111
112
|
).toBe(true);
|
|
112
113
|
expect(
|
|
113
114
|
r.every((w) => typeof w === 'string'),
|
|
114
|
-
|
|
115
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'org-chart-responsibility-view.schema.json', 'responsibilities[] entries MUST be workflow-id strings'),
|
|
115
116
|
).toBe(true);
|
|
116
117
|
// recursive=false MUST keep the response shape (a subset roll-up).
|
|
117
118
|
const direct = await getDepartmentView(probeDeptId, false);
|
|
118
119
|
if (direct.status === 200 && direct.view) {
|
|
119
120
|
expect(
|
|
120
121
|
Array.isArray(direct.view.responsibilities),
|
|
121
|
-
|
|
122
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §D', 'recursive=false MUST return the same shape, scoped to direct members'),
|
|
122
123
|
).toBe(true);
|
|
123
124
|
}
|
|
124
125
|
}
|
|
@@ -130,7 +131,7 @@ describe('agent-org-chart-scoping (RFC 0087 §A/§C/§D)', () => {
|
|
|
130
131
|
const probe = await getDepartmentView(crossTenantDept);
|
|
131
132
|
expect(
|
|
132
133
|
probe.status === 404,
|
|
133
|
-
|
|
134
|
+
req('openwop.it.agent-org-chart-scoping.serves-the-normative-org-chart-responsibility-roll-up-tree-shaped-and-tenant-sco', 'agent-org-chart.md §C / RFC 0074', 'GET /v1/agents/org-chart/{id} for a cross-tenant department MUST 404 (no cross-tenant disclosure)'),
|
|
134
135
|
).toBe(true);
|
|
135
136
|
}
|
|
136
137
|
});
|
|
@@ -32,9 +32,7 @@ import { join } from 'node:path';
|
|
|
32
32
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
33
33
|
import addFormats from 'ajv-formats';
|
|
34
34
|
import { SCHEMAS_DIR } from '../lib/paths.js';
|
|
35
|
-
|
|
36
|
-
/** Server-free assertion-message helper. */
|
|
37
|
-
const why = (specRef: string, requirement: string): string => `${specRef} — ${requirement}`;
|
|
35
|
+
import { req } from '../lib/requirement-ids.js';
|
|
38
36
|
|
|
39
37
|
function loadSchema(name: string): Record<string, unknown> {
|
|
40
38
|
return JSON.parse(readFileSync(join(SCHEMAS_DIR, name), 'utf8')) as Record<string, unknown>;
|
|
@@ -64,9 +62,9 @@ describe('agent-org-chart-shape: capability advertisement (RFC 0087, server-free
|
|
|
64
62
|
const caps = loadSchema('capabilities.schema.json');
|
|
65
63
|
const agents = (caps.properties as Record<string, { properties?: Record<string, { properties?: Record<string, unknown> }> }>).agents;
|
|
66
64
|
const orgChart = agents?.properties?.orgChart;
|
|
67
|
-
expect(orgChart,
|
|
65
|
+
expect(orgChart, req('openwop.it.agent-org-chart-shape.the-capabilities-schema-declares-agents-orgchart-with-its-sub-flags', 'capabilities.md §agents', 'agents.orgChart MUST be declared')).toBeDefined();
|
|
68
66
|
for (const flag of ['supported', 'installScope', 'departmentNesting', 'responsibilityView']) {
|
|
69
|
-
expect(orgChart?.properties?.[flag],
|
|
67
|
+
expect(orgChart?.properties?.[flag], req('openwop.it.agent-org-chart-shape.the-capabilities-schema-declares-agents-orgchart-with-its-sub-flags', 'agent-org-chart.md §E', `agents.orgChart.${flag} MUST be declared`)).toBeDefined();
|
|
70
68
|
}
|
|
71
69
|
});
|
|
72
70
|
});
|
|
@@ -77,13 +75,13 @@ describe('agent-org-chart-shape: chart record (RFC 0087 §A, server-free)', () =
|
|
|
77
75
|
const chart = ajv.compile(loadSchema('agent-org-chart.schema.json'));
|
|
78
76
|
|
|
79
77
|
it('AgentOrgChart validates a conforming chart', () => {
|
|
80
|
-
expect(chart(CHART),
|
|
78
|
+
expect(chart(CHART), req('openwop.it.agent-org-chart-shape.agentorgchart-validates-a-conforming-chart', 'RFC 0087 §A', 'a conforming org-chart MUST validate')).toBe(true);
|
|
81
79
|
});
|
|
82
80
|
|
|
83
81
|
it('rejects a non-host: member rosterId and a chart missing required arrays', () => {
|
|
84
82
|
const badMember = { ...CHART, members: [{ rosterId: 'core.openwop.agents.sally', departmentId: 'dept-marketing', roleId: 'role-bw', reportsTo: null }] };
|
|
85
|
-
expect(chart(badMember),
|
|
86
|
-
expect(chart({ owner: { tenantId: 'acme' }, departments: [] }),
|
|
83
|
+
expect(chart(badMember), req('openwop.it.agent-org-chart-shape.rejects-a-non-host-member-rosterid-and-a-chart-missing-required-arrays', 'RFC 0087 §A', 'a non-`host:` member rosterId MUST be rejected')).toBe(false);
|
|
84
|
+
expect(chart({ owner: { tenantId: 'acme' }, departments: [] }), req('openwop.it.agent-org-chart-shape.rejects-a-non-host-member-rosterid-and-a-chart-missing-required-arrays', 'RFC 0087 §A', 'a chart without `members` MUST be rejected')).toBe(false);
|
|
87
85
|
});
|
|
88
86
|
});
|
|
89
87
|
|
|
@@ -100,14 +98,14 @@ describe('agent-org-chart-shape: §B non-authority guarantee (RFC 0087, server-f
|
|
|
100
98
|
};
|
|
101
99
|
expect(
|
|
102
100
|
chart(withAuthority),
|
|
103
|
-
|
|
101
|
+
req('openwop.it.agent-org-chart-shape.the-schema-rejects-an-authority-bearing-field-on-a-member-org-position-no-author', 'SECURITY invariant org-position-no-authority-escalation', `a member carrying \`${authorityField}\` MUST be rejected (additionalProperties:false — position confers no authority)`),
|
|
104
102
|
).toBe(false);
|
|
105
103
|
}
|
|
106
104
|
});
|
|
107
105
|
|
|
108
106
|
it('a conforming member object carries exactly the descriptive key set — nothing authority-bearing', () => {
|
|
109
107
|
const memberKeys = Object.keys(CHART.members[1]!).sort();
|
|
110
|
-
expect(memberKeys,
|
|
108
|
+
expect(memberKeys, req('openwop.it.agent-org-chart-shape.a-conforming-member-object-carries-exactly-the-descriptive-key-set-nothing-autho', 'RFC 0087 §B', 'a member is descriptive only: {departmentId, reportsTo, roleId, rosterId}')).toEqual(['departmentId', 'reportsTo', 'roleId', 'rosterId']);
|
|
111
109
|
});
|
|
112
110
|
|
|
113
111
|
it('the GET /v1/agents/org-chart/{departmentId} responsibility-view response validates (RFC 0087 §D)', () => {
|
|
@@ -120,8 +118,8 @@ describe('agent-org-chart-shape: §B non-authority guarantee (RFC 0087, server-f
|
|
|
120
118
|
members: CHART.members,
|
|
121
119
|
responsibilities: ['marketing-email-campaign', 'social-post-scheduler'],
|
|
122
120
|
};
|
|
123
|
-
expect(view(good),
|
|
124
|
-
expect(view({ ...good, unexpected: true }),
|
|
125
|
-
expect(view({ department: CHART.departments[0], members: CHART.members }),
|
|
121
|
+
expect(view(good), req('openwop.it.agent-org-chart-shape.the-get-v1-agents-org-chart-departmentid-responsibility-view-response-validates', 'RFC 0087 §D', 'a conforming responsibility-view response MUST validate')).toBe(true);
|
|
122
|
+
expect(view({ ...good, unexpected: true }), req('openwop.it.agent-org-chart-shape.the-get-v1-agents-org-chart-departmentid-responsibility-view-response-validates', 'RFC 0087 §D', 'an extra top-level property MUST be rejected')).toBe(false);
|
|
123
|
+
expect(view({ department: CHART.departments[0], members: CHART.members }), req('openwop.it.agent-org-chart-shape.the-get-v1-agents-org-chart-departmentid-responsibility-view-response-validates', 'RFC 0087 §D', '`responsibilities` is required')).toBe(false);
|
|
126
124
|
});
|
|
127
125
|
});
|
|
@@ -29,6 +29,7 @@ import { describe, it, expect } from 'vitest';
|
|
|
29
29
|
import { driver } from '../lib/driver.js';
|
|
30
30
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
31
31
|
import { isAgentPlatformPartial, isAgentPlatformFull, agentPlatformStatus, agentPlatformSatisfiedTerms } from '../lib/profiles.js';
|
|
32
|
+
import { req } from '../lib/requirement-ids.js';
|
|
32
33
|
|
|
33
34
|
describe('agent-platform-aggregate-evidence (RFC 0085 §C)', () => {
|
|
34
35
|
it('a host claiming openwop-agent-platform satisfies the §B floor on live discovery; full when the operator certifies full', async () => {
|
|
@@ -43,13 +44,13 @@ describe('agent-platform-aggregate-evidence (RFC 0085 §C)', () => {
|
|
|
43
44
|
// the profile string alone.
|
|
44
45
|
expect(
|
|
45
46
|
isAgentPlatformPartial(disco!),
|
|
46
|
-
|
|
47
|
+
req('openwop.it.agent-platform-aggregate-evidence.a-host-claiming-openwop-agent-platform-satisfies-the-b-floor-on-live-discovery-f', 'agent-platform-profile.md §C', 'claiming openwop-agent-platform MUST satisfy the §B floor predicate on live discovery (claim backed by per-capability evidence)'),
|
|
47
48
|
).toBe(true);
|
|
48
49
|
|
|
49
50
|
const status = agentPlatformStatus(disco!);
|
|
50
51
|
expect(
|
|
51
52
|
status === 'partial' || status === 'full',
|
|
52
|
-
|
|
53
|
+
req('openwop.it.agent-platform-aggregate-evidence.a-host-claiming-openwop-agent-platform-satisfies-the-b-floor-on-live-discovery-f', 'agent-platform-profile.md §D', 'a claimed openwop-agent-platform host MUST derive to partial or full, never none'),
|
|
53
54
|
).toBe(true);
|
|
54
55
|
|
|
55
56
|
// Non-vacuous FULL bar: when the operator declares the cert tier `full`,
|
|
@@ -57,11 +58,11 @@ describe('agent-platform-aggregate-evidence (RFC 0085 §C)', () => {
|
|
|
57
58
|
if (process.env.OPENWOP_AGENT_PLATFORM_TIER === 'full') {
|
|
58
59
|
expect(
|
|
59
60
|
isAgentPlatformFull(disco!),
|
|
60
|
-
|
|
61
|
+
req('openwop.it.agent-platform-aggregate-evidence.a-host-claiming-openwop-agent-platform-satisfies-the-b-floor-on-live-discovery-f', 'agent-platform-profile.md §B/§D', 'a host certifying `full` MUST satisfy every governance term: authorization + tenant installScope + memory.attribution + debugBundle + triggerBridge + httpClient.egressPolicy'),
|
|
61
62
|
).toBe(true);
|
|
62
63
|
expect(
|
|
63
64
|
agentPlatformSatisfiedTerms(disco!).length,
|
|
64
|
-
|
|
65
|
+
req('openwop.it.agent-platform-aggregate-evidence.a-host-claiming-openwop-agent-platform-satisfies-the-b-floor-on-live-discovery-f', 'agent-platform-profile.md §D', 'a host certifying `full` satisfies all 16 §D terms'),
|
|
65
66
|
).toBe(16);
|
|
66
67
|
}
|
|
67
68
|
});
|
|
@@ -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
|
});
|