agentfootprint-lens 0.53.0 → 0.53.3

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.
Files changed (67) hide show
  1. package/README.md +1 -0
  2. package/dist/{Lens-CcVUyiCm.d.cts → Lens-DHmINGvn.d.cts} +2 -2
  3. package/dist/{Lens-CdUkz_qq.d.ts → Lens-DKbZBkI8.d.ts} +2 -2
  4. package/dist/chunk-35DQLVDZ.js +88 -0
  5. package/dist/chunk-35DQLVDZ.js.map +1 -0
  6. package/dist/chunk-45QIXKMD.js +133 -0
  7. package/dist/chunk-45QIXKMD.js.map +1 -0
  8. package/dist/chunk-47W3TQT6.js +600 -0
  9. package/dist/chunk-47W3TQT6.js.map +1 -0
  10. package/dist/chunk-7HGQNIMP.js +151 -0
  11. package/dist/chunk-7HGQNIMP.js.map +1 -0
  12. package/dist/{chunk-LZI2QIZ7.js → chunk-A3SG5MAG.js} +4 -140
  13. package/dist/chunk-A3SG5MAG.js.map +1 -0
  14. package/dist/{chunk-BJR32J6H.js → chunk-CUBFVNOW.js} +5 -150
  15. package/dist/chunk-CUBFVNOW.js.map +1 -0
  16. package/dist/{chunk-BRX4SS75.js → chunk-KGQIRUBC.js} +504 -575
  17. package/dist/chunk-KGQIRUBC.js.map +1 -0
  18. package/dist/{chunk-BJ635YAV.js → chunk-RARQT7O5.js} +16 -608
  19. package/dist/chunk-RARQT7O5.js.map +1 -0
  20. package/dist/chunk-SJKOL3IK.js +318 -0
  21. package/dist/chunk-SJKOL3IK.js.map +1 -0
  22. package/dist/chunk-TZZDF3B6.js +121 -0
  23. package/dist/chunk-TZZDF3B6.js.map +1 -0
  24. package/dist/{chunk-MS5XW7GH.js → chunk-UHA4XB4Z.js} +6 -4
  25. package/dist/{chunk-MS5XW7GH.js.map → chunk-UHA4XB4Z.js.map} +1 -1
  26. package/dist/{chunk-OXPEMAMG.js → chunk-XCFEGRQD.js} +6 -120
  27. package/dist/chunk-XCFEGRQD.js.map +1 -0
  28. package/dist/context.cjs +1349 -0
  29. package/dist/context.cjs.map +1 -0
  30. package/dist/context.d.cts +75 -0
  31. package/dist/context.d.ts +75 -0
  32. package/dist/context.js +19 -0
  33. package/dist/context.js.map +1 -0
  34. package/dist/contextAt-CTUNun-q.d.cts +551 -0
  35. package/dist/contextAt-CzaCZP4b.d.ts +551 -0
  36. package/dist/core.cjs +4 -13
  37. package/dist/core.cjs.map +1 -1
  38. package/dist/core.d.cts +11 -554
  39. package/dist/core.d.ts +11 -554
  40. package/dist/core.js +25 -19
  41. package/dist/index.cjs +20 -60
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.d.cts +15 -67
  44. package/dist/index.d.ts +15 -67
  45. package/dist/index.js +277 -590
  46. package/dist/index.js.map +1 -1
  47. package/dist/{lensCursor-B8HFFZgR.d.ts → lensCursor-BQyMCkdo.d.cts} +183 -250
  48. package/dist/{lensCursor-B8HFFZgR.d.cts → lensCursor-BQyMCkdo.d.ts} +183 -250
  49. package/dist/{selectSkillFrameContext-BE7lCVcB.d.cts → selectSkillFrameContext-BYRAxR-U.d.cts} +1 -1
  50. package/dist/{selectSkillFrameContext-D2uHzhJJ.d.ts → selectSkillFrameContext-BhsKCGr4.d.ts} +1 -1
  51. package/dist/skillgraph.d.cts +5 -4
  52. package/dist/skillgraph.d.ts +5 -4
  53. package/dist/skillgraph.js +8 -5
  54. package/dist/stepForRuntimeStageId-Ctlldoq5.d.cts +70 -0
  55. package/dist/stepForRuntimeStageId-DsYG7lad.d.ts +70 -0
  56. package/dist/{tagAxis-BUrsQ1fX.d.cts → tagAxis-Dh-lINvw.d.cts} +1 -1
  57. package/dist/{tagAxis-Cqom3DPf.d.ts → tagAxis-DuOMNXvq.d.ts} +1 -1
  58. package/dist/why.d.cts +6 -5
  59. package/dist/why.d.ts +6 -5
  60. package/dist/why.js +13 -7
  61. package/dist/why.js.map +1 -1
  62. package/package.json +15 -2
  63. package/dist/chunk-BJ635YAV.js.map +0 -1
  64. package/dist/chunk-BJR32J6H.js.map +0 -1
  65. package/dist/chunk-BRX4SS75.js.map +0 -1
  66. package/dist/chunk-LZI2QIZ7.js.map +0 -1
  67. package/dist/chunk-OXPEMAMG.js.map +0 -1
