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.
- package/dist/esm/lib/memory/backtrack.js +272 -0
- package/dist/esm/lib/recorder/QualityRecorder.js +132 -0
- package/dist/esm/lib/recorder/qualityTrace.js +92 -0
- package/dist/esm/trace.js +4 -1
- package/dist/lib/memory/backtrack.js +278 -0
- package/dist/lib/recorder/QualityRecorder.js +136 -0
- package/dist/lib/recorder/qualityTrace.js +97 -0
- package/dist/trace.js +11 -2
- package/dist/types/lib/memory/backtrack.d.ts +120 -0
- package/dist/types/lib/recorder/QualityRecorder.d.ts +108 -0
- package/dist/types/lib/recorder/qualityTrace.d.ts +51 -0
- package/dist/types/trace.d.ts +6 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|