footprintjs 9.12.0 → 9.13.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/slice/forwardSliceForKey.d.ts +84 -0
- package/dist/esm/lib/slice/forwardSliceForKey.js +220 -0
- package/dist/esm/lib/slice/index.d.ts +17 -8
- package/dist/esm/lib/slice/index.js +17 -8
- package/dist/esm/lib/slice/keyIndex.d.ts +95 -0
- package/dist/esm/lib/slice/keyIndex.js +212 -0
- package/dist/esm/lib/slice/keyTimeline.d.ts +49 -0
- package/dist/esm/lib/slice/keyTimeline.js +108 -0
- package/dist/esm/lib/slice/serialize.d.ts +39 -1
- package/dist/esm/lib/slice/serialize.js +176 -1
- package/dist/esm/lib/slice/types.d.ts +268 -0
- package/dist/esm/lib/slice/types.js +6 -1
- package/dist/esm/trace.d.ts +3 -3
- package/dist/esm/trace.js +2 -2
- package/dist/lib/slice/forwardSliceForKey.js +224 -0
- package/dist/lib/slice/index.js +22 -8
- package/dist/lib/slice/keyIndex.js +227 -0
- package/dist/lib/slice/keyTimeline.js +112 -0
- package/dist/lib/slice/serialize.js +180 -2
- package/dist/lib/slice/types.js +6 -1
- package/dist/trace.js +7 -2
- package/dist/types/lib/slice/forwardSliceForKey.d.ts +84 -0
- package/dist/types/lib/slice/index.d.ts +17 -8
- package/dist/types/lib/slice/keyIndex.d.ts +95 -0
- package/dist/types/lib/slice/keyTimeline.d.ts +49 -0
- package/dist/types/lib/slice/serialize.d.ts +39 -1
- package/dist/types/lib/slice/types.d.ts +268 -0
- package/dist/types/trace.d.ts +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slice/forwardSliceForKey.ts — the FORWARD half of variable-first slicing.
|
|
3
|
+
*
|
|
4
|
+
* `sliceForKey` answers "why is `key` what it is?" by walking backward from
|
|
5
|
+
* the value to its causes. This file answers the opposite question, which no
|
|
6
|
+
* query answered before: **"who READ this value, and what did it FEED?"**
|
|
7
|
+
* (the production shape: *who read `recipeId`, and what did it feed?* — one
|
|
8
|
+
* query, not a manual scan of a trace viewer).
|
|
9
|
+
*
|
|
10
|
+
* ## The algorithm: LIVE RANGES, not steps
|
|
11
|
+
*
|
|
12
|
+
* A backward slice hops writer→writer. Forward, the unit is a value's LIFE:
|
|
13
|
+
*
|
|
14
|
+
* 1. Anchor at a write of `key` — the SAME anchor idiom as `sliceForKey`
|
|
15
|
+
* (the last writer, or the last writer before `before`).
|
|
16
|
+
* 2. That value lives until the key's NEXT write (`nextWriteIdx`). Every
|
|
17
|
+
* stage that READ `key` inside that window saw THIS value — a `read`.
|
|
18
|
+
* 3. A reading stage that also WROTE something carried the value onward —
|
|
19
|
+
* a `fed` edge to that write, which is itself the start of a new life.
|
|
20
|
+
* 4. Descend into fed lives breadth-first (visited-set guarded, budgeted).
|
|
21
|
+
*
|
|
22
|
+
* ### LAW — the live range is `(writeIdx, nextWriteIdx]`
|
|
23
|
+
*
|
|
24
|
+
* Open at the bottom, CLOSED at the top, and both ends follow from the
|
|
25
|
+
* engine's event order (`onRead` fires PRE-commit — see CLAUDE.md):
|
|
26
|
+
* - a read by the writing stage itself (`readIdx === writeIdx`) saw the
|
|
27
|
+
* PREVIOUS value: read-modify-write reads belong to the previous life;
|
|
28
|
+
* - a read by the OVERWRITING stage (`readIdx === nextWriteIdx`) also fired
|
|
29
|
+
* before its commit, so it still saw THIS value.
|
|
30
|
+
* A read after that commit attributes to the NEW write, never the old one.
|
|
31
|
+
* (Granularity limit, stated because it cannot be seen: a stage that writes
|
|
32
|
+
* `key` and then re-reads it within the SAME stage read its own value; at
|
|
33
|
+
* commit-index resolution that read is indistinguishable from the one that
|
|
34
|
+
* opened the stage.)
|
|
35
|
+
*
|
|
36
|
+
* ### LAW — a `fed` edge is EXACT only under recorded read provenance
|
|
37
|
+
*
|
|
38
|
+
* With `writeProvenance: 'reads-prefix'` on, the child write's
|
|
39
|
+
* `TraceEntry.readKeys` names the keys read before it: this key IN that list
|
|
40
|
+
* is an exact edge (`basis: 'per-write'`), and this key ABSENT from it is an
|
|
41
|
+
* exact *exclusion* — no edge at all. With the dial off there is no such
|
|
42
|
+
* evidence, only "the stage read this and wrote that": the edge is stamped
|
|
43
|
+
* `basis: 'stage'` and the slice carries a `'conservative-fed-edges'` note.
|
|
44
|
+
* A conservative edge is never presented as an exact one.
|
|
45
|
+
*
|
|
46
|
+
* Budgets mirror `causalChain`'s (maxDepth 20, maxNodes 100) and a cut is
|
|
47
|
+
* STATED — `root.truncated` plus a `'truncated'` note.
|
|
48
|
+
*
|
|
49
|
+
* DAG position: memory ← slice. Imports memory/ only (see README.md).
|
|
50
|
+
*/
|
|
51
|
+
import type { KeysReadLookup } from '../memory/backtrack.js';
|
|
52
|
+
import type { CommitBundle } from '../memory/types.js';
|
|
53
|
+
import type { ForwardSlice, KeysReadSource, StateKey } from './types.js';
|
|
54
|
+
/** Options for {@link forwardSliceForKey} — anchoring plus walk budgets. */
|
|
55
|
+
export interface ForwardSliceForKeyOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Exclusive commit-array-index upper bound for the ANCHOR search: follow
|
|
58
|
+
* the value as it stood BEFORE this idx. Same contract as
|
|
59
|
+
* `sliceForKey`'s `before` / `findLastWriter`'s `beforeIdx`.
|
|
60
|
+
*
|
|
61
|
+
* It bounds the anchor ONLY — the walk then runs forward past it, because
|
|
62
|
+
* "what did the value at step 12 go on to feed?" is the whole question.
|
|
63
|
+
*/
|
|
64
|
+
before?: number;
|
|
65
|
+
/** Maximum BFS depth in value-lives (default: 20 — causalChain's). */
|
|
66
|
+
maxDepth?: number;
|
|
67
|
+
/** Maximum total nodes (default: 100 — causalChain's). */
|
|
68
|
+
maxNodes?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Forward slice for one state key: who read this value, and what did it feed?
|
|
72
|
+
*
|
|
73
|
+
* @param commitLog Ordered commit bundles — `getSnapshot().commitLog`.
|
|
74
|
+
* @param key A {@link StateKey}: the plain key string, or a path array
|
|
75
|
+
* (normalised through the SAME `normaliseStateKey` the backward door uses,
|
|
76
|
+
* so both doors accept identical inputs).
|
|
77
|
+
* @param keysRead A {@link KeysReadSource} strategy or a bare lookup — the
|
|
78
|
+
* same reads providers `sliceForKey` takes. Reads are not in the commit
|
|
79
|
+
* log; without a provider a forward walk can see nothing, which the
|
|
80
|
+
* `'reads-not-recorded'` note says out loud.
|
|
81
|
+
* @returns Always a {@link ForwardSlice}. Absence is a RESULT with a reason
|
|
82
|
+
* and, for an unknown key, a bounded list of the keys the log does know.
|
|
83
|
+
*/
|
|
84
|
+
export declare function forwardSliceForKey(commitLog: CommitBundle[], key: StateKey, keysRead: KeysReadSource | KeysReadLookup, options?: ForwardSliceForKeyOptions): ForwardSlice;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slice/forwardSliceForKey.ts — the FORWARD half of variable-first slicing.
|
|
3
|
+
*
|
|
4
|
+
* `sliceForKey` answers "why is `key` what it is?" by walking backward from
|
|
5
|
+
* the value to its causes. This file answers the opposite question, which no
|
|
6
|
+
* query answered before: **"who READ this value, and what did it FEED?"**
|
|
7
|
+
* (the production shape: *who read `recipeId`, and what did it feed?* — one
|
|
8
|
+
* query, not a manual scan of a trace viewer).
|
|
9
|
+
*
|
|
10
|
+
* ## The algorithm: LIVE RANGES, not steps
|
|
11
|
+
*
|
|
12
|
+
* A backward slice hops writer→writer. Forward, the unit is a value's LIFE:
|
|
13
|
+
*
|
|
14
|
+
* 1. Anchor at a write of `key` — the SAME anchor idiom as `sliceForKey`
|
|
15
|
+
* (the last writer, or the last writer before `before`).
|
|
16
|
+
* 2. That value lives until the key's NEXT write (`nextWriteIdx`). Every
|
|
17
|
+
* stage that READ `key` inside that window saw THIS value — a `read`.
|
|
18
|
+
* 3. A reading stage that also WROTE something carried the value onward —
|
|
19
|
+
* a `fed` edge to that write, which is itself the start of a new life.
|
|
20
|
+
* 4. Descend into fed lives breadth-first (visited-set guarded, budgeted).
|
|
21
|
+
*
|
|
22
|
+
* ### LAW — the live range is `(writeIdx, nextWriteIdx]`
|
|
23
|
+
*
|
|
24
|
+
* Open at the bottom, CLOSED at the top, and both ends follow from the
|
|
25
|
+
* engine's event order (`onRead` fires PRE-commit — see CLAUDE.md):
|
|
26
|
+
* - a read by the writing stage itself (`readIdx === writeIdx`) saw the
|
|
27
|
+
* PREVIOUS value: read-modify-write reads belong to the previous life;
|
|
28
|
+
* - a read by the OVERWRITING stage (`readIdx === nextWriteIdx`) also fired
|
|
29
|
+
* before its commit, so it still saw THIS value.
|
|
30
|
+
* A read after that commit attributes to the NEW write, never the old one.
|
|
31
|
+
* (Granularity limit, stated because it cannot be seen: a stage that writes
|
|
32
|
+
* `key` and then re-reads it within the SAME stage read its own value; at
|
|
33
|
+
* commit-index resolution that read is indistinguishable from the one that
|
|
34
|
+
* opened the stage.)
|
|
35
|
+
*
|
|
36
|
+
* ### LAW — a `fed` edge is EXACT only under recorded read provenance
|
|
37
|
+
*
|
|
38
|
+
* With `writeProvenance: 'reads-prefix'` on, the child write's
|
|
39
|
+
* `TraceEntry.readKeys` names the keys read before it: this key IN that list
|
|
40
|
+
* is an exact edge (`basis: 'per-write'`), and this key ABSENT from it is an
|
|
41
|
+
* exact *exclusion* — no edge at all. With the dial off there is no such
|
|
42
|
+
* evidence, only "the stage read this and wrote that": the edge is stamped
|
|
43
|
+
* `basis: 'stage'` and the slice carries a `'conservative-fed-edges'` note.
|
|
44
|
+
* A conservative edge is never presented as an exact one.
|
|
45
|
+
*
|
|
46
|
+
* Budgets mirror `causalChain`'s (maxDepth 20, maxNodes 100) and a cut is
|
|
47
|
+
* STATED — `root.truncated` plus a `'truncated'` note.
|
|
48
|
+
*
|
|
49
|
+
* DAG position: memory ← slice. Imports memory/ only (see README.md).
|
|
50
|
+
*/
|
|
51
|
+
import { DELIM } from '../memory/utils.js';
|
|
52
|
+
import { buildKeyIndex, conservativeEdgesNote, firstIndexAfter, hasRecordedReads, indicesInRange, lastIndexBefore, lastTraceEntry, preRunOriginNote, readsNotRecordedNote, truncatedNote, unknownKeyNote, writtenPaths, } from './keyIndex.js';
|
|
53
|
+
import { resolveKeysReadSource } from './keysReadSources.js';
|
|
54
|
+
import { normaliseStateKey } from './sliceForKey.js';
|
|
55
|
+
/** Identity of one value life: (write position, key). Never parsed. */
|
|
56
|
+
function nodeKey(commitIdx, key) {
|
|
57
|
+
return `${commitIdx ?? 'pre-run'}${DELIM}${key}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build the node for ONE value life. `writeIdx === undefined` is the pre-run
|
|
61
|
+
* origin: the value was already there before the log's first write of the
|
|
62
|
+
* key, so the writer identity fields stay ABSENT rather than fabricated.
|
|
63
|
+
*/
|
|
64
|
+
function makeNode(commitLog, index, key, writeIdx, depth) {
|
|
65
|
+
const writes = index.writesByKey.get(key);
|
|
66
|
+
if (writeIdx === undefined) {
|
|
67
|
+
const firstWrite = writes?.[0];
|
|
68
|
+
return {
|
|
69
|
+
key,
|
|
70
|
+
origin: 'pre-run',
|
|
71
|
+
...(firstWrite !== undefined && { nextWriteIdx: firstWrite }),
|
|
72
|
+
depth,
|
|
73
|
+
reads: [],
|
|
74
|
+
fedEdges: [],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const bundle = commitLog[writeIdx];
|
|
78
|
+
const entry = lastTraceEntry(bundle, key);
|
|
79
|
+
const next = firstIndexAfter(writes, writeIdx);
|
|
80
|
+
return {
|
|
81
|
+
key,
|
|
82
|
+
origin: 'write',
|
|
83
|
+
runtimeStageId: bundle.runtimeStageId,
|
|
84
|
+
stageId: bundle.stageId,
|
|
85
|
+
stageName: bundle.stage,
|
|
86
|
+
commitIdx: writeIdx,
|
|
87
|
+
...(entry !== undefined && { verb: entry.verb }),
|
|
88
|
+
...(next !== undefined && { nextWriteIdx: next }),
|
|
89
|
+
depth,
|
|
90
|
+
reads: [],
|
|
91
|
+
fedEdges: [],
|
|
92
|
+
// Untracked-read honesty rides through from the bundle exactly as
|
|
93
|
+
// causalChain stamps CausalNode.incompleteSources.
|
|
94
|
+
...(bundle.untrackedSources !== undefined &&
|
|
95
|
+
bundle.untrackedSources.length > 0 && { incompleteSources: bundle.untrackedSources }),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Forward slice for one state key: who read this value, and what did it feed?
|
|
100
|
+
*
|
|
101
|
+
* @param commitLog Ordered commit bundles — `getSnapshot().commitLog`.
|
|
102
|
+
* @param key A {@link StateKey}: the plain key string, or a path array
|
|
103
|
+
* (normalised through the SAME `normaliseStateKey` the backward door uses,
|
|
104
|
+
* so both doors accept identical inputs).
|
|
105
|
+
* @param keysRead A {@link KeysReadSource} strategy or a bare lookup — the
|
|
106
|
+
* same reads providers `sliceForKey` takes. Reads are not in the commit
|
|
107
|
+
* log; without a provider a forward walk can see nothing, which the
|
|
108
|
+
* `'reads-not-recorded'` note says out loud.
|
|
109
|
+
* @returns Always a {@link ForwardSlice}. Absence is a RESULT with a reason
|
|
110
|
+
* and, for an unknown key, a bounded list of the keys the log does know.
|
|
111
|
+
*/
|
|
112
|
+
export function forwardSliceForKey(commitLog, key, keysRead, options) {
|
|
113
|
+
const source = resolveKeysReadSource(keysRead);
|
|
114
|
+
const normalisedKey = normaliseStateKey(key);
|
|
115
|
+
const base = {
|
|
116
|
+
key: normalisedKey,
|
|
117
|
+
...(options?.before !== undefined && { before: options.before }),
|
|
118
|
+
keysReadKind: source.kind,
|
|
119
|
+
...(source.coverage !== undefined && { readsCoverage: source.coverage }),
|
|
120
|
+
};
|
|
121
|
+
if (commitLog.length === 0)
|
|
122
|
+
return { ...base, missing: 'empty-log', notes: [] };
|
|
123
|
+
const index = buildKeyIndex(commitLog, source.lookup);
|
|
124
|
+
const readsRecorded = hasRecordedReads(index);
|
|
125
|
+
const notes = [];
|
|
126
|
+
// ── The typo guard, split by what the recording affords ────────────────
|
|
127
|
+
// Unknown key + reads ARE recorded → the log can see readers and this key
|
|
128
|
+
// has none: honest absence with a named reason, no fabricated life.
|
|
129
|
+
// Unknown key + NO reads recorded → a typo and a seeded-but-unread key are
|
|
130
|
+
// genuinely indistinguishable; the pre-run life below is the only honest
|
|
131
|
+
// answer, and it must carry BOTH notes so nobody reads it as "unread".
|
|
132
|
+
const known = index.knownKeys.has(normalisedKey);
|
|
133
|
+
if (!known) {
|
|
134
|
+
notes.push(unknownKeyNote(index, normalisedKey));
|
|
135
|
+
if (readsRecorded)
|
|
136
|
+
return { ...base, missing: 'never-written', notes };
|
|
137
|
+
}
|
|
138
|
+
if (!readsRecorded)
|
|
139
|
+
notes.push(readsNotRecordedNote());
|
|
140
|
+
const maxDepth = options?.maxDepth ?? 20;
|
|
141
|
+
const maxNodes = options?.maxNodes ?? 100;
|
|
142
|
+
const nodes = new Map();
|
|
143
|
+
let created = 0;
|
|
144
|
+
let truncatedByDepth = false;
|
|
145
|
+
let truncatedByNodes = false;
|
|
146
|
+
let anyConservative = false;
|
|
147
|
+
const anchorIdx = lastIndexBefore(index.writesByKey.get(normalisedKey), options?.before);
|
|
148
|
+
const root = makeNode(commitLog, index, normalisedKey, anchorIdx, 0);
|
|
149
|
+
nodes.set(nodeKey(anchorIdx, normalisedKey), root);
|
|
150
|
+
created = 1;
|
|
151
|
+
const queue = [root];
|
|
152
|
+
while (queue.length > 0) {
|
|
153
|
+
const node = queue.shift();
|
|
154
|
+
// Live range: open below the write, CLOSED at the next write (see LAW).
|
|
155
|
+
const from = node.commitIdx !== undefined ? node.commitIdx + 1 : 0;
|
|
156
|
+
const readers = indicesInRange(index.readsByKey.get(node.key), from, node.nextWriteIdx);
|
|
157
|
+
if (node.depth >= maxDepth) {
|
|
158
|
+
// Only a life that still HAD readers to expand counts as a cut.
|
|
159
|
+
if (readers.length > 0)
|
|
160
|
+
truncatedByDepth = true;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
for (const readerIdx of readers) {
|
|
164
|
+
const bundle = commitLog[readerIdx];
|
|
165
|
+
node.reads.push({
|
|
166
|
+
runtimeStageId: bundle.runtimeStageId,
|
|
167
|
+
stageId: bundle.stageId,
|
|
168
|
+
stageName: bundle.stage,
|
|
169
|
+
commitIdx: readerIdx,
|
|
170
|
+
});
|
|
171
|
+
// The reader IS the writer of everything it committed — each written
|
|
172
|
+
// path is a candidate `fed` edge.
|
|
173
|
+
for (const path of writtenPaths(bundle)) {
|
|
174
|
+
const entry = lastTraceEntry(bundle, path);
|
|
175
|
+
let basis;
|
|
176
|
+
if (entry?.readKeys !== undefined) {
|
|
177
|
+
// EXACT both ways: recorded provenance can include or EXCLUDE.
|
|
178
|
+
if (!entry.readKeys.includes(node.key))
|
|
179
|
+
continue;
|
|
180
|
+
basis = 'per-write';
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
basis = 'stage';
|
|
184
|
+
anyConservative = true;
|
|
185
|
+
}
|
|
186
|
+
const id = nodeKey(readerIdx, path);
|
|
187
|
+
let child = nodes.get(id);
|
|
188
|
+
if (!child) {
|
|
189
|
+
if (created >= maxNodes) {
|
|
190
|
+
truncatedByNodes = true;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
child = makeNode(commitLog, index, path, readerIdx, node.depth + 1);
|
|
194
|
+
nodes.set(id, child);
|
|
195
|
+
created++;
|
|
196
|
+
queue.push(child);
|
|
197
|
+
}
|
|
198
|
+
// One edge per distinct child life (a stage reads a key once).
|
|
199
|
+
if (!node.fedEdges.some((e) => e.child === child))
|
|
200
|
+
node.fedEdges.push({ child, basis });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ── Honesty envelope, deterministic order ─────────────────────────────
|
|
205
|
+
if (root.origin === 'pre-run')
|
|
206
|
+
notes.push(preRunOriginNote(normalisedKey));
|
|
207
|
+
if (anyConservative)
|
|
208
|
+
notes.push(conservativeEdgesNote(normalisedKey));
|
|
209
|
+
if (truncatedByDepth || truncatedByNodes) {
|
|
210
|
+
root.truncated = { byDepth: truncatedByDepth, byNodes: truncatedByNodes };
|
|
211
|
+
notes.push(truncatedNote(truncatedByDepth, truncatedByNodes));
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
...base,
|
|
215
|
+
...(anchorIdx !== undefined && { writer: commitLog[anchorIdx] }),
|
|
216
|
+
root,
|
|
217
|
+
notes,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yd2FyZFNsaWNlRm9yS2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zbGljZS9mb3J3YXJkU2xpY2VGb3JLZXkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpREc7QUFJSCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDM0MsT0FBTyxFQUVMLGFBQWEsRUFDYixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsZUFBZSxFQUNmLGNBQWMsRUFDZCxnQkFBZ0IsRUFDaEIsb0JBQW9CLEVBQ3BCLGFBQWEsRUFDYixjQUFjLEVBQ2QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzdELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBb0JyRCx1RUFBdUU7QUFDdkUsU0FBUyxPQUFPLENBQUMsU0FBNkIsRUFBRSxHQUFXO0lBQ3pELE9BQU8sR0FBRyxTQUFTLElBQUksU0FBUyxHQUFHLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQztBQUNuRCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsUUFBUSxDQUNmLFNBQXlCLEVBQ3pCLEtBQWUsRUFDZixHQUFXLEVBQ1gsUUFBNEIsRUFDNUIsS0FBYTtJQUViLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzNCLE1BQU0sVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9CLE9BQU87WUFDTCxHQUFHO1lBQ0gsTUFBTSxFQUFFLFNBQVM7WUFD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Q0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLElBQUksZ0JBQWdCLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztRQUN6QyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO1FBQzFFLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRUQsT0FBTztRQUNMLEdBQUcsSUFBSTtRQUNQLEdBQUcsQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2hFLElBQUk7UUFDSixLQUFLO0tBQ04sQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIHNsaWNlL2ZvcndhcmRTbGljZUZvcktleS50cyDigJQgdGhlIEZPUldBUkQgaGFsZiBvZiB2YXJpYWJsZS1maXJzdCBzbGljaW5nLlxuICpcbiAqIGBzbGljZUZvcktleWAgYW5zd2VycyBcIndoeSBpcyBga2V5YCB3aGF0IGl0IGlzP1wiIGJ5IHdhbGtpbmcgYmFja3dhcmQgZnJvbVxuICogdGhlIHZhbHVlIHRvIGl0cyBjYXVzZXMuIFRoaXMgZmlsZSBhbnN3ZXJzIHRoZSBvcHBvc2l0ZSBxdWVzdGlvbiwgd2hpY2ggbm9cbiAqIHF1ZXJ5IGFuc3dlcmVkIGJlZm9yZTogKipcIndobyBSRUFEIHRoaXMgdmFsdWUsIGFuZCB3aGF0IGRpZCBpdCBGRUVEP1wiKipcbiAqICh0aGUgcHJvZHVjdGlvbiBzaGFwZTogKndobyByZWFkIGByZWNpcGVJZGAsIGFuZCB3aGF0IGRpZCBpdCBmZWVkPyog4oCUIG9uZVxuICogcXVlcnksIG5vdCBhIG1hbnVhbCBzY2FuIG9mIGEgdHJhY2Ugdmlld2VyKS5cbiAqXG4gKiAjIyBUaGUgYWxnb3JpdGhtOiBMSVZFIFJBTkdFUywgbm90IHN0ZXBzXG4gKlxuICogQSBiYWNrd2FyZCBzbGljZSBob3BzIHdyaXRlcuKGkndyaXRlci4gRm9yd2FyZCwgdGhlIHVuaXQgaXMgYSB2YWx1ZSdzIExJRkU6XG4gKlxuICogMS4gQW5jaG9yIGF0IGEgd3JpdGUgb2YgYGtleWAg4oCUIHRoZSBTQU1FIGFuY2hvciBpZGlvbSBhcyBgc2xpY2VGb3JLZXlgXG4gKiAgICAodGhlIGxhc3Qgd3JpdGVyLCBvciB0aGUgbGFzdCB3cml0ZXIgYmVmb3JlIGBiZWZvcmVgKS5cbiAqIDIuIFRoYXQgdmFsdWUgbGl2ZXMgdW50aWwgdGhlIGtleSdzIE5FWFQgd3JpdGUgKGBuZXh0V3JpdGVJZHhgKS4gRXZlcnlcbiAqICAgIHN0YWdlIHRoYXQgUkVBRCBga2V5YCBpbnNpZGUgdGhhdCB3aW5kb3cgc2F3IFRISVMgdmFsdWUg4oCUIGEgYHJlYWRgLlxuICogMy4gQSByZWFkaW5nIHN0YWdlIHRoYXQgYWxzbyBXUk9URSBzb21ldGhpbmcgY2FycmllZCB0aGUgdmFsdWUgb253YXJkIOKAlFxuICogICAgYSBgZmVkYCBlZGdlIHRvIHRoYXQgd3JpdGUsIHdoaWNoIGlzIGl0c2VsZiB0aGUgc3RhcnQgb2YgYSBuZXcgbGlmZS5cbiAqIDQuIERlc2NlbmQgaW50byBmZWQgbGl2ZXMgYnJlYWR0aC1maXJzdCAodmlzaXRlZC1zZXQgZ3VhcmRlZCwgYnVkZ2V0ZWQpLlxuICpcbiAqICMjIyBMQVcg4oCUIHRoZSBsaXZlIHJhbmdlIGlzIGAod3JpdGVJZHgsIG5leHRXcml0ZUlkeF1gXG4gKlxuICogT3BlbiBhdCB0aGUgYm90dG9tLCBDTE9TRUQgYXQgdGhlIHRvcCwgYW5kIGJvdGggZW5kcyBmb2xsb3cgZnJvbSB0aGVcbiAqIGVuZ2luZSdzIGV2ZW50IG9yZGVyIChgb25SZWFkYCBmaXJlcyBQUkUtY29tbWl0IOKAlCBzZWUgQ0xBVURFLm1kKTpcbiAqIC0gYSByZWFkIGJ5IHRoZSB3cml0aW5nIHN0YWdlIGl0c2VsZiAoYHJlYWRJZHggPT09IHdyaXRlSWR4YCkgc2F3IHRoZVxuICogICBQUkVWSU9VUyB2YWx1ZTogcmVhZC1tb2RpZnktd3JpdGUgcmVhZHMgYmVsb25nIHRvIHRoZSBwcmV2aW91cyBsaWZlO1xuICogLSBhIHJlYWQgYnkgdGhlIE9WRVJXUklUSU5HIHN0YWdlIChgcmVhZElkeCA9PT0gbmV4dFdyaXRlSWR4YCkgYWxzbyBmaXJlZFxuICogICBiZWZvcmUgaXRzIGNvbW1pdCwgc28gaXQgc3RpbGwgc2F3IFRISVMgdmFsdWUuXG4gKiBBIHJlYWQgYWZ0ZXIgdGhhdCBjb21taXQgYXR0cmlidXRlcyB0byB0aGUgTkVXIHdyaXRlLCBuZXZlciB0aGUgb2xkIG9uZS5cbiAqIChHcmFudWxhcml0eSBsaW1pdCwgc3RhdGVkIGJlY2F1c2UgaXQgY2Fubm90IGJlIHNlZW46IGEgc3RhZ2UgdGhhdCB3cml0ZXNcbiAqIGBrZXlgIGFuZCB0aGVuIHJlLXJlYWRzIGl0IHdpdGhpbiB0aGUgU0FNRSBzdGFnZSByZWFkIGl0cyBvd24gdmFsdWU7IGF0XG4gKiBjb21taXQtaW5kZXggcmVzb2x1dGlvbiB0aGF0IHJlYWQgaXMgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSB0aGUgb25lIHRoYXRcbiAqIG9wZW5lZCB0aGUgc3RhZ2UuKVxuICpcbiAqICMjIyBMQVcg4oCUIGEgYGZlZGAgZWRnZSBpcyBFWEFDVCBvbmx5IHVuZGVyIHJlY29yZGVkIHJlYWQgcHJvdmVuYW5jZVxuICpcbiAqIFdpdGggYHdyaXRlUHJvdmVuYW5jZTogJ3JlYWRzLXByZWZpeCdgIG9uLCB0aGUgY2hpbGQgd3JpdGUnc1xuICogYFRyYWNlRW50cnkucmVhZEtleXNgIG5hbWVzIHRoZSBrZXlzIHJlYWQgYmVmb3JlIGl0OiB0aGlzIGtleSBJTiB0aGF0IGxpc3RcbiAqIGlzIGFuIGV4YWN0IGVkZ2UgKGBiYXNpczogJ3Blci13cml0ZSdgKSwgYW5kIHRoaXMga2V5IEFCU0VOVCBmcm9tIGl0IGlzIGFuXG4gKiBleGFjdCAqZXhjbHVzaW9uKiDigJQgbm8gZWRnZSBhdCBhbGwuIFdpdGggdGhlIGRpYWwgb2ZmIHRoZXJlIGlzIG5vIHN1Y2hcbiAqIGV2aWRlbmNlLCBvbmx5IFwidGhlIHN0YWdlIHJlYWQgdGhpcyBhbmQgd3JvdGUgdGhhdFwiOiB0aGUgZWRnZSBpcyBzdGFtcGVkXG4gKiBgYmFzaXM6ICdzdGFnZSdgIGFuZCB0aGUgc2xpY2UgY2FycmllcyBhIGAnY29uc2VydmF0aXZlLWZlZC1lZGdlcydgIG5vdGUuXG4gKiBBIGNvbnNlcnZhdGl2ZSBlZGdlIGlzIG5ldmVyIHByZXNlbnRlZCBhcyBhbiBleGFjdCBvbmUuXG4gKlxuICogQnVkZ2V0cyBtaXJyb3IgYGNhdXNhbENoYWluYCdzIChtYXhEZXB0aCAyMCwgbWF4Tm9kZXMgMTAwKSBhbmQgYSBjdXQgaXNcbiAqIFNUQVRFRCDigJQgYHJvb3QudHJ1bmNhdGVkYCBwbHVzIGEgYCd0cnVuY2F0ZWQnYCBub3RlLlxuICpcbiAqIERBRyBwb3NpdGlvbjogbWVtb3J5IOKGkCBzbGljZS4gSW1wb3J0cyBtZW1vcnkvIG9ubHkgKHNlZSBSRUFETUUubWQpLlxuICovXG5cbmltcG9ydCB0eXBlIHsgS2V5c1JlYWRMb29rdXAgfSBmcm9tICcuLi9tZW1vcnkvYmFja3RyYWNrLmpzJztcbmltcG9ydCB0eXBlIHsgQ29tbWl0QnVuZGxlIH0gZnJvbSAnLi4vbWVtb3J5L3R5cGVzLmpzJztcbmltcG9ydCB7IERFTElNIH0gZnJvbSAnLi4vbWVtb3J5L3V0aWxzLmpzJztcbmltcG9ydCB7XG4gIHR5cGUgS2V5SW5kZXgsXG4gIGJ1aWxkS2V5SW5kZXgsXG4gIGNvbnNlcnZhdGl2ZUVkZ2VzTm90ZSxcbiAgZmlyc3RJbmRleEFmdGVyLFxuICBoYXNSZWNvcmRlZFJlYWRzLFxuICBpbmRpY2VzSW5SYW5nZSxcbiAgbGFzdEluZGV4QmVmb3JlLFxuICBsYXN0VHJhY2VFbnRyeSxcbiAgcHJlUnVuT3JpZ2luTm90ZSxcbiAgcmVhZHNOb3RSZWNvcmRlZE5vdGUsXG4gIHRydW5jYXRlZE5vdGUsXG4gIHVua25vd25LZXlOb3RlLFxuICB3cml0dGVuUGF0aHMsXG59IGZyb20gJy4va2V5SW5kZXguanMnO1xuaW1wb3J0IHsgcmVzb2x2ZUtleXNSZWFkU291cmNlIH0gZnJvbSAnLi9rZXlzUmVhZFNvdXJjZXMuanMnO1xuaW1wb3J0IHsgbm9ybWFsaXNlU3RhdGVLZXkgfSBmcm9tICcuL3NsaWNlRm9yS2V5LmpzJztcbmltcG9ydCB0eXBlIHsgRmVkQmFzaXMsIEZvcndhcmROb2RlLCBGb3J3YXJkU2xpY2UsIEhvbmVzdHlOb3RlLCBLZXlzUmVhZFNvdXJjZSwgU3RhdGVLZXkgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqIE9wdGlvbnMgZm9yIHtAbGluayBmb3J3YXJkU2xpY2VGb3JLZXl9IOKAlCBhbmNob3JpbmcgcGx1cyB3YWxrIGJ1ZGdldHMuICovXG5leHBvcnQgaW50ZXJmYWNlIEZvcndhcmRTbGljZUZvcktleU9wdGlvbnMge1xuICAvKipcbiAgICogRXhjbHVzaXZlIGNvbW1pdC1hcnJheS1pbmRleCB1cHBlciBib3VuZCBmb3IgdGhlIEFOQ0hPUiBzZWFyY2g6IGZvbGxvd1xuICAgKiB0aGUgdmFsdWUgYXMgaXQgc3Rvb2QgQkVGT1JFIHRoaXMgaWR4LiBTYW1lIGNvbnRyYWN0IGFzXG4gICAqIGBzbGljZUZvcktleWAncyBgYmVmb3JlYCAvIGBmaW5kTGFzdFdyaXRlcmAncyBgYmVmb3JlSWR4YC5cbiAgICpcbiAgICogSXQgYm91bmRzIHRoZSBhbmNob3IgT05MWSDigJQgdGhlIHdhbGsgdGhlbiBydW5zIGZvcndhcmQgcGFzdCBpdCwgYmVjYXVzZVxuICAgKiBcIndoYXQgZGlkIHRoZSB2YWx1ZSBhdCBzdGVwIDEyIGdvIG9uIHRvIGZlZWQ/XCIgaXMgdGhlIHdob2xlIHF1ZXN0aW9uLlxuICAgKi9cbiAgYmVmb3JlPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSBCRlMgZGVwdGggaW4gdmFsdWUtbGl2ZXMgKGRlZmF1bHQ6IDIwIOKAlCBjYXVzYWxDaGFpbidzKS4gKi9cbiAgbWF4RGVwdGg/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIHRvdGFsIG5vZGVzIChkZWZhdWx0OiAxMDAg4oCUIGNhdXNhbENoYWluJ3MpLiAqL1xuICBtYXhOb2Rlcz86IG51bWJlcjtcbn1cblxuLyoqIElkZW50aXR5IG9mIG9uZSB2YWx1ZSBsaWZlOiAod3JpdGUgcG9zaXRpb24sIGtleSkuIE5ldmVyIHBhcnNlZC4gKi9cbmZ1bmN0aW9uIG5vZGVLZXkoY29tbWl0SWR4OiBudW1iZXIgfCB1bmRlZmluZWQsIGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2NvbW1pdElkeCA/PyAncHJlLXJ1bid9JHtERUxJTX0ke2tleX1gO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBub2RlIGZvciBPTkUgdmFsdWUgbGlmZS4gYHdyaXRlSWR4ID09PSB1bmRlZmluZWRgIGlzIHRoZSBwcmUtcnVuXG4gKiBvcmlnaW46IHRoZSB2YWx1ZSB3YXMgYWxyZWFkeSB0aGVyZSBiZWZvcmUgdGhlIGxvZydzIGZpcnN0IHdyaXRlIG9mIHRoZVxuICoga2V5LCBzbyB0aGUgd3JpdGVyIGlkZW50aXR5IGZpZWxkcyBzdGF5IEFCU0VOVCByYXRoZXIgdGhhbiBmYWJyaWNhdGVkLlxuICovXG5mdW5jdGlvbiBtYWtlTm9kZShcbiAgY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSxcbiAgaW5kZXg6IEtleUluZGV4LFxuICBrZXk6IHN0cmluZyxcbiAgd3JpdGVJZHg6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZGVwdGg6IG51bWJlcixcbik6IEZvcndhcmROb2RlIHtcbiAgY29uc3Qgd3JpdGVzID0gaW5kZXgud3JpdGVzQnlLZXkuZ2V0KGtleSk7XG4gIGlmICh3cml0ZUlkeCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZmlyc3RXcml0ZSA9IHdyaXRlcz8uWzBdO1xuICAgIHJldHVybiB7XG4gICAgICBrZXksXG4gICAgICBvcmlnaW46ICdwcmUtcnVuJyxcbiAgICAgIC4uLihmaXJzdFdyaXRlICE9PSB1bmRlZmluZWQgJiYgeyBuZXh0V3JpdGVJZHg6IGZpcnN0V3JpdGUgfSksXG4gICAgICBkZXB0aCxcbiAgICAgIHJlYWRzOiBbXSxcbiAgICAgIGZlZEVkZ2VzOiBbXSxcbiAgICB9O1xuICB9XG4gIGNvbnN0IGJ1bmRsZSA9IGNvbW1pdExvZ1t3cml0ZUlkeF07XG4gIGNvbnN0IGVudHJ5ID0gbGFzdFRyYWNlRW50cnkoYnVuZGxlLCBrZXkpO1xuICBjb25zdCBuZXh0ID0gZmlyc3RJbmRleEFmdGVyKHdyaXRlcywgd3JpdGVJZHgpO1xuICByZXR1cm4ge1xuICAgIGtleSxcbiAgICBvcmlnaW46ICd3cml0ZScsXG4gICAgcnVudGltZVN0YWdlSWQ6IGJ1bmRsZS5ydW50aW1lU3RhZ2VJZCxcbiAgICBzdGFnZUlkOiBidW5kbGUuc3RhZ2VJZCxcbiAgICBzdGFnZU5hbWU6IGJ1bmRsZS5zdGFnZSxcbiAgICBjb21taXRJZHg6IHdyaXRlSWR4LFxuICAgIC4uLihlbnRyeSAhPT0gdW5kZWZpbmVkICYmIHsgdmVyYjogZW50cnkudmVyYiB9KSxcbiAgICAuLi4obmV4dCAhPT0gdW5kZWZpbmVkICYmIHsgbmV4dFdyaXRlSWR4OiBuZXh0IH0pLFxuICAgIGRlcHRoLFxuICAgIHJlYWRzOiBbXSxcbiAgICBmZWRFZGdlczogW10sXG4gICAgLy8gVW50cmFja2VkLXJlYWQgaG9uZXN0eSByaWRlcyB0aHJvdWdoIGZyb20gdGhlIGJ1bmRsZSBleGFjdGx5IGFzXG4gICAgLy8gY2F1c2FsQ2hhaW4gc3RhbXBzIENhdXNhbE5vZGUuaW5jb21wbGV0ZVNvdXJjZXMuXG4gICAgLi4uKGJ1bmRsZS51bnRyYWNrZWRTb3VyY2VzICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIGJ1bmRsZS51bnRyYWNrZWRTb3VyY2VzLmxlbmd0aCA+IDAgJiYgeyBpbmNvbXBsZXRlU291cmNlczogYnVuZGxlLnVudHJhY2tlZFNvdXJjZXMgfSksXG4gIH07XG59XG5cbi8qKlxuICogRm9yd2FyZCBzbGljZSBmb3Igb25lIHN0YXRlIGtleTogd2hvIHJlYWQgdGhpcyB2YWx1ZSwgYW5kIHdoYXQgZGlkIGl0IGZlZWQ/XG4gKlxuICogQHBhcmFtIGNvbW1pdExvZyBPcmRlcmVkIGNvbW1pdCBidW5kbGVzIOKAlCBgZ2V0U25hcHNob3QoKS5jb21taXRMb2dgLlxuICogQHBhcmFtIGtleSBBIHtAbGluayBTdGF0ZUtleX06IHRoZSBwbGFpbiBrZXkgc3RyaW5nLCBvciBhIHBhdGggYXJyYXlcbiAqICAgKG5vcm1hbGlzZWQgdGhyb3VnaCB0aGUgU0FNRSBgbm9ybWFsaXNlU3RhdGVLZXlgIHRoZSBiYWNrd2FyZCBkb29yIHVzZXMsXG4gKiAgIHNvIGJvdGggZG9vcnMgYWNjZXB0IGlkZW50aWNhbCBpbnB1dHMpLlxuICogQHBhcmFtIGtleXNSZWFkIEEge0BsaW5rIEtleXNSZWFkU291cmNlfSBzdHJhdGVneSBvciBhIGJhcmUgbG9va3VwIOKAlCB0aGVcbiAqICAgc2FtZSByZWFkcyBwcm92aWRlcnMgYHNsaWNlRm9yS2V5YCB0YWtlcy4gUmVhZHMgYXJlIG5vdCBpbiB0aGUgY29tbWl0XG4gKiAgIGxvZzsgd2l0aG91dCBhIHByb3ZpZGVyIGEgZm9yd2FyZCB3YWxrIGNhbiBzZWUgbm90aGluZywgd2hpY2ggdGhlXG4gKiAgIGAncmVhZHMtbm90LXJlY29yZGVkJ2Agbm90ZSBzYXlzIG91dCBsb3VkLlxuICogQHJldHVybnMgQWx3YXlzIGEge0BsaW5rIEZvcndhcmRTbGljZX0uIEFic2VuY2UgaXMgYSBSRVNVTFQgd2l0aCBhIHJlYXNvblxuICogICBhbmQsIGZvciBhbiB1bmtub3duIGtleSwgYSBib3VuZGVkIGxpc3Qgb2YgdGhlIGtleXMgdGhlIGxvZyBkb2VzIGtub3cuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3J3YXJkU2xpY2VGb3JLZXkoXG4gIGNvbW1pdExvZzogQ29tbWl0QnVuZGxlW10sXG4gIGtleTogU3RhdGVLZXksXG4gIGtleXNSZWFkOiBLZXlzUmVhZFNvdXJjZSB8IEtleXNSZWFkTG9va3VwLFxuICBvcHRpb25zPzogRm9yd2FyZFNsaWNlRm9yS2V5T3B0aW9ucyxcbik6IEZvcndhcmRTbGljZSB7XG4gIGNvbnN0IHNvdXJjZSA9IHJlc29sdmVLZXlzUmVhZFNvdXJjZShrZXlzUmVhZCk7XG4gIGNvbnN0IG5vcm1hbGlzZWRLZXkgPSBub3JtYWxpc2VTdGF0ZUtleShrZXkpO1xuICBjb25zdCBiYXNlOiBQaWNrPEZvcndhcmRTbGljZSwgJ2tleScgfCAnYmVmb3JlJyB8ICdrZXlzUmVhZEtpbmQnIHwgJ3JlYWRzQ292ZXJhZ2UnPiA9IHtcbiAgICBrZXk6IG5vcm1hbGlzZWRLZXksXG4gICAgLi4uKG9wdGlvbnM/LmJlZm9yZSAhPT0gdW5kZWZpbmVkICYmIHsgYmVmb3JlOiBvcHRpb25zLmJlZm9yZSB9KSxcbiAgICBrZXlzUmVhZEtpbmQ6IHNvdXJjZS5raW5kLFxuICAgIC4uLihzb3VyY2UuY292ZXJhZ2UgIT09IHVuZGVmaW5lZCAmJiB7IHJlYWRzQ292ZXJhZ2U6IHNvdXJjZS5jb3ZlcmFnZSB9KSxcbiAgfTtcblxuICBpZiAoY29tbWl0TG9nLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHsgLi4uYmFzZSwgbWlzc2luZzogJ2VtcHR5LWxvZycsIG5vdGVzOiBbXSB9O1xuXG4gIGNvbnN0IGluZGV4ID0gYnVpbGRLZXlJbmRleChjb21taXRMb2csIHNvdXJjZS5sb29rdXApO1xuICBjb25zdCByZWFkc1JlY29yZGVkID0gaGFzUmVjb3JkZWRSZWFkcyhpbmRleCk7XG4gIGNvbnN0IG5vdGVzOiBIb25lc3R5Tm90ZVtdID0gW107XG5cbiAgLy8g4pSA4pSAIFRoZSB0eXBvIGd1YXJkLCBzcGxpdCBieSB3aGF0IHRoZSByZWNvcmRpbmcgYWZmb3JkcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVW5rbm93biBrZXkgKyByZWFkcyBBUkUgcmVjb3JkZWQg4oaSIHRoZSBsb2cgY2FuIHNlZSByZWFkZXJzIGFuZCB0aGlzIGtleVxuICAvLyBoYXMgbm9uZTogaG9uZXN0IGFic2VuY2Ugd2l0aCBhIG5hbWVkIHJlYXNvbiwgbm8gZmFicmljYXRlZCBsaWZlLlxuICAvLyBVbmtub3duIGtleSArIE5PIHJlYWRzIHJlY29yZGVkIOKGkiBhIHR5cG8gYW5kIGEgc2VlZGVkLWJ1dC11bnJlYWQga2V5IGFyZVxuICAvLyBnZW51aW5lbHkgaW5kaXN0aW5ndWlzaGFibGU7IHRoZSBwcmUtcnVuIGxpZmUgYmVsb3cgaXMgdGhlIG9ubHkgaG9uZXN0XG4gIC8vIGFuc3dlciwgYW5kIGl0IG11c3QgY2FycnkgQk9USCBub3RlcyBzbyBub2JvZHkgcmVhZHMgaXQgYXMgXCJ1bnJlYWRcIi5cbiAgY29uc3Qga25vd24gPSBpbmRleC5rbm93bktleXMuaGFzKG5vcm1hbGlzZWRLZXkpO1xuICBpZiAoIWtub3duKSB7XG4gICAgbm90ZXMucHVzaCh1bmtub3duS2V5Tm90ZShpbmRleCwgbm9ybWFsaXNlZEtleSkpO1xuICAgIGlmIChyZWFkc1JlY29yZGVkKSByZXR1cm4geyAuLi5iYXNlLCBtaXNzaW5nOiAnbmV2ZXItd3JpdHRlbicsIG5vdGVzIH07XG4gIH1cbiAgaWYgKCFyZWFkc1JlY29yZGVkKSBub3Rlcy5wdXNoKHJlYWRzTm90UmVjb3JkZWROb3RlKCkpO1xuXG4gIGNvbnN0IG1heERlcHRoID0gb3B0aW9ucz8ubWF4RGVwdGggPz8gMjA7XG4gIGNvbnN0IG1heE5vZGVzID0gb3B0aW9ucz8ubWF4Tm9kZXMgPz8gMTAwO1xuXG4gIGNvbnN0IG5vZGVzID0gbmV3IE1hcDxzdHJpbmcsIEZvcndhcmROb2RlPigpO1xuICBsZXQgY3JlYXRlZCA9IDA7XG4gIGxldCB0cnVuY2F0ZWRCeURlcHRoID0gZmFsc2U7XG4gIGxldCB0cnVuY2F0ZWRCeU5vZGVzID0gZmFsc2U7XG4gIGxldCBhbnlDb25zZXJ2YXRpdmUgPSBmYWxzZTtcblxuICBjb25zdCBhbmNob3JJZHggPSBsYXN0SW5kZXhCZWZvcmUoaW5kZXgud3JpdGVzQnlLZXkuZ2V0KG5vcm1hbGlzZWRLZXkpLCBvcHRpb25zPy5iZWZvcmUpO1xuICBjb25zdCByb290ID0gbWFrZU5vZGUoY29tbWl0TG9nLCBpbmRleCwgbm9ybWFsaXNlZEtleSwgYW5jaG9ySWR4LCAwKTtcbiAgbm9kZXMuc2V0KG5vZGVLZXkoYW5jaG9ySWR4LCBub3JtYWxpc2VkS2V5KSwgcm9vdCk7XG4gIGNyZWF0ZWQgPSAxO1xuXG4gIGNvbnN0IHF1ZXVlOiBGb3J3YXJkTm9kZVtdID0gW3Jvb3RdO1xuICB3aGlsZSAocXVldWUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IG5vZGUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAvLyBMaXZlIHJhbmdlOiBvcGVuIGJlbG93IHRoZSB3cml0ZSwgQ0xPU0VEIGF0IHRoZSBuZXh0IHdyaXRlIChzZWUgTEFXKS5cbiAgICBjb25zdCBmcm9tID0gbm9kZS5jb21taXRJZHggIT09IHVuZGVmaW5lZCA/IG5vZGUuY29tbWl0SWR4ICsgMSA6IDA7XG4gICAgY29uc3QgcmVhZGVycyA9IGluZGljZXNJblJhbmdlKGluZGV4LnJlYWRzQnlLZXkuZ2V0KG5vZGUua2V5KSwgZnJvbSwgbm9kZS5uZXh0V3JpdGVJZHgpO1xuXG4gICAgaWYgKG5vZGUuZGVwdGggPj0gbWF4RGVwdGgpIHtcbiAgICAgIC8vIE9ubHkgYSBsaWZlIHRoYXQgc3RpbGwgSEFEIHJlYWRlcnMgdG8gZXhwYW5kIGNvdW50cyBhcyBhIGN1dC5cbiAgICAgIGlmIChyZWFkZXJzLmxlbmd0aCA+IDApIHRydW5jYXRlZEJ5RGVwdGggPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCByZWFkZXJJZHggb2YgcmVhZGVycykge1xuICAgICAgY29uc3QgYnVuZGxlID0gY29tbWl0TG9nW3JlYWRlcklkeF07XG4gICAgICBub2RlLnJlYWRzLnB1c2goe1xuICAgICAgICBydW50aW1lU3RhZ2VJZDogYnVuZGxlLnJ1bnRpbWVTdGFnZUlkLFxuICAgICAgICBzdGFnZUlkOiBidW5kbGUuc3RhZ2VJZCxcbiAgICAgICAgc3RhZ2VOYW1lOiBidW5kbGUuc3RhZ2UsXG4gICAgICAgIGNvbW1pdElkeDogcmVhZGVySWR4LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFRoZSByZWFkZXIgSVMgdGhlIHdyaXRlciBvZiBldmVyeXRoaW5nIGl0IGNvbW1pdHRlZCDigJQgZWFjaCB3cml0dGVuXG4gICAgICAvLyBwYXRoIGlzIGEgY2FuZGlkYXRlIGBmZWRgIGVkZ2UuXG4gICAgICBmb3IgKGNvbnN0IHBhdGggb2Ygd3JpdHRlblBhdGhzKGJ1bmRsZSkpIHtcbiAgICAgICAgY29uc3QgZW50cnkgPSBsYXN0VHJhY2VFbnRyeShidW5kbGUsIHBhdGgpO1xuICAgICAgICBsZXQgYmFzaXM6IEZlZEJhc2lzO1xuICAgICAgICBpZiAoZW50cnk/LnJlYWRLZXlzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAvLyBFWEFDVCBib3RoIHdheXM6IHJlY29yZGVkIHByb3ZlbmFuY2UgY2FuIGluY2x1ZGUgb3IgRVhDTFVERS5cbiAgICAgICAgICBpZiAoIWVudHJ5LnJlYWRLZXlzLmluY2x1ZGVzKG5vZGUua2V5KSkgY29udGludWU7XG4gICAgICAgICAgYmFzaXMgPSAncGVyLXdyaXRlJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBiYXNpcyA9ICdzdGFnZSc7XG4gICAgICAgICAgYW55Q29uc2VydmF0aXZlID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlkID0gbm9kZUtleShyZWFkZXJJZHgsIHBhdGgpO1xuICAgICAgICBsZXQgY2hpbGQgPSBub2Rlcy5nZXQoaWQpO1xuICAgICAgICBpZiAoIWNoaWxkKSB7XG4gICAgICAgICAgaWYgKGNyZWF0ZWQgPj0gbWF4Tm9kZXMpIHtcbiAgICAgICAgICAgIHRydW5jYXRlZEJ5Tm9kZXMgPSB0cnVlO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNoaWxkID0gbWFrZU5vZGUoY29tbWl0TG9nLCBpbmRleCwgcGF0aCwgcmVhZGVySWR4LCBub2RlLmRlcHRoICsgMSk7XG4gICAgICAgICAgbm9kZXMuc2V0KGlkLCBjaGlsZCk7XG4gICAgICAgICAgY3JlYXRlZCsrO1xuICAgICAgICAgIHF1ZXVlLnB1c2goY2hpbGQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIE9uZSBlZGdlIHBlciBkaXN0aW5jdCBjaGlsZCBsaWZlIChhIHN0YWdlIHJlYWRzIGEga2V5IG9uY2UpLlxuICAgICAgICBpZiAoIW5vZGUuZmVkRWRnZXMuc29tZSgoZSkgPT4gZS5jaGlsZCA9PT0gY2hpbGQpKSBub2RlLmZlZEVkZ2VzLnB1c2goeyBjaGlsZCwgYmFzaXMgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIEhvbmVzdHkgZW52ZWxvcGUsIGRldGVybWluaXN0aWMgb3JkZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGlmIChyb290Lm9yaWdpbiA9PT0gJ3ByZS1ydW4nKSBub3Rlcy5wdXNoKHByZVJ1bk9yaWdpbk5vdGUobm9ybWFsaXNlZEtleSkpO1xuICBpZiAoYW55Q29uc2VydmF0aXZlKSBub3Rlcy5wdXNoKGNvbnNlcnZhdGl2ZUVkZ2VzTm90ZShub3JtYWxpc2VkS2V5KSk7XG4gIGlmICh0cnVuY2F0ZWRCeURlcHRoIHx8IHRydW5jYXRlZEJ5Tm9kZXMpIHtcbiAgICByb290LnRydW5jYXRlZCA9IHsgYnlEZXB0aDogdHJ1bmNhdGVkQnlEZXB0aCwgYnlOb2RlczogdHJ1bmNhdGVkQnlOb2RlcyB9O1xuICAgIG5vdGVzLnB1c2godHJ1bmNhdGVkTm90ZSh0cnVuY2F0ZWRCeURlcHRoLCB0cnVuY2F0ZWRCeU5vZGVzKSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLmJhc2UsXG4gICAgLi4uKGFuY2hvcklkeCAhPT0gdW5kZWZpbmVkICYmIHsgd3JpdGVyOiBjb21taXRMb2dbYW5jaG9ySWR4XSB9KSxcbiAgICByb290LFxuICAgIG5vdGVzLFxuICB9O1xufVxuIl19
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* slice/ — variable-first
|
|
2
|
+
* slice/ — variable-first slicing, both directions (the triage query layer).
|
|
3
3
|
*
|
|
4
|
-
* One
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* One variable, one contract, every surface — asked identically by UI panels
|
|
5
|
+
* (explainable-ui / lens), LLM triage tools (trace toolpacks), and offline
|
|
6
|
+
* autopsy agents:
|
|
7
|
+
*
|
|
8
|
+
* - BACKWARD — "why is this VARIABLE what it is?" (`sliceForKey`,
|
|
9
|
+
* `arrayProvenance` / `elementProvenance`).
|
|
10
|
+
* - FORWARD — "who READ it, and what did it FEED?" (`forwardSliceForKey`),
|
|
11
|
+
* plus the flat chronological view (`keyTimeline`).
|
|
12
|
+
*
|
|
13
|
+
* See README.md for the algorithms (thin-slice composition, append-fold
|
|
14
|
+
* provenance, live-range walking), the honesty model, serialization rules,
|
|
15
|
+
* and the evolution path.
|
|
9
16
|
*
|
|
10
17
|
* DAG position: memory ← slice (leaf-adjacent; imports memory/ only).
|
|
11
18
|
*/
|
|
12
19
|
export { arrayProvenance, elementProvenance } from './elementProvenance.js';
|
|
20
|
+
export { type ForwardSliceForKeyOptions, forwardSliceForKey } from './forwardSliceForKey.js';
|
|
13
21
|
export { keysReadFromExecutionTree, keysReadFromMap, resolveKeysReadSource } from './keysReadSources.js';
|
|
14
|
-
export {
|
|
22
|
+
export { type KeyTimelineOptions, keyTimeline } from './keyTimeline.js';
|
|
23
|
+
export { formatForwardSlice, formatSlice, formatTimeline, forwardSliceToJSON, sliceToJSON } from './serialize.js';
|
|
15
24
|
export { type SliceForKeyOptions, normaliseStateKey, sliceForKey } from './sliceForKey.js';
|
|
16
|
-
export type { ArrayProvenance, AttributionBasis, ElementBirth, KeysReadSource, MissingProvenanceReason, MissingSliceReason, ReadsCoverage, SliceJSON, StateKey, VariableSlice, } from './types.js';
|
|
25
|
+
export type { ArrayProvenance, AttributionBasis, ElementBirth, FedBasis, ForwardEdge, ForwardNode, ForwardRead, ForwardSlice, ForwardSliceJSON, HonestyNote, HonestyNoteCode, KeyMoment, KeysReadSource, KeyTimeline, MissingProvenanceReason, MissingSliceReason, ReadsCoverage, SliceJSON, StateKey, VariableSlice, } from './types.js';
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* slice/ — variable-first
|
|
2
|
+
* slice/ — variable-first slicing, both directions (the triage query layer).
|
|
3
3
|
*
|
|
4
|
-
* One
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* One variable, one contract, every surface — asked identically by UI panels
|
|
5
|
+
* (explainable-ui / lens), LLM triage tools (trace toolpacks), and offline
|
|
6
|
+
* autopsy agents:
|
|
7
|
+
*
|
|
8
|
+
* - BACKWARD — "why is this VARIABLE what it is?" (`sliceForKey`,
|
|
9
|
+
* `arrayProvenance` / `elementProvenance`).
|
|
10
|
+
* - FORWARD — "who READ it, and what did it FEED?" (`forwardSliceForKey`),
|
|
11
|
+
* plus the flat chronological view (`keyTimeline`).
|
|
12
|
+
*
|
|
13
|
+
* See README.md for the algorithms (thin-slice composition, append-fold
|
|
14
|
+
* provenance, live-range walking), the honesty model, serialization rules,
|
|
15
|
+
* and the evolution path.
|
|
9
16
|
*
|
|
10
17
|
* DAG position: memory ← slice (leaf-adjacent; imports memory/ only).
|
|
11
18
|
*/
|
|
12
19
|
export { arrayProvenance, elementProvenance } from './elementProvenance.js';
|
|
20
|
+
export { forwardSliceForKey } from './forwardSliceForKey.js';
|
|
13
21
|
export { keysReadFromExecutionTree, keysReadFromMap, resolveKeysReadSource } from './keysReadSources.js';
|
|
14
|
-
export {
|
|
22
|
+
export { keyTimeline } from './keyTimeline.js';
|
|
23
|
+
export { formatForwardSlice, formatSlice, formatTimeline, forwardSliceToJSON, sliceToJSON } from './serialize.js';
|
|
15
24
|
export { normaliseStateKey, sliceForKey } from './sliceForKey.js';
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NsaWNlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUVILE9BQU8sRUFBRSxlQUFlLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM1RSxPQUFPLEVBQWtDLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0YsT0FBTyxFQUFFLHlCQUF5QixFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3pHLE9BQU8sRUFBMkIsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDeEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLFdBQVcsRUFBRSxjQUFjLEVBQUUsa0JBQWtCLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEgsT0FBTyxFQUEyQixpQkFBaUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogc2xpY2UvIOKAlCB2YXJpYWJsZS1maXJzdCBzbGljaW5nLCBib3RoIGRpcmVjdGlvbnMgKHRoZSB0cmlhZ2UgcXVlcnkgbGF5ZXIpLlxuICpcbiAqIE9uZSB2YXJpYWJsZSwgb25lIGNvbnRyYWN0LCBldmVyeSBzdXJmYWNlIOKAlCBhc2tlZCBpZGVudGljYWxseSBieSBVSSBwYW5lbHNcbiAqIChleHBsYWluYWJsZS11aSAvIGxlbnMpLCBMTE0gdHJpYWdlIHRvb2xzICh0cmFjZSB0b29scGFja3MpLCBhbmQgb2ZmbGluZVxuICogYXV0b3BzeSBhZ2VudHM6XG4gKlxuICogLSBCQUNLV0FSRCDigJQgXCJ3aHkgaXMgdGhpcyBWQVJJQUJMRSB3aGF0IGl0IGlzP1wiIChgc2xpY2VGb3JLZXlgLFxuICogICBgYXJyYXlQcm92ZW5hbmNlYCAvIGBlbGVtZW50UHJvdmVuYW5jZWApLlxuICogLSBGT1JXQVJEIOKAlCBcIndobyBSRUFEIGl0LCBhbmQgd2hhdCBkaWQgaXQgRkVFRD9cIiAoYGZvcndhcmRTbGljZUZvcktleWApLFxuICogICBwbHVzIHRoZSBmbGF0IGNocm9ub2xvZ2ljYWwgdmlldyAoYGtleVRpbWVsaW5lYCkuXG4gKlxuICogU2VlIFJFQURNRS5tZCBmb3IgdGhlIGFsZ29yaXRobXMgKHRoaW4tc2xpY2UgY29tcG9zaXRpb24sIGFwcGVuZC1mb2xkXG4gKiBwcm92ZW5hbmNlLCBsaXZlLXJhbmdlIHdhbGtpbmcpLCB0aGUgaG9uZXN0eSBtb2RlbCwgc2VyaWFsaXphdGlvbiBydWxlcyxcbiAqIGFuZCB0aGUgZXZvbHV0aW9uIHBhdGguXG4gKlxuICogREFHIHBvc2l0aW9uOiBtZW1vcnkg4oaQIHNsaWNlIChsZWFmLWFkamFjZW50OyBpbXBvcnRzIG1lbW9yeS8gb25seSkuXG4gKi9cblxuZXhwb3J0IHsgYXJyYXlQcm92ZW5hbmNlLCBlbGVtZW50UHJvdmVuYW5jZSB9IGZyb20gJy4vZWxlbWVudFByb3ZlbmFuY2UuanMnO1xuZXhwb3J0IHsgdHlwZSBGb3J3YXJkU2xpY2VGb3JLZXlPcHRpb25zLCBmb3J3YXJkU2xpY2VGb3JLZXkgfSBmcm9tICcuL2ZvcndhcmRTbGljZUZvcktleS5qcyc7XG5leHBvcnQgeyBrZXlzUmVhZEZyb21FeGVjdXRpb25UcmVlLCBrZXlzUmVhZEZyb21NYXAsIHJlc29sdmVLZXlzUmVhZFNvdXJjZSB9IGZyb20gJy4va2V5c1JlYWRTb3VyY2VzLmpzJztcbmV4cG9ydCB7IHR5cGUgS2V5VGltZWxpbmVPcHRpb25zLCBrZXlUaW1lbGluZSB9IGZyb20gJy4va2V5VGltZWxpbmUuanMnO1xuZXhwb3J0IHsgZm9ybWF0Rm9yd2FyZFNsaWNlLCBmb3JtYXRTbGljZSwgZm9ybWF0VGltZWxpbmUsIGZvcndhcmRTbGljZVRvSlNPTiwgc2xpY2VUb0pTT04gfSBmcm9tICcuL3NlcmlhbGl6ZS5qcyc7XG5leHBvcnQgeyB0eXBlIFNsaWNlRm9yS2V5T3B0aW9ucywgbm9ybWFsaXNlU3RhdGVLZXksIHNsaWNlRm9yS2V5IH0gZnJvbSAnLi9zbGljZUZvcktleS5qcyc7XG5leHBvcnQgdHlwZSB7XG4gIEFycmF5UHJvdmVuYW5jZSxcbiAgQXR0cmlidXRpb25CYXNpcyxcbiAgRWxlbWVudEJpcnRoLFxuICBGZWRCYXNpcyxcbiAgRm9yd2FyZEVkZ2UsXG4gIEZvcndhcmROb2RlLFxuICBGb3J3YXJkUmVhZCxcbiAgRm9yd2FyZFNsaWNlLFxuICBGb3J3YXJkU2xpY2VKU09OLFxuICBIb25lc3R5Tm90ZSxcbiAgSG9uZXN0eU5vdGVDb2RlLFxuICBLZXlNb21lbnQsXG4gIEtleXNSZWFkU291cmNlLFxuICBLZXlUaW1lbGluZSxcbiAgTWlzc2luZ1Byb3ZlbmFuY2VSZWFzb24sXG4gIE1pc3NpbmdTbGljZVJlYXNvbixcbiAgUmVhZHNDb3ZlcmFnZSxcbiAgU2xpY2VKU09OLFxuICBTdGF0ZUtleSxcbiAgVmFyaWFibGVTbGljZSxcbn0gZnJvbSAnLi90eXBlcy5qcyc7XG4iXX0=
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slice/keyIndex.ts — the one pass over the log both FORWARD queries share.
|
|
3
|
+
*
|
|
4
|
+
* WHY it exists: a backward slice only ever asks "who wrote key k before
|
|
5
|
+
* idx i" — `findLastWriter` answers that with a backward scan. A forward
|
|
6
|
+
* query asks the opposite, and the opposite is not symmetric: reads are NOT
|
|
7
|
+
* in the commit log, and `KeysReadSource` is a LOOKUP (runtimeStageId →
|
|
8
|
+
* keys), not an enumerable collection. So "who read k" cannot be looked up —
|
|
9
|
+
* it has to be inverted.
|
|
10
|
+
*
|
|
11
|
+
* THE INVERSION (and the law it rests on): the engine commits exactly ONE
|
|
12
|
+
* bundle per executed stage, so the commit log IS the list of execution
|
|
13
|
+
* steps. Calling the reads lookup once per bundle turns the strategy into a
|
|
14
|
+
* key → [commit indices that read it] index — and gives every read moment a
|
|
15
|
+
* commit position, the join key the whole library is addressed by.
|
|
16
|
+
*
|
|
17
|
+
* Consequence worth stating (documented, not silently absorbed): a reads
|
|
18
|
+
* provider naming a step that has no commit in THIS log contributes nothing.
|
|
19
|
+
* That is the same log↔reads pairing law the backward side has — a subflow
|
|
20
|
+
* runs in an isolated runtime, so its log and its tree must come from the
|
|
21
|
+
* same scope (see README.md § Subflow boundaries).
|
|
22
|
+
*
|
|
23
|
+
* Cost: one lookup call per bundle, once per query — O(N + total read keys).
|
|
24
|
+
* Both forward queries then run off sorted index arrays.
|
|
25
|
+
*
|
|
26
|
+
* DAG position: internal to slice/ (not exported from the barrel).
|
|
27
|
+
*/
|
|
28
|
+
import type { KeysReadLookup } from '../memory/backtrack.js';
|
|
29
|
+
import type { CommitBundle, TraceEntry } from '../memory/types.js';
|
|
30
|
+
import type { HonestyNote } from './types.js';
|
|
31
|
+
/** How many known keys an unknown-key refusal lists before it says "+N more". */
|
|
32
|
+
export declare const KNOWN_KEYS_LISTED = 10;
|
|
33
|
+
/** The inverted view of one commit log + its reads provider. */
|
|
34
|
+
export interface KeyIndex {
|
|
35
|
+
/** key → commit ARRAY positions that WROTE it, ascending. */
|
|
36
|
+
writesByKey: Map<string, number[]>;
|
|
37
|
+
/** key → commit ARRAY positions whose stage READ it, ascending. */
|
|
38
|
+
readsByKey: Map<string, number[]>;
|
|
39
|
+
/** Every key this log knows: written ∪ recorded-read. */
|
|
40
|
+
knownKeys: Set<string>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build the index. Indices go in ascending order by construction (we iterate
|
|
44
|
+
* the log forwards), which is what lets every range query below be a pair of
|
|
45
|
+
* binary searches instead of a scan.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildKeyIndex(commitLog: CommitBundle[], lookup: KeysReadLookup): KeyIndex;
|
|
48
|
+
/**
|
|
49
|
+
* LAW — an unknown key is NAMED as unknown; it never renders as "no history".
|
|
50
|
+
*
|
|
51
|
+
* The failure this prevents: `forwardSliceForKey(log, 'recipId')` (typo) must
|
|
52
|
+
* not come back looking like a real variable that nothing happened to. The
|
|
53
|
+
* answer says so out loud AND lists the keys the log does know — bounded, so
|
|
54
|
+
* a 400-key agent state is a hint, not a wall.
|
|
55
|
+
*
|
|
56
|
+
* Why a NOTE and not a throw: the module's absence convention is a RESULT,
|
|
57
|
+
* not an exception (`VariableSlice.missing`) — one absence vocabulary across
|
|
58
|
+
* both doors. The loudness comes from the note + `missing: 'never-written'`,
|
|
59
|
+
* not from a stack trace a triage tool would have to catch.
|
|
60
|
+
*/
|
|
61
|
+
export declare function unknownKeyNote(index: KeyIndex, key: string): HonestyNote;
|
|
62
|
+
/**
|
|
63
|
+
* Does this log carry ANY recorded read? The provider-agnostic version of
|
|
64
|
+
* `ReadsCoverage.stepsWithReads > 0` (map / custom-fn strategies carry no
|
|
65
|
+
* coverage), and the switch that decides whether "nobody read it" is a
|
|
66
|
+
* FINDING or a BLIND SPOT.
|
|
67
|
+
*/
|
|
68
|
+
export declare function hasRecordedReads(index: KeyIndex): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Ascending indices in the INCLUSIVE range [from, to]. `to === undefined`
|
|
71
|
+
* means "to the end of the log".
|
|
72
|
+
*/
|
|
73
|
+
export declare function indicesInRange(sorted: number[] | undefined, from: number, to?: number): number[];
|
|
74
|
+
/** The largest index in the ascending array that is < `before`, or undefined. */
|
|
75
|
+
export declare function lastIndexBefore(sorted: number[] | undefined, before?: number): number | undefined;
|
|
76
|
+
/** The smallest index in the ascending array that is > `after`, or undefined. */
|
|
77
|
+
export declare function firstIndexAfter(sorted: number[] | undefined, after: number): number | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The LAST trace entry for `path` in a bundle — the one that decides both the
|
|
80
|
+
* committed verb and (under the writeProvenance dial) the widest read prefix.
|
|
81
|
+
* Full mode can record several ops on one path in one commit; read prefixes
|
|
82
|
+
* only grow during a stage, so the last entry is the honest one to attribute
|
|
83
|
+
* with.
|
|
84
|
+
*/
|
|
85
|
+
export declare function lastTraceEntry(bundle: CommitBundle, path: string): TraceEntry | undefined;
|
|
86
|
+
/** The `readTracking: 'off'` signature — see the HonestyNoteCode docs. */
|
|
87
|
+
export declare function readsNotRecordedNote(): HonestyNote;
|
|
88
|
+
/** The value predates every write this log can see. */
|
|
89
|
+
export declare function preRunOriginNote(key: string): HonestyNote;
|
|
90
|
+
/** At least one fed edge rests on stage-level co-occurrence only. */
|
|
91
|
+
export declare function conservativeEdgesNote(key: string): HonestyNote;
|
|
92
|
+
/** A budget cut the walk — stated, never silent. */
|
|
93
|
+
export declare function truncatedNote(byDepth: boolean, byNodes: boolean): HonestyNote;
|
|
94
|
+
/** Distinct written paths of a bundle, in first-touch order. */
|
|
95
|
+
export declare function writtenPaths(bundle: CommitBundle): string[];
|