foottrace 1.0.0 → 1.0.1
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/README.md +1 -1
- package/dist/esm/lib/memory/backtrack.d.ts +6 -0
- package/dist/esm/lib/memory/backtrack.js +17 -7
- package/dist/esm/lib/slice/sliceForKey.js +4 -2
- package/dist/lib/memory/backtrack.js +19 -8
- package/dist/lib/slice/sliceForKey.js +3 -1
- package/dist/types/lib/memory/backtrack.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Execution records and the tools to read them: replay, time travel, slices, and e
|
|
|
4
4
|
|
|
5
5
|
This package extracts FootPrint's established record layer. It does not introduce a second writer or a different replay law. The first release preserves the frozen record fixtures from footprintjs 9.48.1 and includes the coordinated 9.48.2 copy-safety correction: an own `__proto__` payload field stays data, never the copy's prototype. See the [changelog](CHANGELOG.md) for the limited rich-value behavior change.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Foottrace owns the record layer used by footprintjs 10. Older stored records remain readable without installing their original engine.
|
|
8
8
|
|
|
9
9
|
## Three entry points
|
|
10
10
|
|
|
@@ -257,6 +257,12 @@ export type KeysReadLookup = (runtimeStageId: string) => string[];
|
|
|
257
257
|
* @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
|
|
258
258
|
*/
|
|
259
259
|
export declare function causalChain(commitLog: CommitBundle[], startId: string, getKeysRead: KeysReadLookup, options?: CausalChainOptions): CausalNode | undefined;
|
|
260
|
+
/**
|
|
261
|
+
* Internal slice composition: keep the actual bundle selected by the writer
|
|
262
|
+
* query (including a nonempty continuation). This is not a public entry point.
|
|
263
|
+
* The read position still belongs to the execution's first commit.
|
|
264
|
+
*/
|
|
265
|
+
export declare function causalChainFromCommit(commitLog: CommitBundle[], writer: CommitBundle, getKeysRead: KeysReadLookup, options?: CausalChainOptions): CausalNode | undefined;
|
|
260
266
|
/**
|
|
261
267
|
* Flatten the causal DAG into a BFS-ordered list of nodes.
|
|
262
268
|
* Each node appears exactly once (first occurrence by BFS order).
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
* console.log(formatCausalChain(dag)); // human-readable
|
|
57
57
|
* ```
|
|
58
58
|
*/
|
|
59
|
-
import { findLastWriter } from './commitLogUtils.js';
|
|
59
|
+
import { buildCommitIndex, findLastWriter } from './commitLogUtils.js';
|
|
60
60
|
import { queryWork, relation, writesOnlyInside } from './keyPaths.js';
|
|
61
61
|
import { logModel } from './logModel.js';
|
|
62
62
|
// ── Staged optimization: writer lookup strategies ──────────────────────
|
|
@@ -148,6 +148,17 @@ function incompleteSourcesFragment(commit) {
|
|
|
148
148
|
* @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
|
|
149
149
|
*/
|
|
150
150
|
export function causalChain(commitLog, startId, getKeysRead, options) {
|
|
151
|
+
return buildCausalChain(commitLog, startId, getKeysRead, options);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Internal slice composition: keep the actual bundle selected by the writer
|
|
155
|
+
* query (including a nonempty continuation). This is not a public entry point.
|
|
156
|
+
* The read position still belongs to the execution's first commit.
|
|
157
|
+
*/
|
|
158
|
+
export function causalChainFromCommit(commitLog, writer, getKeysRead, options) {
|
|
159
|
+
return buildCausalChain(commitLog, writer.runtimeStageId, getKeysRead, options, writer);
|
|
160
|
+
}
|
|
161
|
+
function buildCausalChain(commitLog, startId, getKeysRead, options, selectedWriter) {
|
|
151
162
|
const maxDepth = options?.maxDepth ?? 20;
|
|
152
163
|
const maxNodes = options?.maxNodes ?? 100;
|
|
153
164
|
const controlDeps = options?.controlDeps;
|
|
@@ -158,16 +169,15 @@ export function causalChain(commitLog, startId, getKeysRead, options) {
|
|
|
158
169
|
// never mistake a truncated slice for a complete one.
|
|
159
170
|
let truncatedByDepth = false;
|
|
160
171
|
let truncatedByNodes = false;
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
172
|
+
// A continuation may write more data, but it is not another execution of
|
|
173
|
+
// the stage's reads. Use the shared FIRST-commit rule for every read cutoff;
|
|
174
|
+
// keep writer bundles separately for their write metadata and read prefixes.
|
|
175
|
+
const idxMap = buildCommitIndex(commitLog);
|
|
166
176
|
queryWork.units += commitLog.length;
|
|
167
177
|
const startIdx = idxMap.get(startId);
|
|
168
178
|
if (startIdx === undefined)
|
|
169
179
|
return undefined;
|
|
170
|
-
const startCommit = commitLog[startIdx];
|
|
180
|
+
const startCommit = selectedWriter ?? commitLog[startIdx];
|
|
171
181
|
// Pick writer lookup strategy based on log size
|
|
172
182
|
const findWriter = createWriterLookup(commitLog);
|
|
173
183
|
// Node dedup map: runtimeStageId → CausalNode (ensures DAG, not tree)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* it, every surface hand-rolls the anchor step differently and their answers
|
|
13
13
|
* disagree. The value of this function is that they can't.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { causalChainFromCommit } from '../memory/backtrack.js';
|
|
16
16
|
import { commitValueAtWithBasis, findLastWriterWithBasis } from '../memory/commitLogUtils.js';
|
|
17
17
|
import { normaliseStateKey } from '../memory/paths.js';
|
|
18
18
|
import { fromInitialStateNote, nestedRowsNote, redactedValueNote } from './keyIndex.js';
|
|
@@ -69,7 +69,9 @@ export function sliceForKey(commitLog, key, keysRead, options) {
|
|
|
69
69
|
// without `TraceEntry.readKeys` (the writeProvenance dial off) fall back
|
|
70
70
|
// to stage-level expansion per node, byte-identically. Consumers can force
|
|
71
71
|
// 'stage' via options.
|
|
72
|
-
|
|
72
|
+
// Preserve this exact writer's metadata/read prefix, even when it is a
|
|
73
|
+
// continuation. Causal expansion separately uses the execution's first commit.
|
|
74
|
+
const root = causalChainFromCommit(commitLog, writer, source.lookup, {
|
|
73
75
|
...options,
|
|
74
76
|
edgeAttribution: options?.edgeAttribution ?? 'per-write',
|
|
75
77
|
rootLinkKeys: options?.rootLinkKeys ?? [normalisedKey],
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
* ```
|
|
59
59
|
*/
|
|
60
60
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
61
|
-
exports._REVERSE_INDEX_THRESHOLD = exports.formatCausalChain = exports.flattenCausalDAG = exports.causalChain = void 0;
|
|
61
|
+
exports._REVERSE_INDEX_THRESHOLD = exports.formatCausalChain = exports.flattenCausalDAG = exports.causalChainFromCommit = exports.causalChain = void 0;
|
|
62
62
|
const commitLogUtils_js_1 = require("./commitLogUtils.js");
|
|
63
63
|
const keyPaths_js_1 = require("./keyPaths.js");
|
|
64
64
|
const logModel_js_1 = require("./logModel.js");
|
|
@@ -151,6 +151,19 @@ function incompleteSourcesFragment(commit) {
|
|
|
151
151
|
* @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
|
|
152
152
|
*/
|
|
153
153
|
function causalChain(commitLog, startId, getKeysRead, options) {
|
|
154
|
+
return buildCausalChain(commitLog, startId, getKeysRead, options);
|
|
155
|
+
}
|
|
156
|
+
exports.causalChain = causalChain;
|
|
157
|
+
/**
|
|
158
|
+
* Internal slice composition: keep the actual bundle selected by the writer
|
|
159
|
+
* query (including a nonempty continuation). This is not a public entry point.
|
|
160
|
+
* The read position still belongs to the execution's first commit.
|
|
161
|
+
*/
|
|
162
|
+
function causalChainFromCommit(commitLog, writer, getKeysRead, options) {
|
|
163
|
+
return buildCausalChain(commitLog, writer.runtimeStageId, getKeysRead, options, writer);
|
|
164
|
+
}
|
|
165
|
+
exports.causalChainFromCommit = causalChainFromCommit;
|
|
166
|
+
function buildCausalChain(commitLog, startId, getKeysRead, options, selectedWriter) {
|
|
154
167
|
const maxDepth = options?.maxDepth ?? 20;
|
|
155
168
|
const maxNodes = options?.maxNodes ?? 100;
|
|
156
169
|
const controlDeps = options?.controlDeps;
|
|
@@ -161,16 +174,15 @@ function causalChain(commitLog, startId, getKeysRead, options) {
|
|
|
161
174
|
// never mistake a truncated slice for a complete one.
|
|
162
175
|
let truncatedByDepth = false;
|
|
163
176
|
let truncatedByNodes = false;
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
177
|
+
// A continuation may write more data, but it is not another execution of
|
|
178
|
+
// the stage's reads. Use the shared FIRST-commit rule for every read cutoff;
|
|
179
|
+
// keep writer bundles separately for their write metadata and read prefixes.
|
|
180
|
+
const idxMap = (0, commitLogUtils_js_1.buildCommitIndex)(commitLog);
|
|
169
181
|
keyPaths_js_1.queryWork.units += commitLog.length;
|
|
170
182
|
const startIdx = idxMap.get(startId);
|
|
171
183
|
if (startIdx === undefined)
|
|
172
184
|
return undefined;
|
|
173
|
-
const startCommit = commitLog[startIdx];
|
|
185
|
+
const startCommit = selectedWriter ?? commitLog[startIdx];
|
|
174
186
|
// Pick writer lookup strategy based on log size
|
|
175
187
|
const findWriter = createWriterLookup(commitLog);
|
|
176
188
|
// Node dedup map: runtimeStageId → CausalNode (ensures DAG, not tree)
|
|
@@ -374,7 +386,6 @@ function causalChain(commitLog, startId, getKeysRead, options) {
|
|
|
374
386
|
}
|
|
375
387
|
return root;
|
|
376
388
|
}
|
|
377
|
-
exports.causalChain = causalChain;
|
|
378
389
|
// ── Utilities ──────────────────────────────────────────────────────────
|
|
379
390
|
/**
|
|
380
391
|
* Flatten the causal DAG into a BFS-ordered list of nodes.
|
|
@@ -72,7 +72,9 @@ function sliceForKey(commitLog, key, keysRead, options) {
|
|
|
72
72
|
// without `TraceEntry.readKeys` (the writeProvenance dial off) fall back
|
|
73
73
|
// to stage-level expansion per node, byte-identically. Consumers can force
|
|
74
74
|
// 'stage' via options.
|
|
75
|
-
|
|
75
|
+
// Preserve this exact writer's metadata/read prefix, even when it is a
|
|
76
|
+
// continuation. Causal expansion separately uses the execution's first commit.
|
|
77
|
+
const root = (0, backtrack_js_1.causalChainFromCommit)(commitLog, writer, source.lookup, {
|
|
76
78
|
...options,
|
|
77
79
|
edgeAttribution: options?.edgeAttribution ?? 'per-write',
|
|
78
80
|
rootLinkKeys: options?.rootLinkKeys ?? [normalisedKey],
|
|
@@ -257,6 +257,12 @@ export type KeysReadLookup = (runtimeStageId: string) => string[];
|
|
|
257
257
|
* @returns Root CausalNode with .parents forming the DAG, or undefined if startId not found
|
|
258
258
|
*/
|
|
259
259
|
export declare function causalChain(commitLog: CommitBundle[], startId: string, getKeysRead: KeysReadLookup, options?: CausalChainOptions): CausalNode | undefined;
|
|
260
|
+
/**
|
|
261
|
+
* Internal slice composition: keep the actual bundle selected by the writer
|
|
262
|
+
* query (including a nonempty continuation). This is not a public entry point.
|
|
263
|
+
* The read position still belongs to the execution's first commit.
|
|
264
|
+
*/
|
|
265
|
+
export declare function causalChainFromCommit(commitLog: CommitBundle[], writer: CommitBundle, getKeysRead: KeysReadLookup, options?: CausalChainOptions): CausalNode | undefined;
|
|
260
266
|
/**
|
|
261
267
|
* Flatten the causal DAG into a BFS-ordered list of nodes.
|
|
262
268
|
* Each node appears exactly once (first occurrence by BFS order).
|
package/package.json
CHANGED