package/README.md CHANGED
@@ -78,6 +78,7 @@ changes.
78
78
  |---|---|
79
79
  | `agentfootprint-lens/why` | Replay a recording as the agent's own milestones. `<WhyLens recording={...} />` takes the recording straight (`recordRun()`'s `{ snapshot, events, structure }`, or the `persistRecording` envelope), validates it at mount, and mounts the shipped `<Lens>` shell on the milestone axis — plus the axis helpers (`scrubAxisFor`, `stepForCommitIdx`, `stepForRuntimeStageId`, `resolveNavigation`) for hosts holding one cursor across views. |
80
80
  | `agentfootprint-lens/skillgraph` | Debug how a run routed through its skills. `<SkillGraphDebugger recorder={...} />` plus its headless selectors (`selectSkillRoute`, `selectSkillBeats`, `selectSkillTopology`, `selectSkillFrameContext`, `stepForRuntimeStageId`, `resolveNavigation`). |
81
+ | `agentfootprint-lens/context` | The context object at a stop, key by key — who wrote each, what moved, what was served. `<ContextView runner={...} />` walks the milestone axis on its own; hand it `cursor` and it follows the ONE cursor (0.53.1). |
81
82
 
82
83
  The axis model in three sentences: one run leaves one causal trace, and each
83
84
  lens replays one AXIS of it — the Why reading scrubs the milestones, the Flow
@@ -3,8 +3,8 @@ import { ToolChoiceCall, ToolChoiceSummary } from 'agentfootprint/observe';
3
3
  import * as agentfootprint from 'agentfootprint';
4
4
  import { CommentaryTemplates } from 'agentfootprint';
5
5
  import React__default, { Ref } from 'react';
6
- import { a as LensCursorReading, C as CursorPosition, L as LensCursor, e as NavigationResult, h as LensRecorder } from './lensCursor-B8HFFZgR.cjs';
7
- import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-BUrsQ1fX.cjs';
6
+ import { a as LensCursorReading, C as CursorPosition, L as LensCursor, e as NavigationResult, h as LensRecorder } from './lensCursor-BQyMCkdo.cjs';
7
+ import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-Dh-lINvw.cjs';
8
8
  import { NodeTypes } from '@xyflow/react';
9
9
  import { TraceGraph, TraceFlowLayout, RuntimeOverlay } from 'footprint-explainable-ui/flowchart';
10
10
 
@@ -3,8 +3,8 @@ import { ToolChoiceCall, ToolChoiceSummary } from 'agentfootprint/observe';
3
3
  import * as agentfootprint from 'agentfootprint';
4
4
  import { CommentaryTemplates } from 'agentfootprint';
5
5
  import React__default, { Ref } from 'react';
6
- import { a as LensCursorReading, C as CursorPosition, L as LensCursor, e as NavigationResult, h as LensRecorder } from './lensCursor-B8HFFZgR.js';
7
- import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-Cqom3DPf.js';
6
+ import { a as LensCursorReading, C as CursorPosition, L as LensCursor, e as NavigationResult, h as LensRecorder } from './lensCursor-BQyMCkdo.js';
7
+ import { C as ChartGroupHighlight, c as LensCursorPort, H as Humanizer, b as BookmarkStore } from './tagAxis-DuOMNXvq.js';
8
8
  import { NodeTypes } from '@xyflow/react';
9
9
  import { TraceGraph, TraceFlowLayout, RuntimeOverlay } from 'footprint-explainable-ui/flowchart';
10
10
 
