@irisrun/inspect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/inspect.d.ts +26 -0
- package/dist/inspect.js +92 -0
- package/package.json +32 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { StateStore, RecordKind, Json } from "@irisrun/core";
|
|
2
|
+
export interface InspectedRecord {
|
|
3
|
+
seq: number;
|
|
4
|
+
ts: number;
|
|
5
|
+
defDigest: string;
|
|
6
|
+
kind: RecordKind;
|
|
7
|
+
summary: string;
|
|
8
|
+
detail: Json;
|
|
9
|
+
}
|
|
10
|
+
export interface SessionInspection {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
governingDigest: string | null;
|
|
13
|
+
snapshotUpTo: number | null;
|
|
14
|
+
records: InspectedRecord[];
|
|
15
|
+
counts: {
|
|
16
|
+
effects: number;
|
|
17
|
+
results: number;
|
|
18
|
+
markers: number;
|
|
19
|
+
decisions: number;
|
|
20
|
+
};
|
|
21
|
+
terminal: "finished" | "parked" | "open";
|
|
22
|
+
}
|
|
23
|
+
/** Inspect a recorded session. Pure over the journal; never writes. */
|
|
24
|
+
export declare function inspectSession(store: StateStore, sessionId: string): Promise<SessionInspection>;
|
|
25
|
+
/** A deterministic one-line-per-record text rendering. */
|
|
26
|
+
export declare function renderTimeline(inspection: SessionInspection): string;
|
package/dist/inspect.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// inspectSession (ADR-0009 inspect surface) — render a recorded session's
|
|
2
|
+
// decision/effect/marker timeline from a StateStore, keyed by the stable
|
|
3
|
+
// sessionId. READ-ONLY: it reads snapshot + journal, decodes, and summarizes; it
|
|
4
|
+
// never writes and nothing it derives re-enters replayed state (determinism). The
|
|
5
|
+
// governing digest is re-derived LOCALLY (snapshot-safely — the post-snapshot tail,
|
|
6
|
+
// mirroring pin.ts:latestRecord), so @irisrun/inspect deps @irisrun/core ONLY. The result
|
|
7
|
+
// is a pure function of the journal bytes → re-inspecting is byte-identical.
|
|
8
|
+
import { decode } from "@irisrun/core";
|
|
9
|
+
function summarize(rec) {
|
|
10
|
+
switch (rec.kind) {
|
|
11
|
+
case "effect_intent": {
|
|
12
|
+
const p = rec.payload;
|
|
13
|
+
return `effect ${p.effectKind} (intent ${p.effectId}${p.retrySafe ? "" : ", retry-unsafe"})`;
|
|
14
|
+
}
|
|
15
|
+
case "effect_result": {
|
|
16
|
+
const p = rec.payload;
|
|
17
|
+
return `result ${p.effectId} → ${p.outcome.ok ? "ok" : `error: ${p.outcome.error.message}`}`;
|
|
18
|
+
}
|
|
19
|
+
case "decision": {
|
|
20
|
+
const p = rec.payload;
|
|
21
|
+
return `decision ${p.seam} → ${p.tacticId}`;
|
|
22
|
+
}
|
|
23
|
+
case "marker": {
|
|
24
|
+
const p = rec.payload;
|
|
25
|
+
if (p.marker === "wait")
|
|
26
|
+
return `marker wait (${p.wait.kind}${p.wait.kind === "signal" ? `:${p.wait.name}` : ""})`;
|
|
27
|
+
if (p.marker === "finish")
|
|
28
|
+
return "marker finish";
|
|
29
|
+
if (p.marker === "upgraded")
|
|
30
|
+
return `marker upgraded ${p.from}→${p.to} @${p.atTurn}`;
|
|
31
|
+
if (p.marker === "snapshot")
|
|
32
|
+
return `marker snapshot upTo ${p.upToSeq}`;
|
|
33
|
+
return `marker ${p.marker}`;
|
|
34
|
+
}
|
|
35
|
+
default:
|
|
36
|
+
return rec.kind;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function terminalOf(records) {
|
|
40
|
+
for (let i = records.length - 1; i >= 0; i--) {
|
|
41
|
+
const r = records[i];
|
|
42
|
+
if (r.kind !== "marker")
|
|
43
|
+
continue;
|
|
44
|
+
const m = r.detail.marker;
|
|
45
|
+
if (m === "finish")
|
|
46
|
+
return "finished";
|
|
47
|
+
if (m === "wait")
|
|
48
|
+
return "parked";
|
|
49
|
+
}
|
|
50
|
+
return "open";
|
|
51
|
+
}
|
|
52
|
+
/** Inspect a recorded session. Pure over the journal; never writes. */
|
|
53
|
+
export async function inspectSession(store, sessionId) {
|
|
54
|
+
const snap = await store.readLatestSnapshot(sessionId);
|
|
55
|
+
const snapshotUpTo = snap ? snap.upToSeq : null;
|
|
56
|
+
const rows = await store.readJournal(sessionId, (snap?.upToSeq ?? -1) + 1);
|
|
57
|
+
const records = rows.map((row) => {
|
|
58
|
+
const rec = decode(row.bytes);
|
|
59
|
+
return {
|
|
60
|
+
seq: rec.seq,
|
|
61
|
+
ts: rec.ts,
|
|
62
|
+
defDigest: rec.defDigest,
|
|
63
|
+
kind: rec.kind,
|
|
64
|
+
summary: summarize(rec),
|
|
65
|
+
detail: rec.payload,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
const counts = { effects: 0, results: 0, markers: 0, decisions: 0 };
|
|
69
|
+
for (const r of records) {
|
|
70
|
+
if (r.kind === "effect_intent")
|
|
71
|
+
counts.effects += 1;
|
|
72
|
+
else if (r.kind === "effect_result")
|
|
73
|
+
counts.results += 1;
|
|
74
|
+
else if (r.kind === "marker")
|
|
75
|
+
counts.markers += 1;
|
|
76
|
+
else if (r.kind === "decision")
|
|
77
|
+
counts.decisions += 1;
|
|
78
|
+
}
|
|
79
|
+
// governing digest = the latest record's defDigest (snapshot-safe: the terminal
|
|
80
|
+
// marker is committed after the snapshot seq, so it survives truncation). null
|
|
81
|
+
// for a never-started session (empty tail + no snapshot).
|
|
82
|
+
const governingDigest = records.length ? records[records.length - 1].defDigest : null;
|
|
83
|
+
return { sessionId, governingDigest, snapshotUpTo, records, counts, terminal: terminalOf(records) };
|
|
84
|
+
}
|
|
85
|
+
/** A deterministic one-line-per-record text rendering. */
|
|
86
|
+
export function renderTimeline(inspection) {
|
|
87
|
+
const head = `session ${inspection.sessionId} | digest ${inspection.governingDigest ?? "—"} | ` +
|
|
88
|
+
`terminal ${inspection.terminal} | snapshot ${inspection.snapshotUpTo ?? "—"} | ` +
|
|
89
|
+
`${inspection.records.length} record(s)`;
|
|
90
|
+
const lines = inspection.records.map((r) => `#${r.seq} ${r.kind} ${r.summary}`);
|
|
91
|
+
return [head, ...lines].join("\n");
|
|
92
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@irisrun/inspect",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Iris journal/decision viewer (ADR-0009 inspect surface) — reads a recorded session (snapshot + journal) from a StateStore and renders the deterministic decision/effect/marker timeline, keyed by the stable sessionId. READ-ONLY; re-derives the governing digest snapshot-safely; never writes. Pure over @irisrun/core.",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"iris-src": "./src/index.ts",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@irisrun/core": "^0.1.0"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=24"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/xoai/iris.git",
|
|
26
|
+
"directory": "packages/inspect"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/xoai/iris#readme",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
]
|
|
32
|
+
}
|