@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,301 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var protected_context_exports = {};
20
+ __export(protected_context_exports, {
21
+ PROTECTED_CONTEXT_PREFIX: () => PROTECTED_CONTEXT_PREFIX,
22
+ ProtectedContextViolation: () => ProtectedContextViolation,
23
+ applyProtectedContextPatch: () => applyProtectedContextPatch,
24
+ assertWellFormedProtectedKey: () => assertWellFormedProtectedKey,
25
+ createProtectedContextWriter: () => createProtectedContextWriter,
26
+ detachProtectedValue: () => detachProtectedValue,
27
+ forwardProtectedContext: () => forwardProtectedContext,
28
+ freezeDeep: () => freezeDeep,
29
+ isProtectedContextKey: () => isProtectedContextKey,
30
+ listProtectedContextKeys: () => listProtectedContextKeys,
31
+ registerProtectedContext: () => registerProtectedContext
32
+ });
33
+ module.exports = __toCommonJS(protected_context_exports);
34
+ const PROTECTED_CONTEXT_PREFIX = "__adcp_fixture_";
35
+ const PROTECTED_KEY_PATTERN = /^__adcp_fixture_[A-Za-z0-9_]+$/;
36
+ const PROTOTYPE_SENSITIVE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
37
+ function isProtectedContextKey(key) {
38
+ return key.startsWith(PROTECTED_CONTEXT_PREFIX);
39
+ }
40
+ class ProtectedContextViolation extends Error {
41
+ code;
42
+ keys;
43
+ constructor(code, keys, detail) {
44
+ super(detail);
45
+ this.name = "ProtectedContextViolation";
46
+ this.code = code;
47
+ this.keys = [...keys];
48
+ }
49
+ }
50
+ const writers = /* @__PURE__ */ new WeakSet();
51
+ function createProtectedContextWriter() {
52
+ const writer = Object.freeze({
53
+ kind: "adcp.storyboard.protected-context-writer"
54
+ });
55
+ writers.add(writer);
56
+ return writer;
57
+ }
58
+ function isTrustedWriter(writer) {
59
+ return writer !== void 0 && writers.has(writer);
60
+ }
61
+ const states = /* @__PURE__ */ new WeakMap();
62
+ function registerProtectedContext(context, writer) {
63
+ if (!isTrustedWriter(writer)) {
64
+ throw new ProtectedContextViolation(
65
+ "unauthorized_write",
66
+ [],
67
+ "registerProtectedContext requires a runner-owned protected-context capability"
68
+ );
69
+ }
70
+ if (!states.has(context)) states.set(context, { committed: /* @__PURE__ */ new Set(), writer });
71
+ }
72
+ function forwardProtectedContext(from, to) {
73
+ const state = states.get(from);
74
+ if (!state) return;
75
+ const existing = states.get(to);
76
+ if (existing) {
77
+ for (const key of state.committed) existing.committed.add(key);
78
+ return;
79
+ }
80
+ states.set(to, { committed: new Set(state.committed), writer: state.writer });
81
+ }
82
+ function listProtectedContextKeys(context) {
83
+ return [...states.get(context)?.committed ?? []].sort();
84
+ }
85
+ function markUnavailableEntries(markUnavailable) {
86
+ if (markUnavailable === void 0) return [];
87
+ if (Array.isArray(markUnavailable)) return markUnavailable.map((key) => [key, "unavailable"]);
88
+ return Object.entries(markUnavailable);
89
+ }
90
+ function applyProtectedContextPatch(context, patch, options) {
91
+ const state = states.get(context);
92
+ const trusted = isTrustedWriter(options.writer) && state !== void 0 && state.writer === options.writer;
93
+ const setEntries = Object.entries(patch.set ?? {});
94
+ const unsetKeys = patch.unset ?? [];
95
+ const provenanceEntries = Object.entries(patch.setProvenance ?? {});
96
+ const provenanceUnset = patch.unsetProvenance ?? [];
97
+ const unavailableEntries = markUnavailableEntries(patch.markUnavailable);
98
+ const clearUnavailable = patch.clearUnavailable ?? [];
99
+ const prototypeKeys = [
100
+ ...setEntries.map(([key]) => key),
101
+ ...unsetKeys,
102
+ ...provenanceEntries.map(([key]) => key),
103
+ ...provenanceUnset,
104
+ ...unavailableEntries.map(([key]) => key),
105
+ ...clearUnavailable
106
+ ].filter((key) => PROTOTYPE_SENSITIVE_KEYS.has(key));
107
+ if (prototypeKeys.length > 0) {
108
+ throw new ProtectedContextViolation(
109
+ "reserved_key",
110
+ [...new Set(prototypeKeys)],
111
+ `${options.origin}: refused prototype-sensitive context key(s) ${[...new Set(prototypeKeys)].join(", ")}; these can rewrite the context's prototype and shadow reserved fixture keys. Rename them to anything other than __proto__, constructor or prototype.`
112
+ );
113
+ }
114
+ if (!trusted) {
115
+ const valueKeys = setEntries.map(([key]) => key).filter(isProtectedContextKey);
116
+ if (valueKeys.length > 0) {
117
+ throw new ProtectedContextViolation(
118
+ "unauthorized_write",
119
+ valueKeys,
120
+ `${options.origin}: cannot write reserved fixture-preparation context key(s) ${valueKeys.join(", ")}; the "${PROTECTED_CONTEXT_PREFIX}" namespace is owned by fixture preparation. Declare the value under fixture_resolution[].context_outputs instead, or rename the key.`
121
+ );
122
+ }
123
+ const deleteKeys = unsetKeys.filter(isProtectedContextKey);
124
+ if (deleteKeys.length > 0) {
125
+ throw new ProtectedContextViolation(
126
+ "unauthorized_delete",
127
+ deleteKeys,
128
+ `${options.origin}: cannot delete reserved fixture-preparation context key(s) ${deleteKeys.join(", ")}`
129
+ );
130
+ }
131
+ const metadataKeys = [
132
+ ...provenanceEntries.map(([key]) => key),
133
+ ...provenanceUnset,
134
+ ...unavailableEntries.map(([key]) => key),
135
+ ...clearUnavailable
136
+ ].filter(isProtectedContextKey);
137
+ if (metadataKeys.length > 0) {
138
+ throw new ProtectedContextViolation(
139
+ "unauthorized_metadata",
140
+ [...new Set(metadataKeys)],
141
+ `${options.origin}: cannot change provenance or availability metadata for reserved key(s) ${[...new Set(metadataKeys)].join(", ")}; suppressing a prepared capture is as damaging as overwriting it`
142
+ );
143
+ }
144
+ } else {
145
+ const recommitted = [
146
+ ...setEntries.map(([key]) => key),
147
+ ...unsetKeys,
148
+ ...provenanceUnset,
149
+ ...unavailableEntries.map(([key]) => key)
150
+ ].filter((key) => isProtectedContextKey(key) && state?.committed.has(key) === true);
151
+ if (recommitted.length > 0) {
152
+ throw new ProtectedContextViolation(
153
+ "already_committed",
154
+ recommitted,
155
+ `${options.origin}: reserved context key(s) ${recommitted.join(", ")} are already committed by fixture preparation and are immutable for the rest of the run`
156
+ );
157
+ }
158
+ for (const [key] of setEntries) {
159
+ if (isProtectedContextKey(key)) assertWellFormedProtectedKey(key, options.origin);
160
+ }
161
+ }
162
+ const mutatedKeys = [.../* @__PURE__ */ new Set([...setEntries.map(([key]) => key), ...unsetKeys])];
163
+ if (!Object.isExtensible(context)) {
164
+ const unsetSet = new Set(unsetKeys);
165
+ const added = mutatedKeys.filter((key) => !Object.hasOwn(context, key) || unsetSet.has(key));
166
+ if (added.length > 0) {
167
+ throw new ProtectedContextViolation(
168
+ "uncloneable_value",
169
+ added,
170
+ `${options.origin}: the storyboard context is not extensible, so key(s) ${added.join(", ")} cannot be written`
171
+ );
172
+ }
173
+ }
174
+ const locked = mutatedKeys.filter((key) => {
175
+ const descriptor = Object.getOwnPropertyDescriptor(context, key);
176
+ return descriptor !== void 0 && descriptor.configurable === false;
177
+ });
178
+ if (locked.length > 0) {
179
+ throw new ProtectedContextViolation(
180
+ "uncloneable_value",
181
+ locked,
182
+ `${options.origin}: context key(s) ${locked.join(", ")} are non-configurable and cannot be rewritten or removed`
183
+ );
184
+ }
185
+ const snapshots = /* @__PURE__ */ new Map();
186
+ for (const [key, value] of setEntries) {
187
+ if (!isProtectedContextKey(key)) continue;
188
+ let cloned;
189
+ try {
190
+ cloned = structuredClone(value);
191
+ } catch (error) {
192
+ throw new ProtectedContextViolation(
193
+ "uncloneable_value",
194
+ [key],
195
+ `${options.origin}: reserved context key "${key}" holds a value that cannot be detached (${error instanceof Error ? error.message : String(error)}); captures must be plain JSON-shaped data`
196
+ );
197
+ }
198
+ assertFreezable(cloned, key, options.origin);
199
+ snapshots.set(key, freezeDeep(cloned));
200
+ }
201
+ const provenanceSnapshots = /* @__PURE__ */ new Map();
202
+ for (const [key, entry] of provenanceEntries) {
203
+ if (!isProtectedContextKey(key)) continue;
204
+ let cloned;
205
+ try {
206
+ cloned = structuredClone(entry);
207
+ } catch (error) {
208
+ throw new ProtectedContextViolation(
209
+ "uncloneable_value",
210
+ [key],
211
+ `${options.origin}: provenance for reserved context key "${key}" cannot be detached (${error instanceof Error ? error.message : String(error)}); capture provenance must be plain JSON-shaped data`
212
+ );
213
+ }
214
+ assertFreezable(cloned, key, options.origin);
215
+ provenanceSnapshots.set(key, freezeDeep(cloned));
216
+ }
217
+ for (const key of unsetKeys) delete context[key];
218
+ for (const [key, value] of setEntries) {
219
+ Object.defineProperty(context, key, {
220
+ value: snapshots.has(key) ? snapshots.get(key) : value,
221
+ writable: true,
222
+ enumerable: true,
223
+ configurable: true
224
+ });
225
+ if (isProtectedContextKey(key)) state?.committed.add(key);
226
+ }
227
+ const sinks = options.sinks;
228
+ if (sinks?.provenance) {
229
+ for (const key of provenanceUnset) sinks.provenance.delete(key);
230
+ for (const [key, entry] of provenanceEntries) {
231
+ sinks.provenance.set(key, provenanceSnapshots.get(key) ?? entry);
232
+ }
233
+ }
234
+ if (sinks?.unavailable) {
235
+ for (const key of clearUnavailable) sinks.unavailable.delete(key);
236
+ for (const [key, reason] of unavailableEntries) sinks.unavailable.set(key, reason);
237
+ }
238
+ }
239
+ function assertWellFormedProtectedKey(key, location) {
240
+ if (PROTOTYPE_SENSITIVE_KEYS.has(key)) {
241
+ throw new ProtectedContextViolation(
242
+ "invalid_key",
243
+ [key],
244
+ `${location}: "${key}" is a prototype-sensitive key; rename it to anything other than __proto__, constructor or prototype`
245
+ );
246
+ }
247
+ if (!PROTECTED_KEY_PATTERN.test(key)) {
248
+ throw new ProtectedContextViolation(
249
+ "invalid_key",
250
+ [key],
251
+ `${location}: reserved capture key "${key}" must match ${PROTECTED_KEY_PATTERN.source} so whole-key $context.<key> substitution resolves it`
252
+ );
253
+ }
254
+ }
255
+ function assertFreezable(value, key, origin, seen = /* @__PURE__ */ new Set()) {
256
+ if (value === null || typeof value !== "object") return;
257
+ if (seen.has(value)) return;
258
+ seen.add(value);
259
+ if (Array.isArray(value)) {
260
+ for (const nested of value) assertFreezable(nested, key, origin, seen);
261
+ return;
262
+ }
263
+ const prototype = Object.getPrototypeOf(value);
264
+ if (prototype !== Object.prototype && prototype !== null) {
265
+ throw new ProtectedContextViolation(
266
+ "uncloneable_value",
267
+ [key],
268
+ `${origin}: reserved context key "${key}" holds a ${value.constructor?.name ?? "non-plain object"}, which Object.freeze cannot make immutable; captures must be plain JSON-shaped data`
269
+ );
270
+ }
271
+ for (const nested of Reflect.ownKeys(value)) {
272
+ assertFreezable(value[nested], key, origin, seen);
273
+ }
274
+ }
275
+ function freezeDeep(value) {
276
+ if (value === null || typeof value !== "object") return value;
277
+ if (Object.isFrozen(value)) return value;
278
+ Object.freeze(value);
279
+ for (const nested of Reflect.ownKeys(value)) {
280
+ freezeDeep(value[nested]);
281
+ }
282
+ return value;
283
+ }
284
+ function detachProtectedValue(value) {
285
+ if (value === null || typeof value !== "object") return value;
286
+ return structuredClone(value);
287
+ }
288
+ // Annotate the CommonJS export names for ESM import in node:
289
+ 0 && (module.exports = {
290
+ PROTECTED_CONTEXT_PREFIX,
291
+ ProtectedContextViolation,
292
+ applyProtectedContextPatch,
293
+ assertWellFormedProtectedKey,
294
+ createProtectedContextWriter,
295
+ detachProtectedValue,
296
+ forwardProtectedContext,
297
+ freezeDeep,
298
+ isProtectedContextKey,
299
+ listProtectedContextKeys,
300
+ registerProtectedContext
301
+ });
@@ -0,0 +1,267 @@
1
+ const PROTECTED_CONTEXT_PREFIX = "__adcp_fixture_";
2
+ const PROTECTED_KEY_PATTERN = /^__adcp_fixture_[A-Za-z0-9_]+$/;
3
+ const PROTOTYPE_SENSITIVE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
4
+ function isProtectedContextKey(key) {
5
+ return key.startsWith(PROTECTED_CONTEXT_PREFIX);
6
+ }
7
+ class ProtectedContextViolation extends Error {
8
+ code;
9
+ keys;
10
+ constructor(code, keys, detail) {
11
+ super(detail);
12
+ this.name = "ProtectedContextViolation";
13
+ this.code = code;
14
+ this.keys = [...keys];
15
+ }
16
+ }
17
+ const writers = /* @__PURE__ */ new WeakSet();
18
+ function createProtectedContextWriter() {
19
+ const writer = Object.freeze({
20
+ kind: "adcp.storyboard.protected-context-writer"
21
+ });
22
+ writers.add(writer);
23
+ return writer;
24
+ }
25
+ function isTrustedWriter(writer) {
26
+ return writer !== void 0 && writers.has(writer);
27
+ }
28
+ const states = /* @__PURE__ */ new WeakMap();
29
+ function registerProtectedContext(context, writer) {
30
+ if (!isTrustedWriter(writer)) {
31
+ throw new ProtectedContextViolation(
32
+ "unauthorized_write",
33
+ [],
34
+ "registerProtectedContext requires a runner-owned protected-context capability"
35
+ );
36
+ }
37
+ if (!states.has(context)) states.set(context, { committed: /* @__PURE__ */ new Set(), writer });
38
+ }
39
+ function forwardProtectedContext(from, to) {
40
+ const state = states.get(from);
41
+ if (!state) return;
42
+ const existing = states.get(to);
43
+ if (existing) {
44
+ for (const key of state.committed) existing.committed.add(key);
45
+ return;
46
+ }
47
+ states.set(to, { committed: new Set(state.committed), writer: state.writer });
48
+ }
49
+ function listProtectedContextKeys(context) {
50
+ return [...states.get(context)?.committed ?? []].sort();
51
+ }
52
+ function markUnavailableEntries(markUnavailable) {
53
+ if (markUnavailable === void 0) return [];
54
+ if (Array.isArray(markUnavailable)) return markUnavailable.map((key) => [key, "unavailable"]);
55
+ return Object.entries(markUnavailable);
56
+ }
57
+ function applyProtectedContextPatch(context, patch, options) {
58
+ const state = states.get(context);
59
+ const trusted = isTrustedWriter(options.writer) && state !== void 0 && state.writer === options.writer;
60
+ const setEntries = Object.entries(patch.set ?? {});
61
+ const unsetKeys = patch.unset ?? [];
62
+ const provenanceEntries = Object.entries(patch.setProvenance ?? {});
63
+ const provenanceUnset = patch.unsetProvenance ?? [];
64
+ const unavailableEntries = markUnavailableEntries(patch.markUnavailable);
65
+ const clearUnavailable = patch.clearUnavailable ?? [];
66
+ const prototypeKeys = [
67
+ ...setEntries.map(([key]) => key),
68
+ ...unsetKeys,
69
+ ...provenanceEntries.map(([key]) => key),
70
+ ...provenanceUnset,
71
+ ...unavailableEntries.map(([key]) => key),
72
+ ...clearUnavailable
73
+ ].filter((key) => PROTOTYPE_SENSITIVE_KEYS.has(key));
74
+ if (prototypeKeys.length > 0) {
75
+ throw new ProtectedContextViolation(
76
+ "reserved_key",
77
+ [...new Set(prototypeKeys)],
78
+ `${options.origin}: refused prototype-sensitive context key(s) ${[...new Set(prototypeKeys)].join(", ")}; these can rewrite the context's prototype and shadow reserved fixture keys. Rename them to anything other than __proto__, constructor or prototype.`
79
+ );
80
+ }
81
+ if (!trusted) {
82
+ const valueKeys = setEntries.map(([key]) => key).filter(isProtectedContextKey);
83
+ if (valueKeys.length > 0) {
84
+ throw new ProtectedContextViolation(
85
+ "unauthorized_write",
86
+ valueKeys,
87
+ `${options.origin}: cannot write reserved fixture-preparation context key(s) ${valueKeys.join(", ")}; the "${PROTECTED_CONTEXT_PREFIX}" namespace is owned by fixture preparation. Declare the value under fixture_resolution[].context_outputs instead, or rename the key.`
88
+ );
89
+ }
90
+ const deleteKeys = unsetKeys.filter(isProtectedContextKey);
91
+ if (deleteKeys.length > 0) {
92
+ throw new ProtectedContextViolation(
93
+ "unauthorized_delete",
94
+ deleteKeys,
95
+ `${options.origin}: cannot delete reserved fixture-preparation context key(s) ${deleteKeys.join(", ")}`
96
+ );
97
+ }
98
+ const metadataKeys = [
99
+ ...provenanceEntries.map(([key]) => key),
100
+ ...provenanceUnset,
101
+ ...unavailableEntries.map(([key]) => key),
102
+ ...clearUnavailable
103
+ ].filter(isProtectedContextKey);
104
+ if (metadataKeys.length > 0) {
105
+ throw new ProtectedContextViolation(
106
+ "unauthorized_metadata",
107
+ [...new Set(metadataKeys)],
108
+ `${options.origin}: cannot change provenance or availability metadata for reserved key(s) ${[...new Set(metadataKeys)].join(", ")}; suppressing a prepared capture is as damaging as overwriting it`
109
+ );
110
+ }
111
+ } else {
112
+ const recommitted = [
113
+ ...setEntries.map(([key]) => key),
114
+ ...unsetKeys,
115
+ ...provenanceUnset,
116
+ ...unavailableEntries.map(([key]) => key)
117
+ ].filter((key) => isProtectedContextKey(key) && state?.committed.has(key) === true);
118
+ if (recommitted.length > 0) {
119
+ throw new ProtectedContextViolation(
120
+ "already_committed",
121
+ recommitted,
122
+ `${options.origin}: reserved context key(s) ${recommitted.join(", ")} are already committed by fixture preparation and are immutable for the rest of the run`
123
+ );
124
+ }
125
+ for (const [key] of setEntries) {
126
+ if (isProtectedContextKey(key)) assertWellFormedProtectedKey(key, options.origin);
127
+ }
128
+ }
129
+ const mutatedKeys = [.../* @__PURE__ */ new Set([...setEntries.map(([key]) => key), ...unsetKeys])];
130
+ if (!Object.isExtensible(context)) {
131
+ const unsetSet = new Set(unsetKeys);
132
+ const added = mutatedKeys.filter((key) => !Object.hasOwn(context, key) || unsetSet.has(key));
133
+ if (added.length > 0) {
134
+ throw new ProtectedContextViolation(
135
+ "uncloneable_value",
136
+ added,
137
+ `${options.origin}: the storyboard context is not extensible, so key(s) ${added.join(", ")} cannot be written`
138
+ );
139
+ }
140
+ }
141
+ const locked = mutatedKeys.filter((key) => {
142
+ const descriptor = Object.getOwnPropertyDescriptor(context, key);
143
+ return descriptor !== void 0 && descriptor.configurable === false;
144
+ });
145
+ if (locked.length > 0) {
146
+ throw new ProtectedContextViolation(
147
+ "uncloneable_value",
148
+ locked,
149
+ `${options.origin}: context key(s) ${locked.join(", ")} are non-configurable and cannot be rewritten or removed`
150
+ );
151
+ }
152
+ const snapshots = /* @__PURE__ */ new Map();
153
+ for (const [key, value] of setEntries) {
154
+ if (!isProtectedContextKey(key)) continue;
155
+ let cloned;
156
+ try {
157
+ cloned = structuredClone(value);
158
+ } catch (error) {
159
+ throw new ProtectedContextViolation(
160
+ "uncloneable_value",
161
+ [key],
162
+ `${options.origin}: reserved context key "${key}" holds a value that cannot be detached (${error instanceof Error ? error.message : String(error)}); captures must be plain JSON-shaped data`
163
+ );
164
+ }
165
+ assertFreezable(cloned, key, options.origin);
166
+ snapshots.set(key, freezeDeep(cloned));
167
+ }
168
+ const provenanceSnapshots = /* @__PURE__ */ new Map();
169
+ for (const [key, entry] of provenanceEntries) {
170
+ if (!isProtectedContextKey(key)) continue;
171
+ let cloned;
172
+ try {
173
+ cloned = structuredClone(entry);
174
+ } catch (error) {
175
+ throw new ProtectedContextViolation(
176
+ "uncloneable_value",
177
+ [key],
178
+ `${options.origin}: provenance for reserved context key "${key}" cannot be detached (${error instanceof Error ? error.message : String(error)}); capture provenance must be plain JSON-shaped data`
179
+ );
180
+ }
181
+ assertFreezable(cloned, key, options.origin);
182
+ provenanceSnapshots.set(key, freezeDeep(cloned));
183
+ }
184
+ for (const key of unsetKeys) delete context[key];
185
+ for (const [key, value] of setEntries) {
186
+ Object.defineProperty(context, key, {
187
+ value: snapshots.has(key) ? snapshots.get(key) : value,
188
+ writable: true,
189
+ enumerable: true,
190
+ configurable: true
191
+ });
192
+ if (isProtectedContextKey(key)) state?.committed.add(key);
193
+ }
194
+ const sinks = options.sinks;
195
+ if (sinks?.provenance) {
196
+ for (const key of provenanceUnset) sinks.provenance.delete(key);
197
+ for (const [key, entry] of provenanceEntries) {
198
+ sinks.provenance.set(key, provenanceSnapshots.get(key) ?? entry);
199
+ }
200
+ }
201
+ if (sinks?.unavailable) {
202
+ for (const key of clearUnavailable) sinks.unavailable.delete(key);
203
+ for (const [key, reason] of unavailableEntries) sinks.unavailable.set(key, reason);
204
+ }
205
+ }
206
+ function assertWellFormedProtectedKey(key, location) {
207
+ if (PROTOTYPE_SENSITIVE_KEYS.has(key)) {
208
+ throw new ProtectedContextViolation(
209
+ "invalid_key",
210
+ [key],
211
+ `${location}: "${key}" is a prototype-sensitive key; rename it to anything other than __proto__, constructor or prototype`
212
+ );
213
+ }
214
+ if (!PROTECTED_KEY_PATTERN.test(key)) {
215
+ throw new ProtectedContextViolation(
216
+ "invalid_key",
217
+ [key],
218
+ `${location}: reserved capture key "${key}" must match ${PROTECTED_KEY_PATTERN.source} so whole-key $context.<key> substitution resolves it`
219
+ );
220
+ }
221
+ }
222
+ function assertFreezable(value, key, origin, seen = /* @__PURE__ */ new Set()) {
223
+ if (value === null || typeof value !== "object") return;
224
+ if (seen.has(value)) return;
225
+ seen.add(value);
226
+ if (Array.isArray(value)) {
227
+ for (const nested of value) assertFreezable(nested, key, origin, seen);
228
+ return;
229
+ }
230
+ const prototype = Object.getPrototypeOf(value);
231
+ if (prototype !== Object.prototype && prototype !== null) {
232
+ throw new ProtectedContextViolation(
233
+ "uncloneable_value",
234
+ [key],
235
+ `${origin}: reserved context key "${key}" holds a ${value.constructor?.name ?? "non-plain object"}, which Object.freeze cannot make immutable; captures must be plain JSON-shaped data`
236
+ );
237
+ }
238
+ for (const nested of Reflect.ownKeys(value)) {
239
+ assertFreezable(value[nested], key, origin, seen);
240
+ }
241
+ }
242
+ function freezeDeep(value) {
243
+ if (value === null || typeof value !== "object") return value;
244
+ if (Object.isFrozen(value)) return value;
245
+ Object.freeze(value);
246
+ for (const nested of Reflect.ownKeys(value)) {
247
+ freezeDeep(value[nested]);
248
+ }
249
+ return value;
250
+ }
251
+ function detachProtectedValue(value) {
252
+ if (value === null || typeof value !== "object") return value;
253
+ return structuredClone(value);
254
+ }
255
+ export {
256
+ PROTECTED_CONTEXT_PREFIX,
257
+ ProtectedContextViolation,
258
+ applyProtectedContextPatch,
259
+ assertWellFormedProtectedKey,
260
+ createProtectedContextWriter,
261
+ detachProtectedValue,
262
+ forwardProtectedContext,
263
+ freezeDeep,
264
+ isProtectedContextKey,
265
+ listProtectedContextKeys,
266
+ registerProtectedContext
267
+ };
@@ -128,7 +128,12 @@ function formatMessage(input) {
128
128
  const { contextKey, entry, rejectedValue, acceptedValues, requestField, currentTask } = input;
129
129
  const valueRepr = formatScalar(rejectedValue);
130
130
  const fieldRepr = requestField ? `\`${requestField}: ${valueRepr}\`` : `\`${valueRepr}\``;
131
- const sourceDetail = entry.source_kind === "context_outputs" && entry.response_path ? `set by step \`${entry.source_step_id}\` from response path \`${entry.response_path}\`` : entry.source_task ? `set by step \`${entry.source_step_id}\` (convention extractor for \`${entry.source_task}\`)` : `set by step \`${entry.source_step_id}\``;
131
+ const sourceDetail = entry.source_kind === "fixture_preparation" ? (
132
+ // Naming a convention extractor here would point an implementor at
133
+ // machinery that was never involved; the useful pointer is the
134
+ // fixture handle whose pinned entity produced the value.
135
+ `pinned by fixture preparation${entry.fixture_handle ? ` for handle \`${entry.fixture_handle}\`` : ""}`
136
+ ) : entry.source_kind === "context_outputs" && entry.response_path ? `set by step \`${entry.source_step_id}\` from response path \`${entry.response_path}\`` : entry.source_task ? `set by step \`${entry.source_step_id}\` (convention extractor for \`${entry.source_task}\`)` : `set by step \`${entry.source_step_id}\``;
132
137
  const acceptedRepr = `[${acceptedValues.map(formatScalar).join(", ")}]`;
133
138
  const closing = buildClosing(entry.source_task, currentTask);
134
139
  return `Rejected ${fieldRepr} was extracted from \`$context.${contextKey}\` (${sourceDetail}). Seller's accepted values: ${acceptedRepr}. ` + closing;
@@ -142,14 +147,18 @@ function buildClosing(sourceTask, currentTask) {
142
147
  }
143
148
  return `Check that the seller's catalogs agree across tools.`;
144
149
  }
