@adcp/sdk 14.0.0-rc.37 → 14.0.0-rc.39
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/bin/adcp-storyboard-summary.js +286 -0
- package/bin/adcp.js +221 -10
- package/dist/lib/conformance/schemaLoader.d.mts +1 -1
- package/dist/lib/conformance/schemaLoader.d.ts +1 -1
- package/dist/lib/core/AgentClient.d.mts +6 -1
- package/dist/lib/core/AgentClient.d.ts +6 -1
- package/dist/lib/core/AgentClient.js +9 -0
- package/dist/lib/core/AgentClient.mjs +9 -0
- package/dist/lib/core/ConversationTypes.d.mts +29 -0
- package/dist/lib/core/ConversationTypes.d.ts +29 -0
- package/dist/lib/core/SingleAgentClient.d.mts +3 -1
- package/dist/lib/core/SingleAgentClient.d.ts +3 -1
- package/dist/lib/core/SingleAgentClient.js +9 -1
- package/dist/lib/core/SingleAgentClient.mjs +9 -1
- package/dist/lib/core/TaskExecutor.d.mts +13 -1
- package/dist/lib/core/TaskExecutor.d.ts +13 -1
- package/dist/lib/core/TaskExecutor.js +216 -18
- package/dist/lib/core/TaskExecutor.mjs +216 -19
- package/dist/lib/index.d.mts +5 -2
- package/dist/lib/index.d.ts +5 -2
- package/dist/lib/index.js +10 -1
- package/dist/lib/index.mjs +10 -1
- package/dist/lib/media-buy/action-assessment.d.mts +77 -0
- package/dist/lib/media-buy/action-assessment.d.ts +77 -0
- package/dist/lib/media-buy/action-assessment.js +300 -0
- package/dist/lib/media-buy/action-assessment.mjs +284 -0
- package/dist/lib/media-buy/action-constraints.d.mts +9 -0
- package/dist/lib/media-buy/action-constraints.d.ts +9 -0
- package/dist/lib/media-buy/action-constraints.js +170 -0
- package/dist/lib/media-buy/action-constraints.mjs +146 -0
- package/dist/lib/media-buy/action-contracts.d.mts +40 -0
- package/dist/lib/media-buy/action-contracts.d.ts +40 -0
- package/dist/lib/media-buy/action-contracts.js +304 -0
- package/dist/lib/media-buy/action-contracts.mjs +267 -0
- package/dist/lib/media-buy/action-metadata.generated.d.mts +37 -0
- package/dist/lib/media-buy/action-metadata.generated.d.ts +37 -0
- package/dist/lib/media-buy/action-metadata.generated.js +128 -0
- package/dist/lib/media-buy/action-metadata.generated.mjs +101 -0
- package/dist/lib/media-buy/action-types.d.mts +106 -0
- package/dist/lib/media-buy/action-types.d.ts +106 -0
- package/dist/lib/{types/v3-1-beta/tools.generated.js → media-buy/action-types.js} +2 -2
- package/dist/lib/media-buy/actions.d.mts +6 -0
- package/dist/lib/media-buy/actions.d.ts +6 -0
- package/dist/lib/media-buy/actions.js +38 -0
- package/dist/lib/media-buy/actions.mjs +9 -0
- package/dist/lib/media-buy/available-actions.d.mts +2 -1
- package/dist/lib/media-buy/available-actions.d.ts +2 -1
- package/dist/lib/media-buy/available-actions.js +4 -3
- package/dist/lib/media-buy/available-actions.mjs +4 -3
- package/dist/lib/media-buy/compatibility.js +3 -0
- package/dist/lib/media-buy/compatibility.mjs +3 -0
- package/dist/lib/media-buy/index.d.mts +4 -0
- package/dist/lib/media-buy/index.d.ts +4 -0
- package/dist/lib/media-buy/index.js +3 -1
- package/dist/lib/media-buy/index.mjs +1 -0
- package/dist/lib/media-buy/legacy-action-ids.d.mts +1 -0
- package/dist/lib/media-buy/legacy-action-ids.d.ts +1 -0
- package/dist/lib/media-buy/legacy-action-ids.js +50 -0
- package/dist/lib/media-buy/legacy-action-ids.mjs +26 -0
- package/dist/lib/media-buy/mutations.d.mts +70 -0
- package/dist/lib/media-buy/mutations.d.ts +70 -0
- package/dist/lib/media-buy/mutations.js +525 -0
- package/dist/lib/media-buy/mutations.mjs +498 -0
- package/dist/lib/media-buy/preflight.d.mts +20 -69
- package/dist/lib/media-buy/preflight.d.ts +20 -69
- package/dist/lib/media-buy/preflight.js +100 -336
- package/dist/lib/media-buy/preflight.mjs +111 -333
- package/dist/lib/media-buy/targeting-input.d.mts +7 -4
- package/dist/lib/media-buy/targeting-input.d.ts +7 -4
- package/dist/lib/media-buy/types.d.mts +55 -7
- package/dist/lib/media-buy/types.d.ts +55 -7
- package/dist/lib/protocols/rawResponseCapture.d.mts +12 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +12 -0
- package/dist/lib/protocols/rawResponseCapture.js +33 -3
- package/dist/lib/protocols/rawResponseCapture.mjs +32 -3
- package/dist/lib/registry/types.generated.d.mts +377 -9
- package/dist/lib/registry/types.generated.d.ts +377 -9
- package/dist/lib/reporting/content-mismatch.d.mts +126 -0
- package/dist/lib/reporting/content-mismatch.d.ts +126 -0
- package/dist/lib/reporting/content-mismatch.js +90 -0
- package/dist/lib/reporting/content-mismatch.mjs +66 -0
- package/dist/lib/reporting/evidence.d.mts +1 -0
- package/dist/lib/reporting/evidence.d.ts +1 -0
- package/dist/lib/reporting/evidence.js +32 -3
- package/dist/lib/reporting/evidence.mjs +31 -3
- package/dist/lib/reporting/index.d.mts +3 -1
- package/dist/lib/reporting/index.d.ts +3 -1
- package/dist/lib/reporting/index.js +3 -0
- package/dist/lib/reporting/index.mjs +2 -0
- package/dist/lib/reporting/ledger/handler.d.mts +51 -1
- package/dist/lib/reporting/ledger/handler.d.ts +51 -1
- package/dist/lib/reporting/ledger/handler.js +306 -38
- package/dist/lib/reporting/ledger/handler.mjs +304 -37
- package/dist/lib/reporting/ledger/health.d.mts +12 -0
- package/dist/lib/reporting/ledger/health.d.ts +12 -0
- package/dist/lib/reporting/ledger/health.js +15 -2
- package/dist/lib/reporting/ledger/health.mjs +13 -1
- package/dist/lib/reporting/ledger/index.d.mts +3 -0
- package/dist/lib/reporting/ledger/index.d.ts +3 -0
- package/dist/lib/reporting/ledger/index.js +7 -1
- package/dist/lib/reporting/ledger/index.mjs +3 -0
- package/dist/lib/reporting/ledger/lifecycle.d.mts +31 -4
- package/dist/lib/reporting/ledger/lifecycle.d.ts +31 -4
- package/dist/lib/reporting/ledger/lifecycle.js +244 -37
- package/dist/lib/reporting/ledger/lifecycle.mjs +244 -37
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +231 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +231 -0
- package/dist/lib/reporting/ledger/managed-postgres.js +1797 -0
- package/dist/lib/reporting/ledger/managed-postgres.mjs +1776 -0
- package/dist/lib/reporting/ledger/managed.d.mts +355 -0
- package/dist/lib/reporting/ledger/managed.d.ts +355 -0
- package/dist/lib/reporting/ledger/managed.js +661 -0
- package/dist/lib/reporting/ledger/managed.mjs +633 -0
- package/dist/lib/reporting/ledger/notification-activity.d.mts +222 -0
- package/dist/lib/reporting/ledger/notification-activity.d.ts +222 -0
- package/dist/lib/reporting/ledger/notification-activity.js +1139 -0
- package/dist/lib/reporting/ledger/notification-activity.mjs +1110 -0
- package/dist/lib/reporting/ledger/postgres.d.mts +161 -1
- package/dist/lib/reporting/ledger/postgres.d.ts +161 -1
- package/dist/lib/reporting/ledger/postgres.js +1153 -21
- package/dist/lib/reporting/ledger/postgres.mjs +1152 -21
- package/dist/lib/reporting/ledger/producer.d.mts +8 -0
- package/dist/lib/reporting/ledger/producer.d.ts +8 -0
- package/dist/lib/reporting/ledger/producer.js +146 -52
- package/dist/lib/reporting/ledger/producer.mjs +146 -51
- package/dist/lib/reporting/ledger/types.d.mts +358 -1
- package/dist/lib/reporting/ledger/types.d.ts +358 -1
- package/dist/lib/reporting/ledger/types.js +3 -0
- package/dist/lib/reporting/ledger/types.mjs +2 -0
- package/dist/lib/reporting/reconciliation.d.mts +362 -2
- package/dist/lib/reporting/reconciliation.d.ts +362 -2
- package/dist/lib/reporting/reconciliation.js +1051 -7
- package/dist/lib/reporting/reconciliation.mjs +1053 -7
- package/dist/lib/reporting/service/conformance.d.mts +35 -0
- package/dist/lib/reporting/service/conformance.d.ts +35 -0
- package/dist/lib/reporting/service/conformance.js +89 -0
- package/dist/lib/reporting/service/conformance.mjs +68 -0
- package/dist/lib/reporting/service/index.d.mts +182 -0
- package/dist/lib/reporting/service/index.d.ts +182 -0
- package/dist/lib/reporting/service/index.js +793 -0
- package/dist/lib/reporting/service/index.mjs +787 -0
- package/dist/lib/reporting/source/index.d.mts +2 -1
- package/dist/lib/reporting/source/index.d.ts +2 -1
- package/dist/lib/reporting/source/index.js +16 -3
- package/dist/lib/reporting/source/index.mjs +12 -1
- package/dist/lib/reporting/source/inline.d.mts +88 -1
- package/dist/lib/reporting/source/inline.d.ts +88 -1
- package/dist/lib/reporting/source/inline.js +1161 -163
- package/dist/lib/reporting/source/inline.mjs +1166 -163
- package/dist/lib/reporting/source/manifest.js +12 -7
- package/dist/lib/reporting/source/manifest.mjs +12 -7
- package/dist/lib/reporting/source/source.d.mts +26 -0
- package/dist/lib/reporting/source/source.d.ts +26 -0
- package/dist/lib/reporting/source/source.js +71 -2
- package/dist/lib/reporting/source/source.mjs +65 -1
- package/dist/lib/schemas/index.d.mts +22 -1
- package/dist/lib/schemas/index.d.ts +22 -1
- package/dist/lib/schemas/index.js +7 -0
- package/dist/lib/schemas/index.mjs +7 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/create-adcp-server.d.mts +18 -0
- package/dist/lib/server/create-adcp-server.d.ts +18 -0
- package/dist/lib/server/create-adcp-server.js +52 -2
- package/dist/lib/server/create-adcp-server.mjs +52 -2
- package/dist/lib/server/decisioning/account.d.mts +1 -1
- package/dist/lib/server/decisioning/account.d.ts +1 -1
- package/dist/lib/server/decisioning/index.d.mts +1 -0
- package/dist/lib/server/decisioning/index.d.ts +1 -0
- package/dist/lib/server/decisioning/platform.d.mts +3 -0
- package/dist/lib/server/decisioning/platform.d.ts +3 -0
- package/dist/lib/server/decisioning/runtime/from-platform.js +88 -10
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +88 -10
- package/dist/lib/server/decisioning/specialisms/reporting.d.mts +38 -0
- package/dist/lib/server/decisioning/specialisms/reporting.d.ts +38 -0
- package/dist/lib/{types/v3-1-beta/index.js → server/decisioning/specialisms/reporting.js} +2 -8
- package/dist/lib/server/decisioning/specialisms/reporting.mjs +0 -0
- package/dist/lib/server/index.d.mts +4 -2
- package/dist/lib/server/index.d.ts +4 -2
- package/dist/lib/server/index.js +5 -0
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/media-buy-action-resolver.d.mts +63 -0
- package/dist/lib/server/media-buy-action-resolver.d.ts +63 -0
- package/dist/lib/server/media-buy-action-resolver.js +297 -0
- package/dist/lib/server/media-buy-action-resolver.mjs +285 -0
- package/dist/lib/server/media-buy-actions.d.mts +7 -8
- package/dist/lib/server/media-buy-actions.d.ts +7 -8
- package/dist/lib/server/media-buy-actions.js +57 -14
- package/dist/lib/server/media-buy-actions.mjs +63 -14
- package/dist/lib/server/notification-subscriptions/index.d.mts +2 -2
- package/dist/lib/server/notification-subscriptions/index.d.ts +2 -2
- package/dist/lib/server/notification-subscriptions/index.js +2 -0
- package/dist/lib/server/notification-subscriptions/index.mjs +2 -0
- package/dist/lib/server/notification-subscriptions/postgres-runtime.d.mts +3 -1
- package/dist/lib/server/notification-subscriptions/postgres-runtime.d.ts +3 -1
- package/dist/lib/server/notification-subscriptions/postgres-runtime.js +1 -0
- package/dist/lib/server/notification-subscriptions/postgres-runtime.mjs +1 -0
- package/dist/lib/server/notification-subscriptions/runtime.d.mts +12 -1
- package/dist/lib/server/notification-subscriptions/runtime.d.ts +12 -1
- package/dist/lib/server/notification-subscriptions/runtime.js +102 -16
- package/dist/lib/server/notification-subscriptions/runtime.mjs +101 -16
- package/dist/lib/server/notification-subscriptions/types.d.mts +104 -1
- package/dist/lib/server/notification-subscriptions/types.d.ts +104 -1
- package/dist/lib/server/webhook-emitter.d.mts +40 -5
- package/dist/lib/server/webhook-emitter.d.ts +40 -5
- package/dist/lib/server/webhook-emitter.js +23 -12
- package/dist/lib/server/webhook-emitter.mjs +23 -12
- package/dist/lib/storage/interfaces.d.mts +14 -2
- package/dist/lib/storage/interfaces.d.ts +14 -2
- package/dist/lib/testing/compliance/comply.d.mts +9 -3
- package/dist/lib/testing/compliance/comply.d.ts +9 -3
- package/dist/lib/testing/compliance/comply.js +158 -3
- package/dist/lib/testing/compliance/comply.mjs +159 -4
- package/dist/lib/testing/compliance/storyboard-tracks.js +7 -5
- package/dist/lib/testing/compliance/storyboard-tracks.mjs +7 -5
- package/dist/lib/testing/compliance/summary.js +10 -1
- package/dist/lib/testing/compliance/summary.mjs +10 -1
- package/dist/lib/testing/index.d.mts +1 -1
- package/dist/lib/testing/index.d.ts +1 -1
- package/dist/lib/testing/index.js +2 -0
- package/dist/lib/testing/index.mjs +3 -1
- package/dist/lib/testing/storyboard/agent-routing.d.mts +12 -43
- package/dist/lib/testing/storyboard/agent-routing.d.ts +12 -43
- package/dist/lib/testing/storyboard/agent-routing.js +75 -13
- package/dist/lib/testing/storyboard/agent-routing.mjs +70 -12
- package/dist/lib/testing/storyboard/index.d.mts +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +1 -0
- package/dist/lib/testing/storyboard/index.js +3 -0
- package/dist/lib/testing/storyboard/index.mjs +2 -0
- package/dist/lib/testing/storyboard/junit.d.mts +1 -1
- package/dist/lib/testing/storyboard/junit.d.ts +1 -1
- package/dist/lib/testing/storyboard/junit.js +21 -2
- package/dist/lib/testing/storyboard/junit.mjs +21 -2
- package/dist/lib/testing/storyboard/probes.d.mts +130 -0
- package/dist/lib/testing/storyboard/probes.d.ts +130 -0
- package/dist/lib/testing/storyboard/probes.js +682 -10
- package/dist/lib/testing/storyboard/probes.mjs +683 -3
- package/dist/lib/testing/storyboard/request-signing/builder.d.mts +16 -5
- package/dist/lib/testing/storyboard/request-signing/builder.d.ts +16 -5
- package/dist/lib/testing/storyboard/request-signing/grader.d.mts +44 -1
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts +44 -1
- package/dist/lib/testing/storyboard/request-signing/grader.js +46 -22
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +43 -21
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.mts +86 -11
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts +86 -11
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +119 -25
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.mjs +117 -26
- package/dist/lib/testing/storyboard/request-signing/synthesize.js +22 -2
- package/dist/lib/testing/storyboard/request-signing/synthesize.mjs +22 -2
- package/dist/lib/testing/storyboard/runner.d.mts +103 -0
- package/dist/lib/testing/storyboard/runner.d.ts +103 -0
- package/dist/lib/testing/storyboard/runner.js +1090 -268
- package/dist/lib/testing/storyboard/runner.mjs +1096 -261
- package/dist/lib/testing/storyboard/seeding.d.mts +4 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +4 -1
- package/dist/lib/testing/storyboard/seeding.js +55 -24
- package/dist/lib/testing/storyboard/seeding.mjs +55 -24
- package/dist/lib/testing/storyboard/test-kit.d.mts +37 -3
- package/dist/lib/testing/storyboard/test-kit.d.ts +37 -3
- package/dist/lib/testing/storyboard/test-kit.js +8 -2
- package/dist/lib/testing/storyboard/test-kit.mjs +7 -2
- package/dist/lib/testing/storyboard/types.d.mts +132 -10
- package/dist/lib/testing/storyboard/types.d.ts +132 -10
- package/dist/lib/testing/storyboard/types.js +17 -0
- package/dist/lib/testing/storyboard/types.mjs +16 -0
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +16 -0
- package/dist/lib/testing/storyboard/validations.mjs +16 -0
- package/dist/lib/testing/test-controller.d.mts +1 -1
- package/dist/lib/testing/test-controller.d.ts +1 -1
- package/dist/lib/types/buy-products.d.ts +71 -6
- package/dist/lib/types/control-media-buy.d.ts +25 -11
- package/dist/lib/types/core.generated.d.mts +69 -10
- package/dist/lib/types/core.generated.d.ts +69 -10
- package/dist/lib/types/create-media-buy.d.ts +71 -6
- package/dist/lib/types/forward-compat-error-codes.d.mts +7 -6
- package/dist/lib/types/forward-compat-error-codes.d.ts +7 -6
- package/dist/lib/types/index.d.mts +2 -2
- package/dist/lib/types/index.d.ts +2 -2
- package/dist/lib/types/schemas.generated.d.ts +8040 -8116
- package/dist/lib/types/schemas.generated.js +1074 -309
- package/dist/lib/types/schemas.generated.mjs +1068 -309
- package/dist/lib/types/tools.generated.d.mts +65 -6
- package/dist/lib/types/tools.generated.d.ts +65 -6
- package/dist/lib/types/update-media-buy.d.ts +71 -6
- package/dist/lib/utils/redact-secrets.d.mts +1 -1
- package/dist/lib/utils/redact-secrets.d.ts +1 -1
- package/dist/lib/utils/redact-secrets.js +1 -1
- package/dist/lib/utils/redact-secrets.mjs +1 -1
- package/dist/lib/v2/projection/cache-versions.d.mts +0 -1
- package/dist/lib/v2/projection/cache-versions.d.ts +0 -1
- package/dist/lib/v2/projection/cache-versions.js +1 -15
- package/dist/lib/v2/projection/cache-versions.mjs +1 -14
- package/dist/lib/v2/projection/canonical-properties.js +2 -2
- package/dist/lib/v2/projection/canonical-properties.mjs +3 -3
- package/dist/lib/v2/projection/registry.d.mts +1 -1
- package/dist/lib/v2/projection/registry.d.ts +1 -1
- package/dist/lib/v2/projection/registry.js +2 -2
- package/dist/lib/v2/projection/registry.mjs +3 -3
- package/dist/lib/validation/schema-loader.d.mts +9 -1
- package/dist/lib/validation/schema-loader.d.ts +9 -1
- package/dist/lib/validation/schema-loader.js +65 -8
- package/dist/lib/validation/schema-loader.mjs +64 -8
- package/dist/lib/version.d.mts +5 -5
- package/dist/lib/version.d.ts +5 -5
- package/dist/lib/version.js +3 -8
- package/dist/lib/version.mjs +3 -8
- package/dist/lib/wholesale-feed-sync/index.d.mts +1 -0
- package/dist/lib/wholesale-feed-sync/index.d.ts +1 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.d.mts +42 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.d.ts +42 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.js +16 -0
- package/dist/lib/wholesale-feed-sync/protocol-types.mjs +0 -0
- package/dist/lib/wholesale-feed-sync/sync.d.mts +6 -6
- package/dist/lib/wholesale-feed-sync/sync.d.ts +6 -6
- package/dist/lib/wholesale-feed-sync/sync.js +3 -1
- package/dist/lib/wholesale-feed-sync/sync.mjs +3 -1
- package/dist/lib/wholesale-feed-sync/types.d.mts +15 -14
- package/dist/lib/wholesale-feed-sync/types.d.ts +15 -14
- package/dist/lib/wholesale-feed-sync/webhook-notification.d.mts +7 -5
- package/dist/lib/wholesale-feed-sync/webhook-notification.d.ts +7 -5
- package/dist/lib/wholesale-feed-sync/webhook-notification.js +45 -0
- package/dist/lib/wholesale-feed-sync/webhook-notification.mjs +44 -0
- package/docs/CLI.md +1 -1
- package/docs/TYPE-SUMMARY.md +118 -4
- package/docs/guides/ASYNC-API-REFERENCE.md +62 -1
- package/docs/guides/ASYNC-DEVELOPER-GUIDE.md +25 -0
- package/docs/guides/ASYNC-DOCUMENTATION-INDEX.md +3 -0
- package/docs/guides/BUYER-QUICKSTART-3.2.md +5 -0
- package/docs/guides/DURABLE-BUYER-WRITES.md +337 -0
- package/docs/guides/EXISTING-PLATFORM.md +80 -1
- package/docs/guides/MEDIA-BUY-3.2-COMPATIBILITY.md +57 -0
- package/docs/guides/MEDIA-BUY-ACTION-ASSESSMENT.md +300 -0
- package/docs/guides/REPORTING-LEDGER.md +654 -3
- package/docs/guides/REPORTING-RECONCILIATION.md +50 -0
- package/docs/guides/REPORTING-SOURCE-EXECUTOR.md +63 -1
- package/docs/guides/SELLER-QUICKSTART-3.2.md +2 -0
- package/docs/guides/VALIDATE-YOUR-AGENT.md +35 -0
- package/docs/guides/idempotency-crash-recovery.md +4 -0
- package/docs/llms.txt +4 -2
- package/docs/migration-14.x-rc-worksheet.md +60 -5
- package/docs/migration-7.9-to-7.10.md +7 -5
- package/examples/README.md +17 -0
- package/examples/durable-buyer-writes/caller.ts +745 -0
- package/examples/durable-buyer-writes/worker.ts +240 -0
- package/examples/reliable-reporting-service/README.md +100 -0
- package/examples/seller-3.2-starter.ts +7 -8
- package/examples/targeting-input-existing-platform.ts +153 -0
- package/package.json +41 -29
- package/skills/build-seller-agent/SKILL.md +2 -0
- package/skills/build-seller-agent/specialisms/signed-requests.md +11 -1
- package/skills/cross-cutting.md +28 -11
- package/compliance/cache/3.1.0-beta.7/domains/brand/index.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/distributed_brand_resolution.yaml +0 -415
- package/compliance/cache/3.1.0-beta.7/domains/brand/scenarios/single_side_trust_extension.yaml +0 -454
- package/compliance/cache/3.1.0-beta.7/domains/creative/index.yaml +0 -339
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/billing_out_of_band.yaml +0 -153
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
- package/compliance/cache/3.1.0-beta.7/domains/creative/scenarios/native_in_feed.yaml +0 -543
- package/compliance/cache/3.1.0-beta.7/domains/governance/index.yaml +0 -682
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/index.yaml +0 -781
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/audience_buy_flow.yaml +0 -380
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/available_actions.yaml +0 -565
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/canonical_formats.yaml +0 -711
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/create_media_buy_async.yaml +0 -234
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/creative_reception.yaml +0 -247
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/delivery_reporting.yaml +0 -357
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment.yaml +0 -633
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/event_dedup_flow.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_approved.yaml +0 -214
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_conditions.yaml +0 -199
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied.yaml +0 -204
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/invalid_transitions.yaml +0 -289
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_accountability.yaml +0 -244
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow.yaml +0 -428
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/product_signal_targeting.yaml +0 -373
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_enforcement.yaml +0 -517
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/reach_buy_flow.yaml +0 -823
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/refine_products.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
- package/compliance/cache/3.1.0-beta.7/domains/media-buy/state-machine.yaml +0 -442
- package/compliance/cache/3.1.0-beta.7/domains/signals/index.yaml +0 -266
- package/compliance/cache/3.1.0-beta.7/domains/sponsored-intelligence/index.yaml +0 -256
- package/compliance/cache/3.1.0-beta.7/index.json +0 -356
- package/compliance/cache/3.1.0-beta.7/protocols/brand/index.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/distributed_brand_resolution.yaml +0 -415
- package/compliance/cache/3.1.0-beta.7/protocols/brand/scenarios/single_side_trust_extension.yaml +0 -454
- package/compliance/cache/3.1.0-beta.7/protocols/creative/index.yaml +0 -339
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/billing_out_of_band.yaml +0 -153
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +0 -389
- package/compliance/cache/3.1.0-beta.7/protocols/creative/scenarios/native_in_feed.yaml +0 -543
- package/compliance/cache/3.1.0-beta.7/protocols/governance/index.yaml +0 -682
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/index.yaml +0 -781
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/audience_buy_flow.yaml +0 -380
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/available_actions.yaml +0 -565
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/billing_finality_delivery.yaml +0 -354
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/canonical_formats.yaml +0 -711
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/clicks_buy_flow.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +0 -344
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/create_media_buy_async.yaml +0 -234
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +0 -419
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/creative_reception.yaml +0 -247
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/delivery_reporting.yaml +0 -357
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment.yaml +0 -633
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +0 -800
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/event_dedup_flow.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +0 -309
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_approved.yaml +0 -214
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_conditions.yaml +0 -199
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied.yaml +0 -204
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/governance_denied_recovery.yaml +0 -252
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/invalid_transitions.yaml +0 -289
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_no_match.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/inventory_list_targeting.yaml +0 -276
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_accountability.yaml +0 -244
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +0 -203
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +0 -274
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +0 -500
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow.yaml +0 -428
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +0 -470
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/product_signal_targeting.yaml +0 -373
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize.yaml +0 -399
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +0 -264
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +0 -257
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_audit_observation.yaml +0 -333
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_enforcement.yaml +0 -517
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/reach_buy_flow.yaml +0 -823
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +0 -360
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/refine_products.yaml +0 -148
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +0 -293
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +0 -576
- package/compliance/cache/3.1.0-beta.7/protocols/media-buy/state-machine.yaml +0 -442
- package/compliance/cache/3.1.0-beta.7/protocols/signals/index.yaml +0 -266
- package/compliance/cache/3.1.0-beta.7/protocols/sponsored-intelligence/index.yaml +0 -256
- package/compliance/cache/3.1.0-beta.7/specialisms/audience-sync/index.yaml +0 -313
- package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/index.yaml +0 -350
- package/compliance/cache/3.1.0-beta.7/specialisms/brand-rights/scenarios/governance_denied.yaml +0 -226
- package/compliance/cache/3.1.0-beta.7/specialisms/collection-lists/index.yaml +0 -359
- package/compliance/cache/3.1.0-beta.7/specialisms/content-standards/index.yaml +0 -572
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-ad-server/index.yaml +0 -409
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/generative-seller.yaml +0 -807
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-generative/index.yaml +0 -758
- package/compliance/cache/3.1.0-beta.7/specialisms/creative-template/index.yaml +0 -510
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/index.yaml +0 -143
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +0 -117
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-delivery-monitor/index.yaml +0 -441
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/denied.yaml +0 -221
- package/compliance/cache/3.1.0-beta.7/specialisms/governance-spend-authority/index.yaml +0 -330
- package/compliance/cache/3.1.0-beta.7/specialisms/property-lists/index.yaml +0 -482
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-broadcast-tv/index.yaml +0 -738
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-catalog-driven/index.yaml +0 -840
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-guaranteed/index.yaml +0 -601
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-non-guaranteed/index.yaml +0 -546
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-proposal-mode/index.yaml +0 -586
- package/compliance/cache/3.1.0-beta.7/specialisms/sales-social/index.yaml +0 -919
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/index.yaml +0 -424
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-marketplace/scenarios/governance_denied.yaml +0 -211
- package/compliance/cache/3.1.0-beta.7/specialisms/signal-owned/index.yaml +0 -317
- package/compliance/cache/3.1.0-beta.7/specialisms/sponsored-intelligence/index.yaml +0 -59
- package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor-live.yaml +0 -78
- package/compliance/cache/3.1.0-beta.7/test-kits/acme-outdoor.yaml +0 -223
- package/compliance/cache/3.1.0-beta.7/test-kits/billing-gate-runner.yaml +0 -115
- package/compliance/cache/3.1.0-beta.7/test-kits/bistro-oranje.yaml +0 -126
- package/compliance/cache/3.1.0-beta.7/test-kits/distributed-brand-runner.yaml +0 -281
- package/compliance/cache/3.1.0-beta.7/test-kits/nova-motors.yaml +0 -262
- package/compliance/cache/3.1.0-beta.7/test-kits/osei-natural.yaml +0 -126
- package/compliance/cache/3.1.0-beta.7/test-kits/parallel-dispatch-runner.yaml +0 -196
- package/compliance/cache/3.1.0-beta.7/test-kits/rate-limit-trip-runner.yaml +0 -172
- package/compliance/cache/3.1.0-beta.7/test-kits/signed-requests-runner.yaml +0 -155
- package/compliance/cache/3.1.0-beta.7/test-kits/single-side-trust-runner.yaml +0 -294
- package/compliance/cache/3.1.0-beta.7/test-kits/substitution-observer-runner.yaml +0 -688
- package/compliance/cache/3.1.0-beta.7/test-kits/summit-foods.yaml +0 -125
- package/compliance/cache/3.1.0-beta.7/test-kits/webhook-receiver-runner.yaml +0 -265
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/001-minimal-plan.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/002-full-plan.json +0 -217
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/003-bookkeeping-stripped.json +0 -60
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004a-human-review-omitted.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/004b-human-review-explicit-null.json +0 -49
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005a-policy-categories-order-1.json +0 -53
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/005b-policy-categories-order-2.json +0 -57
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006a-ext-trace-v1.json +0 -49
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/006b-ext-trace-v2.json +0 -53
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/007-unicode-objectives.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/plan-hash/008-numeric-canonicalization.json +0 -65
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/README.md +0 -220
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/canonicalization.json +0 -241
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/keys.json +0 -60
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/001-no-signature-header.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/002-wrong-tag.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/003-expired-signature.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/004-window-too-long.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/005-alg-not-allowed.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/006-missing-covered-component.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/007-missing-content-digest.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/008-unknown-keyid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/010-content-digest-mismatch.json +0 -33
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/011-malformed-header.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/012-missing-expires-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/013-expires-le-created.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/014-missing-nonce-param.json +0 -27
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/015-signature-invalid.json +0 -28
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/016-replayed-nonce.json +0 -35
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/017-key-revoked.json +0 -38
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +0 -28
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/019-signature-without-signature-input.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/020-rate-abuse.json +0 -34
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/022-multi-valued-content-type.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/024-unquoted-string-param.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +0 -43
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/026-non-ascii-host.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/001-basic-post.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/002-post-with-content-digest.json +0 -31
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/003-es256-post.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/004-multiple-signature-labels.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/005-default-port-stripped.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/006-dot-segment-path.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/007-query-byte-preserved.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/008-percent-encoded-path.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/011-ipv6-authority.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +0 -30
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/README.md +0 -211
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/keys.json +0 -61
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/001-wrong-tag.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/002-expired-signature.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/003-window-too-long.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/005-missing-authority-component.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/006-missing-content-digest.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/007-unknown-keyid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/011-signature-without-input.json +0 -25
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/012-missing-expires-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/013-expires-le-created.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/015-signature-invalid.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/016-replayed-nonce.json +0 -37
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/017-key-revoked.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/018-rate-abuse.json +0 -33
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/019-revocation-stale.json +0 -32
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +0 -41
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +0 -26
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/001-basic-post.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/002-es256-post.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/004-default-port-stripped.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +0 -24
- package/compliance/cache/3.1.0-beta.7/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +0 -25
- package/compliance/cache/3.1.0-beta.7/universal/billing-gate-dispatch.yaml +0 -450
- package/compliance/cache/3.1.0-beta.7/universal/canonical-format-validate-input.yaml +0 -640
- package/compliance/cache/3.1.0-beta.7/universal/capability-discovery.yaml +0 -125
- package/compliance/cache/3.1.0-beta.7/universal/collection-lists-pagination-integrity.yaml +0 -306
- package/compliance/cache/3.1.0-beta.7/universal/comply-controller-mode-gate.yaml +0 -141
- package/compliance/cache/3.1.0-beta.7/universal/content-standards-pagination-integrity.yaml +0 -326
- package/compliance/cache/3.1.0-beta.7/universal/deterministic-testing.yaml +0 -1430
- package/compliance/cache/3.1.0-beta.7/universal/error-compliance-signals.yaml +0 -377
- package/compliance/cache/3.1.0-beta.7/universal/error-compliance.yaml +0 -528
- package/compliance/cache/3.1.0-beta.7/universal/fictional-entities.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/universal/get-media-buys-pagination-integrity.yaml +0 -160
- package/compliance/cache/3.1.0-beta.7/universal/get-signals-pagination-integrity.yaml +0 -211
- package/compliance/cache/3.1.0-beta.7/universal/idempotency.yaml +0 -861
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-event-scope.yaml +0 -119
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-lifecycle.yaml +0 -337
- package/compliance/cache/3.1.0-beta.7/universal/notification-config-rejections.yaml +0 -107
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-creative-formats.yaml +0 -265
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity-list-accounts.yaml +0 -245
- package/compliance/cache/3.1.0-beta.7/universal/pagination-integrity.yaml +0 -263
- package/compliance/cache/3.1.0-beta.7/universal/property-lists-pagination-integrity.yaml +0 -307
- package/compliance/cache/3.1.0-beta.7/universal/read-tool-idempotency.yaml +0 -405
- package/compliance/cache/3.1.0-beta.7/universal/runner-output-contract.yaml +0 -1266
- package/compliance/cache/3.1.0-beta.7/universal/schema-validation-signals.yaml +0 -181
- package/compliance/cache/3.1.0-beta.7/universal/schema-validation.yaml +0 -548
- package/compliance/cache/3.1.0-beta.7/universal/security.yaml +0 -539
- package/compliance/cache/3.1.0-beta.7/universal/signed-requests.yaml +0 -217
- package/compliance/cache/3.1.0-beta.7/universal/stale-response-advisory.yaml +0 -295
- package/compliance/cache/3.1.0-beta.7/universal/storyboard-schema.yaml +0 -2136
- package/compliance/cache/3.1.0-beta.7/universal/v3-envelope-integrity.yaml +0 -117
- package/compliance/cache/3.1.0-beta.7/universal/version-negotiation.yaml +0 -130
- package/compliance/cache/3.1.0-beta.7/universal/webhook-emission.yaml +0 -411
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-bulk-webhooks.yaml +0 -82
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-product-webhooks.yaml +0 -83
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-products.yaml +0 -151
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signal-webhooks.yaml +0 -83
- package/compliance/cache/3.1.0-beta.7/universal/wholesale-feed-signals.yaml +0 -149
- package/dist/lib/types/v3-1-beta/index.d.mts +0 -1
- package/dist/lib/types/v3-1-beta/index.d.ts +0 -1
- package/dist/lib/types/v3-1-beta/index.mjs +0 -1
- package/dist/lib/types/v3-1-beta/tools.generated.d.mts +0 -26788
- package/dist/lib/types/v3-1-beta/tools.generated.d.ts +0 -26788
- /package/dist/lib/{types/v3-1-beta/tools.generated.mjs → media-buy/action-types.mjs} +0 -0
|
@@ -67,19 +67,39 @@ import {
|
|
|
67
67
|
probeOauthAuthServerMetadata,
|
|
68
68
|
fetchProbe,
|
|
69
69
|
rawMcpProbe,
|
|
70
|
+
rawMcpSessionProbe,
|
|
70
71
|
generateRandomInvalidApiKey,
|
|
71
72
|
generateRandomInvalidJwt
|
|
72
73
|
} from "./probes.mjs";
|
|
73
74
|
import { readBrandJsonUrl } from "../../signing/agent-resolver/capabilities-types.mjs";
|
|
74
75
|
import { selectAgentByUrl } from "../../signing/agent-resolver/select-agent.mjs";
|
|
75
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
PROBE_TASK_ALLOWLIST,
|
|
78
|
+
PROBE_TASK_ALLOWLIST_SUMMARY,
|
|
79
|
+
resolveDeclaredTestKit,
|
|
80
|
+
validateTestKit
|
|
81
|
+
} from "./test-kit.mjs";
|
|
82
|
+
import { MUTATING_TASKS } from "../../utils/idempotency.mjs";
|
|
83
|
+
import { TOOL_REQUEST_SCHEMAS } from "../../utils/tool-request-schemas.mjs";
|
|
84
|
+
import {
|
|
85
|
+
ACCOUNT_TOOLS,
|
|
86
|
+
BRAND_RIGHTS_TOOLS,
|
|
87
|
+
CREATIVE_TOOLS,
|
|
88
|
+
EVENT_TRACKING_TOOLS,
|
|
89
|
+
GOVERNANCE_TOOLS,
|
|
90
|
+
MEDIA_BUY_TOOLS,
|
|
91
|
+
PROTOCOL_TOOLS,
|
|
92
|
+
SIGNALS_TOOLS
|
|
93
|
+
} from "../../utils/capabilities.mjs";
|
|
76
94
|
import { normalizeValidationOnlyTasks, validateStoryboardShape, VALIDATION_ONLY_TASK } from "./loader.mjs";
|
|
77
95
|
import { evaluatePhaseCondition, phaseConditionUsesContext } from "./phase-condition.mjs";
|
|
78
96
|
import { trustedStoryboardComplianceRoot } from "./provenance.mjs";
|
|
79
97
|
import { probeRequestSigningVector } from "./request-signing/probe-dispatch.mjs";
|
|
98
|
+
import { REQUEST_SIGNING_PROBE_TASK } from "./request-signing/synthesize.mjs";
|
|
80
99
|
import { createWebhookReceiver } from "./webhook-receiver.mjs";
|
|
81
100
|
import { WEBHOOK_ASSERTION_TASKS, armWebhookAssertions, executeWebhookAssertionStep } from "./webhook-assertions.mjs";
|
|
82
101
|
import { runControllerSeeding } from "./seeding.mjs";
|
|
102
|
+
import { callControllerRaw } from "../test-controller.mjs";
|
|
83
103
|
import { applyFixtureBindingsToRequest } from "./fixture-resolution.mjs";
|
|
84
104
|
import { getComplianceCacheDir } from "./compliance.mjs";
|
|
85
105
|
import { signWebhook } from "../../signing/client.mjs";
|
|
@@ -105,9 +125,13 @@ import {
|
|
|
105
125
|
buildRoutingContext,
|
|
106
126
|
DiscoveryFailure,
|
|
107
127
|
resolveAgentForStep,
|
|
128
|
+
routedAgentOptions,
|
|
129
|
+
hasAnyRequiredTool,
|
|
130
|
+
normalizeAgentToolNames,
|
|
131
|
+
resolveTaskName,
|
|
108
132
|
RoutingError
|
|
109
133
|
} from "./agent-routing.mjs";
|
|
110
|
-
import { DETAILED_SKIP_TO_CANONICAL, KNOWN_REQUIREMENTS } from "./types.mjs";
|
|
134
|
+
import { DETAILED_SKIP_TO_CANONICAL, KNOWN_REQUIREMENTS, MCP_SESSION_PROBE_TASK } from "./types.mjs";
|
|
111
135
|
import {
|
|
112
136
|
resolveAssertions,
|
|
113
137
|
stepDisablesAssertion,
|
|
@@ -179,11 +203,26 @@ const DETAILED_SKIP_DETAILS = {
|
|
|
179
203
|
rate_abuse_opt_out: "Rate-abuse vector was excluded by request_signing.skipRateAbuse.",
|
|
180
204
|
capability_profile_mismatch: "Vector is outside the agent capability profile selected for this run.",
|
|
181
205
|
transport_ungradable: "Vector cannot be graded faithfully by the selected transport.",
|
|
206
|
+
signing_transport_unavailable: "Request-signing vectors have no shape this run's protocol can carry, so no verifier behavior was graded.",
|
|
182
207
|
rate_limit_not_triggered: "No RATE_LIMITED response was observed within the configured max_attempts."
|
|
183
208
|
};
|
|
184
209
|
const CANONICAL_SKIP_DETAILS = {
|
|
185
|
-
rate_limit_not_triggered: "rate_limit_not_triggered"
|
|
210
|
+
rate_limit_not_triggered: "rate_limit_not_triggered",
|
|
211
|
+
// Same shape as `rate_limit_not_triggered` above, which
|
|
212
|
+
// runner-output-contract.yaml registers under
|
|
213
|
+
// `canonical_detail_sub_reasons.not_applicable` with a test-kit
|
|
214
|
+
// `spec_source`: emit the sub-reason token *exactly* as `skip.detail`,
|
|
215
|
+
// with empty validations and no pass/fail counter movement. The
|
|
216
|
+
// operator-facing remedy travels on the probe result (`response.error`),
|
|
217
|
+
// which is where the renderers read it.
|
|
218
|
+
//
|
|
219
|
+
// Upstream ask, tracked as the remaining external blocker: register
|
|
220
|
+
// `not_applicable.signing_transport_unavailable` with
|
|
221
|
+
// `spec_source: test-kits/signed-requests-runner.yaml`. Emitting the
|
|
222
|
+
// registered *shape* now means that registration changes nothing here.
|
|
223
|
+
signing_transport_unavailable: "signing_transport_unavailable"
|
|
186
224
|
};
|
|
225
|
+
const MCP_SESSION_PROBE_REQUEST_TIMEOUT_MS = 5e3;
|
|
187
226
|
const REPLAY_WEBHOOK_VECTOR_TASK = "replay_webhook_vector";
|
|
188
227
|
const REPLAY_TRUSTED_MATCH_CONTEXT_VECTOR_TASK = "replay_trusted_match_context_vector";
|
|
189
228
|
const WEBHOOK_REPLAY_DEFAULT_TIMEOUT_MS = 1e4;
|
|
@@ -526,6 +565,42 @@ function resetClientSessions(clients) {
|
|
|
526
565
|
if (typeof reset === "function") reset.call(client);
|
|
527
566
|
}
|
|
528
567
|
}
|
|
568
|
+
async function resetControllerState(client, storyboard, options) {
|
|
569
|
+
const controller = options._controllerCapabilities;
|
|
570
|
+
if (controller?.detected !== true || !controller.scenarios.includes("reset_state")) return void 0;
|
|
571
|
+
const outcome = await runStep(
|
|
572
|
+
"Reset test-controller state",
|
|
573
|
+
"comply_test_controller",
|
|
574
|
+
() => callControllerRaw(
|
|
575
|
+
client,
|
|
576
|
+
{
|
|
577
|
+
scenario: "reset_state",
|
|
578
|
+
context: { correlation_id: `${storyboard.id}--__reset_state__` }
|
|
579
|
+
},
|
|
580
|
+
options
|
|
581
|
+
)
|
|
582
|
+
);
|
|
583
|
+
if (!outcome.step.passed) return outcome.step;
|
|
584
|
+
const raw = outcome.result;
|
|
585
|
+
const data = raw?.data;
|
|
586
|
+
if (raw?.success && data?.success === true) return void 0;
|
|
587
|
+
if (raw?.success && data?.success === false && data.error === "UNKNOWN_SCENARIO") return void 0;
|
|
588
|
+
return {
|
|
589
|
+
...outcome.step,
|
|
590
|
+
passed: false,
|
|
591
|
+
error: data?.error_detail ?? data?.error ?? raw?.error ?? "comply_test_controller reset_state failed"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
async function resetControllerStates(targets, storyboard) {
|
|
595
|
+
const seen = /* @__PURE__ */ new Set();
|
|
596
|
+
for (const target of targets) {
|
|
597
|
+
if (seen.has(target.client)) continue;
|
|
598
|
+
seen.add(target.client);
|
|
599
|
+
const failure = await resetControllerState(target.client, storyboard, target.options);
|
|
600
|
+
if (failure) return failure;
|
|
601
|
+
}
|
|
602
|
+
return void 0;
|
|
603
|
+
}
|
|
529
604
|
function isPollEligibleEnvelope(data) {
|
|
530
605
|
if (data == null || typeof data !== "object") return false;
|
|
531
606
|
const obj = data;
|
|
@@ -645,6 +720,15 @@ function __redactSecretsForTest(value) {
|
|
|
645
720
|
function __filterResponseHeadersForTest(headers) {
|
|
646
721
|
return filterResponseHeaders(headers);
|
|
647
722
|
}
|
|
723
|
+
function __selectProtectedToolTargetForTest(tools) {
|
|
724
|
+
return selectProtectedToolTarget(tools);
|
|
725
|
+
}
|
|
726
|
+
function __protectedToolCandidatesForTest(tools) {
|
|
727
|
+
return protectedToolCandidates(tools);
|
|
728
|
+
}
|
|
729
|
+
function __sessionControlCredentialsForTest(mechanism, options, client, agentUrl) {
|
|
730
|
+
return sessionControlCredentials(mechanism, options, client, agentUrl);
|
|
731
|
+
}
|
|
648
732
|
function __defaultAuthHeadersForRawProbeForTest(options) {
|
|
649
733
|
return defaultAuthHeadersForRawProbe(options);
|
|
650
734
|
}
|
|
@@ -711,7 +795,7 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
|
|
|
711
795
|
);
|
|
712
796
|
}
|
|
713
797
|
const hasCapabilityGate = storyboardCapabilityPredicates(storyboard).length > 0;
|
|
714
|
-
const deferCapabilityAndRequires = hasCapabilityGate && options._profile === void 0;
|
|
798
|
+
const deferCapabilityAndRequires = options.agents !== void 0 || hasCapabilityGate && options._profile === void 0;
|
|
715
799
|
if (hasCapabilityGate && !deferCapabilityAndRequires) {
|
|
716
800
|
const unmetDetail = evaluateStoryboardCapabilityGates(
|
|
717
801
|
storyboard,
|
|
@@ -728,8 +812,25 @@ async function runStoryboardBody(agentUrlOrUrls, storyboard, options) {
|
|
|
728
812
|
}
|
|
729
813
|
}
|
|
730
814
|
const allRequires = resolveStoryboardRequires(storyboard, options);
|
|
731
|
-
|
|
732
|
-
|
|
815
|
+
const preflightDefersRequirement = (requirement) => {
|
|
816
|
+
switch (requirement) {
|
|
817
|
+
case "controller":
|
|
818
|
+
return options.agents !== void 0 || !options.agentTools;
|
|
819
|
+
case "request_signer":
|
|
820
|
+
return options.agents !== void 0 || !options._profile?.raw_capabilities;
|
|
821
|
+
default:
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
const firstDeferred = allRequires.findIndex(preflightDefersRequirement);
|
|
826
|
+
const earlyRequires = hasCapabilityGate ? [] : allRequires.slice(0, firstDeferred < 0 ? void 0 : firstDeferred);
|
|
827
|
+
if (earlyRequires.length && (!deferCapabilityAndRequires || options.agents && !hasCapabilityGate)) {
|
|
828
|
+
const requirementCheck = await checkRequires(
|
|
829
|
+
earlyRequires,
|
|
830
|
+
storyboard,
|
|
831
|
+
options,
|
|
832
|
+
options.agents ? void 0 : options._profile
|
|
833
|
+
);
|
|
733
834
|
if ("requirement" in requirementCheck) {
|
|
734
835
|
const resultAgentUrls = options.agents ? Object.values(options.agents).map((e) => e.url) : agentUrls;
|
|
735
836
|
return {
|
|
@@ -998,20 +1099,7 @@ function buildRequiredAnyOfToolsMissingResult(agentUrls, storyboard, detail) {
|
|
|
998
1099
|
notices: []
|
|
999
1100
|
};
|
|
1000
1101
|
}
|
|
1001
|
-
function
|
|
1002
|
-
if (!Array.isArray(tools)) return void 0;
|
|
1003
|
-
const names = [];
|
|
1004
|
-
for (const tool of tools) {
|
|
1005
|
-
if (typeof tool === "string") {
|
|
1006
|
-
names.push(tool);
|
|
1007
|
-
} else if (tool && typeof tool === "object") {
|
|
1008
|
-
const name = tool.name;
|
|
1009
|
-
if (typeof name === "string") names.push(name);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
return names.length > 0 ? names : void 0;
|
|
1013
|
-
}
|
|
1014
|
-
async function checkRequires(requires, storyboard, options, profile) {
|
|
1102
|
+
async function checkRequires(requires, storyboard, options, profile, precomputed) {
|
|
1015
1103
|
let preparedPublisherAuthProbes = getPreparedTrustedMatchPublisherAuth(options);
|
|
1016
1104
|
for (const requirement of requires) {
|
|
1017
1105
|
if (!isKnownRequirement(requirement)) {
|
|
@@ -1020,6 +1108,13 @@ async function checkRequires(requires, storyboard, options, profile) {
|
|
|
1020
1108
|
detail: `Storyboard requires unknown runtime requirement '${requirement}'. This SDK does not know how to satisfy it, so the requirement is treated as unmet for forward compatibility.`
|
|
1021
1109
|
};
|
|
1022
1110
|
}
|
|
1111
|
+
const established = precomputed?.get(requirement);
|
|
1112
|
+
if (established) {
|
|
1113
|
+
if (established.status === "unmet") {
|
|
1114
|
+
return { requirement: established.requirement, detail: established.detail };
|
|
1115
|
+
}
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1023
1118
|
switch (requirement) {
|
|
1024
1119
|
case "controller": {
|
|
1025
1120
|
if (!options.agentTools) continue;
|
|
@@ -1181,6 +1276,28 @@ function detectImplicitRequires(storyboard, options = {}) {
|
|
|
1181
1276
|
if (needsSigner) requires.push("request_signer");
|
|
1182
1277
|
return requires;
|
|
1183
1278
|
}
|
|
1279
|
+
function probeResponseStatus(response) {
|
|
1280
|
+
if (response === null || typeof response !== "object") return 0;
|
|
1281
|
+
const status = response.status;
|
|
1282
|
+
return typeof status === "number" ? status : 0;
|
|
1283
|
+
}
|
|
1284
|
+
function signingCoverage(steps) {
|
|
1285
|
+
const probes = steps.filter((step) => step.task === REQUEST_SIGNING_PROBE_TASK);
|
|
1286
|
+
if (probes.length === 0) return "not_probed";
|
|
1287
|
+
if (probes.some((step) => step.skipped !== true && probeResponseStatus(step.response) > 0 && !isProbeFault(step.response)))
|
|
1288
|
+
return "graded";
|
|
1289
|
+
if (probes.some((step) => isProbeFault(step.response))) return "probe_errored";
|
|
1290
|
+
if (probes.some((step) => step.skip_reason === "signing_transport_unavailable")) return "transport_unverified";
|
|
1291
|
+
if (probes.every((step) => step.skipped === true)) return "scope_excluded";
|
|
1292
|
+
return "self_check_only";
|
|
1293
|
+
}
|
|
1294
|
+
function isProbeFault(response) {
|
|
1295
|
+
return response !== null && typeof response === "object" && response.probe_error === true;
|
|
1296
|
+
}
|
|
1297
|
+
function signingCoverageUnverified(steps) {
|
|
1298
|
+
const coverage = signingCoverage(steps);
|
|
1299
|
+
return coverage !== "not_probed" && coverage !== "graded";
|
|
1300
|
+
}
|
|
1184
1301
|
function buildDiscoveryFailedResult(agentUrls, storyboard, discoveryStep) {
|
|
1185
1302
|
const detail = discoveryStep.error ?? "Discovery failed (no agent tools advertised).";
|
|
1186
1303
|
const syntheticStep = {
|
|
@@ -1400,7 +1517,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1400
1517
|
try {
|
|
1401
1518
|
routingContext = await buildRoutingContext(storyboard, options);
|
|
1402
1519
|
} catch (err) {
|
|
1403
|
-
const detail = err?.message ?? String(err);
|
|
1520
|
+
const detail = redactOAuthUrlsInText(err?.message ?? String(err));
|
|
1404
1521
|
const failedStep = {
|
|
1405
1522
|
step: err instanceof DiscoveryFailure ? `Discover agent capabilities (${err.agentKey})` : "Build agent routing index",
|
|
1406
1523
|
passed: false,
|
|
@@ -1417,11 +1534,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1417
1534
|
for (const p of routingContext.profiles.values()) {
|
|
1418
1535
|
for (const t of normalizeAgentToolNames(p.tools) ?? []) unionedTools.add(t);
|
|
1419
1536
|
}
|
|
1420
|
-
|
|
1421
|
-
options = { ...options, agentTools: [...unionedTools], _profile: profile };
|
|
1422
|
-
} else if (profile && !options._profile) {
|
|
1423
|
-
options = { ...options, _profile: profile };
|
|
1424
|
-
}
|
|
1537
|
+
options = { ...options, agentTools: [...unionedTools], _profile: profile };
|
|
1425
1538
|
} else {
|
|
1426
1539
|
const clientResolutions = agentUrls.map((url) => getOrCreateClientResolution(url, options));
|
|
1427
1540
|
clients = clientResolutions.map((r) => r.client);
|
|
@@ -1460,9 +1573,126 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1460
1573
|
}
|
|
1461
1574
|
}
|
|
1462
1575
|
}
|
|
1576
|
+
if (preSeeded === void 0) {
|
|
1577
|
+
const resetTargets = routingContext && options.agents ? [...routingContext.profiles.entries()].map(([key, profile2]) => ({
|
|
1578
|
+
client: routingContext.clients.get(key),
|
|
1579
|
+
options: routedAgentOptions(options.agents[key], options, profile2)
|
|
1580
|
+
})) : clients.map((client) => ({ client, options }));
|
|
1581
|
+
const resetFailure = await resetControllerStates(resetTargets, storyboard);
|
|
1582
|
+
if (resetFailure) {
|
|
1583
|
+
if (!callerOwnsClients) await closeScopedConnections(options.protocol);
|
|
1584
|
+
return buildDiscoveryFailedResult(agentUrls, storyboard, resetFailure);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
const allRequires = resolveStoryboardRequires(storyboard, options);
|
|
1588
|
+
let dispatch = routingContext && options.agents ? createRoutingDispatcher(routingContext, options, options.agents) : createDispatcher(agentUrls, clients, "round-robin", dispatchOffset, profile);
|
|
1589
|
+
const routedStepCapabilitySkips = /* @__PURE__ */ new Map();
|
|
1590
|
+
const routedPhaseCapabilitySkips = /* @__PURE__ */ new Map();
|
|
1591
|
+
const routedStepRequirements = /* @__PURE__ */ new Map();
|
|
1592
|
+
const routedRootCapabilitySkips = [];
|
|
1593
|
+
const routedRootRequirementSkips = [];
|
|
1594
|
+
const routedControllerRoutes = /* @__PURE__ */ new Map();
|
|
1595
|
+
const routedErrors = /* @__PURE__ */ new Map();
|
|
1596
|
+
const reportedRoutingErrors = /* @__PURE__ */ new Set();
|
|
1597
|
+
let context = { ...storyboard.context, ...options.context };
|
|
1598
|
+
const routingFailedStep = (step, phaseId, err) => {
|
|
1599
|
+
const detail = redactOAuthUrlsInText(
|
|
1600
|
+
err instanceof RoutingError ? err.message : err?.message ?? String(err)
|
|
1601
|
+
);
|
|
1602
|
+
const failedAgentKey = step.agent ?? options.default_agent;
|
|
1603
|
+
const failedAgentUrl = failedAgentKey ? options.agents?.[failedAgentKey]?.url : void 0;
|
|
1604
|
+
const failedAgentIndex = failedAgentKey ? Object.keys(options.agents ?? {}).indexOf(failedAgentKey) : -1;
|
|
1605
|
+
return {
|
|
1606
|
+
storyboard_id: storyboard.id,
|
|
1607
|
+
step_id: step.id,
|
|
1608
|
+
phase_id: phaseId,
|
|
1609
|
+
title: step.title,
|
|
1610
|
+
task: step.task,
|
|
1611
|
+
passed: false,
|
|
1612
|
+
duration_ms: 0,
|
|
1613
|
+
validations: [],
|
|
1614
|
+
context,
|
|
1615
|
+
error: detail,
|
|
1616
|
+
...failedAgentUrl && { agent_url: redactOAuthUrlForOutput(failedAgentUrl) },
|
|
1617
|
+
...failedAgentIndex >= 0 && { agent_index: failedAgentIndex + 1 },
|
|
1618
|
+
extraction: { path: "none" }
|
|
1619
|
+
};
|
|
1620
|
+
};
|
|
1621
|
+
if (routingContext) {
|
|
1622
|
+
for (const phase of storyboard.phases) {
|
|
1623
|
+
for (const step of phase.steps) {
|
|
1624
|
+
if (step.task === VALIDATION_ONLY_TASK) continue;
|
|
1625
|
+
try {
|
|
1626
|
+
const selected = dispatch.nextFor(step);
|
|
1627
|
+
const selectedOptions = selected.options;
|
|
1628
|
+
const rootDetail = evaluateStoryboardCapabilityGates(
|
|
1629
|
+
storyboard,
|
|
1630
|
+
selected.profile,
|
|
1631
|
+
selectedOptions.agentTools,
|
|
1632
|
+
options.adcpVersion
|
|
1633
|
+
);
|
|
1634
|
+
let requirementSkip;
|
|
1635
|
+
if (rootDetail === null && allRequires.includes("request_signer")) {
|
|
1636
|
+
const requirement = await checkRequires(["request_signer"], storyboard, selectedOptions, {
|
|
1637
|
+
...selected.profile,
|
|
1638
|
+
// Routed discovery is authoritative. A legacy agent without a
|
|
1639
|
+
// capabilities response did not opt into request signing.
|
|
1640
|
+
raw_capabilities: selected.profile.raw_capabilities ?? {}
|
|
1641
|
+
});
|
|
1642
|
+
if ("requirement" in requirement) {
|
|
1643
|
+
requirementSkip = requirement;
|
|
1644
|
+
routedStepRequirements.set(step, requirement.requirement);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
const phaseDetail = phase.requires_capability ? evaluateRequiresCapabilityGate(
|
|
1648
|
+
phase.requires_capability,
|
|
1649
|
+
selected.profile,
|
|
1650
|
+
selectedOptions.agentTools,
|
|
1651
|
+
options.adcpVersion
|
|
1652
|
+
) : null;
|
|
1653
|
+
if (allRequires.includes("controller") && rootDetail === null && phaseDetail === null) {
|
|
1654
|
+
const routeKey = selected.agentKey ?? selected.agentUrl;
|
|
1655
|
+
const routeTools = selectedOptions.agentTools ?? [];
|
|
1656
|
+
const resolvedTask = resolveTaskName(step, selectedOptions) ?? step.task;
|
|
1657
|
+
const previous = routedControllerRoutes.get(routeKey);
|
|
1658
|
+
routedControllerRoutes.set(routeKey, {
|
|
1659
|
+
tools: routeTools,
|
|
1660
|
+
// A `comply_test_controller` step is the back-channel itself,
|
|
1661
|
+
// not the state under test, so it cannot vouch for the route it
|
|
1662
|
+
// is dispatched to. One state-exercising step is enough to mark
|
|
1663
|
+
// the route, whatever order the steps arrive in.
|
|
1664
|
+
stateExercising: (previous?.stateExercising ?? false) || resolvedTask !== "comply_test_controller"
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
if (rootDetail !== null) routedRootCapabilitySkips.push(rootDetail);
|
|
1668
|
+
else if (requirementSkip) routedRootRequirementSkips.push(requirementSkip);
|
|
1669
|
+
const detail = rootDetail ?? requirementSkip?.detail ?? phaseDetail;
|
|
1670
|
+
if (detail !== null) routedStepCapabilitySkips.set(step, detail);
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
routedErrors.set(step, error);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
const callableSteps = phase.steps.filter((step) => step.task !== VALIDATION_ONLY_TASK);
|
|
1676
|
+
if (callableSteps.length && callableSteps.every((step) => routedStepCapabilitySkips.has(step))) {
|
|
1677
|
+
routedPhaseCapabilitySkips.set(phase.id, routedStepCapabilitySkips.get(callableSteps[0]));
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const routedPreflightAssignment = routingContext ? (step) => {
|
|
1682
|
+
if (routedStepCapabilitySkips.has(step)) return void 0;
|
|
1683
|
+
try {
|
|
1684
|
+
return dispatch.nextFor(step);
|
|
1685
|
+
} catch {
|
|
1686
|
+
return void 0;
|
|
1687
|
+
}
|
|
1688
|
+
} : void 0;
|
|
1463
1689
|
const preflightNotices = collectCapabilityNotices(storyboard, options._profile);
|
|
1690
|
+
const callableStepCount = storyboard.phases.reduce(
|
|
1691
|
+
(n, phase) => n + phase.steps.filter((step) => step.task !== VALIDATION_ONLY_TASK).length,
|
|
1692
|
+
0
|
|
1693
|
+
);
|
|
1464
1694
|
if (storyboardCapabilityPredicates(storyboard).length > 0) {
|
|
1465
|
-
const unmetDetail = evaluateStoryboardCapabilityGates(storyboard, profile, options.agentTools, options.adcpVersion);
|
|
1695
|
+
const unmetDetail = routingContext ? routedRootCapabilitySkips.length > 0 && routedRootCapabilitySkips.length === callableStepCount ? routedRootCapabilitySkips[0] : null : evaluateStoryboardCapabilityGates(storyboard, profile, options.agentTools, options.adcpVersion);
|
|
1466
1696
|
if (unmetDetail !== null) {
|
|
1467
1697
|
if (!callerOwnsClients) await closeScopedConnections(options.protocol);
|
|
1468
1698
|
return {
|
|
@@ -1471,21 +1701,71 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1471
1701
|
};
|
|
1472
1702
|
}
|
|
1473
1703
|
}
|
|
1474
|
-
const
|
|
1704
|
+
const establishedRequirements = /* @__PURE__ */ new Map();
|
|
1705
|
+
if (routingContext && allRequires.includes("controller")) {
|
|
1706
|
+
const decided = [...routedControllerRoutes].filter(([, route]) => route.stateExercising);
|
|
1707
|
+
const routes = decided.length > 0 ? decided : [...routedControllerRoutes];
|
|
1708
|
+
if (routedErrors.size > 0 || routes.length === 0) {
|
|
1709
|
+
establishedRequirements.set("controller", { status: "unknown" });
|
|
1710
|
+
} else if (routes.some(([, route]) => route.tools.includes("comply_test_controller"))) {
|
|
1711
|
+
establishedRequirements.set("controller", { status: "met" });
|
|
1712
|
+
} else {
|
|
1713
|
+
const exercised = routes.map(([key]) => key);
|
|
1714
|
+
const exercisedKeys = new Set(exercised);
|
|
1715
|
+
const peersWithController = [...routingContext.profiles.entries()].filter(
|
|
1716
|
+
([key, peer]) => !exercisedKeys.has(key) && normalizeAgentToolNames(peer.tools)?.includes("comply_test_controller")
|
|
1717
|
+
).map(([key]) => key);
|
|
1718
|
+
establishedRequirements.set("controller", {
|
|
1719
|
+
status: "unmet",
|
|
1720
|
+
requirement: "controller",
|
|
1721
|
+
detail: `Storyboard requires 'controller'; no route serving this storyboard's steps advertises comply_test_controller. Route(s) exercised: [${exercised.join(", ")}]. ` + (peersWithController.length ? `Agent(s) [${peersWithController.join(", ")}] in this map do advertise it, but a peer route's controller cannot seed another route's state \u2014 a run-level tool union does not grant it. ` : "") + `Add comply_test_controller to the route that owns the state, or pin the seeding step to that route with 'agent:'.`
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
if (routingContext && allRequires.includes("request_signer")) {
|
|
1726
|
+
establishedRequirements.set(
|
|
1727
|
+
"request_signer",
|
|
1728
|
+
routedErrors.size === 0 && routedRootRequirementSkips.length > 0 && routedRootRequirementSkips.length === callableStepCount ? { status: "unmet", ...routedRootRequirementSkips[0] } : { status: "unknown" }
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1475
1731
|
if (allRequires.length) {
|
|
1476
|
-
const requirementCheck = await checkRequires(
|
|
1732
|
+
const requirementCheck = await checkRequires(
|
|
1733
|
+
allRequires,
|
|
1734
|
+
storyboard,
|
|
1735
|
+
options,
|
|
1736
|
+
routingContext ? void 0 : profile,
|
|
1737
|
+
establishedRequirements
|
|
1738
|
+
);
|
|
1477
1739
|
if ("requirement" in requirementCheck) {
|
|
1478
1740
|
if (!callerOwnsClients) await closeScopedConnections(options.protocol);
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1741
|
+
const result2 = buildRequirementUnmetResult(
|
|
1742
|
+
agentUrls,
|
|
1743
|
+
storyboard,
|
|
1744
|
+
requirementCheck.requirement,
|
|
1745
|
+
requirementCheck.detail
|
|
1746
|
+
);
|
|
1747
|
+
for (const phase of storyboard.phases) {
|
|
1748
|
+
const failures = phase.steps.filter((step) => routedErrors.has(step)).map((step) => routingFailedStep(step, phase.id, routedErrors.get(step)));
|
|
1749
|
+
if (failures.length) {
|
|
1750
|
+
result2.phases.push({
|
|
1751
|
+
phase_id: phase.id,
|
|
1752
|
+
phase_title: phase.title,
|
|
1753
|
+
passed: false,
|
|
1754
|
+
steps: failures,
|
|
1755
|
+
duration_ms: 0
|
|
1756
|
+
});
|
|
1757
|
+
result2.failed_count += failures.length;
|
|
1758
|
+
result2.overall_passed = false;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
return { ...result2, notices: preflightNotices };
|
|
1483
1762
|
}
|
|
1484
1763
|
if (requirementCheck.preparedPublisherAuthProbes) {
|
|
1485
1764
|
options = withPreparedTrustedMatchPublisherAuth(options, requirementCheck.preparedPublisherAuthProbes);
|
|
1765
|
+
if (routingContext && options.agents) dispatch = createRoutingDispatcher(routingContext, options, options.agents);
|
|
1486
1766
|
}
|
|
1487
1767
|
}
|
|
1488
|
-
if (storyboard.required_any_of_tools?.length && options.agentTools) {
|
|
1768
|
+
if (storyboard.required_any_of_tools?.length && options.agentTools && !routingContext?.discoveryFailures.length && routedErrors.size === 0) {
|
|
1489
1769
|
const agentTools = new Set(options.agentTools);
|
|
1490
1770
|
const missing = storyboard.required_any_of_tools.find((family) => !family.tools.some((tool) => agentTools.has(tool)));
|
|
1491
1771
|
if (missing) {
|
|
@@ -1497,8 +1777,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1497
1777
|
};
|
|
1498
1778
|
}
|
|
1499
1779
|
}
|
|
1500
|
-
if (storyboard.required_tools?.length && options.agentTools) {
|
|
1501
|
-
const hasAnyRequired = storyboard.required_tools
|
|
1780
|
+
if (storyboard.required_tools?.length && options.agentTools && !routingContext?.discoveryFailures.length && routedErrors.size === 0) {
|
|
1781
|
+
const hasAnyRequired = hasAnyRequiredTool(storyboard.required_tools, options.agentTools);
|
|
1502
1782
|
if (!hasAnyRequired) {
|
|
1503
1783
|
if (!callerOwnsClients) await closeScopedConnections(options.protocol);
|
|
1504
1784
|
return {
|
|
@@ -1511,18 +1791,26 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1511
1791
|
};
|
|
1512
1792
|
}
|
|
1513
1793
|
}
|
|
1514
|
-
let context = { ...storyboard.context, ...options.context };
|
|
1515
1794
|
if (storyboard.context) forwardAliasCache(storyboard.context, context);
|
|
1516
1795
|
if (options.context) forwardAliasCache(options.context, context);
|
|
1517
1796
|
const contributions = /* @__PURE__ */ new Set();
|
|
1518
1797
|
const contributionSources = /* @__PURE__ */ new Map();
|
|
1519
1798
|
const priorStepResults = /* @__PURE__ */ new Map();
|
|
1520
1799
|
const priorProbes = /* @__PURE__ */ new Map();
|
|
1800
|
+
const routedPriorProbes = /* @__PURE__ */ new Map();
|
|
1521
1801
|
const contextProvenance = /* @__PURE__ */ new Map();
|
|
1522
1802
|
const priorA2aEnvelopes = /* @__PURE__ */ new Map();
|
|
1523
1803
|
const stepRequestStarts = /* @__PURE__ */ new Map();
|
|
1524
1804
|
const responseDerivedNotApplicableContextKeys = /* @__PURE__ */ new Map();
|
|
1525
1805
|
const capabilityUnavailableContextKeysByPhase = /* @__PURE__ */ new Map();
|
|
1806
|
+
const missingPrerequisiteContextKeysByPhase = /* @__PURE__ */ new Map();
|
|
1807
|
+
const recordUnavailableOutputs = (phaseId, step, keysByPhase = capabilityUnavailableContextKeysByPhase) => {
|
|
1808
|
+
const keys = keysByPhase.get(phaseId) ?? /* @__PURE__ */ new Set();
|
|
1809
|
+
for (const output of step.context_outputs ?? []) {
|
|
1810
|
+
if (output.key) keys.add(output.key);
|
|
1811
|
+
}
|
|
1812
|
+
keysByPhase.set(phaseId, keys);
|
|
1813
|
+
};
|
|
1526
1814
|
const phaseResults = [];
|
|
1527
1815
|
let passedCount = 0;
|
|
1528
1816
|
let failedCount = 0;
|
|
@@ -1533,28 +1821,31 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1533
1821
|
const branchSetsByPhaseId = resolveBranchSets(storyboard);
|
|
1534
1822
|
const effectiveDependsOn = (phase, prior) => phase.depends_on ?? prior;
|
|
1535
1823
|
const cascadeForPhase = (phase, prior) => {
|
|
1536
|
-
if (phaseStatefulCascades.has(phase.id)) {
|
|
1537
|
-
return { tripped: true, trigger: phaseStatefulCascades.get(phase.id) ?? null };
|
|
1538
|
-
}
|
|
1539
1824
|
const ownSpec = branchSetsByPhaseId.get(phase.id);
|
|
1540
1825
|
const ownAnyOfBranchSet = ownSpec?.semantics === "any_of" ? ownSpec.id : void 0;
|
|
1541
|
-
|
|
1542
|
-
|
|
1826
|
+
let capabilityTrigger;
|
|
1827
|
+
let missingStateTrigger;
|
|
1828
|
+
for (const depId of [phase.id, ...effectiveDependsOn(phase, prior)]) {
|
|
1829
|
+
if (depId !== phase.id && ownAnyOfBranchSet !== void 0 && branchSetsByPhaseId.get(depId)?.id === ownAnyOfBranchSet) {
|
|
1543
1830
|
continue;
|
|
1544
1831
|
}
|
|
1545
1832
|
if (phaseStatefulCascades.has(depId)) {
|
|
1546
|
-
|
|
1833
|
+
const trigger2 = phaseStatefulCascades.get(depId) ?? null;
|
|
1834
|
+
if (trigger2 === null) return { tripped: true, trigger: null };
|
|
1835
|
+
if (trigger2.capabilityUnavailable) capabilityTrigger ??= trigger2;
|
|
1836
|
+
else missingStateTrigger ??= trigger2;
|
|
1547
1837
|
}
|
|
1548
1838
|
}
|
|
1549
|
-
|
|
1839
|
+
const trigger = missingStateTrigger ?? capabilityTrigger;
|
|
1840
|
+
return trigger ? { tripped: true, trigger } : { tripped: false };
|
|
1550
1841
|
};
|
|
1551
|
-
const
|
|
1552
|
-
const keys =
|
|
1842
|
+
const unavailableContextKeysForPhase = (phase, prior, keysByPhase = capabilityUnavailableContextKeysByPhase) => {
|
|
1843
|
+
const keys = new Set(keysByPhase.get(phase.id));
|
|
1553
1844
|
const ownSpec = branchSetsByPhaseId.get(phase.id);
|
|
1554
1845
|
const ownAnyOfBranchSet = ownSpec?.semantics === "any_of" ? ownSpec.id : void 0;
|
|
1555
1846
|
for (const depId of effectiveDependsOn(phase, prior)) {
|
|
1556
1847
|
if (ownAnyOfBranchSet !== void 0 && branchSetsByPhaseId.get(depId)?.id === ownAnyOfBranchSet) continue;
|
|
1557
|
-
for (const key of
|
|
1848
|
+
for (const key of keysByPhase.get(depId) ?? []) keys.add(key);
|
|
1558
1849
|
}
|
|
1559
1850
|
return keys;
|
|
1560
1851
|
};
|
|
@@ -1572,7 +1863,6 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1572
1863
|
});
|
|
1573
1864
|
if (webhookReceiver) armWebhookAssertions(storyboard, runnerVars, webhookReceiver);
|
|
1574
1865
|
const allSteps = flattenSteps(storyboard);
|
|
1575
|
-
const dispatch = routingContext && options.agents ? createRoutingDispatcher(routingContext, options, options.agents) : createDispatcher(agentUrls, clients, "round-robin", dispatchOffset, profile);
|
|
1576
1866
|
const assertions = resolveAssertions(storyboard.invariants);
|
|
1577
1867
|
validateStepInvariants(storyboard, assertions);
|
|
1578
1868
|
const assertionContexts = /* @__PURE__ */ new Map();
|
|
@@ -1590,12 +1880,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1590
1880
|
if (spec.onStart) await spec.onStart(assertionContexts.get(spec.id));
|
|
1591
1881
|
}
|
|
1592
1882
|
const hasExecutableSteps = storyboard.phases.some((p) => p.steps.length > 0);
|
|
1593
|
-
const phaseCapabilitySkipDetails = collectPhaseCapabilitySkipDetails(
|
|
1594
|
-
storyboard,
|
|
1595
|
-
profile,
|
|
1596
|
-
options.agentTools,
|
|
1597
|
-
options.adcpVersion
|
|
1598
|
-
);
|
|
1883
|
+
const phaseCapabilitySkipDetails = routingContext ? routedPhaseCapabilitySkips : collectPhaseCapabilitySkipDetails(storyboard, profile, options.agentTools, options.adcpVersion);
|
|
1599
1884
|
const skipControllerSeedingForPhaseGates = allExecutablePhasesCapabilitySkipped(
|
|
1600
1885
|
storyboard,
|
|
1601
1886
|
phaseCapabilitySkipDetails
|
|
@@ -1626,7 +1911,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1626
1911
|
storyboardRequiresRequestSigner: allRequires.includes("request_signer"),
|
|
1627
1912
|
storyboardRequiresPublisherAuthRunner: storyboard.requires?.includes("trusted_match_publisher_auth_runner") === true
|
|
1628
1913
|
},
|
|
1629
|
-
preflightExcludedPhaseIds
|
|
1914
|
+
preflightExcludedPhaseIds,
|
|
1915
|
+
routedPreflightAssignment
|
|
1630
1916
|
);
|
|
1631
1917
|
let creativeAssetFixtureGapRecorded = false;
|
|
1632
1918
|
if (!hasExecutableSteps) {
|
|
@@ -1671,22 +1957,36 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1671
1957
|
let fixtureResolutionRecords;
|
|
1672
1958
|
let fixtureCoverageGap;
|
|
1673
1959
|
{
|
|
1674
|
-
let
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1960
|
+
let seeding;
|
|
1961
|
+
try {
|
|
1962
|
+
seeding = creativeAssetFixtureGap || skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(
|
|
1963
|
+
clients[0],
|
|
1964
|
+
storyboard,
|
|
1965
|
+
options,
|
|
1966
|
+
context,
|
|
1967
|
+
clients[0],
|
|
1968
|
+
routingContext ? (task) => {
|
|
1969
|
+
if (!options.agentTools?.includes(task))
|
|
1970
|
+
return { client: clients[0], options: { ...options, agentTools: [] } };
|
|
1971
|
+
const selected = dispatch.nextFor({
|
|
1972
|
+
id: `__fixture_resolution_${task}__`,
|
|
1973
|
+
title: `Fixture resolution via ${task}`,
|
|
1974
|
+
task
|
|
1975
|
+
});
|
|
1976
|
+
return { client: selected.client, options: selected.options };
|
|
1977
|
+
} : void 0
|
|
1978
|
+
);
|
|
1979
|
+
} catch (error) {
|
|
1980
|
+
if (webhookReceiver) await webhookReceiver.close();
|
|
1981
|
+
if (!(error instanceof RoutingError)) throw error;
|
|
1982
|
+
if (!callerOwnsClients) await closeScopedConnections(options.protocol);
|
|
1983
|
+
return buildDiscoveryFailedResult(agentUrls, storyboard, {
|
|
1984
|
+
step: "Resolve fixture agent routes",
|
|
1985
|
+
passed: false,
|
|
1986
|
+
duration_ms: 0,
|
|
1987
|
+
error: redactOAuthUrlsInText(error.message)
|
|
1681
1988
|
});
|
|
1682
|
-
if (options.agentTools?.includes("comply_test_controller")) {
|
|
1683
|
-
fixtureSeedClient = dispatch.nextFor(fixtureStep("comply_test_controller")).client;
|
|
1684
|
-
}
|
|
1685
|
-
if (options.agentTools?.includes("get_products")) {
|
|
1686
|
-
fixtureDiscoveryClient = dispatch.nextFor(fixtureStep("get_products")).client;
|
|
1687
|
-
}
|
|
1688
1989
|
}
|
|
1689
|
-
const seeding = creativeAssetFixtureGap ? null : skipControllerSeedingForPhaseGates ? null : preSeeded !== void 0 ? preSeeded.result : await runControllerSeeding(fixtureSeedClient, storyboard, options, context, fixtureDiscoveryClient);
|
|
1690
1990
|
if (seeding) {
|
|
1691
1991
|
const attach = preSeeded === void 0 || preSeeded.attach;
|
|
1692
1992
|
if (attach) {
|
|
@@ -1758,7 +2058,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1758
2058
|
context,
|
|
1759
2059
|
options,
|
|
1760
2060
|
buildExecutionState(),
|
|
1761
|
-
preflightExcludedPhaseIds
|
|
2061
|
+
preflightExcludedPhaseIds,
|
|
2062
|
+
routedPreflightAssignment
|
|
1762
2063
|
);
|
|
1763
2064
|
}
|
|
1764
2065
|
for (const phase of storyboard.phases) {
|
|
@@ -1803,7 +2104,25 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1803
2104
|
}
|
|
1804
2105
|
const phaseCapabilitySkipDetail = phaseCapabilitySkipDetails.get(phase.id);
|
|
1805
2106
|
if (phaseCapabilitySkipDetail !== void 0) {
|
|
1806
|
-
const skippedSteps =
|
|
2107
|
+
const skippedSteps = routingContext ? phase.steps.map((step) => {
|
|
2108
|
+
const selected = step.task === VALIDATION_ONLY_TASK ? void 0 : dispatch.nextFor(step);
|
|
2109
|
+
const skipped = buildPhaseCapabilitySkippedSteps(
|
|
2110
|
+
storyboard,
|
|
2111
|
+
{ ...phase, steps: [step] },
|
|
2112
|
+
routedStepCapabilitySkips.get(step) ?? phaseCapabilitySkipDetail,
|
|
2113
|
+
context
|
|
2114
|
+
)[0];
|
|
2115
|
+
return {
|
|
2116
|
+
...skipped,
|
|
2117
|
+
...routedStepRequirements.has(step) && {
|
|
2118
|
+
skip: { ...skipped.skip, requirement: routedStepRequirements.get(step) }
|
|
2119
|
+
},
|
|
2120
|
+
...selected && {
|
|
2121
|
+
agent_url: redactOAuthUrlForOutput(selected.agentUrl),
|
|
2122
|
+
agent_index: selected.instanceIndex + 1
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
}) : buildPhaseCapabilitySkippedSteps(storyboard, phase, phaseCapabilitySkipDetail, context);
|
|
1807
2126
|
phaseResults.push({
|
|
1808
2127
|
phase_id: phase.id,
|
|
1809
2128
|
phase_title: phase.title,
|
|
@@ -1813,13 +2132,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1813
2132
|
});
|
|
1814
2133
|
skippedCount += skippedSteps.length;
|
|
1815
2134
|
phaseCapabilitySkippedIds.add(phase.id);
|
|
1816
|
-
const unavailableKeys = /* @__PURE__ */ new Set();
|
|
1817
2135
|
for (const step of phase.steps) {
|
|
1818
|
-
|
|
1819
|
-
if (output.key) unavailableKeys.add(output.key);
|
|
1820
|
-
}
|
|
2136
|
+
recordUnavailableOutputs(phase.id, step);
|
|
1821
2137
|
}
|
|
1822
|
-
capabilityUnavailableContextKeysByPhase.set(phase.id, unavailableKeys);
|
|
1823
2138
|
if (phase.steps.some((s) => s.stateful)) {
|
|
1824
2139
|
phaseStatefulCascades.set(phase.id, {
|
|
1825
2140
|
stepId: phase.steps.find((s) => s.stateful).id,
|
|
@@ -1833,6 +2148,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1833
2148
|
const stepResults = [];
|
|
1834
2149
|
let phasePassed = true;
|
|
1835
2150
|
let phasePendingNotApplicable = null;
|
|
2151
|
+
let phaseInheritedCapabilityTrigger;
|
|
1836
2152
|
let phaseEstablishedStatefulState = false;
|
|
1837
2153
|
const phaseSubstitutes = /* @__PURE__ */ new Map();
|
|
1838
2154
|
for (const declaringStep of phase.steps) {
|
|
@@ -1845,13 +2161,27 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1845
2161
|
phaseSubstitutes.set(target, arr);
|
|
1846
2162
|
}
|
|
1847
2163
|
}
|
|
1848
|
-
|
|
2164
|
+
const phasePendingMissingTool = { trigger: null };
|
|
1849
2165
|
const phaseRescuedTargets = /* @__PURE__ */ new Set();
|
|
1850
2166
|
const phaseRescueSource = /* @__PURE__ */ new Map();
|
|
1851
2167
|
const phaseStatefulStepIds = phase.steps.filter((s) => s.stateful).map((s) => s.id);
|
|
1852
2168
|
let phaseAbsent = false;
|
|
2169
|
+
const routedOauthAbsent = /* @__PURE__ */ new Set();
|
|
1853
2170
|
let presenceDetected = false;
|
|
2171
|
+
const routedOauthPresent = /* @__PURE__ */ new Set();
|
|
1854
2172
|
if (shouldSkipPhase(phase, options, context)) {
|
|
2173
|
+
const skippedRoutingFailures = routingContext ? phase.steps.filter((step) => routedErrors.has(step)) : [];
|
|
2174
|
+
const skippedCapabilitySteps = routingContext ? phase.steps.filter((step) => routedStepCapabilitySkips.has(step)) : [];
|
|
2175
|
+
for (const step of skippedCapabilitySteps) recordUnavailableOutputs(phase.id, step);
|
|
2176
|
+
if (skippedRoutingFailures.length > 0) {
|
|
2177
|
+
for (const step of skippedRoutingFailures) {
|
|
2178
|
+
recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
|
|
2179
|
+
}
|
|
2180
|
+
if (skippedRoutingFailures.some((step) => step.stateful)) phaseStatefulCascades.set(phase.id, null);
|
|
2181
|
+
}
|
|
2182
|
+
if (skippedRoutingFailures.length > 0 || skippedCapabilitySteps.length > 0) {
|
|
2183
|
+
priorPhaseIds.push(phase.id);
|
|
2184
|
+
}
|
|
1855
2185
|
phaseResults.push({
|
|
1856
2186
|
phase_id: phase.id,
|
|
1857
2187
|
phase_title: phase.title,
|
|
@@ -1871,7 +2201,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1871
2201
|
context,
|
|
1872
2202
|
options,
|
|
1873
2203
|
buildExecutionState(),
|
|
1874
|
-
preflightExcludedPhaseIds
|
|
2204
|
+
preflightExcludedPhaseIds,
|
|
2205
|
+
routedPreflightAssignment
|
|
1875
2206
|
);
|
|
1876
2207
|
if (creativeAssetFixtureGap?.target.phaseId === phase.id) {
|
|
1877
2208
|
const gapStep = buildCreativeAssetFixtureUnavailableStep(
|
|
@@ -1897,7 +2228,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1897
2228
|
continue;
|
|
1898
2229
|
}
|
|
1899
2230
|
}
|
|
1900
|
-
if (!
|
|
2231
|
+
if (!routingContext && phaseContainsOauthMetadataProbe(phase) && !agentAdvertisesOauth(profile)) {
|
|
1901
2232
|
phaseAbsent = true;
|
|
1902
2233
|
}
|
|
1903
2234
|
context = { ...context };
|
|
@@ -1939,9 +2270,66 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1939
2270
|
skippedCount += cascadeSteps.length;
|
|
1940
2271
|
continue;
|
|
1941
2272
|
}
|
|
2273
|
+
const recordHardPrerequisiteFailure = (step, realFailure = false) => {
|
|
2274
|
+
if (realFailure) {
|
|
2275
|
+
phaseStatefulCascades.set(phase.id, null);
|
|
2276
|
+
} else if (!phaseStatefulCascades.has(phase.id) || phaseStatefulCascades.get(phase.id)?.capabilityUnavailable === true) {
|
|
2277
|
+
phaseStatefulCascades.set(phase.id, { stepId: step.id, reason: "prerequisite_failed" });
|
|
2278
|
+
}
|
|
2279
|
+
};
|
|
2280
|
+
const recordHardMissingState = (step, result2) => {
|
|
2281
|
+
const substitutes = phaseSubstitutes.get(step.id);
|
|
2282
|
+
if (substitutes && substitutes.length > 0) {
|
|
2283
|
+
if (phasePendingMissingTool.trigger === null) {
|
|
2284
|
+
phasePendingMissingTool.trigger = {
|
|
2285
|
+
stepId: step.id,
|
|
2286
|
+
reason: result2.skip_reason ?? "missing_tool",
|
|
2287
|
+
substitutes
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
} else {
|
|
2291
|
+
const hasStatefulPeers = phaseStatefulStepIds.length > 1;
|
|
2292
|
+
if (hasStatefulPeers && !phaseStatefulCascades.has(phase.id)) {
|
|
2293
|
+
phaseStatefulCascades.set(phase.id, {
|
|
2294
|
+
stepId: step.id,
|
|
2295
|
+
reason: result2.skip_reason ?? "missing_tool"
|
|
2296
|
+
});
|
|
2297
|
+
} else if (!hasStatefulPeers && result2.skip) {
|
|
2298
|
+
result2.skip = {
|
|
2299
|
+
...result2.skip,
|
|
2300
|
+
detail: result2.skip.detail + soleStatefulExemptionDetail(phase.id)
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
};
|
|
1942
2305
|
for (const step of phase.steps) {
|
|
1943
2306
|
options.signal?.throwIfAborted();
|
|
1944
|
-
if (
|
|
2307
|
+
if (routingContext && step.task === VALIDATION_ONLY_TASK) {
|
|
2308
|
+
const result3 = validationOnlyCoverageGap(step, phase.id, context, allSteps, runnerVars, storyboard.id);
|
|
2309
|
+
stepResults.push(result3);
|
|
2310
|
+
priorStepResults.set(step.id, result3);
|
|
2311
|
+
skippedCount++;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
let assignment;
|
|
2315
|
+
try {
|
|
2316
|
+
if (routingContext) assignment = dispatch.nextFor(step);
|
|
2317
|
+
} catch (err) {
|
|
2318
|
+
const failed = routingFailedStep(step, phase.id, err);
|
|
2319
|
+
reportedRoutingErrors.add(step);
|
|
2320
|
+
stepResults.push(failed);
|
|
2321
|
+
countedAsFailed.add(failed);
|
|
2322
|
+
priorStepResults.set(step.id, failed);
|
|
2323
|
+
failedCount++;
|
|
2324
|
+
phasePassed = false;
|
|
2325
|
+
recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
|
|
2326
|
+
if (step.stateful) phaseStatefulCascades.set(phase.id, null);
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
if (routingContext && assignment && phaseContainsOauthMetadataProbe(phase) && !agentAdvertisesOauth(assignment.profile)) {
|
|
2330
|
+
routedOauthAbsent.add(assignment.instanceIndex);
|
|
2331
|
+
}
|
|
2332
|
+
if ((phaseAbsent || assignment && routedOauthAbsent.has(assignment.instanceIndex)) && !routedStepCapabilitySkips.has(step)) {
|
|
1945
2333
|
const cascadeResult = {
|
|
1946
2334
|
storyboard_id: storyboard.id,
|
|
1947
2335
|
step_id: step.id,
|
|
@@ -1962,21 +2350,25 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1962
2350
|
skippedCount++;
|
|
1963
2351
|
continue;
|
|
1964
2352
|
}
|
|
2353
|
+
const selectedOptions = assignment?.options ?? options;
|
|
2354
|
+
const routedCapabilityDetail = routedStepCapabilitySkips.get(step);
|
|
1965
2355
|
const cascade = step.stateful ? cascadeForPhase(phase, priorPhaseIds) : { tripped: false };
|
|
1966
|
-
if (cascade.tripped && step.stateful) {
|
|
1967
|
-
const resolvedTask = resolveTaskName(step,
|
|
1968
|
-
|
|
1969
|
-
|
|
2356
|
+
if (cascade.tripped && step.stateful && routedCapabilityDetail === void 0) {
|
|
2357
|
+
const resolvedTask = resolveTaskName(step, selectedOptions);
|
|
2358
|
+
const missingTool = selectedOptions.agentTools && (routingContext && step.requires_tool && !selectedOptions.agentTools.includes(step.requires_tool) ? step.requires_tool : resolvedTask && resolvedTask !== MCP_SESSION_PROBE_TASK && !selectedOptions.agentTools.includes(resolvedTask) ? resolvedTask : void 0);
|
|
2359
|
+
if (missingTool) {
|
|
2360
|
+
const missingReason = routingContext && missingTool === "comply_test_controller" ? "missing_test_controller" : "missing_tool";
|
|
2361
|
+
const toolDetail = `Agent did not advertise tool "${missingTool}"; agent tools: [${selectedOptions.agentTools.join(", ")}].`;
|
|
1970
2362
|
const missingToolResult = {
|
|
1971
2363
|
storyboard_id: storyboard.id,
|
|
1972
2364
|
step_id: step.id,
|
|
1973
2365
|
phase_id: phase.id,
|
|
1974
2366
|
title: step.title,
|
|
1975
|
-
task: resolvedTask,
|
|
2367
|
+
task: resolvedTask ?? step.task,
|
|
1976
2368
|
passed: true,
|
|
1977
2369
|
skipped: true,
|
|
1978
|
-
skip_reason:
|
|
1979
|
-
skip: buildSkip(
|
|
2370
|
+
skip_reason: missingReason,
|
|
2371
|
+
skip: buildSkip(missingReason, toolDetail),
|
|
1980
2372
|
duration_ms: 0,
|
|
1981
2373
|
validations: [],
|
|
1982
2374
|
context,
|
|
@@ -1984,12 +2376,42 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
1984
2376
|
};
|
|
1985
2377
|
stepResults.push(missingToolResult);
|
|
1986
2378
|
priorStepResults.set(step.id, missingToolResult);
|
|
2379
|
+
if (routingContext) {
|
|
2380
|
+
recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
|
|
2381
|
+
recordHardMissingState(step, missingToolResult);
|
|
2382
|
+
}
|
|
1987
2383
|
skippedCount++;
|
|
1988
2384
|
continue;
|
|
1989
2385
|
}
|
|
1990
2386
|
const trigger = cascade.trigger;
|
|
1991
|
-
|
|
1992
|
-
|
|
2387
|
+
let detail = trigger ? trigger.substitution_chain ? `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); ${trigger.substitution_chain}; state never materialized.` : `Skipped: prior stateful step "${trigger.stepId}" skipped (${trigger.reason}); state never materialized.` : "Skipped: prior stateful step failed.";
|
|
2388
|
+
let capabilityUnavailable = trigger?.capabilityUnavailable === true;
|
|
2389
|
+
if (capabilityUnavailable && routingContext && !TRUSTED_MATCH_PUBLISHER_AUTH_TASKS.has(step.task) && !PROBE_TASKS.has(step.task) && !WEBHOOK_ASSERTION_TASKS.has(step.task) && step.task !== REPLAY_WEBHOOK_VECTOR_TASK && (!step.requires_contract || (selectedOptions.contracts ?? []).includes(step.requires_contract))) {
|
|
2390
|
+
const hardKeys = unavailableContextKeysForPhase(phase, priorPhaseIds, missingPrerequisiteContextKeysByPhase);
|
|
2391
|
+
if (hardKeys.size > 0) {
|
|
2392
|
+
const effectiveRequest = buildEffectiveStepRequest(
|
|
2393
|
+
{ ...step, task: resolvedTask ?? step.task },
|
|
2394
|
+
context,
|
|
2395
|
+
selectedOptions,
|
|
2396
|
+
buildExecutionState(assignment?.agentUrl, assignment?.profile)
|
|
2397
|
+
);
|
|
2398
|
+
const missingKeys = /* @__PURE__ */ new Set([
|
|
2399
|
+
...(effectiveRequest.ok ? findUnresolvedContextVars(effectiveRequest.request) : []).filter((v) => hardKeys.has(v.key)).map((v) => v.key),
|
|
2400
|
+
...(step.context_inputs ?? []).filter((input) => !(input.key in context) && hardKeys.has(input.key)).map((input) => input.key)
|
|
2401
|
+
]);
|
|
2402
|
+
if (missingKeys.size > 0) {
|
|
2403
|
+
capabilityUnavailable = false;
|
|
2404
|
+
detail = `Skipped: context required from a failed or unavailable prerequisite is missing: ${[...missingKeys].join(", ")}.`;
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
if (capabilityUnavailable) {
|
|
2409
|
+
recordUnavailableOutputs(phase.id, step);
|
|
2410
|
+
if (routingContext) phaseInheritedCapabilityTrigger ??= trigger ?? void 0;
|
|
2411
|
+
} else if (routingContext) {
|
|
2412
|
+
recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
|
|
2413
|
+
recordHardPrerequisiteFailure(step, trigger === null);
|
|
2414
|
+
}
|
|
1993
2415
|
stepResults.push({
|
|
1994
2416
|
storyboard_id: storyboard.id,
|
|
1995
2417
|
step_id: step.id,
|
|
@@ -2017,46 +2439,47 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2017
2439
|
skippedCount++;
|
|
2018
2440
|
continue;
|
|
2019
2441
|
}
|
|
2020
|
-
|
|
2021
|
-
try {
|
|
2022
|
-
assignment = dispatch.nextFor(step);
|
|
2023
|
-
} catch (err) {
|
|
2024
|
-
const detail = err instanceof RoutingError ? err.message : err?.message ?? String(err);
|
|
2025
|
-
const failed = {
|
|
2026
|
-
storyboard_id: storyboard.id,
|
|
2027
|
-
step_id: step.id,
|
|
2028
|
-
phase_id: phase.id,
|
|
2029
|
-
title: step.title,
|
|
2030
|
-
task: step.task,
|
|
2031
|
-
passed: false,
|
|
2032
|
-
duration_ms: 0,
|
|
2033
|
-
validations: [],
|
|
2034
|
-
context,
|
|
2035
|
-
error: detail,
|
|
2036
|
-
extraction: { path: "none" }
|
|
2037
|
-
};
|
|
2038
|
-
stepResults.push(failed);
|
|
2039
|
-
priorStepResults.set(step.id, failed);
|
|
2040
|
-
failedCount++;
|
|
2041
|
-
phasePassed = false;
|
|
2042
|
-
continue;
|
|
2043
|
-
}
|
|
2442
|
+
assignment ??= dispatch.nextFor(step);
|
|
2044
2443
|
const stepExecutionState = buildExecutionState(assignment.agentUrl, assignment.profile);
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2444
|
+
if (routingContext) {
|
|
2445
|
+
let probes = routedPriorProbes.get(assignment.instanceIndex);
|
|
2446
|
+
if (!probes) {
|
|
2447
|
+
probes = /* @__PURE__ */ new Map();
|
|
2448
|
+
routedPriorProbes.set(assignment.instanceIndex, probes);
|
|
2449
|
+
}
|
|
2450
|
+
stepExecutionState.priorProbes = probes;
|
|
2451
|
+
stepExecutionState.allowPriorProbeFallback = false;
|
|
2452
|
+
}
|
|
2453
|
+
stepExecutionState.capabilityUnavailableContextKeys = unavailableContextKeysForPhase(phase, priorPhaseIds);
|
|
2454
|
+
if (routingContext) {
|
|
2455
|
+
stepExecutionState.missingPrerequisiteContextKeys = unavailableContextKeysForPhase(
|
|
2456
|
+
phase,
|
|
2457
|
+
priorPhaseIds,
|
|
2458
|
+
missingPrerequisiteContextKeysByPhase
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2461
|
+
const rawResult = routedCapabilityDetail !== void 0 ? buildPhaseCapabilitySkippedSteps(
|
|
2462
|
+
storyboard,
|
|
2463
|
+
{ ...phase, steps: [step] },
|
|
2464
|
+
routedCapabilityDetail,
|
|
2465
|
+
context
|
|
2466
|
+
)[0] : await executeStep(
|
|
2050
2467
|
assignment.client,
|
|
2051
2468
|
step,
|
|
2052
2469
|
storyboard.id,
|
|
2053
2470
|
phase.id,
|
|
2054
2471
|
context,
|
|
2055
2472
|
allSteps,
|
|
2056
|
-
options,
|
|
2473
|
+
assignment.options ?? options,
|
|
2057
2474
|
stepExecutionState
|
|
2058
2475
|
);
|
|
2059
2476
|
const result2 = { ...rawResult, storyboard_id: storyboard.id };
|
|
2477
|
+
if (routedCapabilityDetail !== void 0 || result2.skip_reason === "capability_prerequisite_unavailable") {
|
|
2478
|
+
recordUnavailableOutputs(phase.id, step);
|
|
2479
|
+
}
|
|
2480
|
+
if (routedCapabilityDetail !== void 0 && routedStepRequirements.has(step)) {
|
|
2481
|
+
result2.skip = { ...result2.skip, requirement: routedStepRequirements.get(step) };
|
|
2482
|
+
}
|
|
2060
2483
|
if (isMultiInstance || useRouting) {
|
|
2061
2484
|
result2.agent_url = redactOAuthUrlForOutput(assignment.agentUrl);
|
|
2062
2485
|
result2.agent_index = assignment.instanceIndex + 1;
|
|
@@ -2102,11 +2525,13 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2102
2525
|
}
|
|
2103
2526
|
if (step.task === "protected_resource_metadata") {
|
|
2104
2527
|
if (result2.skipped && result2.skip_reason === "oauth_not_advertised") {
|
|
2105
|
-
|
|
2528
|
+
if (routingContext) routedOauthAbsent.add(assignment.instanceIndex);
|
|
2529
|
+
else phaseAbsent = true;
|
|
2106
2530
|
} else {
|
|
2107
2531
|
const status = result2.response?.status;
|
|
2108
2532
|
if (typeof status === "number" && status >= 200 && status < 300) {
|
|
2109
|
-
|
|
2533
|
+
if (routingContext) routedOauthPresent.add(assignment.instanceIndex);
|
|
2534
|
+
else presenceDetected = true;
|
|
2110
2535
|
}
|
|
2111
2536
|
}
|
|
2112
2537
|
}
|
|
@@ -2122,34 +2547,26 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2122
2547
|
if (result2.skipped) {
|
|
2123
2548
|
skippedCount++;
|
|
2124
2549
|
context = result2.context;
|
|
2550
|
+
const hardPrerequisite = isHardMissingStateSkipReason(result2.skip_reason) || result2.skip_reason === "prerequisite_failed";
|
|
2551
|
+
if (result2.skip_reason === "prerequisite_failed" && !result2.passed) phasePassed = false;
|
|
2552
|
+
if (routingContext && hardPrerequisite) {
|
|
2553
|
+
recordUnavailableOutputs(phase.id, step, missingPrerequisiteContextKeysByPhase);
|
|
2554
|
+
if (!result2.passed) {
|
|
2555
|
+
phasePassed = false;
|
|
2556
|
+
if (step.stateful) recordHardPrerequisiteFailure(step);
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2125
2559
|
if (step.stateful) {
|
|
2126
2560
|
if (isHardMissingStateSkipReason(result2.skip_reason)) {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
} else {
|
|
2137
|
-
const hasStatefulPeers = phaseStatefulStepIds.length > 1;
|
|
2138
|
-
if (hasStatefulPeers && !phaseStatefulCascades.has(phase.id)) {
|
|
2139
|
-
phaseStatefulCascades.set(phase.id, {
|
|
2140
|
-
stepId: step.id,
|
|
2141
|
-
reason: result2.skip_reason ?? "missing_tool"
|
|
2142
|
-
});
|
|
2143
|
-
} else if (!hasStatefulPeers && result2.skip) {
|
|
2144
|
-
result2.skip = {
|
|
2145
|
-
...result2.skip,
|
|
2146
|
-
detail: result2.skip.detail + soleStatefulExemptionDetail(phase.id)
|
|
2147
|
-
};
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
} else if (result2.skip_reason === "not_applicable") {
|
|
2151
|
-
if (phasePendingNotApplicable === null) {
|
|
2152
|
-
phasePendingNotApplicable = { stepId: step.id, reason: "not_applicable" };
|
|
2561
|
+
recordHardMissingState(step, result2);
|
|
2562
|
+
} else if (result2.skip_reason === "not_applicable" || result2.skip_reason === "capability_prerequisite_unavailable") {
|
|
2563
|
+
const capabilityUnavailable = routedCapabilityDetail !== void 0 || result2.skip_reason === "capability_prerequisite_unavailable";
|
|
2564
|
+
if (phasePendingNotApplicable === null || phasePendingNotApplicable.capabilityUnavailable === true && !capabilityUnavailable) {
|
|
2565
|
+
phasePendingNotApplicable = {
|
|
2566
|
+
stepId: step.id,
|
|
2567
|
+
reason: result2.skip_reason,
|
|
2568
|
+
...capabilityUnavailable ? { capabilityUnavailable: true } : {}
|
|
2569
|
+
};
|
|
2153
2570
|
}
|
|
2154
2571
|
}
|
|
2155
2572
|
}
|
|
@@ -2171,7 +2588,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2171
2588
|
}
|
|
2172
2589
|
} else {
|
|
2173
2590
|
phasePassed = false;
|
|
2174
|
-
if (!phase.optional || presenceDetected) {
|
|
2591
|
+
if (!phase.optional || (routingContext ? routedOauthPresent.has(assignment.instanceIndex) : presenceDetected)) {
|
|
2175
2592
|
failedCount++;
|
|
2176
2593
|
countedAsFailed.add(result2);
|
|
2177
2594
|
}
|
|
@@ -2193,7 +2610,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2193
2610
|
context,
|
|
2194
2611
|
options,
|
|
2195
2612
|
stepExecutionState,
|
|
2196
|
-
preflightExcludedPhaseIds
|
|
2613
|
+
preflightExcludedPhaseIds,
|
|
2614
|
+
routedPreflightAssignment
|
|
2197
2615
|
);
|
|
2198
2616
|
}
|
|
2199
2617
|
if (creativeAssetFixtureGap) {
|
|
@@ -2216,6 +2634,15 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2216
2634
|
}
|
|
2217
2635
|
}
|
|
2218
2636
|
}
|
|
2637
|
+
if (phasePendingMissingTool.trigger && !phaseRescuedTargets.has(phasePendingMissingTool.trigger.stepId) && !phaseStatefulCascades.has(phase.id)) {
|
|
2638
|
+
const subs = phasePendingMissingTool.trigger.substitutes;
|
|
2639
|
+
const subsList = subs.length === 1 ? `"${subs[0]}"` : subs.map((s) => `"${s}"`).join(", ");
|
|
2640
|
+
phaseStatefulCascades.set(phase.id, {
|
|
2641
|
+
stepId: phasePendingMissingTool.trigger.stepId,
|
|
2642
|
+
reason: phasePendingMissingTool.trigger.reason,
|
|
2643
|
+
substitution_chain: `declared substitute ${subsList} did not pass`
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2219
2646
|
if (phasePendingNotApplicable && !phaseEstablishedStatefulState && !phaseStatefulCascades.has(phase.id)) {
|
|
2220
2647
|
const hadStatefulPeers = phaseStatefulStepIds.some((id) => id !== phasePendingNotApplicable.stepId);
|
|
2221
2648
|
if (hadStatefulPeers) {
|
|
@@ -2230,14 +2657,8 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2230
2657
|
}
|
|
2231
2658
|
}
|
|
2232
2659
|
}
|
|
2233
|
-
if (
|
|
2234
|
-
|
|
2235
|
-
const subsList = subs.length === 1 ? `"${subs[0]}"` : subs.map((s) => `"${s}"`).join(", ");
|
|
2236
|
-
phaseStatefulCascades.set(phase.id, {
|
|
2237
|
-
stepId: phasePendingMissingTool.stepId,
|
|
2238
|
-
reason: phasePendingMissingTool.reason,
|
|
2239
|
-
substitution_chain: `declared substitute ${subsList} did not pass`
|
|
2240
|
-
});
|
|
2660
|
+
if (phaseInheritedCapabilityTrigger && !phaseStatefulCascades.has(phase.id)) {
|
|
2661
|
+
phaseStatefulCascades.set(phase.id, phaseInheritedCapabilityTrigger);
|
|
2241
2662
|
}
|
|
2242
2663
|
for (const target of phaseRescuedTargets) {
|
|
2243
2664
|
const sourceId = phaseRescueSource.get(target);
|
|
@@ -2258,6 +2679,27 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2258
2679
|
});
|
|
2259
2680
|
priorPhaseIds.push(phase.id);
|
|
2260
2681
|
}
|
|
2682
|
+
for (const phase of storyboard.phases) {
|
|
2683
|
+
const result2 = phaseResults.find((p) => p.phase_id === phase.id);
|
|
2684
|
+
for (const step of phase.steps) {
|
|
2685
|
+
if (!routedErrors.has(step) || reportedRoutingErrors.has(step)) continue;
|
|
2686
|
+
const failed = routingFailedStep(step, phase.id, routedErrors.get(step));
|
|
2687
|
+
const existingIndex = result2.steps.findIndex((row) => row.step_id === step.id);
|
|
2688
|
+
if (existingIndex >= 0) {
|
|
2689
|
+
const existing = result2.steps[existingIndex];
|
|
2690
|
+
if (existing.skipped) skippedCount--;
|
|
2691
|
+
if (countedAsFailed.delete(existing)) failedCount--;
|
|
2692
|
+
result2.steps[existingIndex] = failed;
|
|
2693
|
+
} else {
|
|
2694
|
+
result2.steps.push(failed);
|
|
2695
|
+
}
|
|
2696
|
+
reportedRoutingErrors.add(step);
|
|
2697
|
+
countedAsFailed.add(failed);
|
|
2698
|
+
result2.passed = false;
|
|
2699
|
+
priorStepResults.set(step.id, failed);
|
|
2700
|
+
failedCount++;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2261
2703
|
const branchSetDelta = creativeAssetFixtureGap ? { skippedDelta: 0 } : applyBranchSetGrading(
|
|
2262
2704
|
storyboard.phases,
|
|
2263
2705
|
phaseResults,
|
|
@@ -2294,8 +2736,9 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2294
2736
|
const phaseResult = phaseResults.find((p) => p.phase_id === phaseDef.id);
|
|
2295
2737
|
return !!phaseResult && phaseResult.passed && phaseResult.steps.some((s) => !s.skipped && s.passed);
|
|
2296
2738
|
});
|
|
2297
|
-
const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseHasExecutedPass || requiredPhasesNonFailingSkipped || failedCount === 0 && requiredPhasesCoveredByCapabilityGates;
|
|
2739
|
+
const requiredPhasesPassed = !hasExecutableSteps || requiredPhaseDefs.every((phaseDef) => phaseResults.find((p) => p.phase_id === phaseDef.id)?.passed === true) && (requiredPhaseHasExecutedPass || requiredPhasesNonFailingSkipped || failedCount === 0 && requiredPhasesCoveredByCapabilityGates);
|
|
2298
2740
|
const storyboardWideFixtureUnavailable = (seedingUnsupported || fixtureUnsatisfied || creativeAssetFixtureGap !== void 0) && failedCount === 0;
|
|
2741
|
+
const hasUnverifiedCoverage = signingCoverageUnverified(phaseResults.flatMap((phase) => phase.steps));
|
|
2299
2742
|
if (seedingPhaseResult) phaseResults.unshift(seedingPhaseResult);
|
|
2300
2743
|
const schemasUsed = collectSchemasUsed(phaseResults);
|
|
2301
2744
|
const strictSummary = summarizeStrictValidation(phaseResults);
|
|
@@ -2319,7 +2762,7 @@ async function executeStoryboardPass(agentUrls, storyboard, options, dispatchOff
|
|
|
2319
2762
|
Object.entries(routingContext.agentMap).map(([specialism, url]) => [specialism, redactOAuthUrlForOutput(url)])
|
|
2320
2763
|
)
|
|
2321
2764
|
},
|
|
2322
|
-
overall_passed: failedCount === 0 && (requiredPhasesPassed || storyboardWideFixtureUnavailable) && !assertionsFailed,
|
|
2765
|
+
overall_passed: failedCount === 0 && (requiredPhasesPassed || storyboardWideFixtureUnavailable) && !assertionsFailed && !hasUnverifiedCoverage,
|
|
2323
2766
|
phases: phaseResults,
|
|
2324
2767
|
context,
|
|
2325
2768
|
total_duration_ms: Date.now() - start,
|
|
@@ -2372,6 +2815,14 @@ async function runMultiPass(agentUrls, storyboard, options) {
|
|
|
2372
2815
|
...options.agentTools ? {} : { agentTools: normalizeAgentToolNames(preSeedProfile.tools) }
|
|
2373
2816
|
};
|
|
2374
2817
|
}
|
|
2818
|
+
const resetFailure = await resetControllerStates(
|
|
2819
|
+
preSeedClients.map((client) => ({ client, options })),
|
|
2820
|
+
storyboard
|
|
2821
|
+
);
|
|
2822
|
+
if (resetFailure) {
|
|
2823
|
+
await closeScopedConnections(options.protocol);
|
|
2824
|
+
return buildDiscoveryFailedResult(agentUrls, storyboard, resetFailure);
|
|
2825
|
+
}
|
|
2375
2826
|
if (storyboardCapabilityPredicates(storyboard).length > 0) {
|
|
2376
2827
|
const unmetDetail = evaluateStoryboardCapabilityGates(
|
|
2377
2828
|
storyboard,
|
|
@@ -2704,6 +3155,38 @@ async function runStoryboardStepBody(agentUrl, storyboard, stepId, options) {
|
|
|
2704
3155
|
if (ownsWebhookReceiver && webhookReceiver) await webhookReceiver.close();
|
|
2705
3156
|
return { ...result, contributions: Array.from(contributions) };
|
|
2706
3157
|
}
|
|
3158
|
+
function unresolvedStepContextVars(step, request, context, runState) {
|
|
3159
|
+
const unavailableInputs = (step.context_inputs ?? []).filter(
|
|
3160
|
+
(input) => !(input.key in context) && (runState.capabilityUnavailableContextKeys?.has(input.key) === true || runState.missingPrerequisiteContextKeys?.has(input.key) === true)
|
|
3161
|
+
);
|
|
3162
|
+
return [
|
|
3163
|
+
...findUnresolvedContextVars(request),
|
|
3164
|
+
...unavailableInputs.map((input) => ({ key: input.key, token: `$context.${input.key}` }))
|
|
3165
|
+
];
|
|
3166
|
+
}
|
|
3167
|
+
function buildStepRequest(step, effectiveStep, context, options, runnerVars) {
|
|
3168
|
+
let request;
|
|
3169
|
+
if (options.request) {
|
|
3170
|
+
request = injectContext({ ...options.request }, context, runnerVars);
|
|
3171
|
+
} else if (step.expect_error && step.sample_request) {
|
|
3172
|
+
request = injectContext({ ...step.sample_request }, context, runnerVars);
|
|
3173
|
+
} else if (hasRequestEnricher(effectiveStep.task)) {
|
|
3174
|
+
request = enrichRequest(effectiveStep, context, options, runnerVars);
|
|
3175
|
+
} else if (step.sample_request) {
|
|
3176
|
+
request = injectContext({ ...step.sample_request }, context, runnerVars);
|
|
3177
|
+
} else {
|
|
3178
|
+
request = {};
|
|
3179
|
+
}
|
|
3180
|
+
if (step.context_inputs?.length) {
|
|
3181
|
+
request = applyContextInputs(request, step.context_inputs, context);
|
|
3182
|
+
}
|
|
3183
|
+
request = applyBrandInvariant(request, options, effectiveStep.task, { omit_account: step.omit_account });
|
|
3184
|
+
if (options.disable_sandbox === true) {
|
|
3185
|
+
request = applyDisableSandboxHint(request, effectiveStep.task);
|
|
3186
|
+
}
|
|
3187
|
+
request = applyIdempotencyInvariant(request, effectiveStep.task, step);
|
|
3188
|
+
return request;
|
|
3189
|
+
}
|
|
2707
3190
|
async function executeStep(client, step, storyboardId, phaseId, context, allSteps, options, state) {
|
|
2708
3191
|
const runState = state ?? {
|
|
2709
3192
|
contributions: /* @__PURE__ */ new Set(),
|
|
@@ -2807,6 +3290,9 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2807
3290
|
extraction: { path: "none" }
|
|
2808
3291
|
};
|
|
2809
3292
|
}
|
|
3293
|
+
if (effectiveStep.task === MCP_SESSION_PROBE_TASK) {
|
|
3294
|
+
return executeProbeStep(client, effectiveStep, phaseId, context, allSteps, options, runState);
|
|
3295
|
+
}
|
|
2810
3296
|
if (effectiveStep.task === "sync_accounts") {
|
|
2811
3297
|
const rawCaps = options._profile?.raw_capabilities;
|
|
2812
3298
|
if (rawCaps !== void 0) {
|
|
@@ -2852,47 +3338,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2852
3338
|
extraction: { path: "none" }
|
|
2853
3339
|
};
|
|
2854
3340
|
}
|
|
2855
|
-
let request;
|
|
2856
|
-
if (options.request) {
|
|
2857
|
-
request = injectContext({ ...options.request }, context, runState.runnerVars);
|
|
2858
|
-
} else if (step.expect_error && step.sample_request) {
|
|
2859
|
-
request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
|
|
2860
|
-
} else if (hasRequestEnricher(effectiveStep.task)) {
|
|
2861
|
-
request = enrichRequest(effectiveStep, context, options, runState.runnerVars);
|
|
2862
|
-
} else if (step.sample_request) {
|
|
2863
|
-
request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
|
|
2864
|
-
} else {
|
|
2865
|
-
request = {};
|
|
2866
|
-
}
|
|
2867
|
-
if (step.context_inputs?.length) {
|
|
2868
|
-
request = applyContextInputs(request, step.context_inputs, context);
|
|
2869
|
-
}
|
|
2870
|
-
const unavailableContextInputs = (step.context_inputs ?? []).filter(
|
|
2871
|
-
(input) => !(input.key in context) && runState.capabilityUnavailableContextKeys?.has(input.key) === true
|
|
2872
|
-
);
|
|
2873
|
-
if (unavailableContextInputs.length > 0) {
|
|
2874
|
-
const detail = "Skipped: context required by a capability-gated phase is unavailable: " + unavailableContextInputs.map((input) => input.key).join(", ") + ".";
|
|
2875
|
-
return {
|
|
2876
|
-
step_id: step.id,
|
|
2877
|
-
phase_id: phaseId,
|
|
2878
|
-
title: step.title,
|
|
2879
|
-
task: step.task,
|
|
2880
|
-
passed: true,
|
|
2881
|
-
skipped: true,
|
|
2882
|
-
skip_reason: "capability_prerequisite_unavailable",
|
|
2883
|
-
skip: buildSkip("not_applicable", detail),
|
|
2884
|
-
duration_ms: 0,
|
|
2885
|
-
validations: [],
|
|
2886
|
-
context,
|
|
2887
|
-
next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
|
|
2888
|
-
extraction: { path: "none" }
|
|
2889
|
-
};
|
|
2890
|
-
}
|
|
2891
|
-
request = applyBrandInvariant(request, options, effectiveStep.task, { omit_account: step.omit_account });
|
|
2892
|
-
if (options.disable_sandbox === true) {
|
|
2893
|
-
request = applyDisableSandboxHint(request, effectiveStep.task);
|
|
2894
|
-
}
|
|
2895
|
-
request = applyIdempotencyInvariant(request, effectiveStep.task, step);
|
|
3341
|
+
let request = buildStepRequest(step, effectiveStep, context, options, runState.runnerVars);
|
|
2896
3342
|
const fixtureBinding = applyFixtureBindingsSafely(request, effectiveStep.task, options, runState);
|
|
2897
3343
|
if (!fixtureBinding.ok) {
|
|
2898
3344
|
const next2 = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
@@ -2935,7 +3381,7 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2935
3381
|
effectiveStep.task
|
|
2936
3382
|
);
|
|
2937
3383
|
}
|
|
2938
|
-
const unresolvedContextVars =
|
|
3384
|
+
const unresolvedContextVars = unresolvedStepContextVars(step, request, context, runState);
|
|
2939
3385
|
const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(request).map((path) => ({
|
|
2940
3386
|
key: path,
|
|
2941
3387
|
token: BUILD_ASSETS_FROM_FORMAT_DIRECTIVE
|
|
@@ -2944,11 +3390,14 @@ async function executeStep(client, step, storyboardId, phaseId, context, allStep
|
|
|
2944
3390
|
const hasCapabilityUnavailableContext = unresolvedContextVars.some(
|
|
2945
3391
|
(v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true
|
|
2946
3392
|
);
|
|
2947
|
-
|
|
3393
|
+
const hasMissingToolUnavailableContext = unresolvedContextVars.some(
|
|
3394
|
+
(v) => runState.missingPrerequisiteContextKeys?.has(v.key) === true
|
|
3395
|
+
);
|
|
3396
|
+
if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && (!step.expect_error || hasCapabilityUnavailableContext || hasMissingToolUnavailableContext)) {
|
|
2948
3397
|
const next2 = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
2949
3398
|
const responseDerivedDetails = unresolvedVars.map((v) => runState.responseDerivedNotApplicableContextKeys?.get(v.key)).filter((d) => typeof d === "string");
|
|
2950
|
-
const allResponseDerived = responseDerivedDetails.length === unresolvedVars.length && responseDerivedDetails.length > 0;
|
|
2951
|
-
const allCapabilityUnavailable = unresolvedContextVars.length === unresolvedVars.length && unresolvedContextVars.length > 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true);
|
|
3399
|
+
const allResponseDerived = !hasMissingToolUnavailableContext && responseDerivedDetails.length === unresolvedVars.length && responseDerivedDetails.length > 0;
|
|
3400
|
+
const allCapabilityUnavailable = !hasMissingToolUnavailableContext && unresolvedContextVars.length === unresolvedVars.length && unresolvedContextVars.length > 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key) === true);
|
|
2952
3401
|
const detail = allResponseDerived ? [...new Set(responseDerivedDetails)].join("; ") : allCapabilityUnavailable ? `Skipped: context required by a capability-gated phase is unavailable: ${unresolvedVars.map((v) => v.key).join(", ")}.` : `Skipped: unresolved context variables from prior steps: ${unresolvedVars.map((v) => v.key).join(", ")}.`;
|
|
2953
3402
|
const synthesized = [];
|
|
2954
3403
|
if (!allResponseDerived && !allCapabilityUnavailable) {
|
|
@@ -3814,6 +4263,9 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3814
4263
|
fetchFn: options.transport?.trustedFetchFn
|
|
3815
4264
|
};
|
|
3816
4265
|
let requestRecordOverride;
|
|
4266
|
+
let sessionProbeStage;
|
|
4267
|
+
let sessionProbeDetail;
|
|
4268
|
+
let sessionProbeTool;
|
|
3817
4269
|
const contractsInScope = new Set(options.contracts ?? []);
|
|
3818
4270
|
if (step.requires_contract) {
|
|
3819
4271
|
if (!contractsInScope.has(step.requires_contract)) {
|
|
@@ -3895,10 +4347,48 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3895
4347
|
httpResult.skip_reason = "oauth_not_advertised";
|
|
3896
4348
|
}
|
|
3897
4349
|
} else if (step.task === "oauth_auth_server_metadata") {
|
|
3898
|
-
const prior = runState.priorProbes.get("protected_resource_metadata") ?? findPriorProbe(runState.priorStepResults);
|
|
4350
|
+
const prior = runState.priorProbes.get("protected_resource_metadata") ?? (runState.allowPriorProbeFallback !== false ? findPriorProbe(runState.priorStepResults) : void 0);
|
|
3899
4351
|
httpResult = await probeOauthAuthServerMetadata(prior, probeOpts);
|
|
3900
4352
|
} else if (step.task === "assert_contribution") {
|
|
3901
4353
|
httpResult = void 0;
|
|
4354
|
+
} else if (step.task === MCP_SESSION_PROBE_TASK) {
|
|
4355
|
+
const plan = planMcpSessionSentinel(step, options, client, runState.agentUrl);
|
|
4356
|
+
if (plan.kind === "error") {
|
|
4357
|
+
httpResult = { url: runState.agentUrl, status: 0, headers: {}, body: null, error: plan.error };
|
|
4358
|
+
} else if (plan.kind === "skip") {
|
|
4359
|
+
httpResult = {
|
|
4360
|
+
url: runState.agentUrl,
|
|
4361
|
+
status: 0,
|
|
4362
|
+
headers: {},
|
|
4363
|
+
body: null,
|
|
4364
|
+
skipped: true,
|
|
4365
|
+
skip_reason: plan.reason,
|
|
4366
|
+
error: plan.detail
|
|
4367
|
+
};
|
|
4368
|
+
} else {
|
|
4369
|
+
const probe = await rawMcpSessionProbe({
|
|
4370
|
+
agentUrl: runState.agentUrl,
|
|
4371
|
+
headers: plan.headers,
|
|
4372
|
+
toolName: plan.toolNames,
|
|
4373
|
+
control: plan.control,
|
|
4374
|
+
// Values the probe withholds but the run's ordinary steps do send, so
|
|
4375
|
+
// a stateful agent's echo cannot land them in this step's evidence.
|
|
4376
|
+
redactValues: runCredentialValues(options),
|
|
4377
|
+
allowPrivateIp: options.allow_http === true,
|
|
4378
|
+
// Honour run cancellation and cap each request well under the shared
|
|
4379
|
+
// 10 s `ssrfSafeFetch` default. The probe additionally bounds the
|
|
4380
|
+
// whole step — candidate walk included — with one shared request /
|
|
4381
|
+
// byte / wall-clock budget, so a tarpitting agent cannot multiply this
|
|
4382
|
+
// per-request cap by the length of its own tool list.
|
|
4383
|
+
...options.signal && { signal: options.signal },
|
|
4384
|
+
timeoutMs: MCP_SESSION_PROBE_REQUEST_TIMEOUT_MS,
|
|
4385
|
+
...options.transport?.trustedFetchFn && { fetchFn: options.transport.trustedFetchFn }
|
|
4386
|
+
});
|
|
4387
|
+
httpResult = probe.httpResult;
|
|
4388
|
+
sessionProbeStage = probe.stage;
|
|
4389
|
+
sessionProbeDetail = probe.detail;
|
|
4390
|
+
sessionProbeTool = probe.gradedTool;
|
|
4391
|
+
}
|
|
3902
4392
|
} else if (step.task === "request_signing_probe") {
|
|
3903
4393
|
httpResult = await probeRequestSigningVector(step.id, runState.agentUrl, options);
|
|
3904
4394
|
} else if (step.task === "fetch_brand_jwks") {
|
|
@@ -3975,30 +4465,35 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
3975
4465
|
};
|
|
3976
4466
|
}
|
|
3977
4467
|
const resolvedTargetRequest = targetRequestResult.request;
|
|
3978
|
-
const
|
|
4468
|
+
const advertisedTools = resolveAdvertisedTools(options);
|
|
4469
|
+
const routedPrerequisites = runState.missingPrerequisiteContextKeys !== void 0 && (!advertisedTools || advertisedTools.includes(rateLimitTrip.trip_target_task));
|
|
4470
|
+
const unresolvedContextVars = routedPrerequisites ? unresolvedStepContextVars(targetStep, resolvedTargetRequest, context, runState) : findUnresolvedContextVars(resolvedTargetRequest);
|
|
3979
4471
|
const unresolvedAssetDirectives = findUnresolvedCreativeAssetDirectives(resolvedTargetRequest).map((path) => ({
|
|
3980
4472
|
key: path,
|
|
3981
4473
|
token: BUILD_ASSETS_FROM_FORMAT_DIRECTIVE
|
|
3982
4474
|
}));
|
|
3983
4475
|
const unresolvedVars = [...unresolvedContextVars, ...unresolvedAssetDirectives];
|
|
3984
|
-
|
|
4476
|
+
const hardUnavailable = routedPrerequisites && unresolvedContextVars.some((v) => runState.missingPrerequisiteContextKeys?.has(v.key));
|
|
4477
|
+
const capabilityUnavailable = routedPrerequisites && unresolvedContextVars.some((v) => runState.capabilityUnavailableContextKeys?.has(v.key));
|
|
4478
|
+
if (unresolvedAssetDirectives.length > 0 || unresolvedContextVars.length > 0 && (!targetStep.expect_error || hardUnavailable || capabilityUnavailable)) {
|
|
3985
4479
|
const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
3986
|
-
const
|
|
4480
|
+
const allCapabilityUnavailable = capabilityUnavailable && !hardUnavailable && unresolvedAssetDirectives.length === 0 && unresolvedContextVars.every((v) => runState.capabilityUnavailableContextKeys?.has(v.key));
|
|
4481
|
+
const detail = allCapabilityUnavailable ? `Skipped: context required by a capability-gated phase is unavailable: ${unresolvedVars.map((v) => v.key).join(", ")}.` : `Skipped: unresolved context variables from rate_limit_trip.trip_target_sample_request: ${unresolvedVars.map((v) => v.key).join(", ")}.`;
|
|
3987
4482
|
return {
|
|
3988
4483
|
step_id: step.id,
|
|
3989
4484
|
phase_id: phaseId,
|
|
3990
4485
|
title: step.title,
|
|
3991
4486
|
task: step.task,
|
|
3992
|
-
passed:
|
|
4487
|
+
passed: allCapabilityUnavailable,
|
|
3993
4488
|
skipped: true,
|
|
3994
|
-
skip_reason: "prerequisite_failed",
|
|
3995
|
-
skip: buildSkip("prerequisite_failed", detail),
|
|
4489
|
+
skip_reason: allCapabilityUnavailable ? "capability_prerequisite_unavailable" : "prerequisite_failed",
|
|
4490
|
+
skip: buildSkip(allCapabilityUnavailable ? "not_applicable" : "prerequisite_failed", detail),
|
|
3996
4491
|
duration_ms: Date.now() - start,
|
|
3997
4492
|
validations: [],
|
|
3998
4493
|
context,
|
|
3999
4494
|
next,
|
|
4000
4495
|
extraction: { path: "none" },
|
|
4001
|
-
error: detail
|
|
4496
|
+
...!allCapabilityUnavailable && { error: detail }
|
|
4002
4497
|
};
|
|
4003
4498
|
}
|
|
4004
4499
|
const unresolvedRunnerTokens = findUnresolvedRunnerTokens(resolvedTargetRequest);
|
|
@@ -4024,7 +4519,6 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
4024
4519
|
...isPrerequisiteFailure ? { error: detail } : {}
|
|
4025
4520
|
};
|
|
4026
4521
|
}
|
|
4027
|
-
const advertisedTools = resolveAdvertisedTools(options);
|
|
4028
4522
|
if (advertisedTools && !advertisedTools.includes(rateLimitTrip.trip_target_task)) {
|
|
4029
4523
|
const next = getNextStepPreview(step.id, allSteps, context, runState.runnerVars);
|
|
4030
4524
|
const detail = `Agent did not advertise tool "${rateLimitTrip.trip_target_task}"; agent tools: [${advertisedTools.join(", ")}].`;
|
|
@@ -4120,7 +4614,7 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
4120
4614
|
if (httpResult?.skipped) {
|
|
4121
4615
|
const detailedReason = httpResult.skip_reason ?? "probe_skipped";
|
|
4122
4616
|
const canonicalReason = DETAILED_SKIP_TO_CANONICAL[detailedReason] ?? "not_applicable";
|
|
4123
|
-
const detail = CANONICAL_SKIP_DETAILS[detailedReason] ??
|
|
4617
|
+
const detail = CANONICAL_SKIP_DETAILS[detailedReason] ?? redactedHttpResult?.error ?? DETAILED_SKIP_DETAILS[detailedReason] ?? SKIP_DETAILS[canonicalReason];
|
|
4124
4618
|
const selectionResult = selectionForProbeSkip(detailedReason, detail);
|
|
4125
4619
|
return {
|
|
4126
4620
|
step_id: step.id,
|
|
@@ -4167,7 +4661,8 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
4167
4661
|
const allValidationsPassed = validations.every((v) => !validationFailsStep(v));
|
|
4168
4662
|
const fetchOk = httpResult ? !httpResult.error : true;
|
|
4169
4663
|
const passed = fetchOk && allValidationsPassed;
|
|
4170
|
-
const
|
|
4664
|
+
const probeNote = sessionProbeStage !== void 0 ? `MCP session probe graded ${sessionProbeTool ?? "unknown tool"} at ${sessionProbeStage} (${sessionProbeDetail ?? "no detail"})` : "http-probe body parsed as JSON";
|
|
4665
|
+
const extraction = httpResult ? httpResult.error ? { path: "error" } : { path: "structured_content", note: probeNote } : { path: "none" };
|
|
4171
4666
|
return {
|
|
4172
4667
|
step_id: step.id,
|
|
4173
4668
|
phase_id: phaseId,
|
|
@@ -4178,7 +4673,9 @@ async function executeProbeStep(client, step, phaseId, context, allSteps, option
|
|
|
4178
4673
|
response: redactedHttpResult ?? void 0,
|
|
4179
4674
|
validations,
|
|
4180
4675
|
context,
|
|
4181
|
-
|
|
4676
|
+
// Redacted copy on both branches: the sibling skip branch reads the same
|
|
4677
|
+
// seam, and a probe error can carry an agent URL with OAuth params.
|
|
4678
|
+
error: redactedHttpResult?.error ?? (passed ? void 0 : "Probe validations failed."),
|
|
4182
4679
|
next: getNextStepPreview(step.id, allSteps, context, runState.runnerVars),
|
|
4183
4680
|
request: requestRecord,
|
|
4184
4681
|
...responseRecord && { response_record: responseRecord },
|
|
@@ -4201,26 +4698,7 @@ function applyFixtureBindingsSafely(request, task, options, runState) {
|
|
|
4201
4698
|
}
|
|
4202
4699
|
}
|
|
4203
4700
|
function buildEffectiveStepRequest(step, context, options, runState) {
|
|
4204
|
-
|
|
4205
|
-
if (options.request) {
|
|
4206
|
-
request = injectContext({ ...options.request }, context, runState.runnerVars);
|
|
4207
|
-
} else if (step.expect_error && step.sample_request) {
|
|
4208
|
-
request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
|
|
4209
|
-
} else if (hasRequestEnricher(step.task)) {
|
|
4210
|
-
request = enrichRequest(step, context, options, runState.runnerVars);
|
|
4211
|
-
} else if (step.sample_request) {
|
|
4212
|
-
request = injectContext({ ...step.sample_request }, context, runState.runnerVars);
|
|
4213
|
-
} else {
|
|
4214
|
-
request = {};
|
|
4215
|
-
}
|
|
4216
|
-
if (step.context_inputs?.length) {
|
|
4217
|
-
request = applyContextInputs(request, step.context_inputs, context);
|
|
4218
|
-
}
|
|
4219
|
-
request = applyBrandInvariant(request, options, step.task, { omit_account: step.omit_account });
|
|
4220
|
-
if (options.disable_sandbox === true) {
|
|
4221
|
-
request = applyDisableSandboxHint(request, step.task);
|
|
4222
|
-
}
|
|
4223
|
-
request = applyIdempotencyInvariant(request, step.task, step);
|
|
4701
|
+
const request = buildStepRequest(step, step, context, options, runState.runnerVars);
|
|
4224
4702
|
const fixtureBinding = applyFixtureBindingsSafely(request, step.task, options, runState);
|
|
4225
4703
|
if (!fixtureBinding.ok) return fixtureBinding;
|
|
4226
4704
|
const creativeAssetExpansion = expandCreativeAssetDirectivesWithDiagnostics(
|
|
@@ -4236,23 +4714,32 @@ function buildEffectiveStepRequest(step, context, options, runState) {
|
|
|
4236
4714
|
request: creativeAssetExpansion.value
|
|
4237
4715
|
};
|
|
4238
4716
|
}
|
|
4239
|
-
function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, context, options, runState, excludedPhaseIds = /* @__PURE__ */ new Set()) {
|
|
4717
|
+
function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, context, options, runState, excludedPhaseIds = /* @__PURE__ */ new Set(), resolveAssignment) {
|
|
4240
4718
|
const contractsInScope = new Set(options.contracts ?? []);
|
|
4241
4719
|
for (const target of allSteps) {
|
|
4242
4720
|
if (target.globalIndex <= afterGlobalIndex) continue;
|
|
4243
4721
|
if (excludedPhaseIds.has(target.phaseId)) continue;
|
|
4244
|
-
const
|
|
4722
|
+
const assignment = resolveAssignment?.(target.step);
|
|
4723
|
+
if (resolveAssignment && !assignment) continue;
|
|
4724
|
+
const selectedOptions = assignment?.options ?? options;
|
|
4725
|
+
const selectedState = assignment ? {
|
|
4726
|
+
...runState,
|
|
4727
|
+
agentUrl: assignment.agentUrl,
|
|
4728
|
+
agentProfile: assignment.profile,
|
|
4729
|
+
agentLibraryVersion: assignment.profile?.library_version
|
|
4730
|
+
} : runState;
|
|
4731
|
+
const resolvedTask = resolveTaskName(target.step, selectedOptions);
|
|
4245
4732
|
if (!resolvedTask) continue;
|
|
4246
|
-
if (target.step.requires_tool &&
|
|
4733
|
+
if (target.step.requires_tool && selectedOptions.agentTools && !selectedOptions.agentTools.includes(target.step.requires_tool)) {
|
|
4247
4734
|
continue;
|
|
4248
4735
|
}
|
|
4249
4736
|
if (target.step.requires_contract && !contractsInScope.has(target.step.requires_contract)) {
|
|
4250
4737
|
continue;
|
|
4251
4738
|
}
|
|
4252
|
-
if (target.step.task === "expect_rate_limit_not_replayed" && (!contractsInScope.has(RATE_LIMIT_TRIP_CONTRACT) ||
|
|
4739
|
+
if (target.step.task === "expect_rate_limit_not_replayed" && (!contractsInScope.has(RATE_LIMIT_TRIP_CONTRACT) || selectedOptions.allowLiveSideEffects !== true)) {
|
|
4253
4740
|
continue;
|
|
4254
4741
|
}
|
|
4255
|
-
if (!PROBE_TASKS.has(target.step.task) &&
|
|
4742
|
+
if (!PROBE_TASKS.has(target.step.task) && selectedOptions.agentTools && !selectedOptions.agentTools.includes(resolvedTask)) {
|
|
4256
4743
|
continue;
|
|
4257
4744
|
}
|
|
4258
4745
|
let requestStep = resolvedTask === target.step.task ? target.step : { ...target.step, task: resolvedTask };
|
|
@@ -4266,7 +4753,7 @@ function preflightRemainingCreativeAssetDirectives(allSteps, afterGlobalIndex, c
|
|
|
4266
4753
|
omit_idempotency_key: true
|
|
4267
4754
|
};
|
|
4268
4755
|
}
|
|
4269
|
-
const request = buildEffectiveStepRequest(requestStep, context,
|
|
4756
|
+
const request = buildEffectiveStepRequest(requestStep, context, selectedOptions, selectedState);
|
|
4270
4757
|
if (!request.ok && "creativeAssetFailure" in request) {
|
|
4271
4758
|
return { target, failure: request.creativeAssetFailure };
|
|
4272
4759
|
}
|
|
@@ -4934,23 +5421,6 @@ function phaseUsesRuntimeContext(phase) {
|
|
|
4934
5421
|
const expr = phase.skip_if?.trim();
|
|
4935
5422
|
return expr ? phaseConditionUsesContext(expr) : false;
|
|
4936
5423
|
}
|
|
4937
|
-
function resolveTaskName(step, options) {
|
|
4938
|
-
if (!step.task.startsWith("$test_kit.")) return step.task;
|
|
4939
|
-
const path = step.task.slice("$test_kit.".length).split(".");
|
|
4940
|
-
let value = options.test_kit;
|
|
4941
|
-
for (const segment of path) {
|
|
4942
|
-
if (value == null || typeof value !== "object") {
|
|
4943
|
-
value = void 0;
|
|
4944
|
-
break;
|
|
4945
|
-
}
|
|
4946
|
-
value = value[segment];
|
|
4947
|
-
}
|
|
4948
|
-
const configured = typeof value === "string" && value.length > 0 ? value : step.task_default;
|
|
4949
|
-
if (step.task === "$test_kit.auth.probe_task") {
|
|
4950
|
-
return selectProbeTask(configured, options.agentTools);
|
|
4951
|
-
}
|
|
4952
|
-
return configured;
|
|
4953
|
-
}
|
|
4954
5424
|
function defaultAuthHeadersForRawProbe(options) {
|
|
4955
5425
|
const headers = {};
|
|
4956
5426
|
if (options.auth) {
|
|
@@ -4974,6 +5444,354 @@ function defaultAuthHeadersForRawProbe(options) {
|
|
|
4974
5444
|
}
|
|
4975
5445
|
return headers;
|
|
4976
5446
|
}
|
|
5447
|
+
function sessionProbeRoutingHeaders(options) {
|
|
5448
|
+
const headers = {};
|
|
5449
|
+
for (const [name, value] of Object.entries(options.headers ?? {})) {
|
|
5450
|
+
if (!SESSION_PROBE_ROUTING_HEADERS.has(name.toLowerCase())) continue;
|
|
5451
|
+
try {
|
|
5452
|
+
assertSafeAuthHeaderPart(value, `options.headers.${name}`);
|
|
5453
|
+
} catch {
|
|
5454
|
+
continue;
|
|
5455
|
+
}
|
|
5456
|
+
headers[name] = value;
|
|
5457
|
+
}
|
|
5458
|
+
setHeaderIfAbsent(headers, "X-Test-Session-ID", options.test_session_id, "options.test_session_id");
|
|
5459
|
+
setHeaderIfAbsent(headers, "User-Agent", options.userAgent, "options.userAgent");
|
|
5460
|
+
return headers;
|
|
5461
|
+
}
|
|
5462
|
+
function setHeaderIfAbsent(headers, name, value, label) {
|
|
5463
|
+
if (!value) return;
|
|
5464
|
+
const lower = name.toLowerCase();
|
|
5465
|
+
if (Object.keys(headers).some((existing) => existing.toLowerCase() === lower)) return;
|
|
5466
|
+
try {
|
|
5467
|
+
assertSafeAuthHeaderPart(value, label);
|
|
5468
|
+
} catch {
|
|
5469
|
+
return;
|
|
5470
|
+
}
|
|
5471
|
+
headers[name] = value;
|
|
5472
|
+
}
|
|
5473
|
+
function runCredentialValues(options) {
|
|
5474
|
+
const values = [];
|
|
5475
|
+
const auth = options.auth;
|
|
5476
|
+
if (auth?.type === "bearer" && typeof auth.token === "string") values.push(auth.token);
|
|
5477
|
+
if (auth?.type === "basic") {
|
|
5478
|
+
if (typeof auth.password === "string") values.push(auth.password);
|
|
5479
|
+
if (typeof auth.username === "string" && typeof auth.password === "string") {
|
|
5480
|
+
values.push(`${auth.username}:${auth.password}`);
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
if (auth?.type === "oauth" || auth?.type === "oauth_client_credentials") {
|
|
5484
|
+
const token = auth.tokens?.access_token;
|
|
5485
|
+
if (typeof token === "string") values.push(token);
|
|
5486
|
+
}
|
|
5487
|
+
const kit = options.test_kit?.auth;
|
|
5488
|
+
if (typeof kit?.api_key === "string") values.push(kit.api_key);
|
|
5489
|
+
const basic = kit?.basic;
|
|
5490
|
+
if (typeof basic?.password === "string") values.push(basic.password);
|
|
5491
|
+
if (typeof basic?.username === "string" && typeof basic?.password === "string") {
|
|
5492
|
+
values.push(`${basic.username}:${basic.password}`);
|
|
5493
|
+
}
|
|
5494
|
+
if (typeof basic?.credentials === "string") values.push(basic.credentials);
|
|
5495
|
+
for (const [name, value] of Object.entries(options.headers ?? {})) {
|
|
5496
|
+
if (typeof value !== "string" || value.length === 0) continue;
|
|
5497
|
+
if (AUTH_OVERRIDE_HEADER_NAMES.has(name.toLowerCase()) || isCredentialHeaderName(name)) values.push(value);
|
|
5498
|
+
}
|
|
5499
|
+
return values.filter((value) => value.trim().length > 0);
|
|
5500
|
+
}
|
|
5501
|
+
const SESSION_PROBE_ROUTING_HEADERS = /* @__PURE__ */ new Set([
|
|
5502
|
+
"x-tenant-id",
|
|
5503
|
+
"x-tenant",
|
|
5504
|
+
"x-account",
|
|
5505
|
+
"x-account-id",
|
|
5506
|
+
"x-routing-key",
|
|
5507
|
+
"x-partition-key",
|
|
5508
|
+
"x-region",
|
|
5509
|
+
"x-environment",
|
|
5510
|
+
"x-request-id",
|
|
5511
|
+
"x-correlation-id",
|
|
5512
|
+
"x-idempotency-key",
|
|
5513
|
+
"x-test-session-id",
|
|
5514
|
+
"user-agent",
|
|
5515
|
+
"accept-language"
|
|
5516
|
+
]);
|
|
5517
|
+
function unroutableProbeHeader(options) {
|
|
5518
|
+
const runSecrets = runCredentialValues(options);
|
|
5519
|
+
for (const [name, value] of Object.entries(options.headers ?? {})) {
|
|
5520
|
+
const lower = name.toLowerCase();
|
|
5521
|
+
if (SESSION_PROBE_ROUTING_HEADERS.has(lower)) {
|
|
5522
|
+
try {
|
|
5523
|
+
assertSafeAuthHeaderPart(value, `options.headers.${name}`);
|
|
5524
|
+
} catch {
|
|
5525
|
+
return name;
|
|
5526
|
+
}
|
|
5527
|
+
continue;
|
|
5528
|
+
}
|
|
5529
|
+
if (AUTH_OVERRIDE_HEADER_NAMES.has(lower)) continue;
|
|
5530
|
+
if (runSecrets.some((secret) => value.includes(secret))) continue;
|
|
5531
|
+
return name;
|
|
5532
|
+
}
|
|
5533
|
+
return void 0;
|
|
5534
|
+
}
|
|
5535
|
+
function effectiveOAuthAccessToken(client, options, agentUrl) {
|
|
5536
|
+
const live = liveAgentOAuthAccessToken(client, agentUrl);
|
|
5537
|
+
if (live !== void 0) return live;
|
|
5538
|
+
const auth = options.auth;
|
|
5539
|
+
if (auth?.type !== "oauth" && auth?.type !== "oauth_client_credentials") return void 0;
|
|
5540
|
+
const configured = auth.tokens?.access_token;
|
|
5541
|
+
return typeof configured === "string" && configured.length > 0 ? configured : void 0;
|
|
5542
|
+
}
|
|
5543
|
+
function liveAgentOAuthAccessToken(client, agentUrl) {
|
|
5544
|
+
try {
|
|
5545
|
+
const resolved = client?.getAgent?.(TEST_CLIENT_AGENT_ID);
|
|
5546
|
+
if (resolved == null) return void 0;
|
|
5547
|
+
const candidates = [resolved];
|
|
5548
|
+
if (typeof resolved.getAgent === "function") candidates.push(resolved.getAgent());
|
|
5549
|
+
for (const candidate of candidates) {
|
|
5550
|
+
const token = candidate?.oauth_tokens?.access_token;
|
|
5551
|
+
if (typeof token !== "string" || token.length === 0) continue;
|
|
5552
|
+
const configuredUri = candidate?.agent_uri;
|
|
5553
|
+
if (agentUrl !== void 0 && typeof configuredUri === "string" && configuredUri !== agentUrl) continue;
|
|
5554
|
+
if (agentUrl !== void 0 && typeof configuredUri !== "string") continue;
|
|
5555
|
+
return token;
|
|
5556
|
+
}
|
|
5557
|
+
} catch {
|
|
5558
|
+
}
|
|
5559
|
+
return void 0;
|
|
5560
|
+
}
|
|
5561
|
+
const TEST_CLIENT_AGENT_ID = "test";
|
|
5562
|
+
function withMcpBearerParity(headers) {
|
|
5563
|
+
const authorization = headers.authorization;
|
|
5564
|
+
if (authorization === void 0 || !authorization.startsWith("Bearer ")) return headers;
|
|
5565
|
+
const token = authorization.slice("Bearer ".length);
|
|
5566
|
+
if (token.length === 0) return headers;
|
|
5567
|
+
return { ...headers, "x-adcp-auth": token };
|
|
5568
|
+
}
|
|
5569
|
+
function oauthAccessTokenHeaders(options, client, agentUrl) {
|
|
5570
|
+
const token = effectiveOAuthAccessToken(client, options, agentUrl);
|
|
5571
|
+
if (token === void 0) return void 0;
|
|
5572
|
+
try {
|
|
5573
|
+
assertSafeAuthHeaderPart(token, "options.auth.tokens.access_token");
|
|
5574
|
+
} catch {
|
|
5575
|
+
return void 0;
|
|
5576
|
+
}
|
|
5577
|
+
return { authorization: `Bearer ${token}` };
|
|
5578
|
+
}
|
|
5579
|
+
function staticCredentialHeaders(directive, options) {
|
|
5580
|
+
try {
|
|
5581
|
+
const headers = authHeadersForStep(directive, options);
|
|
5582
|
+
return headers.authorization !== void 0 ? { authorization: headers.authorization } : void 0;
|
|
5583
|
+
} catch {
|
|
5584
|
+
}
|
|
5585
|
+
return void 0;
|
|
5586
|
+
}
|
|
5587
|
+
function sessionControlCredentials(mechanism, options, client, agentUrl) {
|
|
5588
|
+
const oauth = oauthAccessTokenHeaders(options, client, agentUrl);
|
|
5589
|
+
const bearer = options.auth?.type === "bearer" ? staticCredentialHeaders({ type: "api_key", value: options.auth.token }, options) : void 0;
|
|
5590
|
+
const basicFromOptions = options.auth?.type === "basic" ? staticCredentialHeaders(
|
|
5591
|
+
{ type: "basic", username: options.auth.username, password: options.auth.password },
|
|
5592
|
+
options
|
|
5593
|
+
) : void 0;
|
|
5594
|
+
const kitApiKey = typeof options.test_kit?.auth?.api_key === "string" && options.test_kit.auth.api_key.length > 0 ? staticCredentialHeaders({ type: "api_key", from_test_kit: true }, options) : void 0;
|
|
5595
|
+
const kitBasic = options.test_kit?.auth?.basic !== void 0 ? staticCredentialHeaders({ type: "basic", from_test_kit: true }, options) : void 0;
|
|
5596
|
+
switch (mechanism) {
|
|
5597
|
+
case "oauth_bearer": {
|
|
5598
|
+
if (oauth) return { headers: oauth };
|
|
5599
|
+
return {
|
|
5600
|
+
unavailable: {
|
|
5601
|
+
reason: `this run holds no OAuth access token, and a static API key or Basic credential is not evidence about the OAuth path at all \u2014 accepting a shared secret says nothing about whether tokens from the issuer advertised in your protected-resource metadata are what gates this resource`,
|
|
5602
|
+
remedy: `Run the storyboard with OAuth so the runner holds a token minted by that issuer (\`adcp --save-auth <alias> <url> --oauth\`, or pass \`--oauth\` to \`storyboard run\`).`
|
|
5603
|
+
}
|
|
5604
|
+
};
|
|
5605
|
+
}
|
|
5606
|
+
case "api_key": {
|
|
5607
|
+
const headers = bearer ?? kitApiKey;
|
|
5608
|
+
if (headers) return { headers };
|
|
5609
|
+
return {
|
|
5610
|
+
unavailable: {
|
|
5611
|
+
reason: `this run holds no valid API key to prove the endpoint accepts one`,
|
|
5612
|
+
remedy: "Declare `auth.api_key` in the test kit, or pass a bearer `options.auth` (CLI: `--auth`)."
|
|
5613
|
+
}
|
|
5614
|
+
};
|
|
5615
|
+
}
|
|
5616
|
+
case "basic": {
|
|
5617
|
+
const headers = basicFromOptions ?? kitBasic;
|
|
5618
|
+
if (headers) return { headers };
|
|
5619
|
+
return {
|
|
5620
|
+
unavailable: {
|
|
5621
|
+
reason: `this run holds no valid Basic credential to prove the endpoint accepts one`,
|
|
5622
|
+
remedy: "Declare `auth.basic` in the test kit, or pass a basic `options.auth`."
|
|
5623
|
+
}
|
|
5624
|
+
};
|
|
5625
|
+
}
|
|
5626
|
+
case "any": {
|
|
5627
|
+
const headers = oauth ?? bearer ?? basicFromOptions ?? kitApiKey ?? kitBasic;
|
|
5628
|
+
if (headers) return { headers };
|
|
5629
|
+
return {
|
|
5630
|
+
unavailable: {
|
|
5631
|
+
reason: `this run holds no valid credential, so a rejection cannot be told apart from an endpoint that refuses every request`,
|
|
5632
|
+
remedy: "Declare `auth.api_key` or `auth.basic` in the test kit, pass `options.auth`, or run with `--oauth`."
|
|
5633
|
+
}
|
|
5634
|
+
};
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5637
|
+
}
|
|
5638
|
+
function summarizeAdvertisedTools(tools) {
|
|
5639
|
+
const names = (tools ?? []).slice(0, 20).map((name) => escapeControlChars(name.slice(0, 64)));
|
|
5640
|
+
const overflow = (tools?.length ?? 0) - names.length;
|
|
5641
|
+
return overflow > 0 ? `${names.join(", ")}, \u2026${overflow} more` : names.join(", ");
|
|
5642
|
+
}
|
|
5643
|
+
function escapeControlChars(value) {
|
|
5644
|
+
return value.replace(
|
|
5645
|
+
/[\u0000-\u001f\u007f-\u009f]/g,
|
|
5646
|
+
(char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`
|
|
5647
|
+
);
|
|
5648
|
+
}
|
|
5649
|
+
const SESSION_PROBE_PUBLIC_TIER = /* @__PURE__ */ new Set([
|
|
5650
|
+
"get_adcp_capabilities",
|
|
5651
|
+
"get_products",
|
|
5652
|
+
"list_products",
|
|
5653
|
+
"list_creative_formats"
|
|
5654
|
+
]);
|
|
5655
|
+
const CANONICAL_ADCP_TOOLS = /* @__PURE__ */ new Set([
|
|
5656
|
+
...MEDIA_BUY_TOOLS,
|
|
5657
|
+
...CREATIVE_TOOLS,
|
|
5658
|
+
...SIGNALS_TOOLS,
|
|
5659
|
+
...GOVERNANCE_TOOLS,
|
|
5660
|
+
...ACCOUNT_TOOLS,
|
|
5661
|
+
...BRAND_RIGHTS_TOOLS,
|
|
5662
|
+
...PROTOCOL_TOOLS,
|
|
5663
|
+
...EVENT_TRACKING_TOOLS
|
|
5664
|
+
]);
|
|
5665
|
+
const PREFERRED_PROBE_TARGET = "get_principal";
|
|
5666
|
+
function hasNoRequiredRequestFields(tool) {
|
|
5667
|
+
const schema = TOOL_REQUEST_SCHEMAS[tool];
|
|
5668
|
+
const shape = schema?.shape;
|
|
5669
|
+
if (!shape) return false;
|
|
5670
|
+
return !Object.values(shape).some((field) => {
|
|
5671
|
+
const candidate = field;
|
|
5672
|
+
if (typeof candidate?.safeParse !== "function") return false;
|
|
5673
|
+
return !candidate.safeParse(void 0).success;
|
|
5674
|
+
});
|
|
5675
|
+
}
|
|
5676
|
+
function protectedToolCandidates(tools) {
|
|
5677
|
+
if (!tools) return [];
|
|
5678
|
+
const advertised = new Set(tools);
|
|
5679
|
+
const eligible = (tool) => advertised.has(tool) && !SESSION_PROBE_PUBLIC_TIER.has(tool) && !MUTATING_TASKS.has(tool);
|
|
5680
|
+
const allowlisted = PROBE_TASK_ALLOWLIST.filter(eligible);
|
|
5681
|
+
const canonicalReads = [...CANONICAL_ADCP_TOOLS].filter((tool) => /^(list|get)_/.test(tool)).filter((tool) => !allowlisted.includes(tool)).filter(eligible).filter(hasNoRequiredRequestFields).sort((a, b) => {
|
|
5682
|
+
if (a === PREFERRED_PROBE_TARGET) return -1;
|
|
5683
|
+
if (b === PREFERRED_PROBE_TARGET) return 1;
|
|
5684
|
+
return a.localeCompare(b);
|
|
5685
|
+
});
|
|
5686
|
+
return [...allowlisted, ...canonicalReads];
|
|
5687
|
+
}
|
|
5688
|
+
function signatureBoundTools(options) {
|
|
5689
|
+
if (options.functional_request_signing === void 0) return /* @__PURE__ */ new Set();
|
|
5690
|
+
const raw = options._profile?.raw_capabilities;
|
|
5691
|
+
if (raw === null || typeof raw !== "object") return "unparseable";
|
|
5692
|
+
const advertised = raw.request_signing;
|
|
5693
|
+
if (advertised === void 0) return /* @__PURE__ */ new Set();
|
|
5694
|
+
if (advertised === null || typeof advertised !== "object") return "unparseable";
|
|
5695
|
+
const buckets = advertised;
|
|
5696
|
+
const bound = /* @__PURE__ */ new Set();
|
|
5697
|
+
for (const bucket of [buckets.required_for, buckets.supported_for]) {
|
|
5698
|
+
if (bucket === void 0) continue;
|
|
5699
|
+
if (!Array.isArray(bucket) || bucket.some((entry) => typeof entry !== "string")) return "unparseable";
|
|
5700
|
+
for (const entry of bucket) bound.add(entry);
|
|
5701
|
+
}
|
|
5702
|
+
return bound;
|
|
5703
|
+
}
|
|
5704
|
+
function selectProtectedToolTarget(tools) {
|
|
5705
|
+
return protectedToolCandidates(tools)[0];
|
|
5706
|
+
}
|
|
5707
|
+
function sessionControlMechanismFor(auth) {
|
|
5708
|
+
if (auth === "none") return "any";
|
|
5709
|
+
switch (auth.type) {
|
|
5710
|
+
case "oauth_bearer":
|
|
5711
|
+
return "oauth_bearer";
|
|
5712
|
+
case "basic":
|
|
5713
|
+
return "basic";
|
|
5714
|
+
case "api_key":
|
|
5715
|
+
return "api_key";
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5718
|
+
function planMcpSessionSentinel(step, options, client, agentUrl) {
|
|
5719
|
+
if (options.protocol !== "mcp") {
|
|
5720
|
+
const declared = options.protocol === void 0 ? "no transport" : `"${options.protocol}"`;
|
|
5721
|
+
return {
|
|
5722
|
+
kind: "error",
|
|
5723
|
+
error: `"${MCP_SESSION_PROBE_TASK}" is an MCP session probe and requires an explicit \`protocol: 'mcp'\` on the run; this run declared ${declared}. A2A has no equivalent parameter-free protected operation, so the runner refuses to substitute one.`
|
|
5724
|
+
};
|
|
5725
|
+
}
|
|
5726
|
+
if (step.auth === void 0) {
|
|
5727
|
+
return {
|
|
5728
|
+
kind: "skip",
|
|
5729
|
+
reason: "session_probe_ungradable",
|
|
5730
|
+
detail: redactOAuthUrlsInText(
|
|
5731
|
+
`Agent advertises no auth-required, read-only AdCP tool that accepts an empty request body, so the runner fell back to the MCP "${MCP_SESSION_PROBE_TASK}" session probe. That probe cannot grade a positive static-credential step: its validations assert an AdCP task response body, which no MCP protocol operation produces, so this mechanism's branch cannot contribute auth_mechanism_verified. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}), or serve RFC 9728 metadata and run with OAuth so the OAuth branch can be verified instead. Advertised tools: [${summarizeAdvertisedTools(options.agentTools)}].`
|
|
5732
|
+
)
|
|
5733
|
+
};
|
|
5734
|
+
}
|
|
5735
|
+
const signatureBound = signatureBoundTools(options);
|
|
5736
|
+
const candidates = protectedToolCandidates(options.agentTools);
|
|
5737
|
+
if (signatureBound === "unparseable") {
|
|
5738
|
+
return {
|
|
5739
|
+
kind: "skip",
|
|
5740
|
+
reason: "session_probe_ungradable",
|
|
5741
|
+
detail: `This run signs functional dispatch (RFC 9421), but the runner could not read which operations your \`request_signing\` capability covers, so it cannot tell whether the session probe's unsigned call would be refused for the signature rather than the credential. Refusing to grade instead of guessing. Remedy: advertise \`request_signing.required_for\` / \`supported_for\` as string arrays, or advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}) so the probe has a protocol-vouched target.`
|
|
5742
|
+
};
|
|
5743
|
+
}
|
|
5744
|
+
const toolNames = candidates.filter((tool) => !signatureBound.has(tool));
|
|
5745
|
+
if (toolNames.length === 0 && candidates.length > 0) {
|
|
5746
|
+
return {
|
|
5747
|
+
kind: "skip",
|
|
5748
|
+
reason: "session_probe_ungradable",
|
|
5749
|
+
detail: redactOAuthUrlsInText(
|
|
5750
|
+
`Every protected read the probe could call (${candidates.join(", ")}) is covered by this agent's \`request_signing\` advertisement, and the session probe mints no RFC 9421 signatures. An unsigned call would be refused for the missing signature, which is not evidence about the credential, so the runner refuses to grade it. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}) outside \`request_signing.required_for\`/\`supported_for\`, or run with OAuth against RFC 9728 metadata so the OAuth branch can be verified instead.`
|
|
5751
|
+
)
|
|
5752
|
+
};
|
|
5753
|
+
}
|
|
5754
|
+
if (toolNames.length === 0) {
|
|
5755
|
+
return {
|
|
5756
|
+
kind: "skip",
|
|
5757
|
+
reason: "session_probe_ungradable",
|
|
5758
|
+
detail: redactOAuthUrlsInText(
|
|
5759
|
+
`Agent advertises no auth-required, read-only AdCP tool the probe can call with an empty request body, so there is no protected operation to grade. MCP discovery (\`tools/list\`) is not a protected task and public-tier tools (${[...SESSION_PROBE_PUBLIC_TIER].join(", ")}) are served unauthenticated by design. Remedy: advertise one allowlisted read tool (${PROBE_TASK_ALLOWLIST_SUMMARY}). Advertised tools: [${summarizeAdvertisedTools(options.agentTools)}].`
|
|
5760
|
+
)
|
|
5761
|
+
};
|
|
5762
|
+
}
|
|
5763
|
+
const unroutable = unroutableProbeHeader(options);
|
|
5764
|
+
if (unroutable !== void 0) {
|
|
5765
|
+
return {
|
|
5766
|
+
kind: "skip",
|
|
5767
|
+
reason: "session_probe_ungradable",
|
|
5768
|
+
detail: `The runner cannot classify run header "${escapeControlChars(unroutable.slice(0, 64))}", and both answers are unsafe \u2014 forwarding it could make the unauthenticated probe authenticated, dropping it could send the probe to a different tenant than the rest of this run. Nothing was graded, and this is a property of the run, not of the agent. Three ways forward: rename it to a recognised routing header (${[...SESSION_PROBE_ROUTING_HEADERS].join(", ")}); drop it from this run if the probe does not need it; or, if it carries a credential, move that into \`options.auth\` / \`test_kit.auth\` where the runner owns it.`
|
|
5769
|
+
};
|
|
5770
|
+
}
|
|
5771
|
+
const routing = sessionProbeRoutingHeaders(options);
|
|
5772
|
+
let headers;
|
|
5773
|
+
try {
|
|
5774
|
+
headers = { ...routing, ...withMcpBearerParity(authHeadersForStep(step.auth, options)) };
|
|
5775
|
+
} catch (err) {
|
|
5776
|
+
return {
|
|
5777
|
+
kind: "error",
|
|
5778
|
+
error: `Step auth configuration error: ${err instanceof Error ? err.message : String(err)}`
|
|
5779
|
+
};
|
|
5780
|
+
}
|
|
5781
|
+
const control = sessionControlCredentials(sessionControlMechanismFor(step.auth), options, client, agentUrl);
|
|
5782
|
+
if ("unavailable" in control) {
|
|
5783
|
+
return { kind: "probe", headers, toolNames, control: { kind: "unavailable", ...control.unavailable } };
|
|
5784
|
+
}
|
|
5785
|
+
if (headers.authorization !== void 0 && control.headers.authorization === headers.authorization) {
|
|
5786
|
+
return { kind: "probe", headers, toolNames, control: { kind: "probe_is_valid_credential" } };
|
|
5787
|
+
}
|
|
5788
|
+
return {
|
|
5789
|
+
kind: "probe",
|
|
5790
|
+
headers,
|
|
5791
|
+
toolNames,
|
|
5792
|
+
control: { kind: "credential", headers: { ...routing, ...withMcpBearerParity(control.headers) } }
|
|
5793
|
+
};
|
|
5794
|
+
}
|
|
4977
5795
|
function authHeadersForStep(directive, options) {
|
|
4978
5796
|
if (directive === "none") return {};
|
|
4979
5797
|
if (directive.type === "basic") return basicAuthHeadersForStep(directive, options);
|
|
@@ -5381,7 +6199,8 @@ function createRoutingDispatcher(ctx, options, agents) {
|
|
|
5381
6199
|
const keyToIndex = new Map(keyOrder.map((k, i) => [k, i]));
|
|
5382
6200
|
return {
|
|
5383
6201
|
nextFor(step) {
|
|
5384
|
-
const
|
|
6202
|
+
const task = resolveTaskName(step, { ...options, agentTools: void 0 });
|
|
6203
|
+
const key = resolveAgentForStep(task ? { ...step, task } : step, options, ctx);
|
|
5385
6204
|
const client = ctx.clients.get(key);
|
|
5386
6205
|
const profile = ctx.profiles.get(key);
|
|
5387
6206
|
const url = agents[key]?.url;
|
|
@@ -5392,11 +6211,21 @@ function createRoutingDispatcher(ctx, options, agents) {
|
|
|
5392
6211
|
`key ${key} unbound`
|
|
5393
6212
|
);
|
|
5394
6213
|
}
|
|
6214
|
+
if (!profile) {
|
|
6215
|
+
const failure = ctx.discoveryFailures.find((failure2) => failure2.agentKey === key);
|
|
6216
|
+
throw new RoutingError(
|
|
6217
|
+
`Agent "${key}" has no discovered profile; its task contract cannot be established.` + (failure ? ` Discovery failed: ${failure.underlying}. Fix the agent or select a healthy route.` : ""),
|
|
6218
|
+
step.task,
|
|
6219
|
+
`agent "${key}" failed discovery`
|
|
6220
|
+
);
|
|
6221
|
+
}
|
|
5395
6222
|
return {
|
|
5396
6223
|
client,
|
|
5397
6224
|
agentUrl: url,
|
|
6225
|
+
agentKey: key,
|
|
5398
6226
|
instanceIndex: keyToIndex.get(key) ?? 0,
|
|
5399
|
-
profile
|
|
6227
|
+
profile,
|
|
6228
|
+
options: routedAgentOptions(agents[key], options, profile)
|
|
5400
6229
|
};
|
|
5401
6230
|
}
|
|
5402
6231
|
};
|
|
@@ -5476,7 +6305,10 @@ function getFirstStepPreview(storyboard, context = {}) {
|
|
|
5476
6305
|
export {
|
|
5477
6306
|
__defaultAuthHeadersForRawProbeForTest,
|
|
5478
6307
|
__filterResponseHeadersForTest,
|
|
6308
|
+
__protectedToolCandidatesForTest,
|
|
5479
6309
|
__redactSecretsForTest,
|
|
6310
|
+
__selectProtectedToolTargetForTest,
|
|
6311
|
+
__sessionControlCredentialsForTest,
|
|
5480
6312
|
applyAdcpVersionRunOptions,
|
|
5481
6313
|
applyBrandInvariant,
|
|
5482
6314
|
applyDisableSandboxHint,
|
|
@@ -5490,5 +6322,8 @@ export {
|
|
|
5490
6322
|
resolveCapabilityPath,
|
|
5491
6323
|
runStoryboard,
|
|
5492
6324
|
runStoryboardStep,
|
|
6325
|
+
signingCoverage,
|
|
6326
|
+
signingCoverageUnverified,
|
|
6327
|
+
storyboardCapabilityPredicates,
|
|
5493
6328
|
summarizeStrictValidation
|
|
5494
6329
|
};
|