@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
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Domain-qualified collection identity: one normalizer, one eligibility
3
+ * predicate, one witness builder, one set comparison.
4
+ *
5
+ * Every consumer of collection identity in the runner goes through this
6
+ * module — the fixture predicate (`collection_selection_satisfies`), the
7
+ * derived witness captures published by fixture preparation, and the
8
+ * `collection_set_equals_context` validator. Splitting those three would let
9
+ * "what counts as the same collection" drift between selection and grading,
10
+ * which is exactly the failure the upstream contract calls out.
11
+ *
12
+ * Identity rules, and the reasons they are what they are:
13
+ *
14
+ * - A selector is normalized to atomic `(publisher_domain, collection_id)`
15
+ * pairs. IDs are never flattened without their domain: two publishers may
16
+ * legitimately declare the same `collection_id`.
17
+ * - `collection_ids` is optional on `CollectionSelector` and means "every
18
+ * collection declared in that domain's adagents.json". That bulk-grant
19
+ * form is a *different* selector from an explicit enumeration, so it
20
+ * normalizes to a pair with `collection_id: null` rather than silently
21
+ * comparing equal to an enumerated set. Product composition is required
22
+ * to name explicit ids, so `null` pairs do not count toward
23
+ * `minimum_pairs`.
24
+ * - Schema-valid redundancy collapses: repeated ids inside one selector,
25
+ * and overlapping atomic pairs across differently-grouped selectors, are
26
+ * one pair. Neither `product.collections[]` nor `collection_ids[]`
27
+ * carries a uniqueness constraint, so redundancy is legal *product
28
+ * composition*. The readback arm is stricter:
29
+ * `core/collection-selection.json` declares `uniqueItems: true` on
30
+ * `collections` in `mode: selected`. Normalizing here is for COMPARISON
31
+ * only and never excuses that — the surrounding response is still
32
+ * schema-validated, which is what rejects a duplicated outer entry.
33
+ * Schema-invalid input (a non-array, a non-object entry, an empty
34
+ * `collection_ids`) stays a visible failure here and is additionally
35
+ * rejected by ordinary response-schema validation upstream.
36
+ * - Ordering is bytewise over UTF-8, on the *pairs*, so outer grouping and
37
+ * inner id order never affect the result while non-ASCII identifiers stay
38
+ * lossless. Nothing is case-folded, trimmed, punycoded or otherwise
39
+ * rewritten. `collection_id` is a plain string with no `minLength` and no
40
+ * declared normalization form, so inventing one would grade agents
41
+ * against a rule the protocol does not state. `publisher_domain` is
42
+ * separately pattern-constrained to lowercase LDH by
43
+ * `core/collection-selector.json`, which response-schema validation
44
+ * already enforces — canonicalizing it here would be redundant at best
45
+ * and would mask a non-conformant catalog at worst.
46
+ */
47
+ /** Maximum distinct pairs any single normalization will materialize. */
48
+ export declare const COLLECTION_PAIR_LIMIT = 10000;
49
+ /** Maximum pairs echoed into a diagnostic before it is elided. */
50
+ export declare const COLLECTION_DIAGNOSTIC_LIMIT = 20;
51
+ /** One atomic, domain-qualified collection identity. */
52
+ export interface CollectionPair {
53
+ publisher_domain: string;
54
+ /** `null` is the domain-only bulk-grant selector, not an empty id. */
55
+ collection_id: string | null;
56
+ }
57
+ /** A concrete `CollectionSelector` as it appears on the wire. */
58
+ export interface CollectionSelectorObject {
59
+ publisher_domain: string;
60
+ collection_ids?: string[];
61
+ }
62
+ export interface NormalizedCollectionSelectors {
63
+ /** Distinct pairs in bytewise order. */
64
+ pairs: CollectionPair[];
65
+ /** Outer selector entries observed, before normalization. */
66
+ selector_count: number;
67
+ /** Distinct publisher domains, bytewise ordered. */
68
+ domains: string[];
69
+ }
70
+ export type CollectionNormalizationCode = 'not_an_array' | 'selector_not_object' | 'publisher_domain_invalid' | 'collection_ids_invalid' | 'collection_id_invalid' | 'pair_limit_exceeded';
71
+ export interface CollectionNormalizationFailure {
72
+ code: CollectionNormalizationCode;
73
+ detail: string;
74
+ }
75
+ export type CollectionNormalizationResult = {
76
+ ok: true;
77
+ value: NormalizedCollectionSelectors;
78
+ } | {
79
+ ok: false;
80
+ failure: CollectionNormalizationFailure;
81
+ };
82
+ /** Total bytewise order over pairs. Domain first, then id; `null` sorts first. */
83
+ export declare function compareCollectionPairs(a: CollectionPair, b: CollectionPair): number;
84
+ /** Stable, unambiguous rendering for diagnostics and dedup keys. */
85
+ export declare function formatCollectionPair(pair: CollectionPair): string;
86
+ /**
87
+ * Normalize an array of `CollectionSelector` objects into distinct atomic
88
+ * pairs. Used for product catalog entries, authored expected sets and
89
+ * seller-returned `selected.collections` alike — same definition everywhere.
90
+ */
91
+ export declare function normalizeCollectionSelectors(value: unknown, options?: {
92
+ limit?: number;
93
+ }): CollectionNormalizationResult;
94
+ /** Exact set difference over normalized pairs, with bounded diagnostics. */
95
+ export declare function diffCollectionPairSets(actual: readonly CollectionPair[], expected: readonly CollectionPair[]): {
96
+ equal: boolean;
97
+ missing: CollectionPair[];
98
+ unexpected: CollectionPair[];
99
+ };
100
+ /** Render at most `COLLECTION_DIAGNOSTIC_LIMIT` pairs, flagging elision. */
101
+ export declare function summarizeCollectionPairs(pairs: readonly CollectionPair[]): string;
102
+ /**
103
+ * Operand of the `collection_selection_satisfies` fixture predicate.
104
+ *
105
+ * `collection_targeting` encodes the schema's omitted-false default
106
+ * explicitly rather than teaching every `equals` comparison to apply
107
+ * arbitrary defaults. It is deliberately NOT named `mode`: the wire's
108
+ * `collection_selection.mode` is `selected | default`, and the two appear in
109
+ * the same storyboard file.
110
+ *
111
+ * - `fixed` — `collection_targeting_allowed` is literal `false` OR
112
+ * absent (the normative default). `true` does not qualify.
113
+ * - `selectable` — literal `true` only.
114
+ * - `any` — either, as long as the flag is absent or a boolean.
115
+ *
116
+ * A non-boolean, non-absent flag never qualifies in any mode: that is a
117
+ * schema failure of the seller's catalog, surfaced by response-schema
118
+ * validation during discovery, not something this predicate repairs.
119
+ */
120
+ export interface CollectionSelectionSelector {
121
+ collection_targeting: 'selectable' | 'fixed' | 'any';
122
+ /**
123
+ * Distinct concrete pairs the product must expose. Defaults to `1`, which
124
+ * covers default materialization / full-bundle restatement; `2` is
125
+ * required before a genuine strict subset exists to exercise.
126
+ */
127
+ minimum_pairs?: 1 | 2;
128
+ /**
129
+ * Require a wire-visible owner/host relation: at least one collection
130
+ * selector whose publisher domain is outside every declared property
131
+ * (host) domain of the same product. Defaults to `false`.
132
+ */
133
+ require_cross_publisher_collection?: boolean;
134
+ }
135
+ /**
136
+ * Post-normalization operand the evaluator consumes, with both defaults
137
+ * applied.
138
+ *
139
+ * Kept separate from the authored form so the type accepts exactly what the
140
+ * loader accepts: `{ collection_targeting: 'fixed' }` is valid YAML and must type-check,
141
+ * while an index signature would have let a typo'd key compile clean and
142
+ * then fail at load against the closed-operand rule.
143
+ */
144
+ export interface ResolvedCollectionSelectionSelector {
145
+ collection_targeting: 'selectable' | 'fixed' | 'any';
146
+ minimum_pairs: 1 | 2;
147
+ require_cross_publisher_collection: boolean;
148
+ }
149
+ export declare const COLLECTION_TARGETING_MODES: readonly ["selectable", "fixed", "any"];
150
+ /** Validate and default the closed operand. Throws on authoring errors. */
151
+ export declare function normalizeCollectionSelectionSelector(value: unknown, location: string): ResolvedCollectionSelectionSelector;
152
+ /** The declared owner/host relation observed on one product. */
153
+ export interface CrossPublisherCollectionRelation {
154
+ /**
155
+ * The collection namespace that lies outside every property namespace of
156
+ * the SAME selected product.
157
+ */
158
+ collection_publisher_domain: string;
159
+ /** Property namespaces declared by that same product. */
160
+ property_publisher_domains: string[];
161
+ /**
162
+ * The concrete selector carrying it. `selector.publisher_domain` always
163
+ * equals `collection_publisher_domain`.
164
+ */
165
+ selector: CollectionSelectorObject;
166
+ }
167
+ /**
168
+ * Everything the resolver retains about the product it actually selected.
169
+ * Built once, from the selected candidate, and never recomputed from a
170
+ * different response.
171
+ */
172
+ export interface CollectionSelectionWitness {
173
+ product_id: string | null;
174
+ /**
175
+ * Effective targeting of the selected product, with the schema's
176
+ * omitted-false default applied. Distinct from the native seller field
177
+ * `collection_targeting_allowed`, whose raw observed value is reported
178
+ * beside it, and from the wire's `collection_selection.mode`.
179
+ */
180
+ collection_targeting: 'selectable' | 'fixed';
181
+ /** The flag exactly as observed — `undefined` when the seller omitted it. */
182
+ collection_targeting_allowed: boolean | undefined;
183
+ /** The product's complete, concrete collection selector bundle. */
184
+ declared_selectors: CollectionSelectorObject[];
185
+ /** Distinct concrete pairs (bulk-grant entries excluded). */
186
+ distinct_pairs: CollectionPair[];
187
+ /**
188
+ * A one-entry selector array naming exactly one of the bundle's pairs, so
189
+ * it is a strict subset whenever the bundle has two or more. Shaped as an
190
+ * array because that is the shape a `collections` field takes on the wire,
191
+ * so a storyboard can substitute it whole.
192
+ *
193
+ * When `require_cross_publisher_collection` was requested, the pair is drawn from the
194
+ * retained external owner, so the subset actually exercises the carriage
195
+ * relation rather than the host's own inventory.
196
+ *
197
+ * `null` when the product exposes fewer than two distinct concrete pairs —
198
+ * a one-pair product still qualifies for default materialization, so the
199
+ * absence of a subset witness must not suppress that coverage.
200
+ */
201
+ strict_subset: CollectionSelectorObject[] | null;
202
+ /**
203
+ * One-entry selector array naming an id verified absent from this
204
+ * product's pairs, under a domain the product does carry.
205
+ */
206
+ undeclared_collection_id_selectors: CollectionSelectorObject[];
207
+ /**
208
+ * One-entry selector array whose domain is verified absent from every
209
+ * COLLECTION namespace this product declares.
210
+ *
211
+ * Property namespaces (`publisher_properties[].publisher_domain`) are not
212
+ * checked — the synthesized domain is a `.invalid` name, which RFC 2606
213
+ * reserves and no real publisher can hold, so a collision is not possible
214
+ * in practice. Stated precisely because "every namespace this product
215
+ * declares" read as including the property side, and it does not.
216
+ */
217
+ undeclared_publisher_domain_selectors: CollectionSelectorObject[];
218
+ /** Present only when the relation was requested and found. */
219
+ cross_publisher_relation: CrossPublisherCollectionRelation | null;
220
+ /** Declared property namespaces, bytewise ordered. */
221
+ property_publisher_domains: string[];
222
+ }
223
+ export type CollectionSelectionEvaluation = {
224
+ eligible: true;
225
+ witness: CollectionSelectionWitness;
226
+ } | {
227
+ eligible: false;
228
+ reason: string;
229
+ };
230
+ /**
231
+ * Decide whether one discovered product qualifies, and retain the witness
232
+ * for the candidate that is actually selected.
233
+ *
234
+ * Qualification is evaluated against the complete validated candidate before
235
+ * any deterministic ordering is applied, so a nonqualifying first product can
236
+ * never hide a later qualifying one.
237
+ */
238
+ export declare function evaluateCollectionSelection(candidate: unknown, selector: CollectionSelectionSelector): CollectionSelectionEvaluation;
239
+ /** Boolean form for the legacy matcher. */
240
+ export declare function productSatisfiesCollectionSelection(candidate: unknown, selector: CollectionSelectionSelector): boolean;
241
+ /** Derived witness captures a declaration may bind to a context key. */
242
+ export declare const COLLECTION_WITNESS_KINDS: readonly ["declared_selectors", "distinct_pairs", "strict_subset", "undeclared_collection_id_selectors", "undeclared_publisher_domain_selectors", "cross_publisher_relation", "property_publisher_domains"];
243
+ export type CollectionWitnessKind = (typeof COLLECTION_WITNESS_KINDS)[number];
244
+ export type CollectionWitnessReadResult = {
245
+ ok: true;
246
+ value: unknown;
247
+ } | {
248
+ ok: false;
249
+ detail: string;
250
+ };
251
+ /**
252
+ * Read one derived capture off a retained witness.
253
+ *
254
+ * A declared capture that cannot be built is a setup failure, never an
255
+ * unsupported/not-applicable downgrade — the storyboard asked for state the
256
+ * selected product does not provide, and silently proceeding would grade the
257
+ * agent against a request the author did not write.
258
+ */
259
+ export declare function readCollectionWitness(witness: CollectionSelectionWitness | undefined, kind: CollectionWitnessKind): CollectionWitnessReadResult;
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Domain-qualified collection identity: one normalizer, one eligibility
3
+ * predicate, one witness builder, one set comparison.
4
+ *
5
+ * Every consumer of collection identity in the runner goes through this
6
+ * module — the fixture predicate (`collection_selection_satisfies`), the
7
+ * derived witness captures published by fixture preparation, and the
8
+ * `collection_set_equals_context` validator. Splitting those three would let
9
+ * "what counts as the same collection" drift between selection and grading,
10
+ * which is exactly the failure the upstream contract calls out.
11
+ *
12
+ * Identity rules, and the reasons they are what they are:
13
+ *
14
+ * - A selector is normalized to atomic `(publisher_domain, collection_id)`
15
+ * pairs. IDs are never flattened without their domain: two publishers may
16
+ * legitimately declare the same `collection_id`.
17
+ * - `collection_ids` is optional on `CollectionSelector` and means "every
18
+ * collection declared in that domain's adagents.json". That bulk-grant
19
+ * form is a *different* selector from an explicit enumeration, so it
20
+ * normalizes to a pair with `collection_id: null` rather than silently
21
+ * comparing equal to an enumerated set. Product composition is required
22
+ * to name explicit ids, so `null` pairs do not count toward
23
+ * `minimum_pairs`.
24
+ * - Schema-valid redundancy collapses: repeated ids inside one selector,
25
+ * and overlapping atomic pairs across differently-grouped selectors, are
26
+ * one pair. Neither `product.collections[]` nor `collection_ids[]`
27
+ * carries a uniqueness constraint, so redundancy is legal *product
28
+ * composition*. The readback arm is stricter:
29
+ * `core/collection-selection.json` declares `uniqueItems: true` on
30
+ * `collections` in `mode: selected`. Normalizing here is for COMPARISON
31
+ * only and never excuses that — the surrounding response is still
32
+ * schema-validated, which is what rejects a duplicated outer entry.
33
+ * Schema-invalid input (a non-array, a non-object entry, an empty
34
+ * `collection_ids`) stays a visible failure here and is additionally
35
+ * rejected by ordinary response-schema validation upstream.
36
+ * - Ordering is bytewise over UTF-8, on the *pairs*, so outer grouping and
37
+ * inner id order never affect the result while non-ASCII identifiers stay
38
+ * lossless. Nothing is case-folded, trimmed, punycoded or otherwise
39
+ * rewritten. `collection_id` is a plain string with no `minLength` and no
40
+ * declared normalization form, so inventing one would grade agents
41
+ * against a rule the protocol does not state. `publisher_domain` is
42
+ * separately pattern-constrained to lowercase LDH by
43
+ * `core/collection-selector.json`, which response-schema validation
44
+ * already enforces — canonicalizing it here would be redundant at best
45
+ * and would mask a non-conformant catalog at worst.
46
+ */
47
+ /** Maximum distinct pairs any single normalization will materialize. */
48
+ export declare const COLLECTION_PAIR_LIMIT = 10000;
49
+ /** Maximum pairs echoed into a diagnostic before it is elided. */
50
+ export declare const COLLECTION_DIAGNOSTIC_LIMIT = 20;
51
+ /** One atomic, domain-qualified collection identity. */
52
+ export interface CollectionPair {
53
+ publisher_domain: string;
54
+ /** `null` is the domain-only bulk-grant selector, not an empty id. */
55
+ collection_id: string | null;
56
+ }
57
+ /** A concrete `CollectionSelector` as it appears on the wire. */
58
+ export interface CollectionSelectorObject {
59
+ publisher_domain: string;
60
+ collection_ids?: string[];
61
+ }
62
+ export interface NormalizedCollectionSelectors {
63
+ /** Distinct pairs in bytewise order. */
64
+ pairs: CollectionPair[];
65
+ /** Outer selector entries observed, before normalization. */
66
+ selector_count: number;
67
+ /** Distinct publisher domains, bytewise ordered. */
68
+ domains: string[];
69
+ }
70
+ export type CollectionNormalizationCode = 'not_an_array' | 'selector_not_object' | 'publisher_domain_invalid' | 'collection_ids_invalid' | 'collection_id_invalid' | 'pair_limit_exceeded';
71
+ export interface CollectionNormalizationFailure {
72
+ code: CollectionNormalizationCode;
73
+ detail: string;
74
+ }
75
+ export type CollectionNormalizationResult = {
76
+ ok: true;
77
+ value: NormalizedCollectionSelectors;
78
+ } | {
79
+ ok: false;
80
+ failure: CollectionNormalizationFailure;
81
+ };
82
+ /** Total bytewise order over pairs. Domain first, then id; `null` sorts first. */
83
+ export declare function compareCollectionPairs(a: CollectionPair, b: CollectionPair): number;
84
+ /** Stable, unambiguous rendering for diagnostics and dedup keys. */
85
+ export declare function formatCollectionPair(pair: CollectionPair): string;
86
+ /**
87
+ * Normalize an array of `CollectionSelector` objects into distinct atomic
88
+ * pairs. Used for product catalog entries, authored expected sets and
89
+ * seller-returned `selected.collections` alike — same definition everywhere.
90
+ */
91
+ export declare function normalizeCollectionSelectors(value: unknown, options?: {
92
+ limit?: number;
93
+ }): CollectionNormalizationResult;
94
+ /** Exact set difference over normalized pairs, with bounded diagnostics. */
95
+ export declare function diffCollectionPairSets(actual: readonly CollectionPair[], expected: readonly CollectionPair[]): {
96
+ equal: boolean;
97
+ missing: CollectionPair[];
98
+ unexpected: CollectionPair[];
99
+ };
100
+ /** Render at most `COLLECTION_DIAGNOSTIC_LIMIT` pairs, flagging elision. */
101
+ export declare function summarizeCollectionPairs(pairs: readonly CollectionPair[]): string;
102
+ /**
103
+ * Operand of the `collection_selection_satisfies` fixture predicate.
104
+ *
105
+ * `collection_targeting` encodes the schema's omitted-false default
106
+ * explicitly rather than teaching every `equals` comparison to apply
107
+ * arbitrary defaults. It is deliberately NOT named `mode`: the wire's
108
+ * `collection_selection.mode` is `selected | default`, and the two appear in
109
+ * the same storyboard file.
110
+ *
111
+ * - `fixed` — `collection_targeting_allowed` is literal `false` OR
112
+ * absent (the normative default). `true` does not qualify.
113
+ * - `selectable` — literal `true` only.
114
+ * - `any` — either, as long as the flag is absent or a boolean.
115
+ *
116
+ * A non-boolean, non-absent flag never qualifies in any mode: that is a
117
+ * schema failure of the seller's catalog, surfaced by response-schema
118
+ * validation during discovery, not something this predicate repairs.
119
+ */
120
+ export interface CollectionSelectionSelector {
121
+ collection_targeting: 'selectable' | 'fixed' | 'any';
122
+ /**
123
+ * Distinct concrete pairs the product must expose. Defaults to `1`, which
124
+ * covers default materialization / full-bundle restatement; `2` is
125
+ * required before a genuine strict subset exists to exercise.
126
+ */
127
+ minimum_pairs?: 1 | 2;
128
+ /**
129
+ * Require a wire-visible owner/host relation: at least one collection
130
+ * selector whose publisher domain is outside every declared property
131
+ * (host) domain of the same product. Defaults to `false`.
132
+ */
133
+ require_cross_publisher_collection?: boolean;
134
+ }
135
+ /**
136
+ * Post-normalization operand the evaluator consumes, with both defaults
137
+ * applied.
138
+ *
139
+ * Kept separate from the authored form so the type accepts exactly what the
140
+ * loader accepts: `{ collection_targeting: 'fixed' }` is valid YAML and must type-check,
141
+ * while an index signature would have let a typo'd key compile clean and
142
+ * then fail at load against the closed-operand rule.
143
+ */
144
+ export interface ResolvedCollectionSelectionSelector {
145
+ collection_targeting: 'selectable' | 'fixed' | 'any';
146
+ minimum_pairs: 1 | 2;
147
+ require_cross_publisher_collection: boolean;
148
+ }
149
+ export declare const COLLECTION_TARGETING_MODES: readonly ["selectable", "fixed", "any"];
150
+ /** Validate and default the closed operand. Throws on authoring errors. */
151
+ export declare function normalizeCollectionSelectionSelector(value: unknown, location: string): ResolvedCollectionSelectionSelector;
152
+ /** The declared owner/host relation observed on one product. */
153
+ export interface CrossPublisherCollectionRelation {
154
+ /**
155
+ * The collection namespace that lies outside every property namespace of
156
+ * the SAME selected product.
157
+ */
158
+ collection_publisher_domain: string;
159
+ /** Property namespaces declared by that same product. */
160
+ property_publisher_domains: string[];
161
+ /**
162
+ * The concrete selector carrying it. `selector.publisher_domain` always
163
+ * equals `collection_publisher_domain`.
164
+ */
165
+ selector: CollectionSelectorObject;
166
+ }
167
+ /**
168
+ * Everything the resolver retains about the product it actually selected.
169
+ * Built once, from the selected candidate, and never recomputed from a
170
+ * different response.
171
+ */
172
+ export interface CollectionSelectionWitness {
173
+ product_id: string | null;
174
+ /**
175
+ * Effective targeting of the selected product, with the schema's
176
+ * omitted-false default applied. Distinct from the native seller field
177
+ * `collection_targeting_allowed`, whose raw observed value is reported
178
+ * beside it, and from the wire's `collection_selection.mode`.
179
+ */
180
+ collection_targeting: 'selectable' | 'fixed';
181
+ /** The flag exactly as observed — `undefined` when the seller omitted it. */
182
+ collection_targeting_allowed: boolean | undefined;
183
+ /** The product's complete, concrete collection selector bundle. */
184
+ declared_selectors: CollectionSelectorObject[];
185
+ /** Distinct concrete pairs (bulk-grant entries excluded). */
186
+ distinct_pairs: CollectionPair[];
187
+ /**
188
+ * A one-entry selector array naming exactly one of the bundle's pairs, so
189
+ * it is a strict subset whenever the bundle has two or more. Shaped as an
190
+ * array because that is the shape a `collections` field takes on the wire,
191
+ * so a storyboard can substitute it whole.
192
+ *
193
+ * When `require_cross_publisher_collection` was requested, the pair is drawn from the
194
+ * retained external owner, so the subset actually exercises the carriage
195
+ * relation rather than the host's own inventory.
196
+ *
197
+ * `null` when the product exposes fewer than two distinct concrete pairs —
198
+ * a one-pair product still qualifies for default materialization, so the
199
+ * absence of a subset witness must not suppress that coverage.
200
+ */
201
+ strict_subset: CollectionSelectorObject[] | null;
202
+ /**
203
+ * One-entry selector array naming an id verified absent from this
204
+ * product's pairs, under a domain the product does carry.
205
+ */
206
+ undeclared_collection_id_selectors: CollectionSelectorObject[];
207
+ /**
208
+ * One-entry selector array whose domain is verified absent from every
209
+ * COLLECTION namespace this product declares.
210
+ *
211
+ * Property namespaces (`publisher_properties[].publisher_domain`) are not
212
+ * checked — the synthesized domain is a `.invalid` name, which RFC 2606
213
+ * reserves and no real publisher can hold, so a collision is not possible
214
+ * in practice. Stated precisely because "every namespace this product
215
+ * declares" read as including the property side, and it does not.
216
+ */
217
+ undeclared_publisher_domain_selectors: CollectionSelectorObject[];
218
+ /** Present only when the relation was requested and found. */
219
+ cross_publisher_relation: CrossPublisherCollectionRelation | null;
220
+ /** Declared property namespaces, bytewise ordered. */
221
+ property_publisher_domains: string[];
222
+ }
223
+ export type CollectionSelectionEvaluation = {
224
+ eligible: true;
225
+ witness: CollectionSelectionWitness;
226
+ } | {
227
+ eligible: false;
228
+ reason: string;
229
+ };
230
+ /**
231
+ * Decide whether one discovered product qualifies, and retain the witness
232
+ * for the candidate that is actually selected.
233
+ *
234
+ * Qualification is evaluated against the complete validated candidate before
235
+ * any deterministic ordering is applied, so a nonqualifying first product can
236
+ * never hide a later qualifying one.
237
+ */
238
+ export declare function evaluateCollectionSelection(candidate: unknown, selector: CollectionSelectionSelector): CollectionSelectionEvaluation;
239
+ /** Boolean form for the legacy matcher. */
240
+ export declare function productSatisfiesCollectionSelection(candidate: unknown, selector: CollectionSelectionSelector): boolean;
241
+ /** Derived witness captures a declaration may bind to a context key. */
242
+ export declare const COLLECTION_WITNESS_KINDS: readonly ["declared_selectors", "distinct_pairs", "strict_subset", "undeclared_collection_id_selectors", "undeclared_publisher_domain_selectors", "cross_publisher_relation", "property_publisher_domains"];
243
+ export type CollectionWitnessKind = (typeof COLLECTION_WITNESS_KINDS)[number];
244
+ export type CollectionWitnessReadResult = {
245
+ ok: true;
246
+ value: unknown;
247
+ } | {
248
+ ok: false;
249
+ detail: string;
250
+ };
251
+ /**
252
+ * Read one derived capture off a retained witness.
253
+ *
254
+ * A declared capture that cannot be built is a setup failure, never an
255
+ * unsupported/not-applicable downgrade — the storyboard asked for state the
256
+ * selected product does not provide, and silently proceeding would grade the
257
+ * agent against a request the author did not write.
258
+ */
259
+ export declare function readCollectionWitness(witness: CollectionSelectionWitness | undefined, kind: CollectionWitnessKind): CollectionWitnessReadResult;