footprintjs 4.11.0 → 4.12.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.
@@ -0,0 +1,272 @@
1
+ /**
2
+ * backtrack.ts — Backward causal chain analysis on the commit log.
3
+ *
4
+ * Implements **backward program slicing** (Weiser 1984, thin-slice variant):
5
+ * given a starting execution step, walk backwards through read→write
6
+ * dependencies to build the causal DAG that produced the data at that step.
7
+ *
8
+ * ## Algorithm
9
+ *
10
+ * BFS on the implicit dependency graph where edges run from reader → writer.
11
+ *
12
+ * 1. Locate startId in commitLog → root node
13
+ * 2. Get keysRead for root via `getKeysRead` callback
14
+ * 3. For each key read, find who last wrote it before this step → parent commit
15
+ * 4. Create parent CausalNode, link to root.parents
16
+ * 5. Enqueue parent. Repeat until queue empty or limits hit.
17
+ *
18
+ * Output is a **DAG** (not a linked list): a stage reading `creditScore` AND `dti`
19
+ * from different writers has two parents.
20
+ *
21
+ * ## Staged Optimization
22
+ *
23
+ * Two writer-lookup strategies, chosen automatically by commit log size:
24
+ *
25
+ * | Strategy | When | Complexity per lookup |
26
+ * |----------|------|----------------------|
27
+ * | Linear scan | N ≤ 256 | O(N) — simple backward scan |
28
+ * | Reverse index | N > 256 | O(K log N) — prebuilt key→[indices], binary search |
29
+ *
30
+ * The threshold (256) is chosen so the O(N) build cost of the reverse index
31
+ * is amortized over the BFS traversal. Below 256, linear scan wins because
32
+ * there's no index build overhead. The consumer never sees this — `causalChain()`
33
+ * picks the right strategy internally (like a query optimizer choosing between
34
+ * sequential scan vs index scan based on table size).
35
+ *
36
+ * ## Complexity
37
+ *
38
+ * - **Small logs (N ≤ 256):** O(V × K × N) total. V=visited, K=avg keys/node.
39
+ * - **Large logs (N > 256):** O(N × U) index build + O(V × K × log N) lookups.
40
+ * U = unique keys. Amortized over all BFS hops.
41
+ *
42
+ * ## References
43
+ *
44
+ * - Weiser, M. (1984). "Program Slicing." IEEE TSE.
45
+ * - Sridharan, M. et al. (2007). "Thin Slicing." PLDI.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * import { causalChain, flattenCausalDAG, formatCausalChain } from 'footprintjs/trace';
50
+ *
51
+ * const dag = causalChain(commitLog, 'decide#2', (id) => recorder.getKeysRead(id));
52
+ * const flat = flattenCausalDAG(dag); // BFS-ordered flat list
53
+ * console.log(formatCausalChain(dag)); // human-readable
54
+ * ```
55
+ */
56
+ import { findLastWriter } from './commitLogUtils.js';
57
+ // ── Staged optimization: writer lookup strategies ──────────────────────
58
+ /**
59
+ * Threshold for switching from linear scan to reverse index.
60
+ * Below this, O(N) scan is faster (no index build cost).
61
+ * Above this, O(log N) binary search wins.
62
+ */
63
+ const REVERSE_INDEX_THRESHOLD = 256;
64
+ /** Strategy 1: Linear scan — O(N) per lookup, zero setup cost. */
65
+ function linearScanLookup(commitLog) {
66
+ return (key, beforeIdx) => findLastWriter(commitLog, key, beforeIdx);
67
+ }
68
+ /**
69
+ * Strategy 2: Reverse index — O(N×U) build, O(log N) per lookup.
70
+ * Builds a Map<key, sortedIndices[]> where indices are commit positions
71
+ * that wrote that key. Lookup uses binary search to find the last writer
72
+ * before a given position.
73
+ */
74
+ function reverseIndexLookup(commitLog) {
75
+ // Build: key → sorted array of commit indices that wrote this key
76
+ const index = new Map();
77
+ for (let i = 0; i < commitLog.length; i++) {
78
+ for (const t of commitLog[i].trace) {
79
+ let arr = index.get(t.path);
80
+ if (!arr) {
81
+ arr = [];
82
+ index.set(t.path, arr);
83
+ }
84
+ arr.push(i); // already sorted (we iterate in order)
85
+ }
86
+ }
87
+ return (key, beforeIdx) => {
88
+ const indices = index.get(key);
89
+ if (!indices || indices.length === 0)
90
+ return undefined;
91
+ // Binary search: find largest index < beforeIdx
92
+ let lo = 0;
93
+ let hi = indices.length - 1;
94
+ let result = -1;
95
+ while (lo <= hi) {
96
+ const mid = (lo + hi) >>> 1;
97
+ if (indices[mid] < beforeIdx) {
98
+ result = indices[mid];
99
+ lo = mid + 1;
100
+ }
101
+ else {
102
+ hi = mid - 1;
103
+ }
104
+ }
105
+ return result >= 0 ? commitLog[result] : undefined;
106
+ };
107
+ }
108
+ /**
109
+ * Staged optimization: pick the right writer-lookup strategy based on data size.
110
+ *
111
+ * Like a database query optimizer choosing between sequential scan and index scan:
112
+ *
113
+ * - **Small log (≤ 256):** Linear scan wins. Zero setup cost, good cache locality.
114
+ * The overhead of building a reverse index isn't worth it for short logs.
115
+ *
116
+ * - **Large log (> 256):** Reverse index wins. O(N×U) upfront build cost is amortized
117
+ * across all BFS hops. Each lookup becomes O(log N) via binary search instead of O(N).
118
+ * For an agent loop with 500 iterations and 5 keys per hop, this is 500×5×log(500)≈22K ops
119
+ * vs 500×5×500=1.25M ops with linear scan.
120
+ *
121
+ * The caller never sees this — `causalChain()` picks automatically.
122
+ */
123
+ function createWriterLookup(commitLog) {
124
+ if (commitLog.length <= REVERSE_INDEX_THRESHOLD) {
125
+ return linearScanLookup(commitLog);
126
+ }
127
+ return reverseIndexLookup(commitLog);
128
+ }
129
+ // ── Core algorithm ─────────────────────────────────────────────────────
130
+ /**
131
+ * Build the causal DAG rooted at `startId` by walking backwards
132
+ * through read→write dependencies in the commit log.
133
+ *
134
+ * Automatically selects the optimal writer lookup strategy:
135
+ * - Linear scan for small logs (≤ 256 commits)
136
+ * - Reverse index with binary search for large logs (> 256 commits)
137
+ *
138
+ * Produces a DAG (not a tree): if two children both read from the same
139
+ * parent, the parent node is shared (deduped by runtimeStageId).
140
+ *
141
+ * @param commitLog Ordered commit bundles from executor.getSnapshot().commitLog
142
+ * @param startId runtimeStageId to start backtracking from
143
+ * @param getKeysRead Callback returning keys read by a given execution step
144
+ * @param options Depth and node limits
145
+ * @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
146
+ */
147
+ export function causalChain(commitLog, startId, getKeysRead, options) {
148
+ var _a, _b;
149
+ const maxDepth = (_a = options === null || options === void 0 ? void 0 : options.maxDepth) !== null && _a !== void 0 ? _a : 20;
150
+ const maxNodes = (_b = options === null || options === void 0 ? void 0 : options.maxNodes) !== null && _b !== void 0 ? _b : 100;
151
+ // Build position index: runtimeStageId → array position (O(n) once)
152
+ const idxMap = new Map();
153
+ for (let i = 0; i < commitLog.length; i++) {
154
+ idxMap.set(commitLog[i].runtimeStageId, i);
155
+ }
156
+ const startIdx = idxMap.get(startId);
157
+ if (startIdx === undefined)
158
+ return undefined;
159
+ const startCommit = commitLog[startIdx];
160
+ // Pick writer lookup strategy based on log size
161
+ const findWriter = createWriterLookup(commitLog);
162
+ // Node dedup map: runtimeStageId → CausalNode (ensures DAG, not tree)
163
+ const nodeMap = new Map();
164
+ const root = {
165
+ runtimeStageId: startId,
166
+ stageId: startCommit.stageId,
167
+ stageName: startCommit.stage,
168
+ keysWritten: startCommit.trace.map((t) => t.path),
169
+ linkedBy: '',
170
+ depth: 0,
171
+ parents: [],
172
+ };
173
+ nodeMap.set(startId, root);
174
+ // BFS queue: [node, commitIdx, depth]
175
+ const queue = [[root, startIdx, 0]];
176
+ let visited = 1;
177
+ while (queue.length > 0) {
178
+ const [node, commitIdx, depth] = queue.shift();
179
+ if (depth >= maxDepth)
180
+ continue;
181
+ const keysRead = getKeysRead(node.runtimeStageId);
182
+ if (keysRead.length === 0)
183
+ continue;
184
+ // For each key read, find who wrote it
185
+ for (const key of keysRead) {
186
+ const writer = findWriter(key, commitIdx);
187
+ if (!writer)
188
+ continue;
189
+ const writerId = writer.runtimeStageId;
190
+ // Check if we already have a node for this writer
191
+ let parentNode = nodeMap.get(writerId);
192
+ if (parentNode) {
193
+ // DAG merge: add as parent if not already linked
194
+ if (!node.parents.some((p) => p.runtimeStageId === writerId)) {
195
+ node.parents.push(parentNode);
196
+ }
197
+ continue;
198
+ }
199
+ // New node — create and enqueue
200
+ if (visited >= maxNodes)
201
+ continue;
202
+ const writerIdx = idxMap.get(writerId);
203
+ if (writerIdx === undefined)
204
+ continue;
205
+ parentNode = {
206
+ runtimeStageId: writerId,
207
+ stageId: writer.stageId,
208
+ stageName: writer.stage,
209
+ keysWritten: writer.trace.map((t) => t.path),
210
+ linkedBy: key,
211
+ depth: depth + 1,
212
+ parents: [],
213
+ };
214
+ nodeMap.set(writerId, parentNode);
215
+ node.parents.push(parentNode);
216
+ visited++;
217
+ queue.push([parentNode, writerIdx, depth + 1]);
218
+ }
219
+ }
220
+ return root;
221
+ }
222
+ // ── Utilities ──────────────────────────────────────────────────────────
223
+ /**
224
+ * Flatten the causal DAG into a BFS-ordered list of nodes.
225
+ * Each node appears exactly once (first occurrence by BFS order).
226
+ * Useful for linear display or iteration.
227
+ */
228
+ export function flattenCausalDAG(root) {
229
+ const result = [];
230
+ const visited = new Set();
231
+ const queue = [root];
232
+ while (queue.length > 0) {
233
+ const node = queue.shift();
234
+ if (visited.has(node.runtimeStageId))
235
+ continue;
236
+ visited.add(node.runtimeStageId);
237
+ result.push(node);
238
+ for (const parent of node.parents) {
239
+ if (!visited.has(parent.runtimeStageId)) {
240
+ queue.push(parent);
241
+ }
242
+ }
243
+ }
244
+ return result;
245
+ }
246
+ /**
247
+ * Format a causal DAG as human-readable indented text.
248
+ * Shows the dependency chain with depth indentation and linked-by keys.
249
+ */
250
+ export function formatCausalChain(root) {
251
+ const lines = [];
252
+ const visited = new Set();
253
+ function walk(node, indent) {
254
+ if (visited.has(node.runtimeStageId)) {
255
+ lines.push(`${' '.repeat(indent)}↳ ${node.runtimeStageId} (see above)`);
256
+ return;
257
+ }
258
+ visited.add(node.runtimeStageId);
259
+ const link = node.linkedBy ? ` ← via ${node.linkedBy}` : '';
260
+ const writes = node.keysWritten.length > 0 ? ` [wrote: ${node.keysWritten.join(', ')}]` : '';
261
+ lines.push(`${' '.repeat(indent)}${node.stageName} (${node.runtimeStageId})${link}${writes}`);
262
+ for (const parent of node.parents) {
263
+ walk(parent, indent + 1);
264
+ }
265
+ }
266
+ walk(root, 0);
267
+ return lines.join('\n');
268
+ }
269
+ // ── Exported for testing (internal) ────────────────────────────────────
270
+ /** @internal Exposed for testing the strategy selection. */
271
+ export const _REVERSE_INDEX_THRESHOLD = REVERSE_INDEX_THRESHOLD;
272
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja3RyYWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tZW1vcnkvYmFja3RyYWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FzREc7QUFFSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUF5Q3JELDBFQUEwRTtBQUUxRTs7OztHQUlHO0FBQ0gsTUFBTSx1QkFBdUIsR0FBRyxHQUFHLENBQUM7QUFRcEMsa0VBQWtFO0FBQ2xFLFNBQVMsZ0JBQWdCLENBQUMsU0FBeUI7SUFDakQsT0FBTyxDQUFDLEdBQUcsRUFBRSxTQUFTLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQVMsa0JBQWtCLENBQUMsU0FBeUI7SUFDbkQsa0VBQWtFO0lBQ2xFLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxFQUFvQixDQUFDO0lBQzFDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDMUMsS0FBSyxNQUFNLENBQUMsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbkMsSUFBSSxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDNUIsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO2dCQUNULEdBQUcsR0FBRyxFQUFFLENBQUM7Z0JBQ1QsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3pCLENBQUM7WUFDRCxHQUFHLENBQUMsSUFB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QyxjQUFjLGNBQWMsQ0FBQyxDQUFDO1lBQ3pFLE9BQU87UUFDVCxDQUFDO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFakMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzdGLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLEtBQUssSUFBSSxDQUFDLGNBQWMsSUFBSSxJQUFJLEdBQUcsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUUvRixLQUFLLE1BQU0sTUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNsQyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMzQixDQUFDO0lBQ0gsQ0FBQztJQUVELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDZCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDMUIsQ0FBQztBQUVELDBFQUEwRTtBQUUxRSw0REFBNEQ7QUFDNUQsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsdUJBQXVCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGJhY2t0cmFjay50cyDigJQgQmFja3dhcmQgY2F1c2FsIGNoYWluIGFuYWx5c2lzIG9uIHRoZSBjb21taXQgbG9nLlxuICpcbiAqIEltcGxlbWVudHMgKipiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcqKiAoV2Vpc2VyIDE5ODQsIHRoaW4tc2xpY2UgdmFyaWFudCk6XG4gKiBnaXZlbiBhIHN0YXJ0aW5nIGV4ZWN1dGlvbiBzdGVwLCB3YWxrIGJhY2t3YXJkcyB0aHJvdWdoIHJlYWTihpJ3cml0ZVxuICogZGVwZW5kZW5jaWVzIHRvIGJ1aWxkIHRoZSBjYXVzYWwgREFHIHRoYXQgcHJvZHVjZWQgdGhlIGRhdGEgYXQgdGhhdCBzdGVwLlxuICpcbiAqICMjIEFsZ29yaXRobVxuICpcbiAqIEJGUyBvbiB0aGUgaW1wbGljaXQgZGVwZW5kZW5jeSBncmFwaCB3aGVyZSBlZGdlcyBydW4gZnJvbSByZWFkZXIg4oaSIHdyaXRlci5cbiAqXG4gKiAxLiBMb2NhdGUgc3RhcnRJZCBpbiBjb21taXRMb2cg4oaSIHJvb3Qgbm9kZVxuICogMi4gR2V0IGtleXNSZWFkIGZvciByb290IHZpYSBgZ2V0S2V5c1JlYWRgIGNhbGxiYWNrXG4gKiAzLiBGb3IgZWFjaCBrZXkgcmVhZCwgZmluZCB3aG8gbGFzdCB3cm90ZSBpdCBiZWZvcmUgdGhpcyBzdGVwIOKGkiBwYXJlbnQgY29tbWl0XG4gKiA0LiBDcmVhdGUgcGFyZW50IENhdXNhbE5vZGUsIGxpbmsgdG8gcm9vdC5wYXJlbnRzXG4gKiA1LiBFbnF1ZXVlIHBhcmVudC4gUmVwZWF0IHVudGlsIHF1ZXVlIGVtcHR5IG9yIGxpbWl0cyBoaXQuXG4gKlxuICogT3V0cHV0IGlzIGEgKipEQUcqKiAobm90IGEgbGlua2VkIGxpc3QpOiBhIHN0YWdlIHJlYWRpbmcgYGNyZWRpdFNjb3JlYCBBTkQgYGR0aWBcbiAqIGZyb20gZGlmZmVyZW50IHdyaXRlcnMgaGFzIHR3byBwYXJlbnRzLlxuICpcbiAqICMjIFN0YWdlZCBPcHRpbWl6YXRpb25cbiAqXG4gKiBUd28gd3JpdGVyLWxvb2t1cCBzdHJhdGVnaWVzLCBjaG9zZW4gYXV0b21hdGljYWxseSBieSBjb21taXQgbG9nIHNpemU6XG4gKlxuICogfCBTdHJhdGVneSB8IFdoZW4gfCBDb21wbGV4aXR5IHBlciBsb29rdXAgfFxuICogfC0tLS0tLS0tLS18LS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18XG4gKiB8IExpbmVhciBzY2FuIHwgTiDiiaQgMjU2IHwgTyhOKSDigJQgc2ltcGxlIGJhY2t3YXJkIHNjYW4gfFxuICogfCBSZXZlcnNlIGluZGV4IHwgTiA+IDI1NiB8IE8oSyBsb2cgTikg4oCUIHByZWJ1aWx0IGtleeKGkltpbmRpY2VzXSwgYmluYXJ5IHNlYXJjaCB8XG4gKlxuICogVGhlIHRocmVzaG9sZCAoMjU2KSBpcyBjaG9zZW4gc28gdGhlIE8oTikgYnVpbGQgY29zdCBvZiB0aGUgcmV2ZXJzZSBpbmRleFxuICogaXMgYW1vcnRpemVkIG92ZXIgdGhlIEJGUyB0cmF2ZXJzYWwuIEJlbG93IDI1NiwgbGluZWFyIHNjYW4gd2lucyBiZWNhdXNlXG4gKiB0aGVyZSdzIG5vIGluZGV4IGJ1aWxkIG92ZXJoZWFkLiBUaGUgY29uc3VtZXIgbmV2ZXIgc2VlcyB0aGlzIOKAlCBgY2F1c2FsQ2hhaW4oKWBcbiAqIHBpY2tzIHRoZSByaWdodCBzdHJhdGVneSBpbnRlcm5hbGx5IChsaWtlIGEgcXVlcnkgb3B0aW1pemVyIGNob29zaW5nIGJldHdlZW5cbiAqIHNlcXVlbnRpYWwgc2NhbiB2cyBpbmRleCBzY2FuIGJhc2VkIG9uIHRhYmxlIHNpemUpLlxuICpcbiAqICMjIENvbXBsZXhpdHlcbiAqXG4gKiAtICoqU21hbGwgbG9ncyAoTiDiiaQgMjU2KToqKiBPKFYgw5cgSyDDlyBOKSB0b3RhbC4gVj12aXNpdGVkLCBLPWF2ZyBrZXlzL25vZGUuXG4gKiAtICoqTGFyZ2UgbG9ncyAoTiA+IDI1Nik6KiogTyhOIMOXIFUpIGluZGV4IGJ1aWxkICsgTyhWIMOXIEsgw5cgbG9nIE4pIGxvb2t1cHMuXG4gKiAgIFUgPSB1bmlxdWUga2V5cy4gQW1vcnRpemVkIG92ZXIgYWxsIEJGUyBob3BzLlxuICpcbiAqICMjIFJlZmVyZW5jZXNcbiAqXG4gKiAtIFdlaXNlciwgTS4gKDE5ODQpLiBcIlByb2dyYW0gU2xpY2luZy5cIiBJRUVFIFRTRS5cbiAqIC0gU3JpZGhhcmFuLCBNLiBldCBhbC4gKDIwMDcpLiBcIlRoaW4gU2xpY2luZy5cIiBQTERJLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICdmb290cHJpbnRqcy90cmFjZSc7XG4gKlxuICogY29uc3QgZGFnID0gY2F1c2FsQ2hhaW4oY29tbWl0TG9nLCAnZGVjaWRlIzInLCAoaWQpID0+IHJlY29yZGVyLmdldEtleXNSZWFkKGlkKSk7XG4gKiBjb25zdCBmbGF0ID0gZmxhdHRlbkNhdXNhbERBRyhkYWcpOyAgICAgLy8gQkZTLW9yZGVyZWQgZmxhdCBsaXN0XG4gKiBjb25zb2xlLmxvZyhmb3JtYXRDYXVzYWxDaGFpbihkYWcpKTsgICAgIC8vIGh1bWFuLXJlYWRhYmxlXG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyBmaW5kTGFzdFdyaXRlciB9IGZyb20gJy4vY29tbWl0TG9nVXRpbHMuanMnO1xuaW1wb3J0IHR5cGUgeyBDb21taXRCdW5kbGUgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLy8g4pSA4pSAIFR5cGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogQSBzaW5nbGUgbm9kZSBpbiB0aGUgY2F1c2FsIERBRy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2F1c2FsTm9kZSB7XG4gIC8qKiBVbmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllci4gKi9cbiAgcnVudGltZVN0YWdlSWQ6IHN0cmluZztcbiAgLyoqIFN0YWJsZSBzdGFnZSBpZGVudGlmaWVyLiAqL1xuICBzdGFnZUlkOiBzdHJpbmc7XG4gIC8qKiBIdW1hbi1yZWFkYWJsZSBzdGFnZSBuYW1lLiAqL1xuICBzdGFnZU5hbWU6IHN0cmluZztcbiAgLyoqIEtleXMgdGhpcyBzdGFnZSB3cm90ZSAoZnJvbSBpdHMgQ29tbWl0QnVuZGxlLnRyYWNlKS4gKi9cbiAga2V5c1dyaXR0ZW46IHN0cmluZ1tdO1xuICAvKiogVGhlIGtleSB3aG9zZSByZWFk4oaSd3JpdGUgZGVwZW5kZW5jeSBsaW5rZWQgdGhpcyBub2RlIHRvIGl0cyBjaGlsZC4gRW1wdHkgZm9yIHRoZSByb290LiAqL1xuICBsaW5rZWRCeTogc3RyaW5nO1xuICAvKiogQkZTIGRlcHRoIGZyb20gdGhlIHN0YXJ0aW5nIG5vZGUgKDAgPSBzdGFydCkuICovXG4gIGRlcHRoOiBudW1iZXI7XG4gIC8qKiBQYXJlbnQgbm9kZXMg4oCUIHN0YWdlcyB0aGF0IHdyb3RlIGRhdGEgdGhpcyBub2RlIHJlYWQuIERBRzogbXVsdGlwbGUgcGFyZW50cyBwb3NzaWJsZS4gKi9cbiAgcGFyZW50czogQ2F1c2FsTm9kZVtdO1xufVxuXG4vKiogT3B0aW9ucyBmb3IgY2F1c2FsQ2hhaW4oKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2F1c2FsQ2hhaW5PcHRpb25zIHtcbiAgLyoqIE1heGltdW0gQkZTIGRlcHRoIChkZWZhdWx0OiAyMCkuIFByZXZlbnRzIHJ1bmF3YXkgdHJhdmVyc2FsLiAqL1xuICBtYXhEZXB0aD86IG51bWJlcjtcbiAgLyoqIE1heGltdW0gdG90YWwgbm9kZXMgdG8gdmlzaXQgKGRlZmF1bHQ6IDEwMCkuIEhhcmQgY2FwIGZvciBzYWZldHkuICovXG4gIG1heE5vZGVzPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENhbGxiYWNrIHRoYXQgcmV0dXJucyB0aGUga2V5cyBhIHN0YWdlIHJlYWQgZHVyaW5nIGV4ZWN1dGlvbi5cbiAqIFRoZSBiYWNrdHJhY2tlciBjYWxscyB0aGlzIGZvciBlYWNoIHZpc2l0ZWQgbm9kZSB0byBkZXRlcm1pbmVcbiAqIHdoaWNoIHJlYWTihpJ3cml0ZSBlZGdlcyB0byBmb2xsb3cuXG4gKlxuICogSW1wbGVtZW50b3JzOiBRdWFsaXR5UmVjb3JkZXIgdHJhY2tzIGtleXNSZWFkIHBlciBzdGVwLFxuICogb3IgYnVpbGQgYSBNYXA8cnVudGltZVN0YWdlSWQsIHN0cmluZ1tdPiBmcm9tIFJlY29yZGVyLm9uUmVhZCBldmVudHMuXG4gKi9cbmV4cG9ydCB0eXBlIEtleXNSZWFkTG9va3VwID0gKHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmcpID0+IHN0cmluZ1tdO1xuXG4vLyDilIDilIAgU3RhZ2VkIG9wdGltaXphdGlvbjogd3JpdGVyIGxvb2t1cCBzdHJhdGVnaWVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFRocmVzaG9sZCBmb3Igc3dpdGNoaW5nIGZyb20gbGluZWFyIHNjYW4gdG8gcmV2ZXJzZSBpbmRleC5cbiAqIEJlbG93IHRoaXMsIE8oTikgc2NhbiBpcyBmYXN0ZXIgKG5vIGluZGV4IGJ1aWxkIGNvc3QpLlxuICogQWJvdmUgdGhpcywgTyhsb2cgTikgYmluYXJ5IHNlYXJjaCB3aW5zLlxuICovXG5jb25zdCBSRVZFUlNFX0lOREVYX1RIUkVTSE9MRCA9IDI1NjtcblxuLyoqXG4gKiBXcml0ZXIgbG9va3VwIGZ1bmN0aW9uIHNpZ25hdHVyZS5cbiAqIFJldHVybnMgdGhlIENvbW1pdEJ1bmRsZSB0aGF0IGxhc3Qgd3JvdGUgYGtleWAgYmVmb3JlIHBvc2l0aW9uIGBiZWZvcmVJZHhgLlxuICovXG50eXBlIFdyaXRlckxvb2t1cCA9IChrZXk6IHN0cmluZywgYmVmb3JlSWR4OiBudW1iZXIpID0+IENvbW1pdEJ1bmRsZSB8IHVuZGVmaW5lZDtcblxuLyoqIFN0cmF0ZWd5IDE6IExpbmVhciBzY2FuIOKAlCBPKE4pIHBlciBsb29rdXAsIHplcm8gc2V0dXAgY29zdC4gKi9cbmZ1bmN0aW9uIGxpbmVhclNjYW5Mb29rdXAoY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSk6IFdyaXRlckxvb2t1cCB7XG4gIHJldHVybiAoa2V5LCBiZWZvcmVJZHgpID0+IGZpbmRMYXN0V3JpdGVyKGNvbW1pdExvZywga2V5LCBiZWZvcmVJZHgpO1xufVxuXG4vKipcbiAqIFN0cmF0ZWd5IDI6IFJldmVyc2UgaW5kZXgg4oCUIE8oTsOXVSkgYnVpbGQsIE8obG9nIE4pIHBlciBsb29rdXAuXG4gKiBCdWlsZHMgYSBNYXA8a2V5LCBzb3J0ZWRJbmRpY2VzW10+IHdoZXJlIGluZGljZXMgYXJlIGNvbW1pdCBwb3NpdGlvbnNcbiAqIHRoYXQgd3JvdGUgdGhhdCBrZXkuIExvb2t1cCB1c2VzIGJpbmFyeSBzZWFyY2ggdG8gZmluZCB0aGUgbGFzdCB3cml0ZXJcbiAqIGJlZm9yZSBhIGdpdmVuIHBvc2l0aW9uLlxuICovXG5mdW5jdGlvbiByZXZlcnNlSW5kZXhMb29rdXAoY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSk6IFdyaXRlckxvb2t1cCB7XG4gIC8vIEJ1aWxkOiBrZXkg4oaSIHNvcnRlZCBhcnJheSBvZiBjb21taXQgaW5kaWNlcyB0aGF0IHdyb3RlIHRoaXMga2V5XG4gIGNvbnN0IGluZGV4ID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcltdPigpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbW1pdExvZy5sZW5ndGg7IGkrKykge1xuICAgIGZvciAoY29uc3QgdCBvZiBjb21taXRMb2dbaV0udHJhY2UpIHtcbiAgICAgIGxldCBhcnIgPSBpbmRleC5nZXQodC5wYXRoKTtcbiAgICAgIGlmICghYXJyKSB7XG4gICAgICAgIGFyciA9IFtdO1xuICAgICAgICBpbmRleC5zZXQodC5wYXRoLCBhcnIpO1xuICAgICAgfVxuICAgICAgYXJyLnB1c2goaSk7IC8vIGFscmVhZHkgc29ydGVkICh3ZSBpdGVyYXRlIGluIG9yZGVyKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiAoa2V5OiBzdHJpbmcsIGJlZm9yZUlkeDogbnVtYmVyKTogQ29tbWl0QnVuZGxlIHwgdW5kZWZpbmVkID0+IHtcbiAgICBjb25zdCBpbmRpY2VzID0gaW5kZXguZ2V0KGtleSk7XG4gICAgaWYgKCFpbmRpY2VzIHx8IGluZGljZXMubGVuZ3RoID09PSAwKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgLy8gQmluYXJ5IHNlYXJjaDogZmluZCBsYXJnZXN0IGluZGV4IDwgYmVmb3JlSWR4XG4gICAgbGV0IGxvID0gMDtcbiAgICBsZXQgaGkgPSBpbmRpY2VzLmxlbmd0aCAtIDE7XG4gICAgbGV0IHJlc3VsdCA9IC0xO1xuXG4gICAgd2hpbGUgKGxvIDw9IGhpKSB7XG4gICAgICBjb25zdCBtaWQgPSAobG8gKyBoaSkgPj4+IDE7XG4gICAgICBpZiAoaW5kaWNlc1ttaWRdIDwgYmVmb3JlSWR4KSB7XG4gICAgICAgIHJlc3VsdCA9IGluZGljZXNbbWlkXTtcbiAgICAgICAgbG8gPSBtaWQgKyAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaGkgPSBtaWQgLSAxO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQgPj0gMCA/IGNvbW1pdExvZ1tyZXN1bHRdIDogdW5kZWZpbmVkO1xuICB9O1xufVxuXG4vKipcbiAqIFN0YWdlZCBvcHRpbWl6YXRpb246IHBpY2sgdGhlIHJpZ2h0IHdyaXRlci1sb29rdXAgc3RyYXRlZ3kgYmFzZWQgb24gZGF0YSBzaXplLlxuICpcbiAqIExpa2UgYSBkYXRhYmFzZSBxdWVyeSBvcHRpbWl6ZXIgY2hvb3NpbmcgYmV0d2VlbiBzZXF1ZW50aWFsIHNjYW4gYW5kIGluZGV4IHNjYW46XG4gKlxuICogLSAqKlNtYWxsIGxvZyAo4omkIDI1Nik6KiogTGluZWFyIHNjYW4gd2lucy4gWmVybyBzZXR1cCBjb3N0LCBnb29kIGNhY2hlIGxvY2FsaXR5LlxuICogICBUaGUgb3ZlcmhlYWQgb2YgYnVpbGRpbmcgYSByZXZlcnNlIGluZGV4IGlzbid0IHdvcnRoIGl0IGZvciBzaG9ydCBsb2dzLlxuICpcbiAqIC0gKipMYXJnZSBsb2cgKD4gMjU2KToqKiBSZXZlcnNlIGluZGV4IHdpbnMuIE8oTsOXVSkgdXBmcm9udCBidWlsZCBjb3N0IGlzIGFtb3J0aXplZFxuICogICBhY3Jvc3MgYWxsIEJGUyBob3BzLiBFYWNoIGxvb2t1cCBiZWNvbWVzIE8obG9nIE4pIHZpYSBiaW5hcnkgc2VhcmNoIGluc3RlYWQgb2YgTyhOKS5cbiAqICAgRm9yIGFuIGFnZW50IGxvb3Agd2l0aCA1MDAgaXRlcmF0aW9ucyBhbmQgNSBrZXlzIHBlciBob3AsIHRoaXMgaXMgNTAww5c1w5dsb2coNTAwKeKJiDIySyBvcHNcbiAqICAgdnMgNTAww5c1w5c1MDA9MS4yNU0gb3BzIHdpdGggbGluZWFyIHNjYW4uXG4gKlxuICogVGhlIGNhbGxlciBuZXZlciBzZWVzIHRoaXMg4oCUIGBjYXVzYWxDaGFpbigpYCBwaWNrcyBhdXRvbWF0aWNhbGx5LlxuICovXG5mdW5jdGlvbiBjcmVhdGVXcml0ZXJMb29rdXAoY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSk6IFdyaXRlckxvb2t1cCB7XG4gIGlmIChjb21taXRMb2cubGVuZ3RoIDw9IFJFVkVSU0VfSU5ERVhfVEhSRVNIT0xEKSB7XG4gICAgcmV0dXJuIGxpbmVhclNjYW5Mb29rdXAoY29tbWl0TG9nKTtcbiAgfVxuICByZXR1cm4gcmV2ZXJzZUluZGV4TG9va3VwKGNvbW1pdExvZyk7XG59XG5cbi8vIOKUgOKUgCBDb3JlIGFsZ29yaXRobSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBCdWlsZCB0aGUgY2F1c2FsIERBRyByb290ZWQgYXQgYHN0YXJ0SWRgIGJ5IHdhbGtpbmcgYmFja3dhcmRzXG4gKiB0aHJvdWdoIHJlYWTihpJ3cml0ZSBkZXBlbmRlbmNpZXMgaW4gdGhlIGNvbW1pdCBsb2cuXG4gKlxuICogQXV0b21hdGljYWxseSBzZWxlY3RzIHRoZSBvcHRpbWFsIHdyaXRlciBsb29rdXAgc3RyYXRlZ3k6XG4gKiAtIExpbmVhciBzY2FuIGZvciBzbWFsbCBsb2dzICjiiaQgMjU2IGNvbW1pdHMpXG4gKiAtIFJldmVyc2UgaW5kZXggd2l0aCBiaW5hcnkgc2VhcmNoIGZvciBsYXJnZSBsb2dzICg+IDI1NiBjb21taXRzKVxuICpcbiAqIFByb2R1Y2VzIGEgREFHIChub3QgYSB0cmVlKTogaWYgdHdvIGNoaWxkcmVuIGJvdGggcmVhZCBmcm9tIHRoZSBzYW1lXG4gKiBwYXJlbnQsIHRoZSBwYXJlbnQgbm9kZSBpcyBzaGFyZWQgKGRlZHVwZWQgYnkgcnVudGltZVN0YWdlSWQpLlxuICpcbiAqIEBwYXJhbSBjb21taXRMb2cgICBPcmRlcmVkIGNvbW1pdCBidW5kbGVzIGZyb20gZXhlY3V0b3IuZ2V0U25hcHNob3QoKS5jb21taXRMb2dcbiAqIEBwYXJhbSBzdGFydElkICAgICBydW50aW1lU3RhZ2VJZCB0byBzdGFydCBiYWNrdHJhY2tpbmcgZnJvbVxuICogQHBhcmFtIGdldEtleXNSZWFkIENhbGxiYWNrIHJldHVybmluZyBrZXlzIHJlYWQgYnkgYSBnaXZlbiBleGVjdXRpb24gc3RlcFxuICogQHBhcmFtIG9wdGlvbnMgICAgIERlcHRoIGFuZCBub2RlIGxpbWl0c1xuICogQHJldHVybnMgUm9vdCBDYXVzYWxOb2RlIHdpdGggLnBhcmVudHMgZm9ybWluZyB0aGUgREFHLCBvciB1bmRlZmluZWQgaWYgc3RhcnRJZCBub3QgZm91bmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNhdXNhbENoYWluKFxuICBjb21taXRMb2c6IENvbW1pdEJ1bmRsZVtdLFxuICBzdGFydElkOiBzdHJpbmcsXG4gIGdldEtleXNSZWFkOiBLZXlzUmVhZExvb2t1cCxcbiAgb3B0aW9ucz86IENhdXNhbENoYWluT3B0aW9ucyxcbik6IENhdXNhbE5vZGUgfCB1bmRlZmluZWQge1xuICBjb25zdCBtYXhEZXB0aCA9IG9wdGlvbnM/Lm1heERlcHRoID8/IDIwO1xuICBjb25zdCBtYXhOb2RlcyA9IG9wdGlvbnM/Lm1heE5vZGVzID8/IDEwMDtcblxuICAvLyBCdWlsZCBwb3NpdGlvbiBpbmRleDogcnVudGltZVN0YWdlSWQg4oaSIGFycmF5IHBvc2l0aW9uIChPKG4pIG9uY2UpXG4gIGNvbnN0IGlkeE1hcCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY29tbWl0TG9nLmxlbmd0aDsgaSsrKSB7XG4gICAgaWR4TWFwLnNldChjb21taXRMb2dbaV0ucnVudGltZVN0YWdlSWQsIGkpO1xuICB9XG5cbiAgY29uc3Qgc3RhcnRJZHggPSBpZHhNYXAuZ2V0KHN0YXJ0SWQpO1xuICBpZiAoc3RhcnRJZHggPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICBjb25zdCBzdGFydENvbW1pdCA9IGNvbW1pdExvZ1tzdGFydElkeF07XG5cbiAgLy8gUGljayB3cml0ZXIgbG9va3VwIHN0cmF0ZWd5IGJhc2VkIG9uIGxvZyBzaXplXG4gIGNvbnN0IGZpbmRXcml0ZXIgPSBjcmVhdGVXcml0ZXJMb29rdXAoY29tbWl0TG9nKTtcblxuICAvLyBOb2RlIGRlZHVwIG1hcDogcnVudGltZVN0YWdlSWQg4oaSIENhdXNhbE5vZGUgKGVuc3VyZXMgREFHLCBub3QgdHJlZSlcbiAgY29uc3Qgbm9kZU1hcCA9IG5ldyBNYXA8c3RyaW5nLCBDYXVzYWxOb2RlPigpO1xuXG4gIGNvbnN0IHJvb3Q6IENhdXNhbE5vZGUgPSB7XG4gICAgcnVudGltZVN0YWdlSWQ6IHN0YXJ0SWQsXG4gICAgc3RhZ2VJZDogc3RhcnRDb21taXQuc3RhZ2VJZCxcbiAgICBzdGFnZU5hbWU6IHN0YXJ0Q29tbWl0LnN0YWdlLFxuICAgIGtleXNXcml0dGVuOiBzdGFydENvbW1pdC50cmFjZS5tYXAoKHQpID0+IHQucGF0aCksXG4gICAgbGlua2VkQnk6ICcnLFxuICAgIGRlcHRoOiAwLFxuICAgIHBhcmVudHM6IFtdLFxuICB9O1xuICBub2RlTWFwLnNldChzdGFydElkLCByb290KTtcblxuICAvLyBCRlMgcXVldWU6IFtub2RlLCBjb21taXRJZHgsIGRlcHRoXVxuICBjb25zdCBxdWV1ZTogQXJyYXk8W0NhdXNhbE5vZGUsIG51bWJlciwgbnVtYmVyXT4gPSBbW3Jvb3QsIHN0YXJ0SWR4LCAwXV07XG4gIGxldCB2aXNpdGVkID0gMTtcblxuICB3aGlsZSAocXVldWUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IFtub2RlLCBjb21taXRJZHgsIGRlcHRoXSA9IHF1ZXVlLnNoaWZ0KCkhO1xuXG4gICAgaWYgKGRlcHRoID49IG1heERlcHRoKSBjb250aW51ZTtcblxuICAgIGNvbnN0IGtleXNSZWFkID0gZ2V0S2V5c1JlYWQobm9kZS5ydW50aW1lU3RhZ2VJZCk7XG4gICAgaWYgKGtleXNSZWFkLmxlbmd0aCA9PT0gMCkgY29udGludWU7XG5cbiAgICAvLyBGb3IgZWFjaCBrZXkgcmVhZCwgZmluZCB3aG8gd3JvdGUgaXRcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzUmVhZCkge1xuICAgICAgY29uc3Qgd3JpdGVyID0gZmluZFdyaXRlcihrZXksIGNvbW1pdElkeCk7XG4gICAgICBpZiAoIXdyaXRlcikgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHdyaXRlcklkID0gd3JpdGVyLnJ1bnRpbWVTdGFnZUlkO1xuXG4gICAgICAvLyBDaGVjayBpZiB3ZSBhbHJlYWR5IGhhdmUgYSBub2RlIGZvciB0aGlzIHdyaXRlclxuICAgICAgbGV0IHBhcmVudE5vZGUgPSBub2RlTWFwLmdldCh3cml0ZXJJZCk7XG4gICAgICBpZiAocGFyZW50Tm9kZSkge1xuICAgICAgICAvLyBEQUcgbWVyZ2U6IGFkZCBhcyBwYXJlbnQgaWYgbm90IGFscmVhZHkgbGlua2VkXG4gICAgICAgIGlmICghbm9kZS5wYXJlbnRzLnNvbWUoKHApID0+IHAucnVudGltZVN0YWdlSWQgPT09IHdyaXRlcklkKSkge1xuICAgICAgICAgIG5vZGUucGFyZW50cy5wdXNoKHBhcmVudE5vZGUpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBOZXcgbm9kZSDigJQgY3JlYXRlIGFuZCBlbnF1ZXVlXG4gICAgICBpZiAodmlzaXRlZCA+PSBtYXhOb2RlcykgY29udGludWU7XG5cbiAgICAgIGNvbnN0IHdyaXRlcklkeCA9IGlkeE1hcC5nZXQod3JpdGVySWQpO1xuICAgICAgaWYgKHdyaXRlcklkeCA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcblxuICAgICAgcGFyZW50Tm9kZSA9IHtcbiAgICAgICAgcnVudGltZVN0YWdlSWQ6IHdyaXRlcklkLFxuICAgICAgICBzdGFnZUlkOiB3cml0ZXIuc3RhZ2VJZCxcbiAgICAgICAgc3RhZ2VOYW1lOiB3cml0ZXIuc3RhZ2UsXG4gICAgICAgIGtleXNXcml0dGVuOiB3cml0ZXIudHJhY2UubWFwKCh0KSA9PiB0LnBhdGgpLFxuICAgICAgICBsaW5rZWRCeToga2V5LFxuICAgICAgICBkZXB0aDogZGVwdGggKyAxLFxuICAgICAgICBwYXJlbnRzOiBbXSxcbiAgICAgIH07XG4gICAgICBub2RlTWFwLnNldCh3cml0ZXJJZCwgcGFyZW50Tm9kZSk7XG4gICAgICBub2RlLnBhcmVudHMucHVzaChwYXJlbnROb2RlKTtcbiAgICAgIHZpc2l0ZWQrKztcblxuICAgICAgcXVldWUucHVzaChbcGFyZW50Tm9kZSwgd3JpdGVySWR4LCBkZXB0aCArIDFdKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcm9vdDtcbn1cblxuLy8g4pSA4pSAIFV0aWxpdGllcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBGbGF0dGVuIHRoZSBjYXVzYWwgREFHIGludG8gYSBCRlMtb3JkZXJlZCBsaXN0IG9mIG5vZGVzLlxuICogRWFjaCBub2RlIGFwcGVhcnMgZXhhY3RseSBvbmNlIChmaXJzdCBvY2N1cnJlbmNlIGJ5IEJGUyBvcmRlcikuXG4gKiBVc2VmdWwgZm9yIGxpbmVhciBkaXNwbGF5IG9yIGl0ZXJhdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZsYXR0ZW5DYXVzYWxEQUcocm9vdDogQ2F1c2FsTm9kZSk6IENhdXNhbE5vZGVbXSB7XG4gIGNvbnN0IHJlc3VsdDogQ2F1c2FsTm9kZVtdID0gW107XG4gIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3QgcXVldWU6IENhdXNhbE5vZGVbXSA9IFtyb290XTtcblxuICB3aGlsZSAocXVldWUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IG5vZGUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICBpZiAodmlzaXRlZC5oYXMobm9kZS5ydW50aW1lU3RhZ2VJZCkpIGNvbnRpbnVlO1xuICAgIHZpc2l0ZWQuYWRkKG5vZGUucnVudGltZVN0YWdlSWQpO1xuICAgIHJlc3VsdC5wdXNoKG5vZGUpO1xuXG4gICAgZm9yIChjb25zdCBwYXJlbnQgb2Ygbm9kZS5wYXJlbnRzKSB7XG4gICAgICBpZiAoIXZpc2l0ZWQuaGFzKHBhcmVudC5ydW50aW1lU3RhZ2VJZCkpIHtcbiAgICAgICAgcXVldWUucHVzaChwYXJlbnQpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogRm9ybWF0IGEgY2F1c2FsIERBRyBhcyBodW1hbi1yZWFkYWJsZSBpbmRlbnRlZCB0ZXh0LlxuICogU2hvd3MgdGhlIGRlcGVuZGVuY3kgY2hhaW4gd2l0aCBkZXB0aCBpbmRlbnRhdGlvbiBhbmQgbGlua2VkLWJ5IGtleXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRDYXVzYWxDaGFpbihyb290OiBDYXVzYWxOb2RlKTogc3RyaW5nIHtcbiAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IHZpc2l0ZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBmdW5jdGlvbiB3YWxrKG5vZGU6IENhdXNhbE5vZGUsIGluZGVudDogbnVtYmVyKTogdm9pZCB7XG4gICAgaWYgKHZpc2l0ZWQuaGFzKG5vZGUucnVudGltZVN0YWdlSWQpKSB7XG4gICAgICBsaW5lcy5wdXNoKGAkeycgICcucmVwZWF0KGluZGVudCl94oazICR7bm9kZS5ydW50aW1lU3RhZ2VJZH0gKHNlZSBhYm92ZSlgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmlzaXRlZC5hZGQobm9kZS5ydW50aW1lU3RhZ2VJZCk7XG5cbiAgICBjb25zdCBsaW5rID0gbm9kZS5saW5rZWRCeSA/IGAg4oaQIHZpYSAke25vZGUubGlua2VkQnl9YCA6ICcnO1xuICAgIGNvbnN0IHdyaXRlcyA9IG5vZGUua2V5c1dyaXR0ZW4ubGVuZ3RoID4gMCA/IGAgW3dyb3RlOiAke25vZGUua2V5c1dyaXR0ZW4uam9pbignLCAnKX1dYCA6ICcnO1xuICAgIGxpbmVzLnB1c2goYCR7JyAgJy5yZXBlYXQoaW5kZW50KX0ke25vZGUuc3RhZ2VOYW1lfSAoJHtub2RlLnJ1bnRpbWVTdGFnZUlkfSkke2xpbmt9JHt3cml0ZXN9YCk7XG5cbiAgICBmb3IgKGNvbnN0IHBhcmVudCBvZiBub2RlLnBhcmVudHMpIHtcbiAgICAgIHdhbGsocGFyZW50LCBpbmRlbnQgKyAxKTtcbiAgICB9XG4gIH1cblxuICB3YWxrKHJvb3QsIDApO1xuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59XG5cbi8vIOKUgOKUgCBFeHBvcnRlZCBmb3IgdGVzdGluZyAoaW50ZXJuYWwpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKiogQGludGVybmFsIEV4cG9zZWQgZm9yIHRlc3RpbmcgdGhlIHN0cmF0ZWd5IHNlbGVjdGlvbi4gKi9cbmV4cG9ydCBjb25zdCBfUkVWRVJTRV9JTkRFWF9USFJFU0hPTEQgPSBSRVZFUlNFX0lOREVYX1RIUkVTSE9MRDtcbiJdfQ==
@@ -0,0 +1,132 @@
1
+ /**
2
+ * QualityRecorder — per-step quality scoring keyed by runtimeStageId.
3
+ *
4
+ * Collects quality scores during traversal (accumulate pattern).
5
+ * After execution, use qualityTrace() to backtrack from any low-scoring step.
6
+ *
7
+ * Extends KeyedRecorder<QualityEntry> for O(1) lookup and standard operations:
8
+ * - **Translate**: `getByKey('call-llm#5')` — quality at this step
9
+ * - **Accumulate**: progressive quality up to slider position
10
+ * - **Aggregate**: overall pipeline quality score
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const quality = new QualityRecorder((runtimeStageId, event) => {
15
+ * // Custom scoring function — return 0.0–1.0
16
+ * if (event.stageName.includes('llm')) return 0.7;
17
+ * return 1.0;
18
+ * });
19
+ * executor.attachRecorder(quality);
20
+ * await executor.run();
21
+ *
22
+ * // Per-step score
23
+ * quality.getByKey('call-llm#5'); // { score: 0.7, stageName: 'CallLLM', factors: [...] }
24
+ *
25
+ * // Overall quality
26
+ * quality.getOverallScore(); // 0.85
27
+ *
28
+ * // Lowest-scoring step
29
+ * quality.getLowest(); // { runtimeStageId: 'call-llm#5', entry: { score: 0.7, ... } }
30
+ * ```
31
+ */
32
+ import { KeyedRecorder } from './KeyedRecorder.js';
33
+ export class QualityRecorder extends KeyedRecorder {
34
+ constructor(scoringFn, options) {
35
+ var _a, _b;
36
+ super();
37
+ // Per-stage buffers (reset on each stageStart)
38
+ this.currentRuntimeStageId = '';
39
+ this.currentStageId = '';
40
+ this.currentStageName = '';
41
+ this.currentKeysRead = [];
42
+ this.currentKeysWritten = [];
43
+ this.scoringFn = scoringFn;
44
+ this.id = (_a = options === null || options === void 0 ? void 0 : options.id) !== null && _a !== void 0 ? _a : `quality-${++QualityRecorder._counter}`;
45
+ this.preferredOperation = (_b = options === null || options === void 0 ? void 0 : options.preferredOperation) !== null && _b !== void 0 ? _b : 'accumulate';
46
+ }
47
+ onStageStart(event) {
48
+ this.currentRuntimeStageId = event.runtimeStageId;
49
+ this.currentStageId = event.stageId;
50
+ this.currentStageName = event.stageName;
51
+ this.currentKeysRead = [];
52
+ this.currentKeysWritten = [];
53
+ }
54
+ onRead(event) {
55
+ if (event.key)
56
+ this.currentKeysRead.push(event.key);
57
+ }
58
+ onWrite(event) {
59
+ this.currentKeysWritten.push(event.key);
60
+ }
61
+ onStageEnd(event) {
62
+ const { score, factors } = this.scoringFn(this.currentRuntimeStageId, {
63
+ stageName: this.currentStageName,
64
+ stageId: this.currentStageId,
65
+ keysRead: this.currentKeysRead,
66
+ keysWritten: this.currentKeysWritten,
67
+ duration: event.duration,
68
+ });
69
+ this.store(this.currentRuntimeStageId, {
70
+ stageName: this.currentStageName,
71
+ stageId: this.currentStageId,
72
+ score: Math.max(0, Math.min(1, score)),
73
+ factors: factors !== null && factors !== void 0 ? factors : [],
74
+ keysRead: [...this.currentKeysRead],
75
+ keysWritten: [...this.currentKeysWritten],
76
+ });
77
+ }
78
+ /** Overall quality score — average of all step scores. */
79
+ getOverallScore() {
80
+ if (this.size === 0)
81
+ return 1.0;
82
+ const total = this.aggregate((sum, e) => sum + e.score, 0);
83
+ return total / this.size;
84
+ }
85
+ /** Find the lowest-scoring step. */
86
+ getLowest() {
87
+ let lowest;
88
+ for (const [key, entry] of this.getMap()) {
89
+ if (!lowest || entry.score < lowest.entry.score) {
90
+ lowest = { runtimeStageId: key, entry };
91
+ }
92
+ }
93
+ return lowest;
94
+ }
95
+ /** Progressive quality score up to a slider position. */
96
+ getScoreUpTo(visibleKeys) {
97
+ let count = 0;
98
+ const total = this.accumulate((sum, e) => {
99
+ count++;
100
+ return sum + e.score;
101
+ }, 0, visibleKeys);
102
+ return count === 0 ? 1.0 : total / count;
103
+ }
104
+ toSnapshot() {
105
+ var _a;
106
+ const steps = {};
107
+ for (const [key, value] of this.getMap()) {
108
+ steps[key] = value;
109
+ }
110
+ return {
111
+ name: 'Quality',
112
+ description: 'Quality scores per execution step with backtracking support',
113
+ preferredOperation: this.preferredOperation,
114
+ data: {
115
+ numericField: 'score',
116
+ overallScore: this.getOverallScore(),
117
+ lowestStep: (_a = this.getLowest()) === null || _a === void 0 ? void 0 : _a.runtimeStageId,
118
+ steps,
119
+ },
120
+ };
121
+ }
122
+ clear() {
123
+ super.clear();
124
+ this.currentRuntimeStageId = '';
125
+ this.currentStageId = '';
126
+ this.currentStageName = '';
127
+ this.currentKeysRead = [];
128
+ this.currentKeysWritten = [];
129
+ }
130
+ }
131
+ QualityRecorder._counter = 0;
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVhbGl0eVJlY29yZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9yZWNvcmRlci9RdWFsaXR5UmVjb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThCRztBQUdILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQTJDbkQsTUFBTSxPQUFPLGVBQWdCLFNBQVEsYUFBMkI7SUFjOUQsWUFBWSxTQUEyQixFQUFFLE9BQWdDOztRQUN2RSxLQUFLLEVBQUUsQ0FBQztRQVJWLCtDQUErQztRQUN2QywwQkFBcUIsR0FBRyxFQUFFLENBQUM7UUFDM0IsbUJBQWMsR0FBRyxFQUFFLENBQUM7UUFDcEIscUJBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQ3RCLG9CQUFlLEdBQWEsRUFBRSxDQUFDO1FBQy9CLHVCQUFrQixHQUFhLEVBQUUsQ0FBQztRQUl4QyxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsRUFBRSxHQUFHLE1BQUEsT0FBTyxhQUFQLE9BQU8sdUJBQVAsT0FBTyxDQUFFLEVBQUUsbUNBQUksV0FBVyxFQUFFLGVBQWUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqRSxJQUFJLENBQUMsa0JBQWtCLEdBQUcsTUFBQSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsa0JBQWtCLG1DQUFJLFlBQVksQ0FBQztJQUN4RSxDQUFDO0lBRUQsWUFBWSxDQUFDLEtBQWlCO1FBQzVCLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxLQUFLLENBQUMsY0FBYyxDQUFDO1FBQ2xELElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztRQUNwQyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQztRQUN4QyxJQUFJLENBQUMsZUFBZSxHQUFHLEVBQUUsQ0FBQztR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QztJQUVELFVBQVU7O1FBQ1IsTUFBTSxLQUFLLEdBQTRCLEVBQUUsQ0FBQztRQUMxQyxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDekMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUNyQixDQUFDO1FBQ0QsT0FBTztZQUNMLElBQUksRUFBRSxTQUFTO1lBQ2YsV0FBVyxFQUFFLDZEQUE2RDtZQUMxRSxrQkFBa0IsRUFBRSxJQUFJLENBQUMsa0JBQWtCO1lBQzNDLElBQUksRUFBRTtnQkFDSixZQUFZLEVBQUUsT0FBTztnQkFDckIsWUFBWSxFQUFFLElBQUksQ0FBQyxlQUFlLEVBQUU7Z0JBQ3BDLFVBQVUsRUFBRSxNQUFBLElBQUksQ0FBQyxTQUFTLEVBQUUsMENBQUUsY0FBYztnQkFDNUMsS0FBSzthQUNOO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFUSxLQUFLO1FBQ1osS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2QsSUFBSSxDQUFDLHFCQUFxQixHQUFHLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsY0FBYyxHQUFHLEVBQUUsQ0FBQztRQUN6QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxFQUFFLENBQUM7SUFDL0IsQ0FBQzs7QUFoSGMsd0JBQVEsR0FBRyxDQUFDLEFBQUosQ0FBSyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUXVhbGl0eVJlY29yZGVyIOKAlCBwZXItc3RlcCBxdWFsaXR5IHNjb3Jpbmcga2V5ZWQgYnkgcnVudGltZVN0YWdlSWQuXG4gKlxuICogQ29sbGVjdHMgcXVhbGl0eSBzY29yZXMgZHVyaW5nIHRyYXZlcnNhbCAoYWNjdW11bGF0ZSBwYXR0ZXJuKS5cbiAqIEFmdGVyIGV4ZWN1dGlvbiwgdXNlIHF1YWxpdHlUcmFjZSgpIHRvIGJhY2t0cmFjayBmcm9tIGFueSBsb3ctc2NvcmluZyBzdGVwLlxuICpcbiAqIEV4dGVuZHMgS2V5ZWRSZWNvcmRlcjxRdWFsaXR5RW50cnk+IGZvciBPKDEpIGxvb2t1cCBhbmQgc3RhbmRhcmQgb3BlcmF0aW9uczpcbiAqICAgLSAqKlRyYW5zbGF0ZSoqOiBgZ2V0QnlLZXkoJ2NhbGwtbGxtIzUnKWAg4oCUIHF1YWxpdHkgYXQgdGhpcyBzdGVwXG4gKiAgIC0gKipBY2N1bXVsYXRlKio6IHByb2dyZXNzaXZlIHF1YWxpdHkgdXAgdG8gc2xpZGVyIHBvc2l0aW9uXG4gKiAgIC0gKipBZ2dyZWdhdGUqKjogb3ZlcmFsbCBwaXBlbGluZSBxdWFsaXR5IHNjb3JlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHF1YWxpdHkgPSBuZXcgUXVhbGl0eVJlY29yZGVyKChydW50aW1lU3RhZ2VJZCwgZXZlbnQpID0+IHtcbiAqICAgLy8gQ3VzdG9tIHNjb3JpbmcgZnVuY3Rpb24g4oCUIHJldHVybiAwLjDigJMxLjBcbiAqICAgaWYgKGV2ZW50LnN0YWdlTmFtZS5pbmNsdWRlcygnbGxtJykpIHJldHVybiAwLjc7XG4gKiAgIHJldHVybiAxLjA7XG4gKiB9KTtcbiAqIGV4ZWN1dG9yLmF0dGFjaFJlY29yZGVyKHF1YWxpdHkpO1xuICogYXdhaXQgZXhlY3V0b3IucnVuKCk7XG4gKlxuICogLy8gUGVyLXN0ZXAgc2NvcmVcbiAqIHF1YWxpdHkuZ2V0QnlLZXkoJ2NhbGwtbGxtIzUnKTsgIC8vIHsgc2NvcmU6IDAuNywgc3RhZ2VOYW1lOiAnQ2FsbExMTScsIGZhY3RvcnM6IFsuLi5dIH1cbiAqXG4gKiAvLyBPdmVyYWxsIHF1YWxpdHlcbiAqIHF1YWxpdHkuZ2V0T3ZlcmFsbFNjb3JlKCk7ICAvLyAwLjg1XG4gKlxuICogLy8gTG93ZXN0LXNjb3Jpbmcgc3RlcFxuICogcXVhbGl0eS5nZXRMb3dlc3QoKTsgIC8vIHsgcnVudGltZVN0YWdlSWQ6ICdjYWxsLWxsbSM1JywgZW50cnk6IHsgc2NvcmU6IDAuNywgLi4uIH0gfVxuICogYGBgXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBSZWFkRXZlbnQsIFJlY29yZGVyLCBTdGFnZUV2ZW50LCBXcml0ZUV2ZW50IH0gZnJvbSAnLi4vc2NvcGUvdHlwZXMuanMnO1xuaW1wb3J0IHsgS2V5ZWRSZWNvcmRlciB9IGZyb20gJy4vS2V5ZWRSZWNvcmRlci5qcyc7XG5pbXBvcnQgdHlwZSB7IFJlY29yZGVyT3BlcmF0aW9uIH0gZnJvbSAnLi9SZWNvcmRlck9wZXJhdGlvbi5qcyc7XG5cbi8qKiBQZXItc3RlcCBxdWFsaXR5IGRhdGEgc3RvcmVkIGJ5IFF1YWxpdHlSZWNvcmRlci4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVhbGl0eUVudHJ5IHtcbiAgLyoqIEh1bWFuLXJlYWRhYmxlIHN0YWdlIG5hbWUuICovXG4gIHN0YWdlTmFtZTogc3RyaW5nO1xuICAvKiogU3RhYmxlIHN0YWdlIGlkZW50aWZpZXIuICovXG4gIHN0YWdlSWQ6IHN0cmluZztcbiAgLyoqIFF1YWxpdHkgc2NvcmUgZm9yIHRoaXMgc3RlcCAoMC4wID0gd29yc3QsIDEuMCA9IGJlc3QpLiAqL1xuICBzY29yZTogbnVtYmVyO1xuICAvKiogV2hhdCBjb250cmlidXRlZCB0byB0aGlzIHNjb3JlLiAqL1xuICBmYWN0b3JzOiBzdHJpbmdbXTtcbiAgLyoqIEtleXMgcmVhZCBkdXJpbmcgdGhpcyBzdGVwIChmb3IgYmFja3RyYWNraW5nKS4gKi9cbiAga2V5c1JlYWQ6IHN0cmluZ1tdO1xuICAvKiogS2V5cyB3cml0dGVuIGR1cmluZyB0aGlzIHN0ZXAgKGZvciBiYWNrdHJhY2tpbmcpLiAqL1xuICBrZXlzV3JpdHRlbjogc3RyaW5nW107XG59XG5cbi8qKlxuICogU2NvcmluZyBmdW5jdGlvbiBjYWxsZWQgYXQgdGhlIGVuZCBvZiBlYWNoIHN0YWdlLlxuICogUmVjZWl2ZXMgdGhlIHJ1bnRpbWVTdGFnZUlkLCBzdGFnZSBldmVudCwgYW5kIGEgc3VtbWFyeSBvZiByZWFkcy93cml0ZXMuXG4gKiBSZXR1cm4gYSBzY29yZSAoMC4w4oCTMS4wKSBhbmQgb3B0aW9uYWwgZmFjdG9ycyBleHBsYWluaW5nIHRoZSBzY29yZS5cbiAqL1xuZXhwb3J0IHR5cGUgUXVhbGl0eVNjb3JpbmdGbiA9IChcbiAgcnVudGltZVN0YWdlSWQ6IHN0cmluZyxcbiAgY29udGV4dDoge1xuICAgIHN0YWdlTmFtZTogc3RyaW5nO1xuICAgIHN0YWdlSWQ6IHN0cmluZztcbiAgICBrZXlzUmVhZDogc3RyaW5nW107XG4gICAga2V5c1dyaXR0ZW46IHN0cmluZ1tdO1xuICAgIGR1cmF0aW9uPzogbnVtYmVyO1xuICB9LFxuKSA9PiB7IHNjb3JlOiBudW1iZXI7IGZhY3RvcnM/OiBzdHJpbmdbXSB9O1xuXG4vKiogT3B0aW9ucyBmb3IgUXVhbGl0eVJlY29yZGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBRdWFsaXR5UmVjb3JkZXJPcHRpb25zIHtcbiAgLyoqIFJlY29yZGVyIElELiBEZWZhdWx0cyB0byBhdXRvLWluY3JlbWVudC4gKi9cbiAgaWQ/OiBzdHJpbmc7XG4gIC8qKiBQcmVmZXJyZWQgVUkgb3BlcmF0aW9uLiBEZWZhdWx0cyB0byAnYWNjdW11bGF0ZScgKHByb2dyZXNzaXZlIHF1YWxpdHkpLiAqL1xuICBwcmVmZXJyZWRPcGVyYXRpb24/OiBSZWNvcmRlck9wZXJhdGlvbjtcbn1cblxuZXhwb3J0IGNsYXNzIFF1YWxpdHlSZWNvcmRlciBleHRlbmRzIEtleWVkUmVjb3JkZXI8UXVhbGl0eUVudHJ5PiBpbXBsZW1lbnRzIFJlY29yZGVyIHtcbiAgcHJpdmF0ZSBzdGF0aWMgX2NvdW50ZXIgPSAwO1xuXG4gIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHByZWZlcnJlZE9wZXJhdGlvbjogUmVjb3JkZXJPcGVyYXRpb247XG4gIHByaXZhdGUgcmVhZG9ubHkgc2NvcmluZ0ZuOiBRdWFsaXR5U2NvcmluZ0ZuO1xuXG4gIC8vIFBlci1zdGFnZSBidWZmZXJzIChyZXNldCBvbiBlYWNoIHN0YWdlU3RhcnQpXG4gIHByaXZhdGUgY3VycmVudFJ1bnRpbWVTdGFnZUlkID0gJyc7XG4gIHByaXZhdGUgY3VycmVudFN0YWdlSWQgPSAnJztcbiAgcHJpdmF0ZSBjdXJyZW50U3RhZ2VOYW1lID0gJyc7XG4gIHByaXZhdGUgY3VycmVudEtleXNSZWFkOiBzdHJpbmdbXSA9IFtdO1xuICBwcml2YXRlIGN1cnJlbnRLZXlzV3JpdHRlbjogc3RyaW5nW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcihzY29yaW5nRm46IFF1YWxpdHlTY29yaW5nRm4sIG9wdGlvbnM/OiBRdWFsaXR5UmVjb3JkZXJPcHRpb25zKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLnNjb3JpbmdGbiA9IHNjb3JpbmdGbjtcbiAgICB0aGlzLmlkID0gb3B0aW9ucz8uaWQgPz8gYHF1YWxpdHktJHsrK1F1YWxpdHlSZWNvcmRlci5fY291bnRlcn1gO1xuICAgIHRoaXMucHJlZmVycmVkT3BlcmF0aW9uID0gb3B0aW9ucz8ucHJlZmVycmVkT3BlcmF0aW9uID8/ICdhY2N1bXVsYXRlJztcbiAgfVxuXG4gIG9uU3RhZ2VTdGFydChldmVudDogU3RhZ2VFdmVudCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudFJ1bnRpbWVTdGFnZUlkID0gZXZlbnQucnVudGltZVN0YWdlSWQ7XG4gICAgdGhpcy5jdXJyZW50U3RhZ2VJZCA9IGV2ZW50LnN0YWdlSWQ7XG4gICAgdGhpcy5jdXJyZW50U3RhZ2VOYW1lID0gZXZlbnQuc3RhZ2VOYW1lO1xuICAgIHRoaXMuY3VycmVudEtleXNSZWFkID0gW107XG4gICAgdGhpcy5jdXJyZW50S2V5c1dyaXR0ZW4gPSBbXTtcbiAgfVxuXG4gIG9uUmVhZChldmVudDogUmVhZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGV2ZW50LmtleSkgdGhpcy5jdXJyZW50S2V5c1JlYWQucHVzaChldmVudC5rZXkpO1xuICB9XG5cbiAgb25Xcml0ZShldmVudDogV3JpdGVFdmVudCk6IHZvaWQge1xuICAgIHRoaXMuY3VycmVudEtleXNXcml0dGVuLnB1c2goZXZlbnQua2V5KTtcbiAgfVxuXG4gIG9uU3RhZ2VFbmQoZXZlbnQ6IFN0YWdlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCB7IHNjb3JlLCBmYWN0b3JzIH0gPSB0aGlzLnNjb3JpbmdGbih0aGlzLmN1cnJlbnRSdW50aW1lU3RhZ2VJZCwge1xuICAgICAgc3RhZ2VOYW1lOiB0aGlzLmN1cnJlbnRTdGFnZU5hbWUsXG4gICAgICBzdGFnZUlkOiB0aGlzLmN1cnJlbnRTdGFnZUlkLFxuICAgICAga2V5c1JlYWQ6IHRoaXMuY3VycmVudEtleXNSZWFkLFxuICAgICAga2V5c1dyaXR0ZW46IHRoaXMuY3VycmVudEtleXNXcml0dGVuLFxuICAgICAgZHVyYXRpb246IGV2ZW50LmR1cmF0aW9uLFxuICAgIH0pO1xuXG4gICAgdGhpcy5zdG9yZSh0aGlzLmN1cnJlbnRSdW50aW1lU3RhZ2VJZCwge1xuICAgICAgc3RhZ2VOYW1lOiB0aGlzLmN1cnJlbnRTdGFnZU5hbWUsXG4gICAgICBzdGFnZUlkOiB0aGlzLmN1cnJlbnRTdGFnZUlkLFxuICAgICAgc2NvcmU6IE1hdGgubWF4KDAsIE1hdGgubWluKDEsIHNjb3JlKSksXG4gICAgICBmYWN0b3JzOiBmYWN0b3JzID8/IFtdLFxuICAgICAga2V5c1JlYWQ6IFsuLi50aGlzLmN1cnJlbnRLZXlzUmVhZF0sXG4gICAgICBrZXlzV3JpdHRlbjogWy4uLnRoaXMuY3VycmVudEtleXNXcml0dGVuXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBPdmVyYWxsIHF1YWxpdHkgc2NvcmUg4oCUIGF2ZXJhZ2Ugb2YgYWxsIHN0ZXAgc2NvcmVzLiAqL1xuICBnZXRPdmVyYWxsU2NvcmUoKTogbnVtYmVyIHtcbiAgICBpZiAodGhpcy5zaXplID09PSAwKSByZXR1cm4gMS4wO1xuICAgIGNvbnN0IHRvdGFsID0gdGhpcy5hZ2dyZWdhdGUoKHN1bSwgZSkgPT4gc3VtICsgZS5zY29yZSwgMCk7XG4gICAgcmV0dXJuIHRvdGFsIC8gdGhpcy5zaXplO1xuICB9XG5cbiAgLyoqIEZpbmQgdGhlIGxvd2VzdC1zY29yaW5nIHN0ZXAuICovXG4gIGdldExvd2VzdCgpOiB7IHJ1bnRpbWVTdGFnZUlkOiBzdHJpbmc7IGVudHJ5OiBRdWFsaXR5RW50cnkgfSB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IGxvd2VzdDogeyBydW50aW1lU3RhZ2VJZDogc3RyaW5nOyBlbnRyeTogUXVhbGl0eUVudHJ5IH0gfCB1bmRlZmluZWQ7XG4gICAgZm9yIChjb25zdCBba2V5LCBlbnRyeV0gb2YgdGhpcy5nZXRNYXAoKSkge1xuICAgICAgaWYgKCFsb3dlc3QgfHwgZW50cnkuc2NvcmUgPCBsb3dlc3QuZW50cnkuc2NvcmUpIHtcbiAgICAgICAgbG93ZXN0ID0geyBydW50aW1lU3RhZ2VJZDoga2V5LCBlbnRyeSB9O1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbG93ZXN0O1xuICB9XG5cbiAgLyoqIFByb2dyZXNzaXZlIHF1YWxpdHkgc2NvcmUgdXAgdG8gYSBzbGlkZXIgcG9zaXRpb24uICovXG4gIGdldFNjb3JlVXBUbyh2aXNpYmxlS2V5czogUmVhZG9ubHlTZXQ8c3RyaW5nPik6IG51bWJlciB7XG4gICAgbGV0IGNvdW50ID0gMDtcbiAgICBjb25zdCB0b3RhbCA9IHRoaXMuYWNjdW11bGF0ZShcbiAgICAgIChzdW0sIGUpID0+IHtcbiAgICAgICAgY291bnQrKztcbiAgICAgICAgcmV0dXJuIHN1bSArIGUuc2NvcmU7XG4gICAgICB9LFxuICAgICAgMCxcbiAgICAgIHZpc2libGVLZXlzLFxuICAgICk7XG4gICAgcmV0dXJuIGNvdW50ID09PSAwID8gMS4wIDogdG90YWwgLyBjb3VudDtcbiAgfVxuXG4gIHRvU25hcHNob3QoKSB7XG4gICAgY29uc3Qgc3RlcHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgdGhpcy5nZXRNYXAoKSkge1xuICAgICAgc3RlcHNba2V5XSA9IHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogJ1F1YWxpdHknLFxuICAgICAgZGVzY3JpcHRpb246ICdRdWFsaXR5IHNjb3JlcyBwZXIgZXhlY3V0aW9uIHN0ZXAgd2l0aCBiYWNrdHJhY2tpbmcgc3VwcG9ydCcsXG4gICAgICBwcmVmZXJyZWRPcGVyYXRpb246IHRoaXMucHJlZmVycmVkT3BlcmF0aW9uLFxuICAgICAgZGF0YToge1xuICAgICAgICBudW1lcmljRmllbGQ6ICdzY29yZScsXG4gICAgICAgIG92ZXJhbGxTY29yZTogdGhpcy5nZXRPdmVyYWxsU2NvcmUoKSxcbiAgICAgICAgbG93ZXN0U3RlcDogdGhpcy5nZXRMb3dlc3QoKT8ucnVudGltZVN0YWdlSWQsXG4gICAgICAgIHN0ZXBzLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgb3ZlcnJpZGUgY2xlYXIoKTogdm9pZCB7XG4gICAgc3VwZXIuY2xlYXIoKTtcbiAgICB0aGlzLmN1cnJlbnRSdW50aW1lU3RhZ2VJZCA9ICcnO1xuICAgIHRoaXMuY3VycmVudFN0YWdlSWQgPSAnJztcbiAgICB0aGlzLmN1cnJlbnRTdGFnZU5hbWUgPSAnJztcbiAgICB0aGlzLmN1cnJlbnRLZXlzUmVhZCA9IFtdO1xuICAgIHRoaXMuY3VycmVudEtleXNXcml0dGVuID0gW107XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,92 @@
1
+ /**
2
+ * qualityTrace() — Quality Stack Trace built on causalChain().
3
+ *
4
+ * Thin layer over `memory/backtrack.causalChain()` that decorates
5
+ * each causal node with quality scores from a QualityRecorder.
6
+ *
7
+ * ```
8
+ * Quality Trace (score: 0.3 at call-llm#5):
9
+ * at call-llm#5 score=0.3 ← quality dropped here
10
+ * at system-prompt#1 score=0.8 ← systemPrompt was good
11
+ * at seed#0 score=1.0 ← input was clean
12
+ *
13
+ * Root cause: quality dropped at call-llm#5 (0.8 → 0.3, Δ0.5)
14
+ * ```
15
+ */
16
+ import { causalChain, flattenCausalDAG } from '../memory/backtrack.js';
17
+ /**
18
+ * Build a quality stack trace by decorating a causal chain with scores.
19
+ *
20
+ * @param commitLog From executor.getSnapshot().commitLog
21
+ * @param qualityRecorder QualityRecorder attached during execution
22
+ * @param startId runtimeStageId to start from
23
+ * @param maxDepth Maximum backtracking depth (default: 20)
24
+ */
25
+ export function qualityTrace(commitLog, qualityRecorder, startId, maxDepth = 20) {
26
+ const startEntry = qualityRecorder.getByKey(startId);
27
+ if (!startEntry) {
28
+ return { startId, startScore: -1, frames: [] };
29
+ }
30
+ // Use causalChain to build the DAG, providing keysRead from the QualityRecorder
31
+ const root = causalChain(commitLog, startId, (id) => { var _a, _b; return (_b = (_a = qualityRecorder.getByKey(id)) === null || _a === void 0 ? void 0 : _a.keysRead) !== null && _b !== void 0 ? _b : []; }, { maxDepth });
32
+ if (!root) {
33
+ return { startId, startScore: startEntry.score, frames: [] };
34
+ }
35
+ // Flatten DAG to BFS-ordered frames, decorate with quality scores
36
+ const nodes = flattenCausalDAG(root);
37
+ const frames = nodes.map((node) => {
38
+ var _a, _b;
39
+ const entry = qualityRecorder.getByKey(node.runtimeStageId);
40
+ return {
41
+ runtimeStageId: node.runtimeStageId,
42
+ stageName: node.stageName,
43
+ score: (_a = entry === null || entry === void 0 ? void 0 : entry.score) !== null && _a !== void 0 ? _a : -1,
44
+ factors: (_b = entry === null || entry === void 0 ? void 0 : entry.factors) !== null && _b !== void 0 ? _b : [],
45
+ linkedBy: node.linkedBy,
46
+ depth: node.depth,
47
+ };
48
+ });
49
+ // Find root cause: biggest quality drop between adjacent frames (BFS order)
50
+ let rootCause;
51
+ for (let i = 0; i < frames.length; i++) {
52
+ const frame = frames[i];
53
+ // Look at each parent (frames at depth + 1)
54
+ for (const parentFrame of frames.filter((f) => f.depth === frame.depth + 1)) {
55
+ if (parentFrame.score < 0)
56
+ continue;
57
+ const drop = parentFrame.score - frame.score;
58
+ if (drop > 0 && (!rootCause || drop > rootCause.drop)) {
59
+ rootCause = { frame, previousFrame: parentFrame, drop };
60
+ }
61
+ }
62
+ }
63
+ return {
64
+ startId,
65
+ startScore: startEntry.score,
66
+ frames,
67
+ rootCause,
68
+ };
69
+ }
70
+ /**
71
+ * Format a QualityStackTrace as human-readable text.
72
+ */
73
+ export function formatQualityTrace(trace) {
74
+ if (trace.frames.length === 0) {
75
+ return `Quality Trace: no data for ${trace.startId}`;
76
+ }
77
+ const lines = [`Quality Trace (score: ${trace.startScore.toFixed(2)} at ${trace.startId}):`];
78
+ for (const frame of trace.frames) {
79
+ const scoreStr = frame.score >= 0 ? frame.score.toFixed(2) : '?';
80
+ const link = frame.linkedBy ? ` (via ${frame.linkedBy})` : '';
81
+ const factors = frame.factors.length > 0 ? ` — ${frame.factors.join(', ')}` : '';
82
+ lines.push(` at ${frame.runtimeStageId.padEnd(30)} score=${scoreStr}${link}${factors}`);
83
+ }
84
+ if (trace.rootCause) {
85
+ lines.push('');
86
+ lines.push(`Root cause: quality dropped at ${trace.rootCause.frame.runtimeStageId} ` +
87
+ `(${trace.rootCause.previousFrame.score.toFixed(2)} → ${trace.rootCause.frame.score.toFixed(2)}, ` +
88
+ `Δ${trace.rootCause.drop.toFixed(2)})`);
89
+ }
90
+ return lines.join('\n');
91
+ }
92
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVhbGl0eVRyYWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFFSCxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUEyQnZFOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUMxQixTQUF5QixFQUN6QixlQUE0QyxFQUM1QyxPQUFlLEVBQ2YsUUFBUSxHQUFHLEVBQUU7SUFFYixNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3JELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoQixPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDakQsQ0FBQztJQUVELGdGQUFnRjtJQUNoRixNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLGVBQUMsT0FBQSxNQUFBLE1BQUEsZUFBZSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsMENBQUUsUUFBUSxtQ0FBSSxFQUFFLENBQUEsRUFBQSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUVqSCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDVixPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUMvRCxDQUFDO0lBRUQsa0VBQWtFO0lBQ2xFLE1BQU0sS0FBSyxHQUFHLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3JDLE1BQU0sTUFBTSxHQUFtQixLQUFLLENBQUMsR0FBRyxDQUFDLENB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UUFBUSxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxRQUFRLEdBQUcsSUFBSSxHQUFHLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDM0YsQ0FBQztJQUVELElBQUksS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ3BCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDZixLQUFLLENBQUMsSUFBSSxDQUNSLGtDQUFrQyxLQUFLLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxjQUFjLEdBQUc7WUFDdkUsSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUk7WUFDbEcsSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FDekMsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDMUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogcXVhbGl0eVRyYWNlKCkg4oCUIFF1YWxpdHkgU3RhY2sgVHJhY2UgYnVpbHQgb24gY2F1c2FsQ2hhaW4oKS5cbiAqXG4gKiBUaGluIGxheWVyIG92ZXIgYG1lbW9yeS9iYWNrdHJhY2suY2F1c2FsQ2hhaW4oKWAgdGhhdCBkZWNvcmF0ZXNcbiAqIGVhY2ggY2F1c2FsIG5vZGUgd2l0aCBxdWFsaXR5IHNjb3JlcyBmcm9tIGEgUXVhbGl0eVJlY29yZGVyLlxuICpcbiAqIGBgYFxuICogUXVhbGl0eSBUcmFjZSAoc2NvcmU6IDAuMyBhdCBjYWxsLWxsbSM1KTpcbiAqICAgYXQgY2FsbC1sbG0jNSAgICAgc2NvcmU9MC4zICDihpAgcXVhbGl0eSBkcm9wcGVkIGhlcmVcbiAqICAgYXQgc3lzdGVtLXByb21wdCMxIHNjb3JlPTAuOCAg4oaQIHN5c3RlbVByb21wdCB3YXMgZ29vZFxuICogICBhdCBzZWVkIzAgICAgICAgICAgc2NvcmU9MS4wICDihpAgaW5wdXQgd2FzIGNsZWFuXG4gKlxuICogUm9vdCBjYXVzZTogcXVhbGl0eSBkcm9wcGVkIGF0IGNhbGwtbGxtIzUgKDAuOCDihpIgMC4zLCDOlDAuNSlcbiAqIGBgYFxuICovXG5cbmltcG9ydCB7IGNhdXNhbENoYWluLCBmbGF0dGVuQ2F1c2FsREFHIH0gZnJvbSAnLi4vbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5pbXBvcnQgdHlwZSB7IENvbW1pdEJ1bmRsZSB9IGZyb20gJy4uL21lbW9yeS90eXBlcy5qcyc7XG5pbXBvcnQgdHlwZSB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL0tleWVkUmVjb3JkZXIuanMnO1xuaW1wb3J0IHR5cGUgeyBRdWFsaXR5RW50cnkgfSBmcm9tICcuL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5cbi8qKiBBIHNpbmdsZSBmcmFtZSBpbiB0aGUgcXVhbGl0eSBzdGFjayB0cmFjZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVhbGl0eUZyYW1lIHtcbiAgcnVudGltZVN0YWdlSWQ6IHN0cmluZztcbiAgc3RhZ2VOYW1lOiBzdHJpbmc7XG4gIHNjb3JlOiBudW1iZXI7XG4gIGZhY3RvcnM6IHN0cmluZ1tdO1xuICBsaW5rZWRCeTogc3RyaW5nO1xuICBkZXB0aDogbnVtYmVyO1xufVxuXG4vKiogVGhlIGZ1bGwgcXVhbGl0eSBzdGFjayB0cmFjZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVhbGl0eVN0YWNrVHJhY2Uge1xuICBzdGFydElkOiBzdHJpbmc7XG4gIHN0YXJ0U2NvcmU6IG51bWJlcjtcbiAgZnJhbWVzOiBRdWFsaXR5RnJhbWVbXTtcbiAgcm9vdENhdXNlPzoge1xuICAgIGZyYW1lOiBRdWFsaXR5RnJhbWU7XG4gICAgcHJldmlvdXNGcmFtZTogUXVhbGl0eUZyYW1lO1xuICAgIGRyb3A6IG51bWJlcjtcbiAgfTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhIHF1YWxpdHkgc3RhY2sgdHJhY2UgYnkgZGVjb3JhdGluZyBhIGNhdXNhbCBjaGFpbiB3aXRoIHNjb3Jlcy5cbiAqXG4gKiBAcGFyYW0gY29tbWl0TG9nICAgICAgICBGcm9tIGV4ZWN1dG9yLmdldFNuYXBzaG90KCkuY29tbWl0TG9nXG4gKiBAcGFyYW0gcXVhbGl0eVJlY29yZGVyICBRdWFsaXR5UmVjb3JkZXIgYXR0YWNoZWQgZHVyaW5nIGV4ZWN1dGlvblxuICogQHBhcmFtIHN0YXJ0SWQgICAgICAgICAgcnVudGltZVN0YWdlSWQgdG8gc3RhcnQgZnJvbVxuICogQHBhcmFtIG1heERlcHRoICAgICAgICAgTWF4aW11bSBiYWNrdHJhY2tpbmcgZGVwdGggKGRlZmF1bHQ6IDIwKVxuICovXG5leHBvcnQgZnVuY3Rpb24gcXVhbGl0eVRyYWNlKFxuICBjb21taXRMb2c6IENvbW1pdEJ1bmRsZVtdLFxuICBxdWFsaXR5UmVjb3JkZXI6IEtleWVkUmVjb3JkZXI8UXVhbGl0eUVudHJ5PixcbiAgc3RhcnRJZDogc3RyaW5nLFxuICBtYXhEZXB0aCA9IDIwLFxuKTogUXVhbGl0eVN0YWNrVHJhY2Uge1xuICBjb25zdCBzdGFydEVudHJ5ID0gcXVhbGl0eVJlY29yZGVyLmdldEJ5S2V5KHN0YXJ0SWQpO1xuICBpZiAoIXN0YXJ0RW50cnkpIHtcbiAgICByZXR1cm4geyBzdGFydElkLCBzdGFydFNjb3JlOiAtMSwgZnJhbWVzOiBbXSB9O1xuICB9XG5cbiAgLy8gVXNlIGNhdXNhbENoYWluIHRvIGJ1aWxkIHRoZSBEQUcsIHByb3ZpZGluZyBrZXlzUmVhZCBmcm9tIHRoZSBRdWFsaXR5UmVjb3JkZXJcbiAgY29uc3Qgcm9vdCA9IGNhdXNhbENoYWluKGNvbW1pdExvZywgc3RhcnRJZCwgKGlkKSA9PiBxdWFsaXR5UmVjb3JkZXIuZ2V0QnlLZXkoaWQpPy5rZXlzUmVhZCA/PyBbXSwgeyBtYXhEZXB0aCB9KTtcblxuICBpZiAoIXJvb3QpIHtcbiAgICByZXR1cm4geyBzdGFydElkLCBzdGFydFNjb3JlOiBzdGFydEVudHJ5LnNjb3JlLCBmcmFtZXM6IFtdIH07XG4gIH1cblxuICAvLyBGbGF0dGVuIERBRyB0byBCRlMtb3JkZXJlZCBmcmFtZXMsIGRlY29yYXRlIHdpdGggcXVhbGl0eSBzY29yZXNcbiAgY29uc3Qgbm9kZXMgPSBmbGF0dGVuQ2F1c2FsREFHKHJvb3QpO1xuICBjb25zdCBmcmFtZXM6IFF1YWxpdHlGcmFtZVtdID0gbm9kZXMubWFwKChub2RlKSA9PiB7XG4gICAgY29uc3QgZW50cnkgPSBxdWFsaXR5UmVjb3JkZXIuZ2V0QnlLZXkobm9kZS5ydW50aW1lU3RhZ2VJZCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJ1bnRpbWVTdGFnZUlkOiBub2RlLnJ1bnRpbWVTdGFnZUlkLFxuICAgICAgc3RhZ2VOYW1lOiBub2RlLnN0YWdlTmFtZSxcbiAgICAgIHNjb3JlOiBlbnRyeT8uc2NvcmUgPz8gLTEsXG4gICAgICBmYWN0b3JzOiBlbnRyeT8uZmFjdG9ycyA/PyBbXSxcbiAgICAgIGxpbmtlZEJ5OiBub2RlLmxpbmtlZEJ5LFxuICAgICAgZGVwdGg6IG5vZGUuZGVwdGgsXG4gICAgfTtcbiAgfSk7XG5cbiAgLy8gRmluZCByb290IGNhdXNlOiBiaWdnZXN0IHF1YWxpdHkgZHJvcCBiZXR3ZWVuIGFkamFjZW50IGZyYW1lcyAoQkZTIG9yZGVyKVxuICBsZXQgcm9vdENhdXNlOiBRdWFsaXR5U3RhY2tUcmFjZVsncm9vdENhdXNlJ107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZnJhbWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgZnJhbWUgPSBmcmFtZXNbaV07XG4gICAgLy8gTG9vayBhdCBlYWNoIHBhcmVudCAoZnJhbWVzIGF0IGRlcHRoICsgMSlcbiAgICBmb3IgKGNvbnN0IHBhcmVudEZyYW1lIG9mIGZyYW1lcy5maWx0ZXIoKGYpID0+IGYuZGVwdGggPT09IGZyYW1lLmRlcHRoICsgMSkpIHtcbiAgICAgIGlmIChwYXJlbnRGcmFtZS5zY29yZSA8IDApIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZHJvcCA9IHBhcmVudEZyYW1lLnNjb3JlIC0gZnJhbWUuc2NvcmU7XG4gICAgICBpZiAoZHJvcCA+IDAgJiYgKCFyb290Q2F1c2UgfHwgZHJvcCA+IHJvb3RDYXVzZS5kcm9wKSkge1xuICAgICAgICByb290Q2F1c2UgPSB7IGZyYW1lLCBwcmV2aW91c0ZyYW1lOiBwYXJlbnRGcmFtZSwgZHJvcCB9O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgc3RhcnRJZCxcbiAgICBzdGFydFNjb3JlOiBzdGFydEVudHJ5LnNjb3JlLFxuICAgIGZyYW1lcyxcbiAgICByb290Q2F1c2UsXG4gIH07XG59XG5cbi8qKlxuICogRm9ybWF0IGEgUXVhbGl0eVN0YWNrVHJhY2UgYXMgaHVtYW4tcmVhZGFibGUgdGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFF1YWxpdHlUcmFjZSh0cmFjZTogUXVhbGl0eVN0YWNrVHJhY2UpOiBzdHJpbmcge1xuICBpZiAodHJhY2UuZnJhbWVzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBgUXVhbGl0eSBUcmFjZTogbm8gZGF0YSBmb3IgJHt0cmFjZS5zdGFydElkfWA7XG4gIH1cblxuICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbYFF1YWxpdHkgVHJhY2UgKHNjb3JlOiAke3RyYWNlLnN0YXJ0U2NvcmUudG9GaXhlZCgyKX0gYXQgJHt0cmFjZS5zdGFydElkfSk6YF07XG5cbiAgZm9yIChjb25zdCBmcmFtZSBvZiB0cmFjZS5mcmFtZXMpIHtcbiAgICBjb25zdCBzY29yZVN0ciA9IGZyYW1lLnNjb3JlID49IDAgPyBmcmFtZS5zY29yZS50b0ZpeGVkKDIpIDogJz8nO1xuICAgIGNvbnN0IGxpbmsgPSBmcmFtZS5saW5rZWRCeSA/IGAgKHZpYSAke2ZyYW1lLmxpbmtlZEJ5fSlgIDogJyc7XG4gICAgY29uc3QgZmFjdG9ycyA9IGZyYW1lLmZhY3RvcnMubGVuZ3RoID4gMCA/IGAg4oCUICR7ZnJhbWUuZmFjdG9ycy5qb2luKCcsICcpfWAgOiAnJztcbiAgICBsaW5lcy5wdXNoKGAgIGF0ICR7ZnJhbWUucnVudGltZVN0YWdlSWQucGFkRW5kKDMwKX0gc2NvcmU9JHtzY29yZVN0cn0ke2xpbmt9JHtmYWN0b3JzfWApO1xuICB9XG5cbiAgaWYgKHRyYWNlLnJvb3RDYXVzZSkge1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIGxpbmVzLnB1c2goXG4gICAgICBgUm9vdCBjYXVzZTogcXVhbGl0eSBkcm9wcGVkIGF0ICR7dHJhY2Uucm9vdENhdXNlLmZyYW1lLnJ1bnRpbWVTdGFnZUlkfSBgICtcbiAgICAgICAgYCgke3RyYWNlLnJvb3RDYXVzZS5wcmV2aW91c0ZyYW1lLnNjb3JlLnRvRml4ZWQoMil9IOKGkiAke3RyYWNlLnJvb3RDYXVzZS5mcmFtZS5zY29yZS50b0ZpeGVkKDIpfSwgYCArXG4gICAgICAgIGDOlCR7dHJhY2Uucm9vdENhdXNlLmRyb3AudG9GaXhlZCgyKX0pYCxcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xufVxuIl19
package/dist/esm/trace.js CHANGED
@@ -23,8 +23,11 @@
23
23
  export { buildRuntimeStageId, createExecutionCounter, parseRuntimeStageId } from './lib/engine/runtimeStageId.js';
