@adcp/sdk 16.1.0 → 16.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/AGENTS.md +2 -0
  2. package/dist/lib/core/AgentClient.js +17 -1
  3. package/dist/lib/core/AgentClient.mjs +17 -1
  4. package/dist/lib/core/SingleAgentClient.js +13 -0
  5. package/dist/lib/core/SingleAgentClient.mjs +13 -0
  6. package/dist/lib/core/TaskExecutor.js +88 -13
  7. package/dist/lib/core/TaskExecutor.mjs +89 -14
  8. package/dist/lib/errors/index.d.mts +34 -0
  9. package/dist/lib/errors/index.d.ts +34 -0
  10. package/dist/lib/errors/index.js +11 -0
  11. package/dist/lib/errors/index.mjs +10 -0
  12. package/dist/lib/governance/authorization.d.mts +66 -0
  13. package/dist/lib/governance/authorization.d.ts +66 -0
  14. package/dist/lib/governance/authorization.js +181 -37
  15. package/dist/lib/governance/authorization.mjs +183 -36
  16. package/dist/lib/governance/index.d.mts +2 -2
  17. package/dist/lib/governance/index.d.ts +2 -2
  18. package/dist/lib/governance/index.js +4 -2
  19. package/dist/lib/governance/index.mjs +3 -1
  20. package/dist/lib/identity-3.3/index.d.mts +1 -0
  21. package/dist/lib/identity-3.3/index.d.ts +1 -0
  22. package/dist/lib/identity-3.3/index.js +3 -1
  23. package/dist/lib/identity-3.3/index.mjs +1 -0
  24. package/dist/lib/identity-3.3/jws-artifacts.d.mts +147 -0
  25. package/dist/lib/identity-3.3/jws-artifacts.d.ts +147 -0
  26. package/dist/lib/identity-3.3/jws-artifacts.js +258 -0
  27. package/dist/lib/identity-3.3/jws-artifacts.mjs +234 -0
  28. package/dist/lib/identity-3.3/revocation.d.mts +7 -0
  29. package/dist/lib/identity-3.3/revocation.d.ts +7 -0
  30. package/dist/lib/identity-3.3/revocation.js +13 -0
  31. package/dist/lib/identity-3.3/revocation.mjs +13 -0
  32. package/dist/lib/index.d.mts +3 -3
  33. package/dist/lib/index.d.ts +3 -3
  34. package/dist/lib/index.js +4 -0
  35. package/dist/lib/index.mjs +4 -0
  36. package/dist/lib/media-buy/compatibility.d.mts +1 -0
  37. package/dist/lib/media-buy/compatibility.d.ts +1 -0
  38. package/dist/lib/media-buy/compatibility.js +33 -10
  39. package/dist/lib/media-buy/compatibility.mjs +32 -14
  40. package/dist/lib/negotiation/buyer.js +11 -5
  41. package/dist/lib/negotiation/buyer.mjs +11 -5
  42. package/dist/lib/negotiation/types.d.mts +4 -2
  43. package/dist/lib/negotiation/types.d.ts +4 -2
  44. package/dist/lib/negotiation/verification.d.mts +15 -6
  45. package/dist/lib/negotiation/verification.d.ts +15 -6
  46. package/dist/lib/negotiation/verification.js +146 -27
  47. package/dist/lib/negotiation/verification.mjs +146 -28
  48. package/dist/lib/negotiation/version.d.mts +6 -0
  49. package/dist/lib/negotiation/version.d.ts +6 -0
  50. package/dist/lib/negotiation/version.js +60 -0
  51. package/dist/lib/negotiation/version.mjs +33 -0
  52. package/dist/lib/registry/types.generated.d.mts +24 -1
  53. package/dist/lib/registry/types.generated.d.ts +24 -1
  54. package/dist/lib/server/create-adcp-server.js +1 -1
  55. package/dist/lib/server/create-adcp-server.mjs +1 -1
  56. package/dist/lib/server/error-arm-tools.d.mts +10 -10
  57. package/dist/lib/server/error-arm-tools.d.ts +10 -10
  58. package/dist/lib/server/error-arm-tools.js +22 -58
  59. package/dist/lib/server/error-arm-tools.mjs +30 -65
  60. package/dist/lib/server/index.d.mts +2 -2
  61. package/dist/lib/server/index.d.ts +2 -2
  62. package/dist/lib/server/index.js +2 -0
  63. package/dist/lib/server/index.mjs +2 -0
  64. package/dist/lib/signing/web-bot-auth.js +5 -0
  65. package/dist/lib/signing/web-bot-auth.mjs +4 -0
  66. package/dist/lib/testing/compliance/comply.js +17 -0
  67. package/dist/lib/testing/compliance/comply.mjs +17 -0
  68. package/dist/lib/testing/index.d.mts +3 -0
  69. package/dist/lib/testing/index.d.ts +3 -0
  70. package/dist/lib/testing/index.js +44 -2
  71. package/dist/lib/testing/index.mjs +42 -0
  72. package/dist/lib/testing/storyboard/collection-selection.d.mts +259 -0
  73. package/dist/lib/testing/storyboard/collection-selection.d.ts +259 -0
  74. package/dist/lib/testing/storyboard/collection-selection.js +384 -0
  75. package/dist/lib/testing/storyboard/collection-selection.mjs +348 -0
  76. package/dist/lib/testing/storyboard/context.js +12 -6
  77. package/dist/lib/testing/storyboard/context.mjs +12 -6
  78. package/dist/lib/testing/storyboard/fixture-resolution.d.mts +39 -1
  79. package/dist/lib/testing/storyboard/fixture-resolution.d.ts +39 -1
  80. package/dist/lib/testing/storyboard/fixture-resolution.js +216 -12
  81. package/dist/lib/testing/storyboard/fixture-resolution.mjs +218 -12
  82. package/dist/lib/testing/storyboard/index.d.mts +9 -2
  83. package/dist/lib/testing/storyboard/index.d.ts +9 -2
  84. package/dist/lib/testing/storyboard/index.js +51 -2
  85. package/dist/lib/testing/storyboard/index.mjs +49 -1
  86. package/dist/lib/testing/storyboard/prepared-fixtures.d.mts +471 -0
  87. package/dist/lib/testing/storyboard/prepared-fixtures.d.ts +471 -0
  88. package/dist/lib/testing/storyboard/prepared-fixtures.js +434 -0
  89. package/dist/lib/testing/storyboard/prepared-fixtures.mjs +389 -0
  90. package/dist/lib/testing/storyboard/protected-context.d.mts +127 -0
  91. package/dist/lib/testing/storyboard/protected-context.d.ts +127 -0
  92. package/dist/lib/testing/storyboard/protected-context.js +301 -0
  93. package/dist/lib/testing/storyboard/protected-context.mjs +267 -0
  94. package/dist/lib/testing/storyboard/rejection-hints.js +13 -4
  95. package/dist/lib/testing/storyboard/rejection-hints.mjs +13 -4
  96. package/dist/lib/testing/storyboard/runner.d.mts +24 -0
  97. package/dist/lib/testing/storyboard/runner.d.ts +24 -0
  98. package/dist/lib/testing/storyboard/runner.js +1061 -105
  99. package/dist/lib/testing/storyboard/runner.mjs +1075 -106
  100. package/dist/lib/testing/storyboard/seeding.d.mts +15 -1
  101. package/dist/lib/testing/storyboard/seeding.d.ts +15 -1
  102. package/dist/lib/testing/storyboard/seeding.js +272 -12
  103. package/dist/lib/testing/storyboard/seeding.mjs +274 -13
  104. package/dist/lib/testing/storyboard/types.d.mts +207 -10
  105. package/dist/lib/testing/storyboard/types.d.ts +207 -10
  106. package/dist/lib/testing/storyboard/types.js +1 -1
  107. package/dist/lib/testing/storyboard/types.mjs +1 -1
  108. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  109. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  110. package/dist/lib/testing/storyboard/validations.js +95 -0
  111. package/dist/lib/testing/storyboard/validations.mjs +95 -0
  112. package/dist/lib/validation/bundled-schema-store.js +5 -0
  113. package/dist/lib/validation/bundled-schema-store.mjs +4 -0
  114. package/dist/lib/validation/schema-loader.js +19 -2
  115. package/dist/lib/validation/schema-loader.mjs +22 -3
  116. package/dist/lib/version.d.mts +3 -3
  117. package/dist/lib/version.d.ts +3 -3
  118. package/dist/lib/version.js +3 -3
  119. package/dist/lib/version.mjs +3 -3
  120. package/docs/TYPE-SUMMARY.md +2 -2
  121. package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +850 -0
  122. package/docs/guides/PROPOSAL-TERMS-VERIFICATION.md +66 -0
  123. package/docs/llms.txt +4 -3
  124. package/docs/migration-14.x-rc-worksheet.md +4 -4
  125. package/docs/migration-agent-identity-3.3.md +51 -6
  126. package/package.json +6 -4