@@ -0,0 +1,88 @@
1
+ import {
2
+ T
3
+ } from "./chunk-7HGQNIMP.js";
4
+
5
+ // src/react/components/ServedBadge.tsx
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ var BADGE_LABELS = Object.freeze({
8
+ verified: "Verified",
9
+ reconstructed: "Reconstructed",
10
+ damaged: "Damaged",
11
+ notOnRecord: "Not on record",
12
+ onReceipt: "on receipt",
13
+ receipt: "receipt",
14
+ rebuilt: "rebuilt"
15
+ });
16
+ function statusLabel(status) {
17
+ switch (status) {
18
+ case "verified":
19
+ return BADGE_LABELS.verified;
20
+ case "reconstructed":
21
+ return BADGE_LABELS.reconstructed;
22
+ case "damaged":
23
+ return BADGE_LABELS.damaged;
24
+ default:
25
+ return BADGE_LABELS.notOnRecord;
26
+ }
27
+ }
28
+ function statusColor(status) {
29
+ switch (status) {
30
+ case "verified":
31
+ return T.success;
32
+ case "damaged":
33
+ return T.error;
34
+ default:
35
+ return T.textMuted;
36
+ }
37
+ }
38
+ function Badge({ check }) {
39
+ const title = [
40
+ check.onReceipt !== void 0 ? `${BADGE_LABELS.receipt} ${check.onReceipt}` : void 0,
41
+ check.rebuilt !== void 0 ? `${BADGE_LABELS.rebuilt} ${check.rebuilt}` : void 0
42
+ ].filter((s) => s !== void 0).join(" \xB7 ");
43
+ const disagree = check.onReceipt !== void 0 && check.rebuilt !== void 0 && check.onReceipt !== check.rebuilt;
44
+ return /* @__PURE__ */ jsxs("span", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
45
+ disagree && /* @__PURE__ */ jsxs("span", { style: hashesStyle, "data-testid": "served-hashes", children: [
46
+ BADGE_LABELS.receipt,
47
+ " ",
48
+ check.onReceipt,
49
+ " \xB7 ",
50
+ BADGE_LABELS.rebuilt,
51
+ " ",
52
+ check.rebuilt
53
+ ] }),
54
+ /* @__PURE__ */ jsx(
55
+ "span",
56
+ {
57
+ style: badgeStyle(statusColor(check.status), check.status === "not-on-record"),
58
+ "data-testid": "served-badge",
59
+ "data-status": check.status,
60
+ ...title !== "" ? { title } : {},
61
+ children: statusLabel(check.status)
62
+ }
63
+ )
64
+ ] });
65
+ }
66
+ function badgeStyle(color, dashed) {
67
+ return {
68
+ padding: "0 6px",
69
+ borderRadius: 999,
70
+ border: `1px ${dashed ? "dashed" : "solid"} ${color}`,
71
+ color,
72
+ fontSize: 10,
73
+ fontWeight: 600,
74
+ letterSpacing: "0.02em",
75
+ whiteSpace: "nowrap"
76
+ };
77
+ }
78
+ var hashesStyle = {
79
+ fontFamily: T.fontMono,
80
+ fontSize: 10.5,
81
+ color: T.textMuted
82
+ };
83
+
84
+ export {
85
+ BADGE_LABELS,
86
+ Badge
87
+ };
88
+ //# sourceMappingURL=chunk-35DQLVDZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/components/ServedBadge.tsx"],"sourcesContent":["/**\n * <Badge> — what the hash check established for one row, on screen.\n *\n * ONE OWNER, TWO VIEWS. The Served tab's list and the Served graph draw the\n * same four verdicts, so the badge, its four words and its colours live here\n * and nowhere else: a badge softened in one view and not the other would be\n * two different accounts of one record. `ServedTab` re-exports it, and its\n * `LABELS` take the four words from {@link BADGE_LABELS} rather than repeating\n * them.\n *\n * A badge is NEVER softened for a prettier picture. `'damaged'` draws Damaged,\n * whatever it sits beside.\n */\n\nimport React from 'react';\n\nimport type { FieldCheck, ServedFieldStatus } from '../../core/served/index.js';\nimport { T } from '../theme/index.js';\n\n/** The four verdicts, and the two words for the hashes they were decided by. */\nexport const BADGE_LABELS = Object.freeze({\n verified: 'Verified',\n reconstructed: 'Reconstructed',\n damaged: 'Damaged',\n notOnRecord: 'Not on record',\n onReceipt: 'on receipt',\n receipt: 'receipt',\n rebuilt: 'rebuilt',\n} as const);\n\nexport function statusLabel(status: ServedFieldStatus): string {\n switch (status) {\n case 'verified':\n return BADGE_LABELS.verified;\n case 'reconstructed':\n return BADGE_LABELS.reconstructed;\n case 'damaged':\n return BADGE_LABELS.damaged;\n default:\n return BADGE_LABELS.notOnRecord;\n }\n}\n\nexport function statusColor(status: ServedFieldStatus): string {\n switch (status) {\n case 'verified':\n return T.success;\n case 'damaged':\n return T.error;\n default:\n return T.textMuted;\n }\n}\n\n/**\n * The status badge. Title carries the two hashes it was decided by — data.\n * When the two DISAGREE they are also printed inline, whatever the status: a\n * disagreement an excusing gap turned into \"reconstructed\" is still a fact the\n * reader wants on screen, not only in a tooltip.\n */\nexport function Badge({ check }: { check: FieldCheck }): React.ReactElement {\n const title = [\n check.onReceipt !== undefined ? `${BADGE_LABELS.receipt} ${check.onReceipt}` : undefined,\n check.rebuilt !== undefined ? `${BADGE_LABELS.rebuilt} ${check.rebuilt}` : undefined,\n ]\n .filter((s) => s !== undefined)\n .join(' · ');\n const disagree =\n check.onReceipt !== undefined &&\n check.rebuilt !== undefined &&\n check.onReceipt !== check.rebuilt;\n return (\n <span style={{ display: 'inline-flex', gap: 6, alignItems: 'center' }}>\n {disagree && (\n <span style={hashesStyle} data-testid=\"served-hashes\">\n {BADGE_LABELS.receipt} {check.onReceipt} · {BADGE_LABELS.rebuilt} {check.rebuilt}\n </span>\n )}\n <span\n style={badgeStyle(statusColor(check.status), check.status === 'not-on-record')}\n data-testid=\"served-badge\"\n data-status={check.status}\n {...(title !== '' ? { title } : {})}\n >\n {statusLabel(check.status)}\n </span>\n </span>\n );\n}\n\nexport function badgeStyle(color: string, dashed: boolean): React.CSSProperties {\n return {\n padding: '0 6px',\n borderRadius: 999,\n border: `1px ${dashed ? 'dashed' : 'solid'} ${color}`,\n color,\n fontSize: 10,\n fontWeight: 600,\n letterSpacing: '0.02em',\n whiteSpace: 'nowrap',\n };\n}\n\nconst hashesStyle: React.CSSProperties = {\n fontFamily: T.fontMono,\n fontSize: 10.5,\n color: T.textMuted,\n};\n"],"mappings":";;;;;AA0EQ,SAIF,KAJE;AAtDD,IAAM,eAAe,OAAO,OAAO;AAAA,EACxC,UAAU;AAAA,EACV,eAAe;AAAA,EACf,SAAS;AAAA,EACT,aAAa;AAAA,EACb,WAAW;AAAA,EACX,SAAS;AAAA,EACT,SAAS;AACX,CAAU;AAEH,SAAS,YAAY,QAAmC;AAC7D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,aAAa;AAAA,IACtB,KAAK;AACH,aAAO,aAAa;AAAA,IACtB,KAAK;AACH,aAAO,aAAa;AAAA,IACtB;AACE,aAAO,aAAa;AAAA,EACxB;AACF;AAEO,SAAS,YAAY,QAAmC;AAC7D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX;AACE,aAAO,EAAE;AAAA,EACb;AACF;AAQO,SAAS,MAAM,EAAE,MAAM,GAA8C;AAC1E,QAAM,QAAQ;AAAA,IACZ,MAAM,cAAc,SAAY,GAAG,aAAa,OAAO,IAAI,MAAM,SAAS,KAAK;AAAA,IAC/E,MAAM,YAAY,SAAY,GAAG,aAAa,OAAO,IAAI,MAAM,OAAO,KAAK;AAAA,EAC7E,EACG,OAAO,CAAC,MAAM,MAAM,MAAS,EAC7B,KAAK,QAAK;AACb,QAAM,WACJ,MAAM,cAAc,UACpB,MAAM,YAAY,UAClB,MAAM,cAAc,MAAM;AAC5B,SACE,qBAAC,UAAK,OAAO,EAAE,SAAS,eAAe,KAAK,GAAG,YAAY,SAAS,GACjE;AAAA,gBACC,qBAAC,UAAK,OAAO,aAAa,eAAY,iBACnC;AAAA,mBAAa;AAAA,MAAQ;AAAA,MAAE,MAAM;AAAA,MAAU;AAAA,MAAI,aAAa;AAAA,MAAQ;AAAA,MAAE,MAAM;AAAA,OAC3E;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,WAAW,YAAY,MAAM,MAAM,GAAG,MAAM,WAAW,eAAe;AAAA,QAC7E,eAAY;AAAA,QACZ,eAAa,MAAM;AAAA,QAClB,GAAI,UAAU,KAAK,EAAE,MAAM,IAAI,CAAC;AAAA,QAEhC,sBAAY,MAAM,MAAM;AAAA;AAAA,IAC3B;AAAA,KACF;AAEJ;AAEO,SAAS,WAAW,OAAe,QAAsC;AAC9E,SAAO;AAAA,IACL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ,OAAO,SAAS,WAAW,OAAO,IAAI,KAAK;AAAA,IACnD;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,YAAY;AAAA,EACd;AACF;AAEA,IAAM,cAAmC;AAAA,EACvC,YAAY,EAAE;AAAA,EACd,UAAU;AAAA,EACV,OAAO,EAAE;AACX;","names":[]}
@@ -0,0 +1,133 @@
1
+ import {
2
+ servedRowAt,
3
+ servedRowForEpoch,
4
+ sincePrevious,
5
+ verify
6
+ } from "./chunk-47W3TQT6.js";
7
+
8
+ // src/core/context/contextAt.ts
9
+ import { pathSegments, stateAt } from "footprintjs/trace";
10
+ function logOf(snapshot) {
11
+ const s = snapshot;
12
+ return Array.isArray(s?.commitLog) ? s.commitLog : [];
13
+ }
14
+ function writersUpTo(log, commitIdx) {
15
+ const out = /* @__PURE__ */ new Map();
16
+ const last = Math.min(commitIdx, log.length - 1);
17
+ for (let i = 0; i <= last; i++) {
18
+ const bundle = log[i];
19
+ if (bundle === void 0 || typeof bundle.runtimeStageId !== "string" || !Array.isArray(bundle.trace))
20
+ continue;
21
+ for (const row of bundle.trace) {
22
+ const key = pathSegments(row.path)[0];
23
+ if (key === void 0) continue;
24
+ const prior = out.get(key);
25
+ out.set(key, {
26
+ wroteBy: bundle.runtimeStageId,
27
+ wroteAt: i,
28
+ enteredAt: prior?.enteredAt ?? i,
29
+ verb: row.verb
30
+ });
31
+ }
32
+ }
33
+ return out;
34
+ }
35
+ function foldAt(snapshot, commitIdx) {
36
+ const source = typeof snapshot === "object" && snapshot !== null ? snapshot : void 0;
37
+ try {
38
+ return stateAt(source, commitIdx);
39
+ } catch (e) {
40
+ return { error: e instanceof Error ? e.message : String(e) };
41
+ }
42
+ }
43
+ var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
44
+ function servedFor(snapshot, cursor) {
45
+ try {
46
+ const row = servedRowAt(snapshot, cursor);
47
+ if (row === void 0) return {};
48
+ const checks = verify(row.view, row.receipt, row.receipt?.basis.runId ?? "", row.receiptCause);
49
+ const previous = row.previousEpoch !== void 0 ? servedRowForEpoch(snapshot, row.previousEpoch) : void 0;
50
+ const since = previous !== void 0 ? sincePrevious(row, previous) : void 0;
51
+ return {
52
+ served: Object.freeze({
53
+ row,
54
+ checks,
55
+ ...since !== void 0 ? { since } : {}
56
+ })
57
+ };
58
+ } catch (e) {
59
+ return { servedError: e instanceof Error ? e.message : String(e) };
60
+ }
61
+ }
62
+ function whyFor(events, stages) {
63
+ if (events === void 0 || stages.size === 0) return Object.freeze([]);
64
+ const out = [];
65
+ for (const entry of events) {
66
+ const id = entry.runtimeStageId;
67
+ if (id === void 0 || !stages.has(id)) continue;
68
+ out.push({ seq: entry.seq, name: entry.event.type, runtimeStageId: id });
69
+ }
70
+ return Object.freeze(out);
71
+ }
72
+ function contextAt(recording, cursor, options = {}) {
73
+ const log = logOf(recording);
74
+ const folded = foldAt(recording, cursor.commitIdx);
75
+ if ("error" in folded) {
76
+ return Object.freeze({
77
+ cursor,
78
+ keys: Object.freeze([]),
79
+ left: Object.freeze([]),
80
+ rows: Object.freeze([]),
81
+ redacted: false,
82
+ foldError: folded.error,
83
+ why: Object.freeze([])
84
+ });
85
+ }
86
+ const writers = writersUpTo(log, cursor.commitIdx);
87
+ const previous = options.previous !== void 0 ? foldAt(recording, options.previous.commitIdx) : void 0;
88
+ const previousState = previous !== void 0 && !("error" in previous) ? previous.state : void 0;
89
+ const keys = [];
90
+ for (const [path, value] of Object.entries(folded.state)) {
91
+ const w = writers.get(path);
92
+ const since = previousState === void 0 ? void 0 : !(path in previousState) ? "entered" : same(previousState[path], value) ? "unchanged" : "changed";
93
+ keys.push(
94
+ Object.freeze({
95
+ path,
96
+ value,
97
+ ...w !== void 0 ? {
98
+ wroteBy: w.wroteBy,
99
+ wroteAt: w.wroteAt,
100
+ enteredAt: w.enteredAt,
101
+ verb: w.verb
102
+ } : {},
103
+ ...since !== void 0 ? { since } : {}
104
+ })
105
+ );
106
+ }
107
+ const left = previousState === void 0 ? [] : Object.keys(previousState).filter((k) => !(k in folded.state));
108
+ const bundle = log[cursor.commitIdx];
109
+ const rows = Array.isArray(bundle?.trace) ? bundle.trace.map((r) => Object.freeze({ path: r.path, verb: r.verb })) : [];
110
+ const stages = /* @__PURE__ */ new Set();
111
+ if (bundle !== void 0 && typeof bundle.runtimeStageId === "string") stages.add(bundle.runtimeStageId);
112
+ for (const k of keys)
113
+ if (k.since !== void 0 && k.since !== "unchanged" && k.wroteBy !== void 0) stages.add(k.wroteBy);
114
+ const skipped = folded.skipped !== void 0 && folded.skipped.length > 0 ? folded.skipped.map((g) => g.index) : void 0;
115
+ const { served, servedError } = servedFor(recording, cursor);
116
+ return Object.freeze({
117
+ cursor,
118
+ keys: Object.freeze(keys),
119
+ left: Object.freeze(left),
120
+ rows: Object.freeze(rows),
121
+ basis: folded.basis,
122
+ redacted: folded.redacted,
123
+ ...skipped !== void 0 ? { skipped: Object.freeze(skipped) } : {},
124
+ ...served !== void 0 ? { served } : {},
125
+ ...servedError !== void 0 ? { servedError } : {},
126
+ why: whyFor(options.events, stages)
127
+ });
128
+ }
129
+
130
+ export {
131
+ contextAt
132
+ };
133
+ //# sourceMappingURL=chunk-45QIXKMD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/context/contextAt.ts"],"sourcesContent":["/**\n * core/context/contextAt — the context object at a stop, with who wrote each\n * key, what moved since the previous stop, and what was served beside it.\n *\n * THE JOIN, nothing more. Three records already exist and this file writes\n * none of its own:\n *\n * 1. the COMMIT LOG — `stateAt(snapshot, commitIdx)` is the object at the\n * stop; the trace rows of the bundles up to it name, per top-level key,\n * the stage that last wrote it (`runtimeStageId`) and the first that\n * did; the bundle's own rows are the DELTA of the stop;\n * 2. the RECEIPT at the stop's epoch — `servedRowAt` (the Served tab's own\n * core) says what crossed into the model call and what the catalogue\n * withheld; it is handed through untouched, never re-derived;\n * 3. the EVENT STREAM — entries stamped with the stages that wrote this\n * stop's delta, or with the stop's own stage, are the \"why\" beside the\n * keys; names only, no sentence.\n *\n * Join keys: `runtimeStageId` (commit log ⟂ events), `epoch` (commit log ⟂\n * receipt, through `servedRowAt`). A key the fold holds with no writer row —\n * the run's initial state, or a row the log lost — is `wroteBy: undefined`:\n * UNATTRIBUTED, never guessed (the reads law: omit, never deny). Owners are\n * stage ids, because that is what the record says; a word like \"host\" or\n * \"model\" is a reader's mapping, not this file's.\n *\n * Pure; frozen returns; no React. Consumers with their own UI read this.\n */\nimport { pathSegments, stateAt } from 'footprintjs/trace';\nimport type { FoldSource, FoldedState } from 'footprintjs/trace';\n\nimport type { EventLogEntry } from '../types.js';\nimport { servedRowAt, servedRowForEpoch } from '../served/servedRowAt.js';\nimport { sincePrevious, type SincePrevious } from '../served/sincePrevious.js';\nimport { verify, type ServedVerification } from '../served/verify.js';\nimport type { ServedCursor, ServedRow } from '../served/types.js';\n\n/** The slice of a footprintjs commit bundle this file reads — narrowed per row, never trusted whole. */\ninterface TraceRow {\n readonly path: string;\n readonly verb: string;\n}\ninterface CommitBundle {\n readonly idx?: number;\n readonly runtimeStageId: string;\n readonly trace?: readonly TraceRow[];\n}\n\n/** One top-level key of the context object at the stop. */\nexport interface ContextKey {\n readonly path: string;\n readonly value: unknown;\n /** The stage that LAST wrote the key, from its trace row; absent = unattributed. */\n readonly wroteBy?: string;\n /** The commit index of that last write. */\n readonly wroteAt?: number;\n /** The first commit that wrote the key — when it ENTERED the context. */\n readonly enteredAt?: number;\n /** The verb of the last write, from the trace row. */\n readonly verb?: string;\n /** How the key moved since the previous stop (absent when no previous stop was given). */\n readonly since?: 'entered' | 'changed' | 'unchanged';\n}\n\n/** What is served beside the object at this stop — the Served tab's own row, handed through. */\nexport interface ContextServed {\n readonly row: ServedRow;\n readonly checks: ServedVerification;\n readonly since?: SincePrevious;\n}\n\nexport interface ContextAt {\n readonly cursor: ServedCursor;\n /** Every top-level key of the fold at the stop, in the fold's key order. */\n readonly keys: readonly ContextKey[];\n /** Keys the previous stop held that this one does not (only with a previous stop). */\n readonly left: readonly string[];\n /** The trace rows the stop's own bundle wrote — its delta as the log spells it. */\n readonly rows: readonly { readonly path: string; readonly verb: string }[];\n /** The fold's honesty facts, as `stateAt` reports them. */\n readonly basis?: FoldedState['basis'];\n readonly redacted: boolean;\n readonly skipped?: readonly number[];\n readonly foldError?: string;\n /** The served side at this stop's epoch, when the stop is at or after a model call. */\n readonly served?: ContextServed;\n /** The Served core refused this snapshot — its message, verbatim; `served` is then absent. */\n readonly servedError?: string;\n /** Event names raised by the stages that wrote this stop's delta, or by its own stage. */\n readonly why: readonly {\n readonly seq: number;\n readonly name: string;\n readonly runtimeStageId: string;\n }[];\n}\n\nexport interface ContextAtOptions {\n /** The previous stop on the reader's axis — enables `since` and `left`. */\n readonly previous?: ServedCursor;\n /** The recording's event stream, when the reader has one (a replay's `getEntries()`). */\n readonly events?: readonly EventLogEntry[];\n}\n\ninterface WriterFacts {\n readonly wroteBy: string;\n readonly wroteAt: number;\n readonly enteredAt: number;\n readonly verb: string;\n}\n\nfunction logOf(snapshot: unknown): readonly CommitBundle[] {\n const s = snapshot as { commitLog?: unknown } | null | undefined;\n return Array.isArray(s?.commitLog) ? (s.commitLog as CommitBundle[]) : [];\n}\n\n/** Per top-level key, the first and last trace rows up to `commitIdx` (inclusive). */\nfunction writersUpTo(log: readonly CommitBundle[], commitIdx: number): ReadonlyMap<string, WriterFacts> {\n const out = new Map<string, WriterFacts>();\n const last = Math.min(commitIdx, log.length - 1);\n for (let i = 0; i <= last; i++) {\n const bundle = log[i];\n if (bundle === undefined || typeof bundle.runtimeStageId !== 'string' || !Array.isArray(bundle.trace))\n continue;\n for (const row of bundle.trace) {\n const key = pathSegments(row.path)[0];\n if (key === undefined) continue;\n const prior = out.get(key);\n out.set(key, {\n wroteBy: bundle.runtimeStageId,\n wroteAt: i,\n enteredAt: prior?.enteredAt ?? i,\n verb: row.verb,\n });\n }\n }\n return out;\n}\n\nfunction foldAt(snapshot: unknown, commitIdx: number): FoldedState | { readonly error: string } {\n const source: FoldSource | undefined =\n typeof snapshot === 'object' && snapshot !== null ? (snapshot as FoldSource) : undefined;\n try {\n return stateAt(source, commitIdx);\n } catch (e) {\n return { error: e instanceof Error ? e.message : String(e) };\n }\n}\n\nconst same = (a: unknown, b: unknown): boolean => JSON.stringify(a) === JSON.stringify(b);\n\nfunction servedFor(\n snapshot: unknown,\n cursor: ServedCursor,\n): { readonly served?: ContextServed; readonly servedError?: string } {\n try {\n const row = servedRowAt(snapshot, cursor);\n if (row === undefined) return {};\n const checks = verify(row.view, row.receipt, row.receipt?.basis.runId ?? '', row.receiptCause);\n const previous =\n row.previousEpoch !== undefined ? servedRowForEpoch(snapshot, row.previousEpoch) : undefined;\n const since = previous !== undefined ? sincePrevious(row, previous) : undefined;\n return {\n served: Object.freeze({\n row,\n checks,\n ...(since !== undefined ? { since } : {}),\n }),\n };\n } catch (e) {\n return { servedError: e instanceof Error ? e.message : String(e) };\n }\n}\n\nfunction whyFor(events: readonly EventLogEntry[] | undefined, stages: ReadonlySet<string>): ContextAt['why'] {\n if (events === undefined || stages.size === 0) return Object.freeze([]);\n const out: { seq: number; name: string; runtimeStageId: string }[] = [];\n for (const entry of events) {\n const id = entry.runtimeStageId;\n if (id === undefined || !stages.has(id)) continue;\n out.push({ seq: entry.seq, name: entry.event.type, runtimeStageId: id });\n }\n return Object.freeze(out);\n}\n\n/**\n * The context at `cursor`: the fold's keys with their writers, the delta\n * since `options.previous`, the served side at this epoch, and the events\n * beside the delta. Returns a frozen object; a fold that cannot be replayed\n * reports `foldError` with no keys rather than an empty object pretending to\n * be one.\n */\nexport function contextAt(\n recording: unknown,\n cursor: ServedCursor,\n options: ContextAtOptions = {},\n): ContextAt {\n const log = logOf(recording);\n const folded = foldAt(recording, cursor.commitIdx);\n if ('error' in folded) {\n return Object.freeze({\n cursor,\n keys: Object.freeze([]),\n left: Object.freeze([]),\n rows: Object.freeze([]),\n redacted: false,\n foldError: folded.error,\n why: Object.freeze([]),\n });\n }\n const writers = writersUpTo(log, cursor.commitIdx);\n const previous = options.previous !== undefined ? foldAt(recording, options.previous.commitIdx) : undefined;\n const previousState = previous !== undefined && !('error' in previous) ? previous.state : undefined;\n\n const keys: ContextKey[] = [];\n for (const [path, value] of Object.entries(folded.state)) {\n const w = writers.get(path);\n const since: ContextKey['since'] | undefined =\n previousState === undefined\n ? undefined\n : !(path in previousState)\n ? 'entered'\n : same(previousState[path], value)\n ? 'unchanged'\n : 'changed';\n keys.push(\n Object.freeze({\n path,\n value,\n ...(w !== undefined\n ? {\n wroteBy: w.wroteBy,\n wroteAt: w.wroteAt,\n enteredAt: w.enteredAt,\n verb: w.verb,\n }\n : {}),\n ...(since !== undefined ? { since } : {}),\n }),\n );\n }\n const left =\n previousState === undefined ? [] : Object.keys(previousState).filter((k) => !(k in folded.state));\n\n const bundle = log[cursor.commitIdx];\n const rows = Array.isArray(bundle?.trace)\n ? bundle.trace.map((r: TraceRow) => Object.freeze({ path: r.path, verb: r.verb }))\n : [];\n\n const stages = new Set<string>();\n if (bundle !== undefined && typeof bundle.runtimeStageId === 'string') stages.add(bundle.runtimeStageId);\n for (const k of keys)\n if (k.since !== undefined && k.since !== 'unchanged' && k.wroteBy !== undefined) stages.add(k.wroteBy);\n\n const skipped =\n folded.skipped !== undefined && folded.skipped.length > 0\n ? folded.skipped.map((g) => g.index)\n : undefined;\n const { served, servedError } = servedFor(recording, cursor);\n\n return Object.freeze({\n cursor,\n keys: Object.freeze(keys),\n left: Object.freeze(left),\n rows: Object.freeze(rows),\n basis: folded.basis,\n redacted: folded.redacted,\n ...(skipped !== undefined ? { skipped: Object.freeze(skipped) } : {}),\n ...(served !== undefined ? { served } : {}),\n ...(servedError !== undefined ? { servedError } : {}),\n why: whyFor(options.events, stages),\n });\n}\n"],"mappings":"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","names":[]}