24
24
  // Commit log queries — typed utilities for backtracking
25
25
  export { findCommit, findCommits, findLastWriter } from './lib/memory/commitLogUtils.js';
26
+ export { causalChain, flattenCausalDAG, formatCausalChain } from './lib/memory/backtrack.js';
26
27
  // KeyedRecorder — base class for 1:1 Map-based recorders
27
28
  export { KeyedRecorder } from './lib/recorder/KeyedRecorder.js';
28
29
  // SequenceRecorder — base class for 1:N ordered sequence recorders with keyed index
29
30
  export { SequenceRecorder } from './lib/recorder/SequenceRecorder.js';
30
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUlILE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWxILHdEQUF3RDtBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUV6Rix5REFBeUQ7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWhFLG9GQUFvRjtBQUNwRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcbiJdfQ==
31
+ export { QualityRecorder } from './lib/recorder/QualityRecorder.js';
32
+ export { formatQualityTrace, qualityTrace } from './lib/recorder/qualityTrace.js';
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJhY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUlILE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWxILHdEQUF3RDtBQUN4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RixPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFN0YseURBQXlEO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVoRSxvRkFBb0Y7QUFDcEYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFJdEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBSXBFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogZm9vdHByaW50anMvdHJhY2Ug4oCUIEV4ZWN1dGlvbiB0cmFjaW5nLCBkZWJ1Z2dpbmcsIGFuZCBiYWNrdHJhY2tpbmcgdXRpbGl0aWVzLlxuICpcbiAqIFJ1bnRpbWUgc3RhZ2UgSURzLCBjb21taXQgbG9nIHF1ZXJpZXMsIGFuZCByZWNvcmRlciBiYXNlIGNsYXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IHBhcnNlUnVudGltZVN0YWdlSWQsIGZpbmRMYXN0V3JpdGVyLCBLZXllZFJlY29yZGVyLCBTZXF1ZW5jZVJlY29yZGVyIH0gZnJvbSAnZm9vdHByaW50anMvdHJhY2UnO1xuICpcbiAqIC8vIFBhcnNlIGEgcnVudGltZVN0YWdlSWRcbiAqIGNvbnN0IHsgc3RhZ2VJZCwgZXhlY3V0aW9uSW5kZXggfSA9IHBhcnNlUnVudGltZVN0YWdlSWQoJ2NhbGwtbGxtIzUnKTtcbiAqXG4gKiAvLyBCYWNrdHJhY2s6IHdobyB3cm90ZSAnc3lzdGVtUHJvbXB0JyBiZWZvcmUgc3RhZ2UgYXQgaWR4IDg/XG4gKiBjb25zdCB3cml0ZXIgPSBmaW5kTGFzdFdyaXRlcihjb21taXRMb2csICdzeXN0ZW1Qcm9tcHQnLCA4KTtcbiAqXG4gKiAvLyBCdWlsZCBhIGtleWVkIHJlY29yZGVyICgxOjEg4oCUIG9uZSBlbnRyeSBwZXIgc3RlcClcbiAqIGNsYXNzIE15UmVjb3JkZXIgZXh0ZW5kcyBLZXllZFJlY29yZGVyPE15RW50cnk+IHsgLi4uIH1cbiAqXG4gKiAvLyBCdWlsZCBhIHNlcXVlbmNlIHJlY29yZGVyICgxOk4g4oCUIG11bHRpcGxlIGVudHJpZXMgcGVyIHN0ZXAsIG9yZGVyaW5nIG1hdHRlcnMpXG4gKiBjbGFzcyBBdWRpdFJlY29yZGVyIGV4dGVuZHMgU2VxdWVuY2VSZWNvcmRlcjxBdWRpdEVudHJ5PiB7IC4uLiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBSdW50aW1lIHN0YWdlIElEIOKAlCB1bmlxdWUgZXhlY3V0aW9uIHN0ZXAgaWRlbnRpZmllcnNcbmV4cG9ydCB0eXBlIHsgRXhlY3V0aW9uQ291bnRlciB9IGZyb20gJy4vbGliL2VuZ2luZS9ydW50aW1lU3RhZ2VJZC5qcyc7XG5leHBvcnQgeyBidWlsZFJ1bnRpbWVTdGFnZUlkLCBjcmVhdGVFeGVjdXRpb25Db3VudGVyLCBwYXJzZVJ1bnRpbWVTdGFnZUlkIH0gZnJvbSAnLi9saWIvZW5naW5lL3J1bnRpbWVTdGFnZUlkLmpzJztcblxuLy8gQ29tbWl0IGxvZyBxdWVyaWVzIOKAlCB0eXBlZCB1dGlsaXRpZXMgZm9yIGJhY2t0cmFja2luZ1xuZXhwb3J0IHsgZmluZENvbW1pdCwgZmluZENvbW1pdHMsIGZpbmRMYXN0V3JpdGVyIH0gZnJvbSAnLi9saWIvbWVtb3J5L2NvbW1pdExvZ1V0aWxzLmpzJztcblxuLy8gQ2F1c2FsIGNoYWluIOKAlCBiYWNrd2FyZCBwcm9ncmFtIHNsaWNpbmcgb24gY29tbWl0IGxvZyAoREFHKVxuZXhwb3J0IHR5cGUgeyBDYXVzYWxDaGFpbk9wdGlvbnMsIENhdXNhbE5vZGUsIEtleXNSZWFkTG9va3VwIH0gZnJvbSAnLi9saWIvbWVtb3J5L2JhY2t0cmFjay5qcyc7XG5leHBvcnQgeyBjYXVzYWxDaGFpbiwgZmxhdHRlbkNhdXNhbERBRywgZm9ybWF0Q2F1c2FsQ2hhaW4gfSBmcm9tICcuL2xpYi9tZW1vcnkvYmFja3RyYWNrLmpzJztcblxuLy8gS2V5ZWRSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMToxIE1hcC1iYXNlZCByZWNvcmRlcnNcbmV4cG9ydCB7IEtleWVkUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9LZXllZFJlY29yZGVyLmpzJztcblxuLy8gU2VxdWVuY2VSZWNvcmRlciDigJQgYmFzZSBjbGFzcyBmb3IgMTpOIG9yZGVyZWQgc2VxdWVuY2UgcmVjb3JkZXJzIHdpdGgga2V5ZWQgaW5kZXhcbmV4cG9ydCB7IFNlcXVlbmNlUmVjb3JkZXIgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9TZXF1ZW5jZVJlY29yZGVyLmpzJztcblxuLy8gUXVhbGl0eVJlY29yZGVyIOKAlCBwZXItc3RlcCBxdWFsaXR5IHNjb3Jpbmcgd2l0aCBiYWNrdHJhY2tpbmdcbmV4cG9ydCB0eXBlIHsgUXVhbGl0eUVudHJ5LCBRdWFsaXR5UmVjb3JkZXJPcHRpb25zLCBRdWFsaXR5U2NvcmluZ0ZuIH0gZnJvbSAnLi9saWIvcmVjb3JkZXIvUXVhbGl0eVJlY29yZGVyLmpzJztcbmV4cG9ydCB7IFF1YWxpdHlSZWNvcmRlciB9IGZyb20gJy4vbGliL3JlY29yZGVyL1F1YWxpdHlSZWNvcmRlci5qcyc7XG5cbi8vIHF1YWxpdHlUcmFjZSDigJQgUXVhbGl0eSBTdGFjayBUcmFjZSAoYmFja3RyYWNrIGZyb20gbG93LXNjb3Jpbmcgc3RlcHMpXG5leHBvcnQgdHlwZSB7IFF1YWxpdHlGcmFtZSwgUXVhbGl0eVN0YWNrVHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuZXhwb3J0IHsgZm9ybWF0UXVhbGl0eVRyYWNlLCBxdWFsaXR5VHJhY2UgfSBmcm9tICcuL2xpYi9yZWNvcmRlci9xdWFsaXR5VHJhY2UuanMnO1xuIl19