150
+ const HINT_VALUE_MAX_CHARS = 200;
151
+ function truncateForHint(rendered) {
152
+ return rendered.length <= HINT_VALUE_MAX_CHARS ? rendered : `${rendered.slice(0, HINT_VALUE_MAX_CHARS)}\u2026 (${rendered.length} chars)`;
153
+ }
145
154
  function formatScalar(value) {
146
- if (typeof value === "string") return value;
155
+ if (typeof value === "string") return truncateForHint(value);
147
156
  if (value === null) return "null";
148
157
  if (value === void 0) return "undefined";
149
158
  try {
150
- return JSON.stringify(value);
159
+ return truncateForHint(JSON.stringify(value) ?? String(value));
151
160
  } catch {
152
- return String(value);
161
+ return truncateForHint(String(value));
153
162
  }
154
163
  }
155
164
  function resolveErrorsList(data) {
@@ -105,7 +105,12 @@ function formatMessage(input) {
105
105
  const { contextKey, entry, rejectedValue, acceptedValues, requestField, currentTask } = input;
106
106
  const valueRepr = formatScalar(rejectedValue);
107
107
  const fieldRepr = requestField ? `\`${requestField}: ${valueRepr}\`` : `\`${valueRepr}\``;
108
- const sourceDetail = entry.source_kind === "context_outputs" && entry.response_path ? `set by step \`${entry.source_step_id}\` from response path \`${entry.response_path}\`` : entry.source_task ? `set by step \`${entry.source_step_id}\` (convention extractor for \`${entry.source_task}\`)` : `set by step \`${entry.source_step_id}\``;
108
+ const sourceDetail = entry.source_kind === "fixture_preparation" ? (
109
+ // Naming a convention extractor here would point an implementor at
110
+ // machinery that was never involved; the useful pointer is the
111
+ // fixture handle whose pinned entity produced the value.
112
+ `pinned by fixture preparation${entry.fixture_handle ? ` for handle \`${entry.fixture_handle}\`` : ""}`
113
+ ) : entry.source_kind === "context_outputs" && entry.response_path ? `set by step \`${entry.source_step_id}\` from response path \`${entry.response_path}\`` : entry.source_task ? `set by step \`${entry.source_step_id}\` (convention extractor for \`${entry.source_task}\`)` : `set by step \`${entry.source_step_id}\``;
109
114
  const acceptedRepr = `[${acceptedValues.map(formatScalar).join(", ")}]`;
110
115
  const closing = buildClosing(entry.source_task, currentTask);
111
116
  return `Rejected ${fieldRepr} was extracted from \`$context.${contextKey}\` (${sourceDetail}). Seller's accepted values: ${acceptedRepr}. ` + closing;
@@ -119,14 +124,18 @@ function buildClosing(sourceTask, currentTask) {
119
124
  }
120
125
  return `Check that the seller's catalogs agree across tools.`;
121
126
  }
127
+ const HINT_VALUE_MAX_CHARS = 200;
128
+ function truncateForHint(rendered) {
129
+ return rendered.length <= HINT_VALUE_MAX_CHARS ? rendered : `${rendered.slice(0, HINT_VALUE_MAX_CHARS)}\u2026 (${rendered.length} chars)`;
130
+ }
122
131
  function formatScalar(value) {
123
- if (typeof value === "string") return value;
132
+ if (typeof value === "string") return truncateForHint(value);
124
133
  if (value === null) return "null";
125
134
  if (value === void 0) return "undefined";
126
135
  try {
127
- return JSON.stringify(value);
136
+ return truncateForHint(JSON.stringify(value) ?? String(value));
128
137
  } catch {
129
- return String(value);
138
+ return truncateForHint(String(value));
130
139
  }
131
140
  }
132
141
  function resolveErrorsList(data) {
@@ -5,6 +5,7 @@
5
5
  * - runStoryboard(): run all phases/steps sequentially
6
6
  * - runStoryboardStep(): run a single step (stateless, LLM-friendly)
7
7
  */
8
+ import { PreparedStoryboardFixtures } from './prepared-fixtures.mjs';
8
9
  import type { RequiresCapabilityPredicate, Storyboard, StoryboardStep, StoryboardContext, StoryboardRunOptions, StoryboardResult, StoryboardPhaseResult, StoryboardStepResult, StoryboardStepPreview, StrictValidationSummary, SchemaValidationError } from './types.mjs';
9
10
  import type { TestStepResult } from '../types.mjs';
10
11
  export declare function applyStoryboardVersionOptions(storyboard: Storyboard, options: StoryboardRunOptions): StoryboardRunOptions;
@@ -161,6 +162,29 @@ export declare function signingCoverageUnverified(steps: readonly SigningCoverag
161
162
  * called from `runStoryboard` when discovery throws.
162
163
  */
163
164
  export declare function buildDiscoveryFailedResult(agentUrls: string[], storyboard: Storyboard, discoveryStep: TestStepResult): StoryboardResult;
165
+ /**
166
+ * Resolve a storyboard's fixture graph once and return reusable, immutable
167
+ * prepared state.
168
+ *
169
+ * This is the public form of what `executeStoryboardPass` already does
170
+ * internally, promoted so the standalone step runner and hosted step routes
171
+ * stop falling back to literal authored handles. The returned state carries
172
+ * the pinned seller identities, the declaration-local captures from the
173
+ * SAME selected graph, the retained collection witnesses, the resolution
174
+ * evidence, any coverage gaps, and the terminal preparation disposition.
175
+ *
176
+ * The state is deliberately process-local: its trust is a live object
177
+ * identity, and its credential fingerprint is keyed by a per-process random
178
+ * HMAC key. It will not survive serialization, and it is not meant to — a
179
+ * frozen JSON snapshot carries no evidence that its grant is still live.
180
+ * Hosted multi-process reuse belongs behind an authenticated reference
181
+ * lookup with the authorizer hook. See `docs/guides/COLLECTION-FIXTURE-FOUNDATION.md`.
182
+ *
183
+ * A failed or unsatisfied preparation is returned, not thrown: the terminal
184
+ * disposition is part of the evidence and must be carried forward verbatim
185
+ * so a retry cannot hide it behind a freshly discovered alternative.
186
+ */
187
+ export declare function prepareStoryboardFixtures(agentUrl: string | string[], storyboard: Storyboard, options?: StoryboardRunOptions): Promise<PreparedStoryboardFixtures>;
164
188
  /**
165
189
  * Walk every response_schema validation and aggregate the strict/lenient
166
190
  * delta. Always returns a summary; `observable: false` signals "run had