@@ -1,3 +1,5 @@
1
+ import type { CollectionSelectionSelector, CollectionWitnessKind } from './collection-selection.mjs';
2
+ import type { PreparedFixturesAuthorizer, PreparedFixturesReference, PreparedStoryboardFixtures } from './prepared-fixtures.mjs';
1
3
  import type { CreativeBuildProbeSpec } from './creative-build-probe.mjs';
2
4
  /**
3
5
  * Types for storyboard-driven testing.
@@ -411,7 +413,7 @@ export interface StoryboardFixtures {
411
413
  /** Ordered setup strategies supported by the first AdCP 3.2 runner slice. */
412
414
  export type FixtureResolutionStrategy = 'seed' | 'discover';
413
415
  /** Operators supported by the closed AdCP 3.2 fixture predicate DSL. */
414
- export type FixtureMatchOperator = 'equals' | 'present' | 'contains_all' | 'any_match' | 'canonical_format_satisfies';
416
+ export type FixtureMatchOperator = 'equals' | 'present' | 'contains_all' | 'any_match' | 'canonical_format_satisfies' | 'collection_selection_satisfies';
415
417
  export interface FixtureCanonicalFormatSelector extends Record<string, unknown> {
416
418
  format_kind: string;
417
419
  params?: Record<string, unknown>;
@@ -441,12 +443,83 @@ export type FixtureMatchClause = {
441
443
  operator: 'canonical_format_satisfies';
442
444
  value: FixtureCanonicalFormatSelector;
443
445
  where?: never;
446
+ } | {
447
+ path: string;
448
+ operator: 'collection_selection_satisfies';
449
+ /**
450
+ * The AUTHORED operand: `minimum_pairs` and `require_cross_publisher_collection`
451
+ * are optional, so `{ collection_targeting: 'fixed' }` type-checks exactly as the
452
+ * loader accepts it. `normalizeFixtureMatchExpression` resolves it to
453
+ * `ResolvedCollectionSelectionSelector` before evaluation.
454
+ */
455
+ value: CollectionSelectionSelector;
456
+ where?: never;
444
457
  } | {
445
458
  path: string;
446
459
  operator: 'any_match';
447
460
  where: FixtureMatchClause[];
448
461
  value?: never;
449
462
  };
463
+ /**
464
+ * One declaration-local capture published by fixture preparation.
465
+ *
466
+ * `path` resolves against the SELECTED entity snapshot — the product or
467
+ * scoped pricing option the resolver actually pinned — not against the first
468
+ * row of a later unfiltered read. `witness` instead binds a bounded derived
469
+ * value from the `collection_selection_satisfies` match witness retained for
470
+ * that same selection. Exactly one of the two is set.
471
+ *
472
+ * `key` must sit inside the reserved `__adcp_fixture_` namespace: these
473
+ * values decide what gets purchased, so later convention extraction, step
474
+ * captures, caller context and seller responses must not be able to replace
475
+ * or suppress them.
476
+ */
477
+ export type FixtureContextOutput =
478
+ /**
479
+ * Dotted storyboard grammar relative to the selected entity snapshot —
480
+ * `currency`, `pricing_options[0].rate`.
481
+ *
482
+ * NOT the RFC 6901 pointer the sibling `FixtureMatchClause.path` takes,
483
+ * which is the natural mistake when the two are authored side by side.
484
+ * A leading `/`, an empty dotted segment, and anything else that
485
+ * resolves to zero segments are all refused at load — the last of those
486
+ * would otherwise capture the whole entity under a scalar's key.
487
+ */
488
+ {
489
+ key: string;
490
+ path: string;
491
+ witness?: never;
492
+ snapshot?: never;
493
+ }
494
+ /** Bounded derived capture from the retained match witness. */
495
+ | {
496
+ key: string;
497
+ witness: CollectionWitnessKind;
498
+ path?: never;
499
+ snapshot?: never;
500
+ }
501
+ /**
502
+ * The WHOLE selected entity, captured as an immutable snapshot.
503
+ *
504
+ * The explicit spelling exists because optional commercial fields must be
505
+ * able to be absent. `fixed_price` and `min_spend_per_package` are both
506
+ * optional on `cpm-option.json` — absent `fixed_price` means auction
507
+ * pricing, absent `min_spend_per_package` means no minimum — so a `path:`
508
+ * capture of either turns a legal supporting seller into a setup failure,
509
+ * while gating the declaration on `present` would suppress that seller
510
+ * from qualifying at all.
511
+ *
512
+ * With a snapshot, absence stays absence: the key is simply not on the
513
+ * captured object, and a storyboard branches on it with an ordinary phase
514
+ * condition or a context-reading validation. Nothing is defaulted and no
515
+ * zero is fabricated.
516
+ */
517
+ | {
518
+ key: string;
519
+ snapshot: 'selected_entity';
520
+ path?: never;
521
+ witness?: never;
522
+ };
450
523
  export interface FixtureResolutionDeclaration {
451
524
  /** Authored run-scoped fixture handle. */
452
525
  handle: string;
@@ -456,6 +529,12 @@ export interface FixtureResolutionDeclaration {
456
529
  match?: FixtureMatchClause[];
457
530
  /** Default false: one seller entity cannot satisfy two handles. */
458
531
  allow_reuse?: boolean;
532
+ /**
533
+ * Opt-in captures published into the reserved context namespace once the
534
+ * WHOLE fixture graph resolves. A declared capture that cannot be built is
535
+ * a setup failure, never an unsupported downgrade.
536
+ */
537
+ context_outputs?: FixtureContextOutput[];
459
538
  }
460
539
  export type ProductFixtureResolutionDeclaration = FixtureResolutionDeclaration;
461
540
  export interface PricingOptionFixtureResolutionDeclaration extends FixtureResolutionDeclaration {
@@ -996,6 +1075,25 @@ export type StoryboardValidationCheck = 'response_schema' | 'field_present'
996
1075
  * terminal set passes vacuously; missing context is branch-safe.
997
1076
  */
998
1077
  | 'all_fields_in_context_array'
1078
+ /**
1079
+ * Compare a response array of `CollectionSelector` objects against a
1080
+ * context-captured array as exact sets of atomic
1081
+ * `(publisher_domain, collection_id)` pairs.
1082
+ *
1083
+ * Grouping and ordering are irrelevant — a seller may legally regroup
1084
+ * selectors or reorder ids — but namespaces are never dropped, so an id
1085
+ * carried under the wrong publisher is a failure rather than a match.
1086
+ * Schema-valid redundancy (a repeated id, an overlapping pair expressed in
1087
+ * two groups) normalizes to one pair; schema-invalid input fails with a
1088
+ * distinct diagnostic and ordinary response-schema validation still applies
1089
+ * on top.
1090
+ *
1091
+ * Unlike the branch-safe `field_equals_context` family, a missing
1092
+ * `context_key` is a setup failure: a mandatory set comparison that
1093
+ * silently passes when its expected state was never captured would certify
1094
+ * exactly the case it exists to catch.
1095
+ */
1096
+ | 'collection_set_equals_context'
999
1097
  /**
1000
1098
  * Asserts upstream side-effects against the adopter's
1001
1099
  * `comply_test_controller`'s `query_upstream_traffic` scenario. The
@@ -1932,6 +2030,71 @@ export interface StoryboardRunOptions extends TestOptions {
1932
2030
  * that doesn't host `comply_test_controller`.
1933
2031
  */
1934
2032
  skip_controller_seeding?: boolean;
2033
+ /**
2034
+ * Prepared fixture state to execute against, instead of resolving the
2035
+ * fixture graph again.
2036
+ *
2037
+ * Pass the `PreparedStoryboardFixtures` returned by
2038
+ * `prepareStoryboardFixtures`, or a `{ ref, resolve }` reference backed by
2039
+ * the host's authenticated run scope. Both forms are re-validated and
2040
+ * re-authorized on EVERY lookup, not once: a direct object reused after
2041
+ * its grant was revoked fails the next step. Requires
2042
+ * `prepared_fixtures_authorizer`.
2043
+ */
2044
+ prepared_fixtures?: PreparedStoryboardFixtures | PreparedFixturesReference;
2045
+ /**
2046
+ * Host authorization resolver, consulted on every prepared-state lookup.
2047
+ *
2048
+ * **Required for any reuse.** Omitting it fails closed — for direct
2049
+ * in-process state exactly as for an opaque reference, with zero seller
2050
+ * calls. Trusted object identity proves a state came from
2051
+ * `prepareStoryboardFixtures` in this process; it does not establish a
2052
+ * current grant, and binding coherence observes a reroute, account switch,
2053
+ * schema swap or credential change but never a revocation. A warning in
2054
+ * place of a refusal would let an unenforced authorization boundary ship
2055
+ * while being described as every-lookup enforcement.
2056
+ *
2057
+ * The SDK does not implement a grant service: resolving the principal and
2058
+ * tenant from trusted session state, and storing grant/revocation, stay
2059
+ * host duties behind this hook.
2060
+ */
2061
+ prepared_fixtures_authorizer?: PreparedFixturesAuthorizer;
2062
+ /**
2063
+ * Authorized-scope sink for the record of a REFUSED run.
2064
+ *
2065
+ * An authorization failure is an access-control error, not a grading
2066
+ * outcome: the refused caller gets a `PreparedFixturesDeniedError`
2067
+ * carrying the machine refusal code and no result at all. But the
2068
+ * evidence still has to exist somewhere accountable, so the runner
2069
+ * builds the complete, UNREDACTED record — the synthesized
2070
+ * `prepared_fixtures_authorization` check, `fixture_resolutions` with
2071
+ * `seller_ids`, exact request and response records for every step that
2072
+ * ran — and hands it here before throwing.
2073
+ *
2074
+ * This is an authorized scope. Whatever you do with the record (audit
2075
+ * log, incident store, operator console) is inside the host's trust
2076
+ * boundary; it must not be routed back to the refused caller. Where no
2077
+ * sink is configured the record is simply not produced to anyone.
2078
+ *
2079
+ * A sink that throws or rejects does not change the outcome: the
2080
+ * denial is thrown either way, and the sink's own failure is not
2081
+ * reported to the caller, since it would be an oracle over host state.
2082
+ */
2083
+ prepared_fixtures_audit_sink?: (record: StoryboardResult | StoryboardStepResult) => void | Promise<void>;
2084
+ /**
2085
+ * Nonsecret principal recorded in the prepared-state binding. Never a
2086
+ * credential: it is an identity label the host authorizer can correlate,
2087
+ * not evidence of authentication.
2088
+ */
2089
+ prepared_fixtures_principal?: string;
2090
+ /**
2091
+ * Stable run identity recorded in the prepared-state binding. Namespaced
2092
+ * with the rest of the family: it is prepared-state metadata, not a
2093
+ * general run-correlation id, and it is the one binding field that is NOT
2094
+ * re-compared on reuse (the whole point of reuse is that later steps share
2095
+ * the preparation's run).
2096
+ */
2097
+ prepared_fixtures_run_id?: string;
1935
2098
  /**
1936
2099
  * Dependencies for `expect_webhook_signature_valid`. When omitted the step
1937
2100
  * grades `not_applicable` — matches the spec's "pending" gate. Supply the
@@ -1962,7 +2125,15 @@ export interface RunnerRequestRecord {
1962
2125
  transport: RunnerTransport;
1963
2126
  /** Task/tool/skill name actually invoked (after test-kit resolution). */
1964
2127
  operation: string;
1965
- /** Fully-resolved JSON payload with secrets redacted as "[redacted]". */
2128
+ /**
2129
+ * Fully-resolved JSON payload with secrets redacted as "[redacted]".
2130
+ *
2131
+ * After a prepared-state refusal, values that came from the reserved
2132
+ * `__adcp_fixture_` namespace are replaced with the SAME marker. A
2133
+ * projected payload is evidence, not a replayable request: the marker
2134
+ * is a string whatever the original field's type was, and a
2135
+ * `"[redacted]"` does not say which of the two rules produced it.
2136
+ */
1966
2137
  payload: unknown;
1967
2138
  /**
1968
2139
  * Observed request headers. Deliberately NOT populated today — the runner
@@ -2049,7 +2220,19 @@ export type RunnerSkipReason = 'not_applicable' | 'no_phases' | 'prerequisite_fa
2049
2220
  * Kept distinct from `peer_branch_taken` (branch-set routing) and
2050
2221
  * `not_applicable` (coverage gap). Spec source: adcp#3734 (AdCP 3.0.3+).
2051
2222
  */
2052
- | 'peer_substituted';
2223
+ | 'peer_substituted'
2224
+ /**
2225
+ * Every enabled strategy for at least one declared `fixture_resolution`
2226
+ * handle was exhausted without finding or creating a qualifying entity.
2227
+ *
2228
+ * `runner-output-contract.yaml` lists this as a canonical
2229
+ * `skip_result.reason` in its own right, and the distinction matters:
2230
+ * bucketing a fixture coverage gap under `not_applicable` puts it in the
2231
+ * same bin as a genuine applicability gate, which is exactly the split
2232
+ * the contract's reason list exists to preserve. It was previously
2233
+ * detailed-only and mapped down to `not_applicable`.
2234
+ */
2235
+ | 'fixture_unsatisfied';
2053
2236
  /**
2054
2237
  * Grader-specific skip reasons. These are narrower than the canonical
2055
2238
  * `RunnerSkipReason` values — they carry runner-local context (which probe,
@@ -2325,10 +2508,14 @@ export interface ValidationResult {
2325
2508
  schema_id?: string | null;
2326
2509
  /** Resolvable schema URL; set only for `response_schema`. */
2327
2510
  schema_url?: string | null;
2328
- /** Exact request the runner sent (present on failure when available). */
2329
- request?: RunnerRequestRecord;
2330
- /** Exact response observed (present on failure when available). */
2331
- response?: RunnerResponseRecord;
2511
+ /**
2512
+ * Exact request the runner sent. Required on failure; explicitly `null`
2513
+ * for a PRE-WIRE failure, where omitting the key could not be told apart
2514
+ * from a runner that forgot to record it.
2515
+ */
2516
+ request?: RunnerRequestRecord | null;
2517
+ /** Exact response observed. Required on failure; `null` when pre-wire. */
2518
+ response?: RunnerResponseRecord | null;
2332
2519
  /** Optional remediation hint. */
2333
2520
  remediation?: string;
2334
2521
  /**
@@ -2524,11 +2711,20 @@ export interface ContextProvenanceEntry {
2524
2711
  * `convention`: task-default extractor in CONTEXT_EXTRACTORS.
2525
2712
  * `generator`: runner-minted value (no response path involved).
2526
2713
  */
2527
- source_kind: 'context_outputs' | 'convention' | 'generator';
2714
+ source_kind: 'context_outputs' | 'convention' | 'generator' | 'fixture_preparation';
2528
2715
  /** Response path the value was extracted from (set for `context_outputs`). */
2529
2716
  response_path?: string;
2530
2717
  /** Task name whose response this value was extracted from. */
2531
2718
  source_task?: string;
2719
+ /**
2720
+ * Fixture handle whose selected-entity snapshot produced this value.
2721
+ * Present only for `fixture_preparation`; it records WHICH pinned entity a
2722
+ * reserved capture came from, so evidence can tie a request field back to
2723
+ * the exact graph the resolver bound.
2724
+ */
2725
+ fixture_handle?: string;
2726
+ /** Parent product handle for a scoped-pricing capture. */
2727
+ fixture_product_handle?: string;
2532
2728
  }
2533
2729
  /**
2534
2730
  * Common shape every `StoryboardStepHint` member shares: the discriminator
@@ -2591,10 +2787,11 @@ export interface ContextValueRejectedHint extends StoryboardStepHintBase {
2591
2787
  */
2592
2788
  source_step_id: string;
2593
2789
  /**
2594
- * How the context key was written (`context_outputs` vs convention vs generator).
2790
+ * How the context key was written (`context_outputs` vs convention vs
2791
+ * generator vs fixture preparation).
2595
2792
  * @provenance runner
2596
2793
  */
2597
- source_kind: 'context_outputs' | 'convention' | 'generator';
2794
+ source_kind: 'context_outputs' | 'convention' | 'generator' | 'fixture_preparation';
2598
2795
  /**
2599
2796
  * YAML response path set for `context_outputs`; absent for convention extractors and generators.
2600
2797
  * @provenance storyboard
@@ -1,3 +1,5 @@
1
+ import type { CollectionSelectionSelector, CollectionWitnessKind } from './collection-selection';
2
+ import type { PreparedFixturesAuthorizer, PreparedFixturesReference, PreparedStoryboardFixtures } from './prepared-fixtures';
1
3
  import type { CreativeBuildProbeSpec } from './creative-build-probe';
2
4
  /**
3
5
  * Types for storyboard-driven testing.
@@ -411,7 +413,7 @@ export interface StoryboardFixtures {
411
413
  /** Ordered setup strategies supported by the first AdCP 3.2 runner slice. */
412
414
  export type FixtureResolutionStrategy = 'seed' | 'discover';
413
415
  /** Operators supported by the closed AdCP 3.2 fixture predicate DSL. */
414
- export type FixtureMatchOperator = 'equals' | 'present' | 'contains_all' | 'any_match' | 'canonical_format_satisfies';
416
+ export type FixtureMatchOperator = 'equals' | 'present' | 'contains_all' | 'any_match' | 'canonical_format_satisfies' | 'collection_selection_satisfies';
415
417
  export interface FixtureCanonicalFormatSelector extends Record<string, unknown> {
416
418
  format_kind: string;
417
419
  params?: Record<string, unknown>;
@@ -441,12 +443,83 @@ export type FixtureMatchClause = {
441
443
  operator: 'canonical_format_satisfies';
442
444
  value: FixtureCanonicalFormatSelector;
443
445
  where?: never;
446
+ } | {
447
+ path: string;
448
+ operator: 'collection_selection_satisfies';
449
+ /**
450
+ * The AUTHORED operand: `minimum_pairs` and `require_cross_publisher_collection`
451
+ * are optional, so `{ collection_targeting: 'fixed' }` type-checks exactly as the
452
+ * loader accepts it. `normalizeFixtureMatchExpression` resolves it to
453
+ * `ResolvedCollectionSelectionSelector` before evaluation.
454
+ */
455
+ value: CollectionSelectionSelector;
456
+ where?: never;
444
457
  } | {
445
458
  path: string;
446
459
  operator: 'any_match';
447
460
  where: FixtureMatchClause[];
448
461
  value?: never;
449
462
  };
463
+ /**
464
+ * One declaration-local capture published by fixture preparation.
465
+ *
466
+ * `path` resolves against the SELECTED entity snapshot — the product or
467
+ * scoped pricing option the resolver actually pinned — not against the first
468
+ * row of a later unfiltered read. `witness` instead binds a bounded derived
469
+ * value from the `collection_selection_satisfies` match witness retained for
470
+ * that same selection. Exactly one of the two is set.
471
+ *
472
+ * `key` must sit inside the reserved `__adcp_fixture_` namespace: these
473
+ * values decide what gets purchased, so later convention extraction, step
474
+ * captures, caller context and seller responses must not be able to replace
475
+ * or suppress them.
476
+ */
477
+ export type FixtureContextOutput =
478
+ /**
479
+ * Dotted storyboard grammar relative to the selected entity snapshot —
480
+ * `currency`, `pricing_options[0].rate`.
481
+ *
482
+ * NOT the RFC 6901 pointer the sibling `FixtureMatchClause.path` takes,
483
+ * which is the natural mistake when the two are authored side by side.
484
+ * A leading `/`, an empty dotted segment, and anything else that
485
+ * resolves to zero segments are all refused at load — the last of those
486
+ * would otherwise capture the whole entity under a scalar's key.
487
+ */
488
+ {
489
+ key: string;
490
+ path: string;
491
+ witness?: never;
492
+ snapshot?: never;
493
+ }
494
+ /** Bounded derived capture from the retained match witness. */
495
+ | {
496
+ key: string;
497
+ witness: CollectionWitnessKind;
498
+ path?: never;
499
+ snapshot?: never;
500
+ }
501
+ /**
502
+ * The WHOLE selected entity, captured as an immutable snapshot.
503
+ *
504
+ * The explicit spelling exists because optional commercial fields must be
505
+ * able to be absent. `fixed_price` and `min_spend_per_package` are both
506
+ * optional on `cpm-option.json` — absent `fixed_price` means auction
507
+ * pricing, absent `min_spend_per_package` means no minimum — so a `path:`
508
+ * capture of either turns a legal supporting seller into a setup failure,
509
+ * while gating the declaration on `present` would suppress that seller
510
+ * from qualifying at all.
511
+ *
512
+ * With a snapshot, absence stays absence: the key is simply not on the
513
+ * captured object, and a storyboard branches on it with an ordinary phase
514
+ * condition or a context-reading validation. Nothing is defaulted and no
515
+ * zero is fabricated.
516
+ */
517
+ | {
518
+ key: string;
519
+ snapshot: 'selected_entity';
520
+ path?: never;
521
+ witness?: never;
522
+ };
450
523
  export interface FixtureResolutionDeclaration {
451
524
  /** Authored run-scoped fixture handle. */
452
525
  handle: string;
@@ -456,6 +529,12 @@ export interface FixtureResolutionDeclaration {
456
529
  match?: FixtureMatchClause[];
457
530
  /** Default false: one seller entity cannot satisfy two handles. */
458
531
  allow_reuse?: boolean;
532
+ /**
533
+ * Opt-in captures published into the reserved context namespace once the
534
+ * WHOLE fixture graph resolves. A declared capture that cannot be built is
535
+ * a setup failure, never an unsupported downgrade.
536
+ */
537
+ context_outputs?: FixtureContextOutput[];
459
538
  }
460
539
  export type ProductFixtureResolutionDeclaration = FixtureResolutionDeclaration;
461
540
  export interface PricingOptionFixtureResolutionDeclaration extends FixtureResolutionDeclaration {
@@ -996,6 +1075,25 @@ export type StoryboardValidationCheck = 'response_schema' | 'field_present'
996
1075
  * terminal set passes vacuously; missing context is branch-safe.
997
1076
  */
998
1077
  | 'all_fields_in_context_array'
1078
+ /**
1079
+ * Compare a response array of `CollectionSelector` objects against a
1080
+ * context-captured array as exact sets of atomic
1081
+ * `(publisher_domain, collection_id)` pairs.
1082
+ *
1083
+ * Grouping and ordering are irrelevant — a seller may legally regroup
1084
+ * selectors or reorder ids — but namespaces are never dropped, so an id
1085
+ * carried under the wrong publisher is a failure rather than a match.
1086
+ * Schema-valid redundancy (a repeated id, an overlapping pair expressed in
1087
+ * two groups) normalizes to one pair; schema-invalid input fails with a
1088
+ * distinct diagnostic and ordinary response-schema validation still applies
1089
+ * on top.
1090
+ *
1091
+ * Unlike the branch-safe `field_equals_context` family, a missing
1092
+ * `context_key` is a setup failure: a mandatory set comparison that
1093
+ * silently passes when its expected state was never captured would certify
1094
+ * exactly the case it exists to catch.
1095
+ */
1096
+ | 'collection_set_equals_context'
999
1097
  /**
1000
1098
  * Asserts upstream side-effects against the adopter's
1001
1099
  * `comply_test_controller`'s `query_upstream_traffic` scenario. The
@@ -1932,6 +2030,71 @@ export interface StoryboardRunOptions extends TestOptions {
1932
2030
  * that doesn't host `comply_test_controller`.
1933
2031
  */
1934
2032
  skip_controller_seeding?: boolean;
2033
+ /**
2034
+ * Prepared fixture state to execute against, instead of resolving the
2035
+ * fixture graph again.
2036
+ *
2037
+ * Pass the `PreparedStoryboardFixtures` returned by
2038
+ * `prepareStoryboardFixtures`, or a `{ ref, resolve }` reference backed by
2039
+ * the host's authenticated run scope. Both forms are re-validated and
2040
+ * re-authorized on EVERY lookup, not once: a direct object reused after
2041
+ * its grant was revoked fails the next step. Requires
2042
+ * `prepared_fixtures_authorizer`.
2043
+ */
2044
+ prepared_fixtures?: PreparedStoryboardFixtures | PreparedFixturesReference;
2045
+ /**
2046
+ * Host authorization resolver, consulted on every prepared-state lookup.
2047
+ *
2048
+ * **Required for any reuse.** Omitting it fails closed — for direct
2049
+ * in-process state exactly as for an opaque reference, with zero seller
2050
+ * calls. Trusted object identity proves a state came from
2051
+ * `prepareStoryboardFixtures` in this process; it does not establish a
2052
+ * current grant, and binding coherence observes a reroute, account switch,
2053
+ * schema swap or credential change but never a revocation. A warning in
2054
+ * place of a refusal would let an unenforced authorization boundary ship
2055
+ * while being described as every-lookup enforcement.
2056
+ *
2057
+ * The SDK does not implement a grant service: resolving the principal and
2058
+ * tenant from trusted session state, and storing grant/revocation, stay
2059
+ * host duties behind this hook.
2060
+ */
2061
+ prepared_fixtures_authorizer?: PreparedFixturesAuthorizer;
2062
+ /**
2063
+ * Authorized-scope sink for the record of a REFUSED run.
2064
+ *
2065
+ * An authorization failure is an access-control error, not a grading
2066
+ * outcome: the refused caller gets a `PreparedFixturesDeniedError`
2067
+ * carrying the machine refusal code and no result at all. But the
2068
+ * evidence still has to exist somewhere accountable, so the runner
2069
+ * builds the complete, UNREDACTED record — the synthesized
2070
+ * `prepared_fixtures_authorization` check, `fixture_resolutions` with
2071
+ * `seller_ids`, exact request and response records for every step that
2072
+ * ran — and hands it here before throwing.
2073
+ *
2074
+ * This is an authorized scope. Whatever you do with the record (audit
2075
+ * log, incident store, operator console) is inside the host's trust
2076
+ * boundary; it must not be routed back to the refused caller. Where no
2077
+ * sink is configured the record is simply not produced to anyone.
2078
+ *
2079
+ * A sink that throws or rejects does not change the outcome: the
2080
+ * denial is thrown either way, and the sink's own failure is not
2081
+ * reported to the caller, since it would be an oracle over host state.
2082
+ */
2083
+ prepared_fixtures_audit_sink?: (record: StoryboardResult | StoryboardStepResult) => void | Promise<void>;
2084
+ /**
2085
+ * Nonsecret principal recorded in the prepared-state binding. Never a
2086
+ * credential: it is an identity label the host authorizer can correlate,
2087
+ * not evidence of authentication.
2088
+ */
2089
+ prepared_fixtures_principal?: string;
2090
+ /**
2091
+ * Stable run identity recorded in the prepared-state binding. Namespaced
2092
+ * with the rest of the family: it is prepared-state metadata, not a
2093
+ * general run-correlation id, and it is the one binding field that is NOT
2094
+ * re-compared on reuse (the whole point of reuse is that later steps share
2095
+ * the preparation's run).
2096
+ */
2097
+ prepared_fixtures_run_id?: string;
1935
2098
  /**
1936
2099
  * Dependencies for `expect_webhook_signature_valid`. When omitted the step
1937
2100
  * grades `not_applicable` — matches the spec's "pending" gate. Supply the
@@ -1962,7 +2125,15 @@ export interface RunnerRequestRecord {
1962
2125
  transport: RunnerTransport;
1963
2126
  /** Task/tool/skill name actually invoked (after test-kit resolution). */
1964
2127
  operation: string;
1965
- /** Fully-resolved JSON payload with secrets redacted as "[redacted]". */
2128
+ /**
2129
+ * Fully-resolved JSON payload with secrets redacted as "[redacted]".
2130
+ *
2131
+ * After a prepared-state refusal, values that came from the reserved
2132
+ * `__adcp_fixture_` namespace are replaced with the SAME marker. A
2133
+ * projected payload is evidence, not a replayable request: the marker
2134
+ * is a string whatever the original field's type was, and a
2135
+ * `"[redacted]"` does not say which of the two rules produced it.
2136
+ */
1966
2137
  payload: unknown;
1967
2138
  /**
1968
2139
  * Observed request headers. Deliberately NOT populated today — the runner
@@ -2049,7 +2220,19 @@ export type RunnerSkipReason = 'not_applicable' | 'no_phases' | 'prerequisite_fa
2049
2220
  * Kept distinct from `peer_branch_taken` (branch-set routing) and
2050
2221
  * `not_applicable` (coverage gap). Spec source: adcp#3734 (AdCP 3.0.3+).
2051
2222
  */
2052
- | 'peer_substituted';
2223
+ | 'peer_substituted'
2224
+ /**
2225
+ * Every enabled strategy for at least one declared `fixture_resolution`
2226
+ * handle was exhausted without finding or creating a qualifying entity.
2227
+ *
2228
+ * `runner-output-contract.yaml` lists this as a canonical
2229
+ * `skip_result.reason` in its own right, and the distinction matters:
2230
+ * bucketing a fixture coverage gap under `not_applicable` puts it in the
2231
+ * same bin as a genuine applicability gate, which is exactly the split
2232
+ * the contract's reason list exists to preserve. It was previously
2233
+ * detailed-only and mapped down to `not_applicable`.
2234
+ */
2235
+ | 'fixture_unsatisfied';
2053
2236
  /**
2054
2237
  * Grader-specific skip reasons. These are narrower than the canonical
2055
2238
  * `RunnerSkipReason` values — they carry runner-local context (which probe,
@@ -2325,10 +2508,14 @@ export interface ValidationResult {
2325
2508
  schema_id?: string | null;
2326
2509
  /** Resolvable schema URL; set only for `response_schema`. */
2327
2510
  schema_url?: string | null;
2328
- /** Exact request the runner sent (present on failure when available). */
2329
- request?: RunnerRequestRecord;
2330
- /** Exact response observed (present on failure when available). */
2331
- response?: RunnerResponseRecord;
2511
+ /**
2512
+ * Exact request the runner sent. Required on failure; explicitly `null`
2513
+ * for a PRE-WIRE failure, where omitting the key could not be told apart
2514
+ * from a runner that forgot to record it.
2515
+ */
2516
+ request?: RunnerRequestRecord | null;
2517
+ /** Exact response observed. Required on failure; `null` when pre-wire. */
2518
+ response?: RunnerResponseRecord | null;
2332
2519
  /** Optional remediation hint. */
2333
2520
  remediation?: string;
2334
2521
  /**
@@ -2524,11 +2711,20 @@ export interface ContextProvenanceEntry {
2524
2711
  * `convention`: task-default extractor in CONTEXT_EXTRACTORS.
2525
2712
  * `generator`: runner-minted value (no response path involved).
2526
2713
  */
2527
- source_kind: 'context_outputs' | 'convention' | 'generator';
2714
+ source_kind: 'context_outputs' | 'convention' | 'generator' | 'fixture_preparation';
2528
2715
  /** Response path the value was extracted from (set for `context_outputs`). */
2529
2716
  response_path?: string;
2530
2717
  /** Task name whose response this value was extracted from. */
2531
2718
  source_task?: string;
2719
+ /**
2720
+ * Fixture handle whose selected-entity snapshot produced this value.
2721
+ * Present only for `fixture_preparation`; it records WHICH pinned entity a
2722
+ * reserved capture came from, so evidence can tie a request field back to
2723
+ * the exact graph the resolver bound.
2724
+ */
2725
+ fixture_handle?: string;
2726
+ /** Parent product handle for a scoped-pricing capture. */
2727
+ fixture_product_handle?: string;
2532
2728
  }
2533
2729
  /**
2534
2730
  * Common shape every `StoryboardStepHint` member shares: the discriminator
@@ -2591,10 +2787,11 @@ export interface ContextValueRejectedHint extends StoryboardStepHintBase {
2591
2787
  */
2592
2788
  source_step_id: string;
2593
2789
  /**
2594
- * How the context key was written (`context_outputs` vs convention vs generator).
2790
+ * How the context key was written (`context_outputs` vs convention vs
2791
+ * generator vs fixture preparation).
2595
2792
  * @provenance runner
2596
2793
  */
2597
- source_kind: 'context_outputs' | 'convention' | 'generator';
2794
+ source_kind: 'context_outputs' | 'convention' | 'generator' | 'fixture_preparation';
2598
2795
  /**
2599
2796
  * YAML response path set for `context_outputs`; absent for convention extractors and generators.
2600
2797
  * @provenance storyboard
@@ -50,7 +50,7 @@ const DETAILED_SKIP_TO_CANONICAL = {
50
50
  rate_limit_not_triggered: "not_applicable",
51
51
  force_scenario_unsupported: "not_applicable",
52
52
  fixture_seed_unsupported: "not_applicable",
53
- fixture_unsatisfied: "not_applicable",
53
+ fixture_unsatisfied: "fixture_unsatisfied",
54
54
  session_probe_ungradable: "not_applicable",
55
55
  capability_unsupported: "not_applicable",
56
56
  capability_prerequisite_unavailable: "not_applicable",
@@ -24,7 +24,7 @@ const DETAILED_SKIP_TO_CANONICAL = {
24
24
  rate_limit_not_triggered: "not_applicable",
25
25
  force_scenario_unsupported: "not_applicable",
26
26
  fixture_seed_unsupported: "not_applicable",
27
- fixture_unsatisfied: "not_applicable",
27
+ fixture_unsatisfied: "fixture_unsatisfied",
28
28
  session_probe_ungradable: "not_applicable",
29
29
  capability_unsupported: "not_applicable",
30
30
  capability_prerequisite_unavailable: "not_applicable",
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "16.1.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "16.3.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**
@@ -197,7 +197,7 @@ export interface UpstreamTrafficQueryResult {
197
197
  */
198
198
  export declare function runValidations(validations: StoryboardValidation[], context: ValidationContext): ValidationResult[];
199
199
  /** Capability semver emitted in run summaries and used for advisory expiry. */
200
- export declare const RUNNER_CAPABILITY_VERSION = "16.1.0";
200
+ export declare const RUNNER_CAPABILITY_VERSION = "16.3.0";
201
201
  /** True when a failed validation contributes to the owning step's grade. */
202
202
  export declare function validationFailsStep(result: ValidationResult): boolean;
203
203
  /**