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.
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yd2FyZFNsaWNlRm9yS2V5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zbGljZS9mb3J3YXJkU2xpY2VGb3JLZXkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpREc7QUFJSCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDM0MsT0FBTyxFQUVMLGFBQWEsRUFDYixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsZUFBZSxFQUNmLGNBQWMsRUFDZCxnQkFBZ0IsRUFDaEIsb0JBQW9CLEVBQ3BCLGFBQWEsRUFDYixjQUFjLEVBQ2QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzdELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBb0JyRCx1RUFBdUU7QUFDdkUsU0FBUyxPQUFPLENBQUMsU0FBNkIsRUFBRSxHQUFXO0lBQ3pELE9BQU8sR0FBRyxTQUFTLElBQUksU0FBUyxHQUFHLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQztBQUNuRCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsUUFBUSxDQUNmLFNBQXlCLEVBQ3pCLEtBQWUsRUFDZixHQUFXLEVBQ1gsUUFBNEIsRUFDNUIsS0FBYTtJQUViLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzNCLE1BQU0sVUFBVSxHQUFHLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9CLE9BQU87WUFDTCxHQUFHO1lBQ0gsTUFBTSxFQUFFLFNBQVM7WUFDakIsR0FBRyxDQUFDLFVBQVUsS0FBSyxTQUFTLElBQUksRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLENBQUM7WUFDN0QsS0FBSztZQUNMLEtBQUssRUFBRSxFQUFFO1lBQ1QsUUFBUSxFQUFFLEVBQUU7U0FDYixDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNuQyxNQUFNLEtBQUssR0FBRyxjQUFjLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sSUFBSSxHQUFHLGVBQWUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDL0MsT0FBTztRQUNMLEdBQUc7UUFDSCxNQUFNLEVBQUUsT0FBTztRQUNmLGNBQWMsRUFBRSxNQUFNLENBQUMsY0FBYztRQUNyQyxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87UUFDdkIsU0FBUyxFQUFFLE1BQU0sQ0FBQyxLQUFLO1FBQ3ZCLFNBQVMsRUFBRSxRQUFRO1FBQ25CLEdBQUcsQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoRCxHQUFHLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUNqRCxLQUFLO1FBQ0wsS0FBSyxFQUFFLEVBQUU7UUFDVCxRQUFRLEVBQUUsRUFBRTtRQUNaLGtFQUFrRTtRQUNsRSxtREFBbUQ7UUFDbkQsR0FBRyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsS0FBSyxTQUFTO1lBQ3ZDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUM7S0FDeEYsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxTQUF5QixFQUN6QixHQUFhLEVBQ2IsUUFBeUMsRUFDekMsT0FBbUM7SUFFbkMsTUFBTSxNQUFNLEdBQUcscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0MsTUFBTSxhQUFhLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0MsTUFBTSxJQUFJLEdBQTRFO1FBQ3BGLEdBQUcsRUFBRSxhQUFhO1FBQ2xCLEdBQUcsQ0FBQyxPQUFPLEVBQUUsTUFBTSxLQUFLLFNBQVMsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDaEUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxJQUFJO1FBQ3pCLEdBQUcsQ0FBQyxNQUFNLENBQUMsUUFBUSxLQUFLLFNBQVMsSUFBSSxFQUFFLGFBQWEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7S0FDekUsQ0FBQztJQUVGLElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBRWhGLE1BQU0sS0FBSyxHQUFHLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlDLE1BQU0sS0FBSyxHQUFrQixFQUFFLENBQUM7SUFFaEMsMEVBQTBFO0lBQzFFLDBFQUEwRTtJQUMxRSxvRUFBb0U7SUFDcEUsMkVBQTJFO0lBQzNFLHlFQUF5RTtJQUN6RSx1RUFBdUU7SUFDdkUsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7UUFDakQsSUFBSSxhQUFhO1lBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDekUsQ0FBQztJQUNELElBQUksQ0FBQyxhQUFhO1FBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDLENBQUM7SUFFdkQsTUFBTSxRQUFRLEdBQUcsT0FBTyxFQUFFLFFBQVEsSUFBSSxFQUFFLENBQUM7SUFDekMsTUFBTSxRQUFRLEdBQUcsT0FBTyxFQUFFLFFBQVEsSUFBSSxHQUFHLENBQUM7SUFFMUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFDN0MsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLElBQUksZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQzdCLElBQUksZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQzdCLElBQUksZUFBZSxHQUFHLEtBQUssQ0FBQztJQUU1QixNQUFNLFNBQVMsR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3pGLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDckUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLGFBQWEsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ25ELE9BQU8sR0FBRyxDQUFDLENBQUM7SUFFWixNQUFNLEtBQUssR0FBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQyxPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDeEIsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLEtBQUssRUFBRyxDQUFDO1FBQzVCLHdFQUF3RTtRQUN4RSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRSxNQUFNLE9BQU8sR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFeEYsSUFBSSxJQUFJLENBQUMsS0FBSyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQzNCLGdFQUFnRTtZQUNoRSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztnQkFBRSxnQkFBZ0IsR0FBRyxJQUFJLENBQUM7WUFDaEQsU0FBUztRQUNYLENBQUM7UUFFRCxLQUFLLE1BQU0sU0FBUyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ2hDLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNwQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDZCxjQUFjLEVBQUUsTUFBTSxDQUFDLGNBQWM7Z0JBQ3JDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztnQkFDdkIsU0FBUyxFQUFFLE1BQU0sQ0FBQyxLQUFLO2dCQUN2QixTQUFTLEVBQUUsU0FBUzthQUNyQixDQUFDLENBQUM7WUFFSCxxRUFBcUU7WUFDckUsa0NBQWtDO1lBQ2xDLEtBQUssTUFBTSxJQUFJLElBQUksWUFBWSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQ3hDLE1BQU0sS0FBSyxHQUFHLGNBQWMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQzNDLElBQUksS0FBZSxDQUFDO2dCQUNwQixJQUFJLEtBQUssRUFBRSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ2xDLCtEQUErRDtvQkFDL0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7d0JBQUUsU0FBUztvQkFDakQsS0FBSyxHQUFHLFdBQVcsQ0FBQztnQkFDdEIsQ0FBQztxQkFBTSxDQUFDO29CQUNOLEtBQUssR0FBRyxPQUFPLENBQUM7b0JBQ2hCLGVBQWUsR0FBRyxJQUFJLENBQUM7Z0JBQ3pCLENBQUM7Z0JBRUQsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFDcEMsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDMUIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNYLElBQUksT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO3dCQUN4QixnQkFBZ0IsR0FBRyxJQUFJLENBQUM7d0JBQ3hCLFNBQVM7b0JBQ1gsQ0FBQztvQkFDRCxLQUFLLEdBQUcsUUFBUSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUNwRSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztvQkFDckIsT0FBTyxFQUFFLENBQUM7b0JBQ1YsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDcEIsQ0FBQztnQkFDRCwrREFBK0Q7Z0JBQy9ELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssS0FBSyxLQUFLLENBQUM7b0JBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUMxRixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCx5RUFBeUU7SUFDekUsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLFNBQVM7UUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDM0UsSUFBSSxlQUFlO1FBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLElBQUksZ0JBQWdCLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztRQUN6QyxJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDO1FBQzFFLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRUQsT0FBTztRQUNMLEdBQUcsSUFBSTtRQUNQLEdBQUcsQ0FBQyxTQUFTLEtBQUssU0FBUyxJQUFJLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2hFLElBQUk7UUFDSixLQUFLO0tBQ04sQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIHNsaWNlL2ZvcndhcmRTbGljZUZvcktleS50cyDigJQgdGhlIEZPUldBUkQgaGFsZiBvZiB2YXJpYWJsZS1maXJzdCBzbGljaW5nLlxuICpcbiAqIGBzbGljZUZvcktleWAgYW5zd2VycyBcIndoeSBpcyBga2V5YCB3aGF0IGl0IGlzP1wiIGJ5IHdhbGtpbmcgYmFja3dhcmQgZnJvbVxuICogdGhlIHZhbHVlIHRvIGl0cyBjYXVzZXMuIFRoaXMgZmlsZSBhbnN3ZXJzIHRoZSBvcHBvc2l0ZSBxdWVzdGlvbiwgd2hpY2ggbm9cbiAqIHF1ZXJ5IGFuc3dlcmVkIGJlZm9yZTogKipcIndobyBSRUFEIHRoaXMgdmFsdWUsIGFuZCB3aGF0IGRpZCBpdCBGRUVEP1wiKipcbiAqICh0aGUgcHJvZHVjdGlvbiBzaGFwZTogKndobyByZWFkIGByZWNpcGVJZGAsIGFuZCB3aGF0IGRpZCBpdCBmZWVkPyog4oCUIG9uZVxuICogcXVlcnksIG5vdCBhIG1hbnVhbCBzY2FuIG9mIGEgdHJhY2Ugdmlld2VyKS5cbiAqXG4gKiAjIyBUaGUgYWxnb3JpdGhtOiBMSVZFIFJBTkdFUywgbm90IHN0ZXBzXG4gKlxuICogQSBiYWNrd2FyZCBzbGljZSBob3BzIHdyaXRlcuKGkndyaXRlci4gRm9yd2FyZCwgdGhlIHVuaXQgaXMgYSB2YWx1ZSdzIExJRkU6XG4gKlxuICogMS4gQW5jaG9yIGF0IGEgd3JpdGUgb2YgYGtleWAg4oCUIHRoZSBTQU1FIGFuY2hvciBpZGlvbSBhcyBgc2xpY2VGb3JLZXlgXG4gKiAgICAodGhlIGxhc3Qgd3JpdGVyLCBvciB0aGUgbGFzdCB3cml0ZXIgYmVmb3JlIGBiZWZvcmVgKS5cbiAqIDIuIFRoYXQgdmFsdWUgbGl2ZXMgdW50aWwgdGhlIGtleSdzIE5FWFQgd3JpdGUgKGBuZXh0V3JpdGVJZHhgKS4gRXZlcnlcbiAqICAgIHN0YWdlIHRoYXQgUkVBRCBga2V5YCBpbnNpZGUgdGhhdCB3aW5kb3cgc2F3IFRISVMgdmFsdWUg4oCUIGEgYHJlYWRgLlxuICogMy4gQSByZWFkaW5nIHN0YWdlIHRoYXQgYWxzbyBXUk9URSBzb21ldGhpbmcgY2FycmllZCB0aGUgdmFsdWUgb253YXJkIOKAlFxuICogICAgYSBgZmVkYCBlZGdlIHRvIHRoYXQgd3JpdGUsIHdoaWNoIGlzIGl0c2VsZiB0aGUgc3RhcnQgb2YgYSBuZXcgbGlmZS5cbiAqIDQuIERlc2NlbmQgaW50byBmZWQgbGl2ZXMgYnJlYWR0aC1maXJzdCAodmlzaXRlZC1zZXQgZ3VhcmRlZCwgYnVkZ2V0ZWQpLlxuICpcbiAqICMjIyBMQVcg4oCUIHRoZSBsaXZlIHJhbmdlIGlzIGAod3JpdGVJZHgsIG5leHRXcml0ZUlkeF1gXG4gKlxuICogT3BlbiBhdCB0aGUgYm90dG9tLCBDTE9TRUQgYXQgdGhlIHRvcCwgYW5kIGJvdGggZW5kcyBmb2xsb3cgZnJvbSB0aGVcbiAqIGVuZ2luZSdzIGV2ZW50IG9yZGVyIChgb25SZWFkYCBmaXJlcyBQUkUtY29tbWl0IOKAlCBzZWUgQ0xBVURFLm1kKTpcbiAqIC0gYSByZWFkIGJ5IHRoZSB3cml0aW5nIHN0YWdlIGl0c2VsZiAoYHJlYWRJZHggPT09IHdyaXRlSWR4YCkgc2F3IHRoZVxuICogICBQUkVWSU9VUyB2YWx1ZTogcmVhZC1tb2RpZnktd3JpdGUgcmVhZHMgYmVsb25nIHRvIHRoZSBwcmV2aW91cyBsaWZlO1xuICogLSBhIHJlYWQgYnkgdGhlIE9WRVJXUklUSU5HIHN0YWdlIChgcmVhZElkeCA9PT0gbmV4dFdyaXRlSWR4YCkgYWxzbyBmaXJlZFxuICogICBiZWZvcmUgaXRzIGNvbW1pdCwgc28gaXQgc3RpbGwgc2F3IFRISVMgdmFsdWUuXG4gKiBBIHJlYWQgYWZ0ZXIgdGhhdCBjb21taXQgYXR0cmlidXRlcyB0byB0aGUgTkVXIHdyaXRlLCBuZXZlciB0aGUgb2xkIG9uZS5cbiAqIChHcmFudWxhcml0eSBsaW1pdCwgc3RhdGVkIGJlY2F1c2UgaXQgY2Fubm90IGJlIHNlZW46IGEgc3RhZ2UgdGhhdCB3cml0ZXNcbiAqIGBrZXlgIGFuZCB0aGVuIHJlLXJlYWRzIGl0IHdpdGhpbiB0aGUgU0FNRSBzdGFnZSByZWFkIGl0cyBvd24gdmFsdWU7IGF0XG4gKiBjb21taXQtaW5kZXggcmVzb2x1dGlvbiB0aGF0IHJlYWQgaXMgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSB0aGUgb25lIHRoYXRcbiAqIG9wZW5lZCB0aGUgc3RhZ2UuKVxuICpcbiAqICMjIyBMQVcg4oCUIGEgYGZlZGAgZWRnZSBpcyBFWEFDVCBvbmx5IHVuZGVyIHJlY29yZGVkIHJlYWQgcHJvdmVuYW5jZVxuICpcbiAqIFdpdGggYHdyaXRlUHJvdmVuYW5jZTogJ3JlYWRzLXByZWZpeCdgIG9uLCB0aGUgY2hpbGQgd3JpdGUnc1xuICogYFRyYWNlRW50cnkucmVhZEtleXNgIG5hbWVzIHRoZSBrZXlzIHJlYWQgYmVmb3JlIGl0OiB0aGlzIGtleSBJTiB0aGF0IGxpc3RcbiAqIGlzIGFuIGV4YWN0IGVkZ2UgKGBiYXNpczogJ3Blci13cml0ZSdgKSwgYW5kIHRoaXMga2V5IEFCU0VOVCBmcm9tIGl0IGlzIGFuXG4gKiBleGFjdCAqZXhjbHVzaW9uKiDigJQgbm8gZWRnZSBhdCBhbGwuIFdpdGggdGhlIGRpYWwgb2ZmIHRoZXJlIGlzIG5vIHN1Y2hcbiAqIGV2aWRlbmNlLCBvbmx5IFwidGhlIHN0YWdlIHJlYWQgdGhpcyBhbmQgd3JvdGUgdGhhdFwiOiB0aGUgZWRnZSBpcyBzdGFtcGVkXG4gKiBgYmFzaXM6ICdzdGFnZSdgIGFuZCB0aGUgc2xpY2UgY2FycmllcyBhIGAnY29uc2VydmF0aXZlLWZlZC1lZGdlcydgIG5vdGUuXG4gKiBBIGNvbnNlcnZhdGl2ZSBlZGdlIGlzIG5ldmVyIHByZXNlbnRlZCBhcyBhbiBleGFjdCBvbmUuXG4gKlxuICogQnVkZ2V0cyBtaXJyb3IgYGNhdXNhbENoYWluYCdzIChtYXhEZXB0aCAyMCwgbWF4Tm9kZXMgMTAwKSBhbmQgYSBjdXQgaXNcbiAqIFNUQVRFRCDigJQgYHJvb3QudHJ1bmNhdGVkYCBwbHVzIGEgYCd0cnVuY2F0ZWQnYCBub3RlLlxuICpcbiAqIERBRyBwb3NpdGlvbjogbWVtb3J5IOKGkCBzbGljZS4gSW1wb3J0cyBtZW1vcnkvIG9ubHkgKHNlZSBSRUFETUUubWQpLlxuICovXG5cbmltcG9ydCB0eXBlIHsgS2V5c1JlYWRMb29rdXAgfSBmcm9tICcuLi9tZW1vcnkvYmFja3RyYWNrLmpzJztcbmltcG9ydCB0eXBlIHsgQ29tbWl0QnVuZGxlIH0gZnJvbSAnLi4vbWVtb3J5L3R5cGVzLmpzJztcbmltcG9ydCB7IERFTElNIH0gZnJvbSAnLi4vbWVtb3J5L3V0aWxzLmpzJztcbmltcG9ydCB7XG4gIHR5cGUgS2V5SW5kZXgsXG4gIGJ1aWxkS2V5SW5kZXgsXG4gIGNvbnNlcnZhdGl2ZUVkZ2VzTm90ZSxcbiAgZmlyc3RJbmRleEFmdGVyLFxuICBoYXNSZWNvcmRlZFJlYWRzLFxuICBpbmRpY2VzSW5SYW5nZSxcbiAgbGFzdEluZGV4QmVmb3JlLFxuICBsYXN0VHJhY2VFbnRyeSxcbiAgcHJlUnVuT3JpZ2luTm90ZSxcbiAgcmVhZHNOb3RSZWNvcmRlZE5vdGUsXG4gIHRydW5jYXRlZE5vdGUsXG4gIHVua25vd25LZXlOb3RlLFxuICB3cml0dGVuUGF0aHMsXG59IGZyb20gJy4va2V5SW5kZXguanMnO1xuaW1wb3J0IHsgcmVzb2x2ZUtleXNSZWFkU291cmNlIH0gZnJvbSAnLi9rZXlzUmVhZFNvdXJjZXMuanMnO1xuaW1wb3J0IHsgbm9ybWFsaXNlU3RhdGVLZXkgfSBmcm9tICcuL3NsaWNlRm9yS2V5LmpzJztcbmltcG9ydCB0eXBlIHsgRmVkQmFzaXMsIEZvcndhcmROb2RlLCBGb3J3YXJkU2xpY2UsIEhvbmVzdHlOb3RlLCBLZXlzUmVhZFNvdXJjZSwgU3RhdGVLZXkgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqIE9wdGlvbnMgZm9yIHtAbGluayBmb3J3YXJkU2xpY2VGb3JLZXl9IOKAlCBhbmNob3JpbmcgcGx1cyB3YWxrIGJ1ZGdldHMuICovXG5leHBvcnQgaW50ZXJmYWNlIEZvcndhcmRTbGljZUZvcktleU9wdGlvbnMge1xuICAvKipcbiAgICogRXhjbHVzaXZlIGNvbW1pdC1hcnJheS1pbmRleCB1cHBlciBib3VuZCBmb3IgdGhlIEFOQ0hPUiBzZWFyY2g6IGZvbGxvd1xuICAgKiB0aGUgdmFsdWUgYXMgaXQgc3Rvb2QgQkVGT1JFIHRoaXMgaWR4LiBTYW1lIGNvbnRyYWN0IGFzXG4gICAqIGBzbGljZUZvcktleWAncyBgYmVmb3JlYCAvIGBmaW5kTGFzdFdyaXRlcmAncyBgYmVmb3JlSWR4YC5cbiAgICpcbiAgICogSXQgYm91bmRzIHRoZSBhbmNob3IgT05MWSDigJQgdGhlIHdhbGsgdGhlbiBydW5zIGZvcndhcmQgcGFzdCBpdCwgYmVjYXVzZVxuICAgKiBcIndoYXQgZGlkIHRoZSB2YWx1ZSBhdCBzdGVwIDEyIGdvIG9uIHRvIGZlZWQ/XCIgaXMgdGhlIHdob2xlIHF1ZXN0aW9uLlxuICAgKi9cbiAgYmVmb3JlPzogbnVtYmVyO1xuICAvKiogTWF4aW11bSBCRlMgZGVwdGggaW4gdmFsdWUtbGl2ZXMgKGRlZmF1bHQ6IDIwIOKAlCBjYXVzYWxDaGFpbidzKS4gKi9cbiAgbWF4RGVwdGg/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIHRvdGFsIG5vZGVzIChkZWZhdWx0OiAxMDAg4oCUIGNhdXNhbENoYWluJ3MpLiAqL1xuICBtYXhOb2Rlcz86IG51bWJlcjtcbn1cblxuLyoqIElkZW50aXR5IG9mIG9uZSB2YWx1ZSBsaWZlOiAod3JpdGUgcG9zaXRpb24sIGtleSkuIE5ldmVyIHBhcnNlZC4gKi9cbmZ1bmN0aW9uIG5vZGVLZXkoY29tbWl0SWR4OiBudW1iZXIgfCB1bmRlZmluZWQsIGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2NvbW1pdElkeCA/PyAncHJlLXJ1bid9JHtERUxJTX0ke2tleX1gO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBub2RlIGZvciBPTkUgdmFsdWUgbGlmZS4gYHdyaXRlSWR4ID09PSB1bmRlZmluZWRgIGlzIHRoZSBwcmUtcnVuXG4gKiBvcmlnaW46IHRoZSB2YWx1ZSB3YXMgYWxyZWFkeSB0aGVyZSBiZWZvcmUgdGhlIGxvZydzIGZpcnN0IHdyaXRlIG9mIHRoZVxuICoga2V5LCBzbyB0aGUgd3JpdGVyIGlkZW50aXR5IGZpZWxkcyBzdGF5IEFCU0VOVCByYXRoZXIgdGhhbiBmYWJyaWNhdGVkLlxuICovXG5mdW5jdGlvbiBtYWtlTm9kZShcbiAgY29tbWl0TG9nOiBDb21taXRCdW5kbGVbXSxcbiAgaW5kZXg6IEtleUluZGV4LFxuICBrZXk6IHN0cmluZyxcbiAgd3JpdGVJZHg6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZGVwdGg6IG51bWJlcixcbik6IEZvcndhcmROb2RlIHtcbiAgY29uc3Qgd3JpdGVzID0gaW5kZXgud3JpdGVzQnlLZXkuZ2V0KGtleSk7XG4gIGlmICh3cml0ZUlkeCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZmlyc3RXcml0ZSA9IHdyaXRlcz8uWzBdO1xuICAgIHJldHVybiB7XG4gICAgICBrZXksXG4gICAgICBvcmlnaW46ICdwcmUtcnVuJyxcbiAgICAgIC4uLihmaXJzdFdyaXRlICE9PSB1bmRlZmluZWQgJiYgeyBuZXh0V3JpdGVJZHg6IGZpcnN0V3JpdGUgfSksXG4gICAgICBkZXB0aCxcbiAgICAgIHJlYWRzOiBbXSxcbiAgICAgIGZlZEVkZ2VzOiBbXSxcbiAgICB9O1xuICB9XG4gIGNvbnN0IGJ1bmRsZSA9IGNvbW1pdExvZ1t3cml0ZUlkeF07XG4gIGNvbnN0IGVudHJ5ID0gbGFzdFRyYWNlRW50cnkoYnVuZGxlLCBrZXkpO1xuICBjb25zdCBuZXh0ID0gZmlyc3RJbmRleEFmdGVyKHdyaXRlcywgd3JpdGVJZHgpO1xuICByZXR1cm4ge1xuICAgIGtleSxcbiAgICBvcmlnaW46ICd3cml0ZScsXG4gICAgcnVudGltZVN0YWdlSWQ6IGJ1bmRsZS5ydW50aW1lU3RhZ2VJZCxcbiAgICBzdGFnZUlkOiBidW5kbGUuc3RhZ2VJZCxcbiAgICBzdGFnZU5hbWU6IGJ1bmRsZS5zdGFnZSxcbiAgICBjb21taXRJZHg6IHdyaXRlSWR4LFxuICAgIC4uLihlbnRyeSAhPT0gdW5kZWZpbmVkICYmIHsgdmVyYjogZW50cnkudmVyYiB9KSxcbiAgICAuLi4obmV4dCAhPT0gdW5kZWZpbmVkICYmIHsgbmV4dFdyaXRlSWR4OiBuZXh0IH0pLFxuICAgIGRlcHRoLFxuICAgIHJlYWRzOiBbXSxcbiAgICBmZWRFZGdlczogW10sXG4gICAgLy8gVW50cmFja2VkLXJlYWQgaG9uZXN0eSByaWRlcyB0aHJvdWdoIGZyb20gdGhlIGJ1bmRsZSBleGFjdGx5IGFzXG4gICAgLy8gY2F1c2FsQ2hhaW4gc3RhbXBzIENhdXNhbE5vZGUuaW5jb21wbGV0ZVNvdXJjZXMuXG4gICAgLi4uKGJ1bmRsZS51bnRyYWNrZWRTb3VyY2VzICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIGJ1bmRsZS51bnRyYWNrZWRTb3VyY2VzLmxlbmd0aCA+IDAgJiYgeyBpbmNvbXBsZXRlU291cmNlczogYnVuZGxlLnVudHJhY2tlZFNvdXJjZXMgfSksXG4gIH07XG59XG5cbi8qKlxuICogRm9yd2FyZCBzbGljZSBmb3Igb25lIHN0YXRlIGtleTogd2hvIHJlYWQgdGhpcyB2YWx1ZSwgYW5kIHdoYXQgZGlkIGl0IGZlZWQ/XG4gKlxuICogQHBhcmFtIGNvbW1pdExvZyBPcmRlcmVkIGNvbW1pdCBidW5kbGVzIOKAlCBgZ2V0U25hcHNob3QoKS5jb21taXRMb2dgLlxuICogQHBhcmFtIGtleSBBIHtAbGluayBTdGF0ZUtleX06IHRoZSBwbGFpbiBrZXkgc3RyaW5nLCBvciBhIHBhdGggYXJyYXlcbiAqICAgKG5vcm1hbGlzZWQgdGhyb3VnaCB0aGUgU0FNRSBgbm9ybWFsaXNlU3RhdGVLZXlgIHRoZSBiYWNrd2FyZCBkb29yIHVzZXMsXG4gKiAgIHNvIGJvdGggZG9vcnMgYWNjZXB0IGlkZW50aWNhbCBpbnB1dHMpLlxuICogQHBhcmFtIGtleXNSZWFkIEEge0BsaW5rIEtleXNSZWFkU291cmNlfSBzdHJhdGVneSBvciBhIGJhcmUgbG9va3VwIOKAlCB0aGVcbiAqICAgc2FtZSByZWFkcyBwcm92aWRlcnMgYHNsaWNlRm9yS2V5YCB0YWtlcy4gUmVhZHMgYXJlIG5vdCBpbiB0aGUgY29tbWl0XG4gKiAgIGxvZzsgd2l0aG91dCBhIHByb3ZpZGVyIGEgZm9yd2FyZCB3YWxrIGNhbiBzZWUgbm90aGluZywgd2hpY2ggdGhlXG4gKiAgIGAncmVhZHMtbm90LXJlY29yZGVkJ2Agbm90ZSBzYXlzIG91dCBsb3VkLlxuICogQHJldHVybnMgQWx3YXlzIGEge0BsaW5rIEZvcndhcmRTbGljZX0uIEFic2VuY2UgaXMgYSBSRVNVTFQgd2l0aCBhIHJlYXNvblxuICogICBhbmQsIGZvciBhbiB1bmtub3duIGtleSwgYSBib3VuZGVkIGxpc3Qgb2YgdGhlIGtleXMgdGhlIGxvZyBkb2VzIGtub3cuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3J3YXJkU2xpY2VGb3JLZXkoXG4gIGNvbW1pdExvZzogQ29tbWl0QnVuZGxlW10sXG4gIGtleTogU3RhdGVLZXksXG4gIGtleXNSZWFkOiBLZXlzUmVhZFNvdXJjZSB8IEtleXNSZWFkTG9va3VwLFxuICBvcHRpb25zPzogRm9yd2FyZFNsaWNlRm9yS2V5T3B0aW9ucyxcbik6IEZvcndhcmRTbGljZSB7XG4gIGNvbnN0IHNvdXJjZSA9IHJlc29sdmVLZXlzUmVhZFNvdXJjZShrZXlzUmVhZCk7XG4gIGNvbnN0IG5vcm1hbGlzZWRLZXkgPSBub3JtYWxpc2VTdGF0ZUtleShrZXkpO1xuICBjb25zdCBiYXNlOiBQaWNrPEZvcndhcmRTbGljZSwgJ2tleScgfCAnYmVmb3JlJyB8ICdrZXlzUmVhZEtpbmQnIHwgJ3JlYWRzQ292ZXJhZ2UnPiA9IHtcbiAgICBrZXk6IG5vcm1hbGlzZWRLZXksXG4gICAgLi4uKG9wdGlvbnM/LmJlZm9yZSAhPT0gdW5kZWZpbmVkICYmIHsgYmVmb3JlOiBvcHRpb25zLmJlZm9yZSB9KSxcbiAgICBrZXlzUmVhZEtpbmQ6IHNvdXJjZS5raW5kLFxuICAgIC4uLihzb3VyY2UuY292ZXJhZ2UgIT09IHVuZGVmaW5lZCAmJiB7IHJlYWRzQ292ZXJhZ2U6IHNvdXJjZS5jb3ZlcmFnZSB9KSxcbiAgfTtcblxuICBpZiAoY29tbWl0TG9nLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHsgLi4uYmFzZSwgbWlzc2luZzogJ2VtcHR5LWxvZycsIG5vdGVzOiBbXSB9O1xuXG4gIGNvbnN0IGluZGV4ID0gYnVpbGRLZXlJbmRleChjb21taXRMb2csIHNvdXJjZS5sb29rdXApO1xuICBjb25zdCByZWFkc1JlY29yZGVkID0gaGFzUmVjb3JkZWRSZWFkcyhpbmRleCk7XG4gIGNvbnN0IG5vdGVzOiBIb25lc3R5Tm90ZVtdID0gW107XG5cbiAgLy8g4pSA4pSAIFRoZSB0eXBvIGd1YXJkLCBzcGxpdCBieSB3aGF0IHRoZSByZWNvcmRpbmcgYWZmb3JkcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgLy8gVW5rbm93biBrZXkgKyByZWFkcyBBUkUgcmVjb3JkZWQg4oaSIHRoZSBsb2cgY2FuIHNlZSByZWFkZXJzIGFuZCB0aGlzIGtleVxuICAvLyBoYXMgbm9uZTogaG9uZXN0IGFic2VuY2Ugd2l0aCBhIG5hbWVkIHJlYXNvbiwgbm8gZmFicmljYXRlZCBsaWZlLlxuICAvLyBVbmtub3duIGtleSArIE5PIHJlYWRzIHJlY29yZGVkIOKGkiBhIHR5cG8gYW5kIGEgc2VlZGVkLWJ1dC11bnJlYWQga2V5IGFyZVxuICAvLyBnZW51aW5lbHkgaW5kaXN0aW5ndWlzaGFibGU7IHRoZSBwcmUtcnVuIGxpZmUgYmVsb3cgaXMgdGhlIG9ubHkgaG9uZXN0XG4gIC8vIGFuc3dlciwgYW5kIGl0IG11c3QgY2FycnkgQk9USCBub3RlcyBzbyBub2JvZHkgcmVhZHMgaXQgYXMgXCJ1bnJlYWRcIi5cbiAgY29uc3Qga25vd24gPSBpbmRleC5rbm93bktleXMuaGFzKG5vcm1hbGlzZWRLZXkpO1xuICBpZiAoIWtub3duKSB7XG4gICAgbm90ZXMucHVzaCh1bmtub3duS2V5Tm90ZShpbmRleCwgbm9ybWFsaXNlZEtleSkpO1xuICAgIGlmIChyZWFkc1JlY29yZGVkKSByZXR1cm4geyAuLi5iYXNlLCBtaXNzaW5nOiAnbmV2ZXItd3JpdHRlbicsIG5vdGVzIH07XG4gIH1cbiAgaWYgKCFyZWFkc1JlY29yZGVkKSBub3Rlcy5wdXNoKHJlYWRzTm90UmVjb3JkZWROb3RlKCkpO1xuXG4gIGNvbnN0IG1heERlcHRoID0gb3B0aW9ucz8ubWF4RGVwdGggPz8gMjA7XG4gIGNvbnN0IG1heE5vZGVzID0gb3B0aW9ucz8ubWF4Tm9kZXMgPz8gMTAwO1xuXG4gIGNvbnN0IG5vZGVzID0gbmV3IE1hcDxzdHJpbmcsIEZvcndhcmROb2RlPigpO1xuICBsZXQgY3JlYXRlZCA9IDA7XG4gIGxldCB0cnVuY2F0ZWRCeURlcHRoID0gZmFsc2U7XG4gIGxldCB0cnVuY2F0ZWRCeU5vZGVzID0gZmFsc2U7XG4gIGxldCBhbnlDb25zZXJ2YXRpdmUgPSBmYWxzZTtcblxuICBjb25zdCBhbmNob3JJZHggPSBsYXN0SW5kZXhCZWZvcmUoaW5kZXgud3JpdGVzQnlLZXkuZ2V0KG5vcm1hbGlzZWRLZXkpLCBvcHRpb25zPy5iZWZvcmUpO1xuICBjb25zdCByb290ID0gbWFrZU5vZGUoY29tbWl0TG9nLCBpbmRleCwgbm9ybWFsaXNlZEtleSwgYW5jaG9ySWR4LCAwKTtcbiAgbm9kZXMuc2V0KG5vZGVLZXkoYW5jaG9ySWR4LCBub3JtYWxpc2VkS2V5KSwgcm9vdCk7XG4gIGNyZWF0ZWQgPSAxO1xuXG4gIGNvbnN0IHF1ZXVlOiBGb3J3YXJkTm9kZVtdID0gW3Jvb3RdO1xuICB3aGlsZSAocXVldWUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IG5vZGUgPSBxdWV1ZS5zaGlmdCgpITtcbiAgICAvLyBMaXZlIHJhbmdlOiBvcGVuIGJlbG93IHRoZSB3cml0ZSwgQ0xPU0VEIGF0IHRoZSBuZXh0IHdyaXRlIChzZWUgTEFXKS5cbiAgICBjb25zdCBmcm9tID0gbm9kZS5jb21taXRJZHggIT09IHVuZGVmaW5lZCA/IG5vZGUuY29tbWl0SWR4ICsgMSA6IDA7XG4gICAgY29uc3QgcmVhZGVycyA9IGluZGljZXNJblJhbmdlKGluZGV4LnJlYWRzQnlLZXkuZ2V0KG5vZGUua2V5KSwgZnJvbSwgbm9kZS5uZXh0V3JpdGVJZHgpO1xuXG4gICAgaWYgKG5vZGUuZGVwdGggPj0gbWF4RGVwdGgpIHtcbiAgICAgIC8vIE9ubHkgYSBsaWZlIHRoYXQgc3RpbGwgSEFEIHJlYWRlcnMgdG8gZXhwYW5kIGNvdW50cyBhcyBhIGN1dC5cbiAgICAgIGlmIChyZWFkZXJzLmxlbmd0aCA+IDApIHRydW5jYXRlZEJ5RGVwdGggPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCByZWFkZXJJZHggb2YgcmVhZGVycykge1xuICAgICAgY29uc3QgYnVuZGxlID0gY29tbWl0TG9nW3JlYWRlcklkeF07XG4gICAgICBub2RlLnJlYWRzLnB1c2goe1xuICAgICAgICBydW50aW1lU3RhZ2VJZDogYnVuZGxlLnJ1bnRpbWVTdGFnZUlkLFxuICAgICAgICBzdGFnZUlkOiBidW5kbGUuc3RhZ2VJZCxcbiAgICAgICAgc3RhZ2VOYW1lOiBidW5kbGUuc3RhZ2UsXG4gICAgICAgIGNvbW1pdElkeDogcmVhZGVySWR4LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFRoZSByZWFkZXIgSVMgdGhlIHdyaXRlciBvZiBldmVyeXRoaW5nIGl0IGNvbW1pdHRlZCDigJQgZWFjaCB3cml0dGVuXG4gICAgICAvLyBwYXRoIGlzIGEgY2FuZGlkYXRlIGBmZWRgIGVkZ2UuXG4gICAgICBmb3IgKGNvbnN0IHBhdGggb2Ygd3JpdHRlblBhdGhzKGJ1bmRsZSkpIHtcbiAgICAgICAgY29uc3QgZW50cnkgPSBsYXN0VHJhY2VFbnRyeShidW5kbGUsIHBhdGgpO1xuICAgICAgICBsZXQgYmFzaXM6IEZlZEJhc2lzO1xuICAgICAgICBpZiAoZW50cnk/LnJlYWRLZXlzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAvLyBFWEFDVCBib3RoIHdheXM6IHJlY29yZGVkIHByb3ZlbmFuY2UgY2FuIGluY2x1ZGUgb3IgRVhDTFVERS5cbiAgICAgICAgICBpZiAoIWVudHJ5LnJlYWRLZXlzLmluY2x1ZGVzKG5vZGUua2V5KSkgY29udGludWU7XG4gICAgICAgICAgYmFzaXMgPSAncGVyLXdyaXRlJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBiYXNpcyA9ICdzdGFnZSc7XG4gICAgICAgICAgYW55Q29uc2VydmF0aXZlID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGlkID0gbm9kZUtleShyZWFkZXJJZHgsIHBhdGgpO1xuICAgICAgICBsZXQgY2hpbGQgPSBub2Rlcy5nZXQoaWQpO1xuICAgICAgICBpZiAoIWNoaWxkKSB7XG4gICAgICAgICAgaWYgKGNyZWF0ZWQgPj0gbWF4Tm9kZXMpIHtcbiAgICAgICAgICAgIHRydW5jYXRlZEJ5Tm9kZXMgPSB0cnVlO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNoaWxkID0gbWFrZU5vZGUoY29tbWl0TG9nLCBpbmRleCwgcGF0aCwgcmVhZGVySWR4LCBub2RlLmRlcHRoICsgMSk7XG4gICAgICAgICAgbm9kZXMuc2V0KGlkLCBjaGlsZCk7XG4gICAgICAgICAgY3JlYXRlZCsrO1xuICAgICAgICAgIHF1ZXVlLnB1c2goY2hpbGQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIE9uZSBlZGdlIHBlciBkaXN0aW5jdCBjaGlsZCBsaWZlIChhIHN0YWdlIHJlYWRzIGEga2V5IG9uY2UpLlxuICAgICAgICBpZiAoIW5vZGUuZmVkRWRnZXMuc29tZSgoZSkgPT4gZS5jaGlsZCA9PT0gY2hpbGQpKSBub2RlLmZlZEVkZ2VzLnB1c2goeyBjaGlsZCwgYmFzaXMgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8g4pSA4pSAIEhvbmVzdHkgZW52ZWxvcGUsIGRldGVybWluaXN0aWMgb3JkZXIg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gIGlmIChyb290Lm9yaWdpbiA9PT0gJ3ByZS1ydW4nKSBub3Rlcy5wdXNoKHByZVJ1bk9yaWdpbk5vdGUobm9ybWFsaXNlZEtleSkpO1xuICBpZiAoYW55Q29uc2VydmF0aXZlKSBub3Rlcy5wdXNoKGNvbnNlcnZhdGl2ZUVkZ2VzTm90ZShub3JtYWxpc2VkS2V5KSk7XG4gIGlmICh0cnVuY2F0ZWRCeURlcHRoIHx8IHRydW5jYXRlZEJ5Tm9kZXMpIHtcbiAgICByb290LnRydW5jYXRlZCA9IHsgYnlEZXB0aDogdHJ1bmNhdGVkQnlEZXB0aCwgYnlOb2RlczogdHJ1bmNhdGVkQnlOb2RlcyB9O1xuICAgIG5vdGVzLnB1c2godHJ1bmNhdGVkTm90ZSh0cnVuY2F0ZWRCeURlcHRoLCB0cnVuY2F0ZWRCeU5vZGVzKSk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLmJhc2UsXG4gICAgLi4uKGFuY2hvcklkeCAhPT0gdW5kZWZpbmVkICYmIHsgd3JpdGVyOiBjb21taXRMb2dbYW5jaG9ySWR4XSB9KSxcbiAgICByb290LFxuICAgIG5vdGVzLFxuICB9O1xufVxuIl19
@@ -1,16 +1,25 @@
1
1
  /**
2
- * slice/ — variable-first backward slicing (the triage query layer).
2
+ * slice/ — variable-first slicing, both directions (the triage query layer).
3
3
  *
4
- * One question, one contract, every surface: "why is this VARIABLE what it
5
- * is?" — asked identically by UI panels (explainable-ui / lens), LLM triage
6
- * tools (trace toolpacks), and offline autopsy agents. See README.md for the
7
- * algorithms (thin-slice composition, append-fold provenance), the honesty
8
- * model, serialization rules, and the evolution path.
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 { formatSlice, sliceToJSON } from './serialize.js';
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 backward slicing (the triage query layer).
2
+ * slice/ — variable-first slicing, both directions (the triage query layer).
3
3
  *
4
- * One question, one contract, every surface: "why is this VARIABLE what it
5
- * is?" — asked identically by UI panels (explainable-ui / lens), LLM triage
6
- * tools (trace toolpacks), and offline autopsy agents. See README.md for the
7
- * algorithms (thin-slice composition, append-fold provenance), the honesty
8
- * model, serialization rules, and the evolution path.
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 { formatSlice, sliceToJSON } from './serialize.js';
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NsaWNlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsZUFBZSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDNUUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3pHLE9BQU8sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUQsT0FBTyxFQUEyQixpQkFBaUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogc2xpY2UvIOKAlCB2YXJpYWJsZS1maXJzdCBiYWNrd2FyZCBzbGljaW5nICh0aGUgdHJpYWdlIHF1ZXJ5IGxheWVyKS5cbiAqXG4gKiBPbmUgcXVlc3Rpb24sIG9uZSBjb250cmFjdCwgZXZlcnkgc3VyZmFjZTogXCJ3aHkgaXMgdGhpcyBWQVJJQUJMRSB3aGF0IGl0XG4gKiBpcz9cIiDigJQgYXNrZWQgaWRlbnRpY2FsbHkgYnkgVUkgcGFuZWxzIChleHBsYWluYWJsZS11aSAvIGxlbnMpLCBMTE0gdHJpYWdlXG4gKiB0b29scyAodHJhY2UgdG9vbHBhY2tzKSwgYW5kIG9mZmxpbmUgYXV0b3BzeSBhZ2VudHMuIFNlZSBSRUFETUUubWQgZm9yIHRoZVxuICogYWxnb3JpdGhtcyAodGhpbi1zbGljZSBjb21wb3NpdGlvbiwgYXBwZW5kLWZvbGQgcHJvdmVuYW5jZSksIHRoZSBob25lc3R5XG4gKiBtb2RlbCwgc2VyaWFsaXphdGlvbiBydWxlcywgYW5kIHRoZSBldm9sdXRpb24gcGF0aC5cbiAqXG4gKiBEQUcgcG9zaXRpb246IG1lbW9yeSDihpAgc2xpY2UgKGxlYWYtYWRqYWNlbnQ7IGltcG9ydHMgbWVtb3J5LyBvbmx5KS5cbiAqL1xuXG5leHBvcnQgeyBhcnJheVByb3ZlbmFuY2UsIGVsZW1lbnRQcm92ZW5hbmNlIH0gZnJvbSAnLi9lbGVtZW50UHJvdmVuYW5jZS5qcyc7XG5leHBvcnQgeyBrZXlzUmVhZEZyb21FeGVjdXRpb25UcmVlLCBrZXlzUmVhZEZyb21NYXAsIHJlc29sdmVLZXlzUmVhZFNvdXJjZSB9IGZyb20gJy4va2V5c1JlYWRTb3VyY2VzLmpzJztcbmV4cG9ydCB7IGZvcm1hdFNsaWNlLCBzbGljZVRvSlNPTiB9IGZyb20gJy4vc2VyaWFsaXplLmpzJztcbmV4cG9ydCB7IHR5cGUgU2xpY2VGb3JLZXlPcHRpb25zLCBub3JtYWxpc2VTdGF0ZUtleSwgc2xpY2VGb3JLZXkgfSBmcm9tICcuL3NsaWNlRm9yS2V5LmpzJztcbmV4cG9ydCB0eXBlIHtcbiAgQXJyYXlQcm92ZW5hbmNlLFxuICBBdHRyaWJ1dGlvbkJhc2lzLFxuICBFbGVtZW50QmlydGgsXG4gIEtleXNSZWFkU291cmNlLFxuICBNaXNzaW5nUHJvdmVuYW5jZVJlYXNvbixcbiAgTWlzc2luZ1NsaWNlUmVhc29uLFxuICBSZWFkc0NvdmVyYWdlLFxuICBTbGljZUpTT04sXG4gIFN0YXRlS2V5LFxuICBWYXJpYWJsZVNsaWNlLFxufSBmcm9tICcuL3R5cGVzLmpzJztcbiJdfQ==
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[];