progmune-runtime 2.0.2 → 2.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.
Files changed (107) hide show
  1. package/.mcp.json +11 -0
  2. package/.progmune_allowlist +50 -0
  3. package/.test_report/test_report.md +87 -0
  4. package/Dockerfile +2 -10
  5. package/FAQ.md +167 -0
  6. package/demo-project/auth.ts +55 -0
  7. package/demo-project/tsconfig.json +8 -0
  8. package/dist/ab-stats.js +11 -0
  9. package/dist/acl-breakdown.js +13 -0
  10. package/dist/all-sessions.js +11 -0
  11. package/dist/antibody-stats.js +11 -0
  12. package/dist/audit.js +218 -0
  13. package/dist/benchmark-count.js +7 -0
  14. package/dist/benchmark-full.js +17 -0
  15. package/dist/benchmark-pass-rate.js +54 -0
  16. package/dist/benchmark-report.js +67 -0
  17. package/dist/benchmark-save.js +62 -0
  18. package/dist/benchmark-status.js +15 -0
  19. package/dist/branch-ledger.js +365 -0
  20. package/dist/branch-tree-count.js +14 -0
  21. package/dist/check.js +506 -0
  22. package/dist/common-fixpath.js +12 -0
  23. package/dist/constraint-types.js +12 -0
  24. package/dist/deterministic-replay.js +277 -0
  25. package/dist/emitter.js +112 -12
  26. package/dist/exec-metrics.js +11 -0
  27. package/dist/execute.js +242 -0
  28. package/dist/extract-ir.js +550 -5
  29. package/dist/failure-collector.js +143 -0
  30. package/dist/failure-corpus.js +481 -35
  31. package/dist/failure-report.js +11 -0
  32. package/dist/failures.js +11 -0
  33. package/dist/fast-path-hits.js +13 -0
  34. package/dist/feedback.js +6 -3
  35. package/dist/file-lock.js +82 -0
  36. package/dist/find-session.js +10 -0
  37. package/dist/fingerprint-list.js +15 -0
  38. package/dist/gen-history-log.js +13 -0
  39. package/dist/generate.js +2 -1
  40. package/dist/generate_500.js +4 -2
  41. package/dist/genome.js +11 -0
  42. package/dist/heatmap-data.js +11 -0
  43. package/dist/heatmap.js +11 -0
  44. package/dist/immune-reporter.js +137 -0
  45. package/dist/learned.js +11 -0
  46. package/dist/ledger-registry.js +241 -0
  47. package/dist/llm.js +43 -2
  48. package/dist/load-benchmarks.js +47 -0
  49. package/dist/main.js +2 -1
  50. package/dist/mcp-server.mjs +446 -34
  51. package/dist/memory-layer.js +51 -13
  52. package/dist/metrics.js +11 -0
  53. package/dist/obs-web.js +561 -0
  54. package/dist/p0_ssg_demo.js +255 -40
  55. package/dist/planner.js +933 -65
  56. package/dist/protocol-registry.js +105 -0
  57. package/dist/recent-session.js +12 -0
  58. package/dist/repair-proposal.js +353 -0
  59. package/dist/report.js +32 -0
  60. package/dist/runtime-invariants.js +161 -0
  61. package/dist/runtime-types.js +117 -0
  62. package/dist/search-planner.js +38 -9
  63. package/dist/semantic-snapshot.js +155 -0
  64. package/dist/semantic-trace.js +1497 -0
  65. package/dist/semantic-validator.js +3 -2
  66. package/dist/semantic_guard_test.js +2 -1
  67. package/dist/sessions.js +11 -0
  68. package/dist/ssg-validator.js +658 -20
  69. package/dist/svl-distribution.js +11 -0
  70. package/dist/terminal-status.js +11 -0
  71. package/dist/test_failure_corpus.js +3 -1
  72. package/dist/token-savings.js +11 -0
  73. package/dist/total-repairs.js +12 -0
  74. package/dist/unresolved-count.js +12 -0
  75. package/dist/valid-fingerprints.js +13 -0
  76. package/dist/validator.js +116 -60
  77. package/dist/verify-fps.js +11 -0
  78. package/dist/verify-ledgers.js +11 -0
  79. package/docs/whitepaper-style.css +77 -0
  80. package/docs/whitepaper-v2.1.md +609 -0
  81. package/docs/whitepaper-v2.2.md +1064 -0
  82. package/docs/whitepaper-v2.2.pdf +0 -0
  83. package/fly.toml +1 -1
  84. package/package.json +13 -4
  85. package/protocols.json +136 -0
  86. package/public/dashboard.html +119 -0
  87. package/readme.md +829 -0
  88. package/server/hub.js +84 -12
  89. package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
  90. package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
  91. package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
  92. package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
  93. package/test/replay-golden.ts +84 -0
  94. package/test_benchmark.js +165 -0
  95. package/test_comprehensive.mjs +638 -0
  96. package/test_concurrency.js +129 -0
  97. package/test_ir_robustness.js +85 -0
  98. package/test_semantic_contracts.js +269 -0
  99. package/test_ssg_stress.js +156 -0
  100. package/test_svl3.js +58 -0
  101. package/tsconfig.json +1 -1
  102. package/.env.example +0 -3
  103. package/.progmune_memory/fingerprints.json +0 -7
  104. package/.progmune_memory/opt_in.json +0 -4
  105. package/README.md +0 -118
  106. package/dist/mcp-server.js +0 -55
  107. package/immune_hub_data/2026-05-14.json +0 -50
@@ -0,0 +1,1497 @@
1
+ "use strict";
2
+ /**
3
+ * Semantic Observatory — Terminal-based Semantic Trace Viewer
4
+ *
5
+ * Reads IntentSessions from the failure corpus and renders a timeline-first
6
+ * view of AI reasoning evolution: attempts, failures, repair paths, and success.
7
+ *
8
+ * Usage:
9
+ * ts-node src/semantic-trace.ts → all sessions summary
10
+ * ts-node src/semantic-trace.ts <sessionId> → full timeline for one session
11
+ * ts-node src/semantic-trace.ts replay <sessionId> → step-by-step cognitive replay
12
+ * ts-node src/semantic-trace.ts --states <sessionId> → state transition visualization
13
+ * ts-node src/semantic-trace.ts --genome → failure genome summary
14
+ * ts-node src/semantic-trace.ts --learned → antibody registry with ACL levels
15
+ * ts-node src/semantic-trace.ts --antibodies → antibody efficacy metrics
16
+ * ts-node src/semantic-trace.ts --heatmap → semantic heatmap
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ const failure_corpus_1 = require("./failure-corpus");
53
+ // ── ANSI colors ──
54
+ const C = { reset: "\x1b[0m", green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m", gray: "\x1b[90m", bold: "\x1b[1m", dim: "\x1b[2m" };
55
+ const G = (s) => `${C.green}${s}${C.reset}`;
56
+ const R = (s) => `${C.red}${s}${C.reset}`;
57
+ const Y = (s) => `${C.yellow}${s}${C.reset}`;
58
+ const C_ = (s) => `${C.cyan}${s}${C.reset}`;
59
+ const D = (s) => `${C.gray}${s}${C.reset}`;
60
+ const B = (s) => `${C.bold}${s}${C.reset}`;
61
+ function narrateRejection(v) {
62
+ const svlStr = `SVL-${v.svl}`;
63
+ const missing = v.missingStates?.length ? v.missingStates.join(", ") : null;
64
+ const blocked = v.description.match(/(\w+)\s*(要求|requires|blocked|不允许|不合法)/)?.[1] || "unknown";
65
+ switch (svlStr) {
66
+ case "SVL-1":
67
+ return `Planner referenced a function that does not exist in the project.\n ${D("→ " + v.description)}`;
68
+ case "SVL-2":
69
+ return `Planner called a function with incorrect argument types.\n ${D("→ " + v.description)}`;
70
+ case "SVL-3":
71
+ return `Planner used a variable before it was defined or referenced it circularly.\n ${D("→ " + v.description)}`;
72
+ case "SVL-4":
73
+ if (missing) {
74
+ return `Planner attempted to call ${R(blocked)} before ${C_(missing)} was established.`;
75
+ }
76
+ return `Planner violated the protocol contract for ${R(blocked)}.\n ${D("→ " + v.description)}`;
77
+ default:
78
+ return v.description;
79
+ }
80
+ }
81
+ function narrateSuccess(actions) {
82
+ const names = actions
83
+ .filter(a => a.kind === "call" && a.function)
84
+ .map(a => a.function)
85
+ .join(" → ");
86
+ return `Successfully completed: ${G(names)}.`;
87
+ }
88
+ // ── Timeline rendering ──
89
+ function formatActionSequence(actions) {
90
+ return actions
91
+ .filter(a => a.kind === "call" && a.function)
92
+ .map(a => C_(a.function + "()"))
93
+ .join(` ${D("→")} `);
94
+ }
95
+ function formatSessionTimeline(session) {
96
+ const width = 66;
97
+ const title = `Intent: ${session.intent}`;
98
+ const header = `┌─ ${B(title)} ${"─".repeat(Math.max(2, width - title.length - 5))}┐`;
99
+ const failedCount = session.attempts.filter(a => a.outcome !== "success").length;
100
+ const resolvedIcon = session.resolved ? G("✔") : R("✖");
101
+ const snapTag = session.snapshotId ? ` │ ${D("Snapshot:")} ${D(session.snapshotId.slice(-16))}` : "";
102
+ const info = `│ Session: ${D(session.sessionId)} │ Retries: ${failedCount} │ Resolved: ${resolvedIcon} ${" ".repeat(Math.max(1, 15))}│`;
103
+ const footer = `└${"─".repeat(width - 2)}┘`;
104
+ const lines = [header, info];
105
+ if (snapTag)
106
+ lines.push(snapTag);
107
+ lines.push(footer, "");
108
+ // Render all failure attempts
109
+ const failedAttempts = session.attempts.filter(a => a.outcome !== "success");
110
+ for (let i = 0; i < failedAttempts.length; i++) {
111
+ const a = failedAttempts[i];
112
+ const num = a.attemptNumber;
113
+ const actions = a.generatedActions || [];
114
+ const actionDisplay = formatActionSequence(actions);
115
+ lines.push(` Attempt ${num} ${"─".repeat(62)}`);
116
+ lines.push(` │ ${actionDisplay || D("(no actions)")}`);
117
+ lines.push(` │`);
118
+ // Render each violation in the attempt
119
+ for (const v of a.violations) {
120
+ const narration = narrateRejection(v);
121
+ const lines_narration = narration.split("\n");
122
+ lines.push(` ${R("✖")} ${lines_narration[0]}`);
123
+ for (let j = 1; j < lines_narration.length; j++) {
124
+ lines.push(` ${lines_narration[j]}`);
125
+ }
126
+ // Show SSG context for protocol failures
127
+ if (v.svl === 4) {
128
+ if (v.missingStates?.length) {
129
+ const missingList = v.missingStates.join(", ");
130
+ lines.push(` ${D("→")} Missing: ${C_(missingList)}`);
131
+ }
132
+ if (v.fixPath?.length) {
133
+ const fixList = v.fixPath.join(" → ");
134
+ lines.push(` ${D("→")} Repair: ${Y(fixList)}`);
135
+ }
136
+ if (v.namespace && v.namespace !== "_global") {
137
+ lines.push(` ${D("→")} Namespace: ${D(v.namespace)}`);
138
+ }
139
+ }
140
+ }
141
+ lines.push(` ${D(`(attempt ${num}/${session.attempts.length})`)}`);
142
+ lines.push("");
143
+ }
144
+ // Final resolution
145
+ if (session.resolved && session.successfulAttempt) {
146
+ const actions = session.successfulAttempt.generatedActions || [];
147
+ const actionDisplay = formatActionSequence(actions);
148
+ lines.push(` ${G("✔")} Resolution ${"─".repeat(51)}`);
149
+ lines.push(` │ ${actionDisplay}`);
150
+ lines.push(` │`);
151
+ const narration = narrateSuccess(actions);
152
+ lines.push(` ${G("✔")} ${narration}`);
153
+ lines.push(` ${D(`Resolved after ${failedCount} retries.`)}`);
154
+ // Phase 3: Ledger consistency check
155
+ if (session.successfulAttempt.transitions.length > 0) {
156
+ const nsInit = new Map([["_global", "INIT"]]);
157
+ const consistency = (0, ssg_validator_1.checkLedgerConsistency)(session.successfulAttempt.transitions, nsInit);
158
+ if (consistency.consistent) {
159
+ lines.push(` ${G("Ledger: consistent")}`);
160
+ }
161
+ else {
162
+ lines.push(` ${R(`Ledger: ${consistency.violations.length} violation(s)`)}`);
163
+ for (const v of consistency.violations) {
164
+ lines.push(` ${D(`[${v.invariant}] index=${v.index}`)}`);
165
+ }
166
+ }
167
+ }
168
+ lines.push("");
169
+ }
170
+ else if (!session.resolved) {
171
+ lines.push(` ${R("✖")} ${B("Unresolved")} ${"─".repeat(50)}`);
172
+ lines.push(` ${D(`Failed after ${failedCount} retries with no successful path.`)}`);
173
+ lines.push("");
174
+ }
175
+ return lines.join("\n");
176
+ }
177
+ // ── Summary table rendering ──
178
+ function pad(s, w) {
179
+ const visible = s.replace(/\x1b\[[0-9;]*m/g, "").length;
180
+ return s + " ".repeat(Math.max(0, w - visible));
181
+ }
182
+ function formatSessionSummary(sessions) {
183
+ if (sessions.length === 0) {
184
+ return `${D("No sessions recorded yet.")}\nRun the planner to generate semantic traces.`;
185
+ }
186
+ const header = `Sessions in failure corpus (${sessions.length} total):\n`;
187
+ const colW = { session: 16, intent: 28, attempts: 10, resolved: 10 };
188
+ const sep = "─".repeat(70);
189
+ const lines = [
190
+ header,
191
+ `┌${sep}┐`,
192
+ `│ ${pad("Session", colW.session)}│ ${pad("Intent", colW.intent)}│ ${pad("Attempts", colW.attempts)}│ ${pad("Resolved", colW.resolved)}│`,
193
+ `├${sep}┤`,
194
+ ];
195
+ for (const s of sessions) {
196
+ const shortId = s.sessionId.length > 14 ? s.sessionId.slice(0, 13) + "…" : s.sessionId;
197
+ const shortIntent = s.intent.length > 26 ? s.intent.slice(0, 25) + "…" : s.intent;
198
+ const resolved = s.resolved ? G("✔ resolved") : R("✖ unresolved");
199
+ lines.push(`│ ${pad(D(shortId), colW.session)}│ ${pad(shortIntent, colW.intent)}│ ${pad(String(s.attempts.length), colW.attempts)}│ ${pad(resolved, colW.resolved)}│`);
200
+ }
201
+ lines.push(`└${sep}┘`);
202
+ lines.push("");
203
+ lines.push(`${D("Commands:")} timeline | replay | --states | --genome | --learned | --antibodies | --heatmap`);
204
+ return lines.join("\n");
205
+ }
206
+ // ── Genome summary ──
207
+ function formatGenomeSummary() {
208
+ const g = (0, failure_corpus_1.getFailureGenome)();
209
+ if (g.totalFailures === 0) {
210
+ return `${D("No failures recorded yet.")}`;
211
+ }
212
+ const bar = "─".repeat(56);
213
+ const lines = [
214
+ `┌─ ${B("Failure Genome")} ${bar.slice(0, 40)}┐`,
215
+ `│ Total failures: ${R(String(g.totalFailures))}${" ".repeat(39)}│`,
216
+ `│ Average retries: ${Y(String(g.averageRetriesToSuccess))}${" ".repeat(38)}│`,
217
+ `├${bar}┤`,
218
+ `│ ${B("By SVL Level")}${" ".repeat(44)}│`,
219
+ `│ SVL-1 (Symbol): ${barChart(g.bySVL["SVL-1"], g.totalFailures)} ${g.bySVL["SVL-1"]} │`,
220
+ `│ SVL-2 (Type): ${barChart(g.bySVL["SVL-2"], g.totalFailures)} ${g.bySVL["SVL-2"]} │`,
221
+ `│ SVL-3 (Dataflow): ${barChart(g.bySVL["SVL-3"], g.totalFailures)} ${g.bySVL["SVL-3"]} │`,
222
+ `│ SVL-4 (Protocol): ${barChart(g.bySVL["SVL-4"], g.totalFailures)} ${g.bySVL["SVL-4"]} │`,
223
+ `├${bar}┤`,
224
+ ];
225
+ if (g.topPatterns.length > 0) {
226
+ lines.push(`│ ${B("Top Failure Patterns")}${" ".repeat(37)}│`);
227
+ for (const p of g.topPatterns) {
228
+ const label = `${p.pattern}: ${p.count}x`;
229
+ lines.push(`│ ${label}${" ".repeat(Math.max(1, 52 - label.length))}│`);
230
+ }
231
+ lines.push(`├${bar}┤`);
232
+ }
233
+ if (g.commonFixPaths.length > 0) {
234
+ lines.push(`│ ${B("Common Repair Paths")}${" ".repeat(36)}│`);
235
+ for (const fp of g.commonFixPaths.slice(0, 4)) {
236
+ const path = fp.fixPath.join(" → ");
237
+ const label = ` ${path} (${fp.count}x)`;
238
+ const trimmed = label.length > 52 ? label.slice(0, 49) + "..." : label;
239
+ lines.push(`│ ${trimmed}${" ".repeat(Math.max(1, 52 - trimmed.length))}│`);
240
+ }
241
+ lines.push(`├${bar}┤`);
242
+ }
243
+ // By constraint type
244
+ const constraints = Object.entries(g.byConstraintType).sort((a, b) => b[1] - a[1]);
245
+ if (constraints.length > 0) {
246
+ lines.push(`│ ${B("By Constraint Type")}${" ".repeat(37)}│`);
247
+ for (const [k, v] of constraints) {
248
+ lines.push(`│ ${k}: ${v}${" ".repeat(Math.max(1, 51 - k.length - String(v).length))}│`);
249
+ }
250
+ }
251
+ lines.push(`└${bar}┘`);
252
+ return lines.join("\n");
253
+ }
254
+ function barChart(count, total) {
255
+ if (total === 0)
256
+ return D("▏".repeat(0));
257
+ const maxBars = 20;
258
+ const n = Math.round((count / total) * maxBars);
259
+ if (n === 0 && count > 0)
260
+ return Y("▏");
261
+ if (n === 0)
262
+ return D("▏".repeat(0));
263
+ return Y("█".repeat(n)) + D("░".repeat(maxBars - n));
264
+ }
265
+ // ── Learned patterns ──
266
+ function aclBadge(level) {
267
+ switch (level) {
268
+ case "ACL-4": return G(`◆ ${level} (globally stable)`);
269
+ case "ACL-3": return C_(`◈ ${level} (cross-task validated)`);
270
+ case "ACL-2": return Y(`◇ ${level} (repeated observation)`);
271
+ case "ACL-1": return D(`◌ ${level} (single case)`);
272
+ default: return D(level);
273
+ }
274
+ }
275
+ function formatLearnedPatterns() {
276
+ const learned = (0, failure_corpus_1.getLearnedPatterns)();
277
+ const patterns = learned.failureToFix;
278
+ if (patterns.length === 0) {
279
+ return `${D("No learned patterns yet.")}\nPatterns emerge when sessions capture failures with repair paths.`;
280
+ }
281
+ const lines = [
282
+ `${B("Antibody Registry")} (${patterns.length} patterns)`,
283
+ "─".repeat(72),
284
+ ];
285
+ for (const p of patterns) {
286
+ const path = p.fixPath.join(" → ");
287
+ const intents = p.distinctIntents.slice(0, 3).join(", ");
288
+ const moreIntents = p.distinctIntents.length > 3 ? ` +${p.distinctIntents.length - 3} more` : "";
289
+ const ratePct = Math.round(p.resolvedRate * 100);
290
+ lines.push(` ${B("Signature:")} ${R(p.violation)}`);
291
+ lines.push(` ${D("Repair:")} ${Y(path)}`);
292
+ lines.push(` ${D("Confidence:")} ${aclBadge(p.antibodyLevel)}`);
293
+ lines.push(` ${D("Occurrences:")} ${p.occurrenceCount}x │ ${D("Resolved:")} ${ratePct}% │ ${D("Intents:")} ${intents}${moreIntents}`);
294
+ lines.push("");
295
+ }
296
+ return lines.join("\n");
297
+ }
298
+ // ── Antibody efficacy stats ──
299
+ function formatAntibodyStats() {
300
+ const stats = (0, failure_corpus_1.getAntibodyStats)();
301
+ if (stats.totalHits === 0) {
302
+ return `${D("No antibody hits recorded yet.")}\nAntibodies are recorded when the immune system accelerates planning via learned fix paths.`;
303
+ }
304
+ const lines = [];
305
+ lines.push(`${B("Antibody Efficacy Report")}`);
306
+ lines.push("═".repeat(68));
307
+ lines.push("");
308
+ // Summary
309
+ lines.push(` ${B("Immune Acceleration Summary")}`);
310
+ lines.push(` ${D("─".repeat(44))}`);
311
+ lines.push(` Total antibody hits: ${C_(String(stats.totalHits))}`);
312
+ lines.push(` ACL-4 fast-path (0 LLM): ${G(String(stats.fastPathHits))}`);
313
+ lines.push(` ACL-3 injected hints: ${Y(String(stats.injectedHintHits))}`);
314
+ lines.push(` LLM calls saved: ${G(String(stats.totalLLMCallsSaved))}`);
315
+ lines.push(` Est. tokens saved: ${G(stats.totalTokensSaved.toLocaleString())}`);
316
+ lines.push("");
317
+ // By Level
318
+ if (Object.keys(stats.byLevel).length > 0) {
319
+ lines.push(` ${B("By Antibody Level")}`);
320
+ lines.push(` ${D("─".repeat(34))}`);
321
+ const levels = ["ACL-4", "ACL-3", "ACL-2", "ACL-1"];
322
+ for (const lvl of levels) {
323
+ const d = stats.byLevel[lvl];
324
+ if (!d)
325
+ continue;
326
+ const icon = lvl === "ACL-4" ? G("◆") : lvl === "ACL-3" ? C_("◈") : lvl === "ACL-2" ? Y("◇") : D("◌");
327
+ lines.push(` ${icon} ${lvl}: ${d.hits} hits, ${d.llmSaved} LLM saved, ${d.tokensSaved.toLocaleString()} tokens`);
328
+ }
329
+ lines.push("");
330
+ }
331
+ // Top signatures
332
+ if (stats.topSignatures.length > 0) {
333
+ lines.push(` ${B("Top Antibody Signatures")}`);
334
+ lines.push(` ${D("─".repeat(40))}`);
335
+ for (const s of stats.topSignatures.slice(0, 5)) {
336
+ const sig = s.signature.length > 42 ? s.signature.slice(0, 39) + "..." : s.signature;
337
+ lines.push(` ${s.hits}x ${sig.padEnd(44)} ~${s.avgSimilarity}`);
338
+ }
339
+ lines.push("");
340
+ }
341
+ // Efficiency note
342
+ if (stats.fastPathHits > 0) {
343
+ const pct = Math.round((stats.fastPathHits / stats.totalHits) * 100);
344
+ lines.push(` ${G(`Immune efficiency: ${pct}% of hits bypassed LLM entirely`)}`);
345
+ }
346
+ return lines.join("\n");
347
+ }
348
+ // ── Semantic heatmap ──
349
+ const failure_corpus_2 = require("./failure-corpus");
350
+ const ssg_validator_1 = require("./ssg-validator");
351
+ const semantic_snapshot_1 = require("./semantic-snapshot");
352
+ const fs = __importStar(require("fs"));
353
+ const path = __importStar(require("path"));
354
+ function formatHeatmap() {
355
+ const h = (0, failure_corpus_2.getSemanticHeatmap)();
356
+ if (h.fragileProtocols.length === 0 && h.svlHotspots.length === 0) {
357
+ return `${D("No heatmap data yet.")}`;
358
+ }
359
+ const lines = [];
360
+ lines.push(`${B("Semantic Heatmap")}`);
361
+ lines.push("═".repeat(72));
362
+ lines.push("");
363
+ // SVL hotspots as horizontal bars
364
+ if (h.svlHotspots.length > 0) {
365
+ lines.push(` ${B("Immune Layer Activity")}`);
366
+ lines.push(` ${D("─".repeat(44))}`);
367
+ const maxCount = Math.max(...h.svlHotspots.map(s => s.count), 1);
368
+ const maxBar = 30;
369
+ for (const s of h.svlHotspots) {
370
+ const n = Math.round((s.count / maxCount) * maxBar) || (s.count > 0 ? 1 : 0);
371
+ const bar = R("█".repeat(n)) + D("░".repeat(maxBar - n));
372
+ const pct = `${s.percentage}%`.padStart(4);
373
+ lines.push(` ${s.svl.padEnd(8)} ${bar} ${String(s.count).padStart(2)} (${pct})`);
374
+ }
375
+ lines.push("");
376
+ }
377
+ // Fragile protocols
378
+ if (h.fragileProtocols.length > 0) {
379
+ lines.push(` ${B("Fragile Protocols (most blocked functions)")}`);
380
+ lines.push(` ${D("─".repeat(52))}`);
381
+ for (const fp of h.fragileProtocols.slice(0, 6)) {
382
+ const heat = fp.violationCount >= 5 ? R("●●●") : fp.violationCount >= 3 ? Y("●●") : Y("●");
383
+ lines.push(` ${heat} ${C_(fp.function + "()")} ${D(`— ${fp.violationCount}x, ${fp.svl}`)}`);
384
+ }
385
+ lines.push("");
386
+ }
387
+ // Constraint clusters
388
+ if (h.constraintClusters.length > 0) {
389
+ lines.push(` ${B("Constraint Co-occurrence")}`);
390
+ lines.push(` ${D("─".repeat(40))}`);
391
+ for (const cc of h.constraintClusters.slice(0, 4)) {
392
+ const cluster = cc.constraints.map(c => Y(c)).join(" + ");
393
+ lines.push(` ${cluster}`);
394
+ lines.push(` ${D(` ↳ ${cc.count} anomalies in "${cc.intent.slice(0, 40)}"`)}`);
395
+ }
396
+ lines.push("");
397
+ }
398
+ // High friction intents
399
+ if (h.highFrictionIntents.length > 0) {
400
+ lines.push(` ${B("High Friction Intents (most adaptations required)")}`);
401
+ lines.push(` ${D("─".repeat(52))}`);
402
+ for (const fi of h.highFrictionIntents.slice(0, 5)) {
403
+ const friction = fi.adaptationCount >= 4 ? R("■■■") : fi.adaptationCount >= 2 ? Y("■■") : Y("■");
404
+ const types = fi.anomalyTypes.join(", ");
405
+ lines.push(` ${friction} ${fi.intent.slice(0, 40).padEnd(42)} ${D(`${fi.adaptationCount} adapts, ${types}`)}`);
406
+ }
407
+ lines.push("");
408
+ }
409
+ return lines.join("\n");
410
+ }
411
+ // ── State transition visualization ──
412
+ function loadProtocols() {
413
+ const protocolsJson = path.join(__dirname, "..", "protocols.json");
414
+ const protocols = [];
415
+ if (fs.existsSync(protocolsJson)) {
416
+ const raw = JSON.parse(fs.readFileSync(protocolsJson, "utf-8"));
417
+ for (const [funcName, rule] of Object.entries(raw.rules || {})) {
418
+ const r = rule;
419
+ protocols.push({
420
+ function: funcName,
421
+ protocol: {
422
+ pre_states: r.pre_states || [],
423
+ post_states: r.post_states || [],
424
+ invalidate: r.invalidate,
425
+ namespace: r.namespace,
426
+ },
427
+ });
428
+ }
429
+ }
430
+ return protocols;
431
+ }
432
+ function formatStateTransitionPathFromLedger(transitions) {
433
+ if (transitions.length === 0) {
434
+ return `${D("No protocol-governed transitions in this sequence.")}`;
435
+ }
436
+ const lines = [];
437
+ // Initial state from first transition
438
+ const initState = transitions[0].statesBefore;
439
+ const mergeStates = (rec) => {
440
+ const all = new Set();
441
+ for (const states of Object.values(rec)) {
442
+ for (const s of states)
443
+ all.add(s);
444
+ }
445
+ return all;
446
+ };
447
+ lines.push(` ${D([...mergeStates(initState)].join(", ") || "—")}`);
448
+ for (const t of transitions) {
449
+ if (!t.valid)
450
+ continue;
451
+ const fnLabel = C_(t.function + "()");
452
+ const beforeAll = mergeStates(t.statesBefore);
453
+ const afterAll = mergeStates(t.statesAfter);
454
+ const beforeStr = [...beforeAll].join(", ");
455
+ const afterStr = [...afterAll].join(", ");
456
+ const gained = t.acquired || [];
457
+ const lost = t.invalidated || [];
458
+ let delta = "";
459
+ if (gained.length > 0)
460
+ delta += ` ${G("+" + gained.join(",+"))}`;
461
+ if (lost.length > 0)
462
+ delta += ` ${R("-" + lost.join(",-"))}`;
463
+ lines.push(` │`);
464
+ lines.push(` ├─ ${fnLabel}`);
465
+ lines.push(` │ ${D(beforeStr || "—")} ${D("──▶")} ${afterStr || "—"}${delta}`);
466
+ lines.push(` │`);
467
+ }
468
+ return lines.join("\n");
469
+ }
470
+ function formatStateTransitions(session) {
471
+ const width = 66;
472
+ const title = `State Transitions: ${session.intent}`;
473
+ const header = `┌─ ${B(title)} ${"─".repeat(Math.max(2, width - title.length - 5))}┐`;
474
+ const resolvedIcon = session.resolved ? G("✔") : R("✖");
475
+ const info = `│ Session: ${D(session.sessionId)} │ Resolved: ${resolvedIcon} ${" ".repeat(Math.max(1, 15))}│`;
476
+ const footer = `└${"─".repeat(width - 2)}┘`;
477
+ const lines = [header, info, footer, ""];
478
+ if (session.successfulAttempt) {
479
+ lines.push(` ${B("Successful Path State Machine:")}`);
480
+ lines.push("");
481
+ lines.push(formatStateTransitionPathFromLedger(session.successfulAttempt.transitions));
482
+ lines.push("");
483
+ }
484
+ for (const a of session.attempts) {
485
+ for (const v of a.violations) {
486
+ if (v.svl === 4 && v.fixPath?.length) {
487
+ lines.push(` ${D("─".repeat(50))}`);
488
+ const actions = a.generatedActions.filter((x) => x.kind === "call" && x.function).map((x) => x.function).join(" → ");
489
+ lines.push(` ${R("Blocked at:")} ${actions}`);
490
+ lines.push(` ${D("Repair:")} ${Y(v.fixPath.join(" → "))}`);
491
+ lines.push("");
492
+ }
493
+ }
494
+ }
495
+ return lines.join("\n");
496
+ }
497
+ // ── Session Replay ──
498
+ function sleep(ms) {
499
+ return new Promise(resolve => setTimeout(resolve, ms));
500
+ }
501
+ function clearScreen() {
502
+ process.stdout.write("\x1b[2J\x1b[H");
503
+ }
504
+ function svlLabel(svl) {
505
+ switch (svl) {
506
+ case "SVL-1": return "symbol anomaly";
507
+ case "SVL-2": return "type anomaly";
508
+ case "SVL-3": return "dataflow anomaly";
509
+ case "SVL-4": return "protocol anomaly";
510
+ default: return "semantic anomaly";
511
+ }
512
+ }
513
+ function describeSVLLayer(svl) {
514
+ switch (svl) {
515
+ case "SVL-1": return "Immune Layer 1 — Symbol Existence";
516
+ case "SVL-2": return "Immune Layer 2 — Type Integrity";
517
+ case "SVL-3": return "Immune Layer 3 — Dataflow Validity";
518
+ case "SVL-4": return "Immune Layer 4 — Protocol Legality";
519
+ default: return `Immune Layer — ${svl}`;
520
+ }
521
+ }
522
+ function formatReplayHeader(session) {
523
+ const lines = [];
524
+ const w = 62;
525
+ const totalRetries = session.attempts.filter(a => a.outcome !== "success").length;
526
+ lines.push("");
527
+ lines.push(` ${B("Semantic Observatory — Cognitive Session Replay")}`);
528
+ lines.push(` ${D("─".repeat(w))}`);
529
+ lines.push("");
530
+ lines.push(` ${D("Intent:")} ${C_(session.intent)}`);
531
+ lines.push(` ${D("Session:")} ${session.sessionId}`);
532
+ lines.push(` ${D("Adaptations:")} ${totalRetries}`);
533
+ lines.push(` ${D("Outcome:")} ${session.resolved ? G("cognitive adaptation successful") : R("cognitive adaptation incomplete")}`);
534
+ lines.push("");
535
+ lines.push(` ${D("─".repeat(w))}`);
536
+ lines.push("");
537
+ return lines.join("\n");
538
+ }
539
+ function formatActionList(actions) {
540
+ if (!actions || actions.length === 0)
541
+ return D("(empty sequence)");
542
+ return actions
543
+ .filter(a => a.kind === "call" && a.function)
544
+ .map(a => ` ${C_(a.function + "()")}`)
545
+ .join("\n");
546
+ }
547
+ function formatAdaptationDiff(prev, current) {
548
+ const prevFns = (prev.generatedActions || []).filter(a => a.kind === "call").map(a => a.function);
549
+ const currFns = (current.generatedActions || []).filter(a => a.kind === "call").map(a => a.function);
550
+ const added = currFns.filter(f => !prevFns.includes(f));
551
+ const removed = prevFns.filter(f => !currFns.includes(f));
552
+ const kept = currFns.filter(f => prevFns.includes(f));
553
+ const lines = [];
554
+ lines.push(` ${B("Adaptation shift:")}`);
555
+ if (kept.length > 0) {
556
+ lines.push(` ${D("persisted")} ${kept.map(f => C_(f + "()")).join(" → ")}`);
557
+ }
558
+ if (removed.length > 0) {
559
+ lines.push(` ${R("dropped")} ${removed.map(f => R(f + "()")).join(" → ")}`);
560
+ }
561
+ if (added.length > 0) {
562
+ lines.push(` ${G("acquired")} ${added.map(f => G(f + "()")).join(" → ")}`);
563
+ }
564
+ return lines.join("\n");
565
+ }
566
+ function formatAnomalyReport(a) {
567
+ const lines = [];
568
+ const primary = a.violations[0];
569
+ if (!primary) {
570
+ lines.push(` ${B("Semantic anomaly:")} ${R("unknown")}`);
571
+ return lines.join("\n");
572
+ }
573
+ const svl = `SVL-${primary.svl}`;
574
+ lines.push(` ${B("Semantic anomaly:")} ${R(svlLabel(svl))}`);
575
+ lines.push(` ${D("Layer:")} ${describeSVLLayer(svl)}`);
576
+ if (primary.svl === 4) {
577
+ const blockedMatch = primary.description.match(/(\w+)\s*(要求|requires|blocked|不允许|不合法)/);
578
+ const blocked = blockedMatch ? blockedMatch[1] : a.generatedActions.find(x => x.kind === "call")?.function || "unknown";
579
+ lines.push(` ${D("Blocked:")} ${R(blocked + "()")}`);
580
+ if (primary.missingStates?.length) {
581
+ const missing = primary.missingStates.join(", ");
582
+ lines.push(` ${D("Missing:")} ${C_(missing)}`);
583
+ }
584
+ if (primary.fixPath?.length) {
585
+ const fixPath = primary.fixPath.join(" → ");
586
+ lines.push(` ${D("Required:")} ${C_(fixPath)}`);
587
+ }
588
+ }
589
+ else {
590
+ const detail = primary.description.length > 80 ? primary.description.slice(0, 77) + "..." : primary.description;
591
+ lines.push(` ${D("Detail:")} ${detail}`);
592
+ }
593
+ return lines.join("\n");
594
+ }
595
+ function formatImmuneResponse(a) {
596
+ const lines = [];
597
+ const primary = a.violations[0];
598
+ if (primary?.fixPath?.length) {
599
+ const path = primary.fixPath.join(" → ");
600
+ lines.push(` ${B("Immune response:")} ${Y("repair path activated")}`);
601
+ lines.push(` ${D("Repair:")} ${Y(path)}`);
602
+ }
603
+ else if (a.llmCallCount > 1) {
604
+ lines.push(` ${B("Immune response:")} ${Y("adaptation requested")}`);
605
+ }
606
+ else {
607
+ lines.push(` ${B("Immune response:")} ${Y("constraint violation recorded")}`);
608
+ }
609
+ return lines.join("\n");
610
+ }
611
+ function formatReplayProgress(current, total) {
612
+ const filled = "█".repeat(current);
613
+ const empty = "░".repeat(total - current);
614
+ return ` ${D("[" + filled + empty + "]")} ${current}/${total}`;
615
+ }
616
+ async function replaySession(session) {
617
+ clearScreen();
618
+ console.log(formatReplayHeader(session));
619
+ await sleep(1200);
620
+ const attempts = session.attempts;
621
+ const totalAdaptations = attempts.length;
622
+ for (let i = 0; i < attempts.length; i++) {
623
+ const a = attempts[i];
624
+ const prev = i > 0 ? attempts[i - 1] : null;
625
+ // ── Step header ──
626
+ console.log(` ${B("━━━ Adaptation " + (i + 1) + " of " + totalAdaptations + " ━━━")}`);
627
+ console.log("");
628
+ await sleep(300);
629
+ // ── What the cognitive planner attempted ──
630
+ console.log(` ${D("Cognitive planner action:")}`);
631
+ console.log(formatActionList(a.generatedActions));
632
+ console.log("");
633
+ await sleep(400);
634
+ // ── Semantic anomaly ──
635
+ console.log(formatAnomalyReport(a));
636
+ console.log("");
637
+ await sleep(500);
638
+ // ── Immune response ──
639
+ console.log(formatImmuneResponse(a));
640
+ console.log("");
641
+ await sleep(400);
642
+ // ── Adaptation diff (if not first attempt) ──
643
+ if (prev) {
644
+ console.log(formatAdaptationDiff(prev, a));
645
+ console.log("");
646
+ await sleep(400);
647
+ }
648
+ // ── Progress bar ──
649
+ console.log(formatReplayProgress(i + 1, totalAdaptations));
650
+ console.log("");
651
+ // ── Inter-adaptation pause ──
652
+ if (i < attempts.length - 1) {
653
+ console.log(` ${D("⏳ Cognitive planner re-evaluating...")}`);
654
+ console.log("");
655
+ await sleep(1200);
656
+ }
657
+ }
658
+ // ── Resolution ──
659
+ await sleep(600);
660
+ console.log(` ${B("━━━ Cognitive Adaptation Complete ━━━")}`);
661
+ console.log("");
662
+ if (session.resolved && session.successfulAttempt) {
663
+ const actions = session.successfulAttempt.generatedActions || [];
664
+ console.log(` ${G("✔")} ${B("Successful cognitive path established:")}`);
665
+ console.log(formatActionList(actions));
666
+ console.log("");
667
+ const names = actions.filter(a => a.kind === "call").map(a => a.function).join(" → ");
668
+ console.log(` ${G("✔")} ${names}`);
669
+ console.log("");
670
+ // State machine trace (from Semantic Ledger)
671
+ const transitions = session.successfulAttempt.transitions;
672
+ if (transitions.length > 0) {
673
+ console.log(` ${B("State machine trace (from Ledger):")}`);
674
+ console.log(formatStateTransitionPathFromLedger(transitions));
675
+ console.log("");
676
+ }
677
+ const totalRetries = session.attempts.filter(a => a.outcome !== "success").length;
678
+ console.log(` ${D(`Total adaptations: ${totalRetries}`)}`);
679
+ console.log(` ${D(`Session: ${session.sessionId}`)}`);
680
+ }
681
+ else {
682
+ console.log(` ${R("✖")} ${B("Cognitive adaptation incomplete")}`);
683
+ console.log("");
684
+ console.log(` ${D("The planner was unable to find a valid path within the constraint space.")}`);
685
+ const totalRetries = session.attempts.length;
686
+ console.log(` ${D(`Total adaptations attempted: ${totalRetries}`)}`);
687
+ }
688
+ console.log("");
689
+ console.log(` ${D("─".repeat(62))}`);
690
+ console.log(` ${D("Semantic Observatory — replay complete")}`);
691
+ console.log("");
692
+ // Ledger replay validation
693
+ console.log(formatLedgerReplayValidation(session));
694
+ }
695
+ // ── Ledger Replay Validation (P1-B) ──
696
+ function formatLedgerReplayValidation(session) {
697
+ const lines = [];
698
+ lines.push("");
699
+ lines.push(`${C_("Ledger Replay Validation")}`);
700
+ lines.push(`${D("═".repeat(62))}`);
701
+ if (!session.attempts || session.attempts.length === 0) {
702
+ lines.push(` ${D("No attempts to replay.")}`);
703
+ return lines.join("\n");
704
+ }
705
+ // Load current protocols for ruleHash comparison
706
+ let currentRuleHash = null;
707
+ try {
708
+ const protoPath = path.join(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "protocols.json");
709
+ if (fs.existsSync(protoPath)) {
710
+ const protoDef = JSON.parse(fs.readFileSync(protoPath, "utf-8"));
711
+ const protocols = (0, ssg_validator_1.parseProtocolsFromJSON)(protoDef);
712
+ const rules = new Map();
713
+ for (const p of protocols)
714
+ rules.set(p.function, p.protocol);
715
+ currentRuleHash = (0, ssg_validator_1.hashRules)(rules);
716
+ }
717
+ }
718
+ catch { }
719
+ const nsInit = new Map();
720
+ nsInit.set("_global", "UNAUTHENTICATED");
721
+ try {
722
+ const protoPath = path.join(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "protocols.json");
723
+ if (fs.existsSync(protoPath)) {
724
+ const protoDef = JSON.parse(fs.readFileSync(protoPath, "utf-8"));
725
+ if (protoDef.namespaceInitialStates) {
726
+ for (const [ns, s] of Object.entries(protoDef.namespaceInitialStates)) {
727
+ nsInit.set(ns, s);
728
+ }
729
+ }
730
+ }
731
+ }
732
+ catch { }
733
+ let totalLedgers = 0;
734
+ let consistentLedgers = 0;
735
+ let stateMatchLedgers = 0;
736
+ for (const attempt of session.attempts) {
737
+ const transitions = attempt.transitions || [];
738
+ if (transitions.length === 0)
739
+ continue;
740
+ totalLedgers++;
741
+ const attemptLabel = `Attempt #${attempt.attemptNumber} (${attempt.outcome})`;
742
+ // 1. Invariant check
743
+ const consistency = (0, ssg_validator_1.checkLedgerConsistency)(transitions, nsInit);
744
+ if (consistency.consistent) {
745
+ consistentLedgers++;
746
+ lines.push(` ${G("✔")} ${attemptLabel}: Invariants clean`);
747
+ }
748
+ else {
749
+ lines.push(` ${R("✖")} ${attemptLabel}: ${consistency.violations.length} invariant violation(s)`);
750
+ for (const v of consistency.violations.slice(0, 2)) {
751
+ lines.push(` ${D(`[${v.invariant}] index=${v.index}: ${v.detail || ""}`)}`);
752
+ }
753
+ }
754
+ // 2. rebuildState matches recorded statesAfter (normalized)
755
+ const rebuilt = (0, ssg_validator_1.rebuildState)(transitions, nsInit);
756
+ const lastTransition = transitions[transitions.length - 1];
757
+ const recorded = lastTransition.statesAfter;
758
+ // Normalize: collect all namespace keys, fill empty arrays for missing ones
759
+ const allNs = new Set([...Object.keys(rebuilt), ...Object.keys(recorded)]);
760
+ const norm = (snap) => {
761
+ const out = {};
762
+ for (const ns of [...allNs].sort()) {
763
+ out[ns] = [...(snap[ns] || [])].sort();
764
+ }
765
+ return out;
766
+ };
767
+ const rebuiltNorm = JSON.stringify(norm(rebuilt));
768
+ const recordedNorm = JSON.stringify(norm(recorded));
769
+ if (rebuiltNorm === recordedNorm) {
770
+ stateMatchLedgers++;
771
+ lines.push(` ${G("rebuildState === recorded")}`);
772
+ }
773
+ else {
774
+ lines.push(` ${R("rebuildState !== recorded")}`);
775
+ lines.push(` ${D(" rebuilt: " + rebuiltNorm)}`);
776
+ lines.push(` ${D(" recorded: " + recordedNorm)}`);
777
+ }
778
+ // 3. ruleHash comparison
779
+ if (attempt.ruleHash && currentRuleHash) {
780
+ if (attempt.ruleHash === currentRuleHash) {
781
+ lines.push(` ${G("ruleHash match")} ${D(attempt.ruleHash)}`);
782
+ }
783
+ else {
784
+ lines.push(` ${Y("ruleHash mismatch")} ${D("attempt: " + attempt.ruleHash + " | current: " + currentRuleHash)}`);
785
+ }
786
+ }
787
+ else if (attempt.ruleHash && !currentRuleHash) {
788
+ lines.push(` ${D("ruleHash: " + attempt.ruleHash + " (no current protocols to compare)")}`);
789
+ }
790
+ }
791
+ // Session-level ruleHash
792
+ if (session.ruleHash) {
793
+ lines.push("");
794
+ lines.push(` ${D("Session ruleHash:")} ${session.ruleHash}`);
795
+ if (currentRuleHash) {
796
+ if (session.ruleHash === currentRuleHash) {
797
+ lines.push(` ${G("Session ruleHash matches current protocols.")}`);
798
+ }
799
+ else {
800
+ lines.push(` ${Y("Session ruleHash differs from current protocols.")} ${D("Replay may yield different results.")}`);
801
+ }
802
+ }
803
+ }
804
+ // Ledger integrity hash
805
+ {
806
+ const allTransitions = session.attempts.flatMap(a => a.transitions || []);
807
+ if (allTransitions.length > 0) {
808
+ const ledgerHash = (0, ssg_validator_1.hashLedger)(allTransitions);
809
+ lines.push(` ${D("Ledger hash:")} ${ledgerHash} ${D("(tamper-evident integrity)")}`);
810
+ }
811
+ }
812
+ lines.push("");
813
+ if (totalLedgers === 0) {
814
+ lines.push(` ${D("No ledger data in this session.")}`);
815
+ }
816
+ else {
817
+ const allOk = consistentLedgers === totalLedgers && stateMatchLedgers === totalLedgers;
818
+ if (allOk) {
819
+ lines.push(` ${G("✦")} ${B(`Ledger Replay: ${totalLedgers}/${totalLedgers} consistent, all states match`)}`);
820
+ }
821
+ else {
822
+ lines.push(` ${Y("◇")} ${B(`Ledger Replay: ${consistentLedgers}/${totalLedgers} consistent, ${stateMatchLedgers}/${totalLedgers} state-match`)}`);
823
+ }
824
+ }
825
+ return lines.join("\n");
826
+ }
827
+ // ── Corpus-wide Ledger Statistics (P1) ──
828
+ function formatLedgerStats() {
829
+ const sessions = (0, failure_corpus_1.getAllSessions)();
830
+ const lines = [];
831
+ lines.push(`${C_("Ledger Corpus Statistics")}`);
832
+ lines.push(`${D("═".repeat(62))}`);
833
+ lines.push("");
834
+ let totalSessions = 0;
835
+ let totalLedgers = 0;
836
+ let totalTransitions = 0;
837
+ let validTransitions = 0;
838
+ let invalidTransitions = 0;
839
+ let sessionsWithRuleHash = 0;
840
+ const stateProducers = new Map();
841
+ const stateConsumers = new Map();
842
+ const allRuleHashes = new Set();
843
+ for (const session of sessions) {
844
+ const allTransitions = session.attempts.flatMap(a => a.transitions || []);
845
+ if (allTransitions.length === 0)
846
+ continue;
847
+ totalSessions++;
848
+ totalLedgers += session.attempts.filter(a => (a.transitions || []).length > 0).length;
849
+ totalTransitions += allTransitions.length;
850
+ for (const t of allTransitions) {
851
+ if (t.valid)
852
+ validTransitions++;
853
+ else
854
+ invalidTransitions++;
855
+ for (const s of t.acquired) {
856
+ stateProducers.set(s, (stateProducers.get(s) || 0) + 1);
857
+ }
858
+ for (const states of Object.values(t.statesBefore)) {
859
+ for (const s of states) {
860
+ stateConsumers.set(s, (stateConsumers.get(s) || 0) + 1);
861
+ }
862
+ }
863
+ }
864
+ if (session.ruleHash) {
865
+ sessionsWithRuleHash++;
866
+ allRuleHashes.add(session.ruleHash);
867
+ }
868
+ }
869
+ if (totalSessions === 0) {
870
+ lines.push(` ${D("No sessions with ledger data.")}`);
871
+ return lines.join("\n");
872
+ }
873
+ lines.push(` ${B("Sessions:")} ${totalSessions} (${D(`${sessions.length} total`)})`);
874
+ lines.push(` ${B("Ledgers:")} ${totalLedgers}`);
875
+ lines.push(` ${B("Transitions:")} ${totalTransitions} (${G(`${validTransitions} valid`)}, ${R(`${invalidTransitions} invalid`)})`);
876
+ const validPct = totalTransitions > 0 ? Math.round((validTransitions / totalTransitions) * 100) : 0;
877
+ lines.push(` ${B("Validity rate:")} ${validPct >= 90 ? G(`${validPct}%`) : Y(`${validPct}%`)}`);
878
+ lines.push(` ${B("Rule hashes:")} ${allRuleHashes.size} unique (${sessionsWithRuleHash}/${totalSessions} sessions have ruleHash)`);
879
+ // Top producers
880
+ const topProducers = [...stateProducers.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
881
+ if (topProducers.length > 0) {
882
+ lines.push("");
883
+ lines.push(` ${B("Top produced states:")}`);
884
+ for (const [state, count] of topProducers) {
885
+ lines.push(` ${G("+" + state)}: ${count}x`);
886
+ }
887
+ }
888
+ // Top consumers
889
+ const topConsumers = [...stateConsumers.entries()]
890
+ .filter(([s]) => !s.startsWith("_"))
891
+ .sort((a, b) => b[1] - a[1]).slice(0, 5);
892
+ if (topConsumers.length > 0) {
893
+ lines.push("");
894
+ lines.push(` ${B("Top consumed states:")}`);
895
+ for (const [state, count] of topConsumers) {
896
+ lines.push(` ${Y("←" + state)}: ${count}x`);
897
+ }
898
+ }
899
+ // Per-session detail
900
+ lines.push("");
901
+ lines.push(` ${B("Per-session breakdown:")}`);
902
+ for (const session of sessions) {
903
+ const allTransitions = session.attempts.flatMap(a => a.transitions || []);
904
+ if (allTransitions.length === 0)
905
+ continue;
906
+ const validCount = allTransitions.filter(t => t.valid).length;
907
+ const hashTag = session.ruleHash ? ` [${D(session.ruleHash.slice(0, 8))}]` : "";
908
+ const intentShort = session.intent.length > 40 ? session.intent.slice(0, 37) + "..." : session.intent;
909
+ lines.push(` ${D(session.sessionId.slice(-8))} ${validCount}/${allTransitions.length} valid ${D("·")} ${intentShort}${hashTag}`);
910
+ }
911
+ return lines.join("\n");
912
+ }
913
+ // ── Cross-session Query ──
914
+ function formatCrossSessionQuery(operation, state) {
915
+ const sessions = (0, failure_corpus_1.getAllSessions)();
916
+ const lines = [];
917
+ const label = operation === "producer" ? `Producers of "${state}"` : `Consumers of "${state}"`;
918
+ lines.push(`${C_(`Cross-session: ${label}`)}`);
919
+ lines.push(`${D("═".repeat(62))}`);
920
+ lines.push("");
921
+ let found = 0;
922
+ for (const session of sessions) {
923
+ const allTransitions = session.attempts.flatMap(a => a.transitions || []);
924
+ if (allTransitions.length === 0)
925
+ continue;
926
+ let results;
927
+ if (operation === "producer") {
928
+ results = (0, ssg_validator_1.findProducer)(state, allTransitions);
929
+ }
930
+ else {
931
+ results = (0, ssg_validator_1.findConsumer)(state, allTransitions);
932
+ }
933
+ if (results.length === 0)
934
+ continue;
935
+ found++;
936
+ const intentShort = session.intent.length > 50 ? session.intent.slice(0, 47) + "..." : session.intent;
937
+ const funcs = [...new Set(results.map(r => r.transition.function))].join(", ");
938
+ const validCount = allTransitions.filter(t => t.valid).length;
939
+ const hashTag = session.ruleHash ? ` ${D(session.ruleHash.slice(0, 8))}` : "";
940
+ lines.push(` ${D(session.sessionId.slice(-8))} ${G(`${results.length}x`)} via ${C_(funcs)} ${D(`(${validCount}/${allTransitions.length} valid)${hashTag}`)}`);
941
+ lines.push(` ${D(intentShort)}`);
942
+ }
943
+ if (found === 0) {
944
+ lines.push(` ${D(`No sessions found with ${operation} for "${state}".`)}`);
945
+ }
946
+ else {
947
+ lines.push("");
948
+ lines.push(` ${B(`Found in ${found} session(s).`)}`);
949
+ }
950
+ return lines.join("\n");
951
+ }
952
+ // ── CLI entry ──
953
+ // ── Semantic Snapshot formatting ──
954
+ function formatSnapshotList() {
955
+ const snapshots = (0, semantic_snapshot_1.listSnapshots)();
956
+ if (snapshots.length === 0) {
957
+ return `${D("No IR snapshots recorded yet. Run the planner to capture the first snapshot.")}`;
958
+ }
959
+ const lines = [];
960
+ const C_ = (s) => `${C.cyan}${s}${C.reset}`;
961
+ lines.push(`${C_("IR Snapshots")} (${snapshots.length} total):\n`);
962
+ lines.push(`${B("┌──────────────────────┬──────────────────────┬──────────┬────────────────────────────────┐")}`);
963
+ lines.push(`${B("│")} ${B("Snapshot ID")} ${B("│")} ${B("Timestamp")} ${B("│")} ${B("Funcs")} ${B("│")} ${B("Intent")} ${B("│")}`);
964
+ lines.push(`${B("├──────────────────────┼──────────────────────┼──────────┼────────────────────────────────┤")}`);
965
+ for (const snap of snapshots.slice(0, 20)) {
966
+ const id = snap.id.slice(-16);
967
+ const ts = snap.timestamp.slice(0, 19).replace("T", " ");
968
+ const count = String(snap.functions.length).padStart(4);
969
+ const intent = (snap.intent || "").slice(0, 30).padEnd(30);
970
+ lines.push(`${D("│")} ${D(id)} ${D("│")} ${ts} ${D("│")} ${count} ${D("│")} ${intent} ${D("│")}`);
971
+ }
972
+ lines.push(`${B("└──────────────────────┴──────────────────────┴──────────┴────────────────────────────────┘")}`);
973
+ return lines.join("\n");
974
+ }
975
+ function formatSnapshotDiff(snapIdA, snapIdB) {
976
+ const a = (0, semantic_snapshot_1.loadSnapshot)(snapIdA);
977
+ const b = (0, semantic_snapshot_1.loadSnapshot)(snapIdB);
978
+ if (!a)
979
+ return `${R("Snapshot not found:")} ${snapIdA}`;
980
+ if (!b)
981
+ return `${R("Snapshot not found:")} ${snapIdB}`;
982
+ const diff = (0, semantic_snapshot_1.diffSnapshots)(a, b);
983
+ const lines = [];
984
+ const C_ = (s) => `${C.cyan}${s}${C.reset}`;
985
+ lines.push(`${C_("IR Snapshot Diff")}`);
986
+ lines.push(`${D(`${a.id}`)} → ${D(`${b.id}`)}`);
987
+ lines.push(` ${a.timestamp.slice(0, 19)} → ${b.timestamp.slice(0, 19)}`);
988
+ lines.push("");
989
+ if (diff.added.length > 0) {
990
+ lines.push(` ${G("+ Added")} (${diff.added.length}):`);
991
+ for (const f of diff.added) {
992
+ lines.push(` ${G("+")} ${f.name}(${f.params.map(p => `${p.name}:${p.type}`).join(", ")}) → ${f.returnType}`);
993
+ }
994
+ lines.push("");
995
+ }
996
+ if (diff.removed.length > 0) {
997
+ lines.push(` ${R("- Removed")} (${diff.removed.length}):`);
998
+ for (const f of diff.removed) {
999
+ lines.push(` ${R("-")} ${f.name}(${f.params.map(p => `${p.name}:${p.type}`).join(", ")}) → ${f.returnType}`);
1000
+ }
1001
+ lines.push("");
1002
+ }
1003
+ if (diff.changed.length > 0) {
1004
+ lines.push(` ${Y("~ Changed")} (${diff.changed.length}):`);
1005
+ for (const { before, after } of diff.changed) {
1006
+ lines.push(` ${Y("~")} ${before.name}:`);
1007
+ lines.push(` ${R("-")} ${before.returnType} (${before.params.map(p => `${p.name}:${p.type}`).join(", ")})`);
1008
+ lines.push(` ${G("+")} ${after.returnType} (${after.params.map(p => `${p.name}:${p.type}`).join(", ")})`);
1009
+ }
1010
+ lines.push("");
1011
+ }
1012
+ if (diff.unchanged > 0) {
1013
+ lines.push(` ${D(`${diff.unchanged} functions unchanged`)}`);
1014
+ }
1015
+ if (diff.added.length === 0 && diff.removed.length === 0 && diff.changed.length === 0) {
1016
+ lines.push(` ${D("No differences — snapshots are identical.")}`);
1017
+ }
1018
+ return lines.join("\n");
1019
+ }
1020
+ // ── Deterministic Replay: validate session against snapshot vs. live IR ──
1021
+ function formatSessionValidation(session) {
1022
+ const lines = [];
1023
+ const C_ = (s) => `${C.cyan}${s}${C.reset}`;
1024
+ lines.push(`${C_("Deterministic Replay Validation")}`);
1025
+ lines.push(`${D(`Session: ${session.sessionId}`)}`);
1026
+ lines.push(`${D(`Intent: ${session.intent}`)}`);
1027
+ lines.push("");
1028
+ // Collect all called functions from all attempts + successful path
1029
+ const allCalledFns = new Set();
1030
+ for (const a of session.attempts) {
1031
+ for (const act of (a.generatedActions || [])) {
1032
+ if (act.kind === "call" && act.function)
1033
+ allCalledFns.add(act.function);
1034
+ }
1035
+ }
1036
+ if (session.successfulAttempt) {
1037
+ for (const act of session.successfulAttempt.generatedActions) {
1038
+ if (act.kind === "call" && act.function)
1039
+ allCalledFns.add(act.function);
1040
+ }
1041
+ }
1042
+ // Load snapshotted IR
1043
+ let snapshotFns = null;
1044
+ if (session.snapshotId) {
1045
+ const snap = (0, semantic_snapshot_1.loadSnapshot)(session.snapshotId);
1046
+ if (snap) {
1047
+ snapshotFns = new Set(snap.functions.map(f => f.name));
1048
+ lines.push(`${D("Snapshot IR:")} ${snap.id} (${snap.functions.length} functions)`);
1049
+ }
1050
+ else {
1051
+ lines.push(`${Y("Snapshot not found:")} ${session.snapshotId}`);
1052
+ }
1053
+ }
1054
+ else {
1055
+ lines.push(`${D("No snapshot linked to this session.")}`);
1056
+ }
1057
+ // Load current IR
1058
+ let currentFns = null;
1059
+ try {
1060
+ const irPath = path.join(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "ir.json");
1061
+ if (fs.existsSync(irPath)) {
1062
+ const ir = JSON.parse(fs.readFileSync(irPath, "utf-8"));
1063
+ currentFns = new Set(ir.map((f) => f.name));
1064
+ lines.push(`${D("Current IR:")} ir.json (${ir.length} functions)`);
1065
+ }
1066
+ }
1067
+ catch { }
1068
+ lines.push("");
1069
+ if (!snapshotFns && !currentFns) {
1070
+ lines.push(`${D("No IR data available for comparison.")}`);
1071
+ return lines.join("\n");
1072
+ }
1073
+ // Per-function validation table
1074
+ const fns = [...allCalledFns].sort();
1075
+ if (fns.length === 0) {
1076
+ lines.push(`${D("No function calls recorded in this session.")}`);
1077
+ return lines.join("\n");
1078
+ }
1079
+ lines.push(`${B("Function validation (then vs. now):")}`);
1080
+ lines.push(`${B("┌────────────────────────────┬──────────┬──────────┬──────────────────────────────────────┐")}`);
1081
+ lines.push(`${B("│")} ${B("Function")} ${B("│")} ${B("Then")} ${B("│")} ${B("Now")} ${B("│")} ${B("Status")} ${B("│")}`);
1082
+ lines.push(`${B("├────────────────────────────┼──────────┼──────────┼──────────────────────────────────────┤")}`);
1083
+ let regressions = 0;
1084
+ let additions = 0;
1085
+ for (const fn of fns) {
1086
+ const existed = snapshotFns ? snapshotFns.has(fn) : null;
1087
+ const exists = currentFns ? currentFns.has(fn) : null;
1088
+ const thenIcon = existed === null ? D("?") : existed ? G("✔") : R("✖");
1089
+ const nowIcon = exists === null ? D("?") : exists ? G("✔") : R("✖");
1090
+ let status;
1091
+ if (existed === true && exists === true) {
1092
+ status = D("stable");
1093
+ }
1094
+ else if (existed === true && exists === false) {
1095
+ status = R("REGRESSION — removed from IR");
1096
+ regressions++;
1097
+ }
1098
+ else if (existed === false && exists === true) {
1099
+ status = G("ADDED — new in IR");
1100
+ additions++;
1101
+ }
1102
+ else if (existed === false && exists === false) {
1103
+ status = R("MISSING — never existed");
1104
+ }
1105
+ else {
1106
+ status = D("unknown");
1107
+ }
1108
+ const fnPad = fn.padEnd(26).slice(0, 26);
1109
+ lines.push(`${D("│")} ${fnPad} ${D("│")} ${thenIcon} ${D("│")} ${nowIcon} ${D("│")} ${status.padEnd(36)} ${D("│")}`);
1110
+ }
1111
+ lines.push(`${B("└────────────────────────────┴──────────┴──────────┴──────────────────────────────────────┘")}`);
1112
+ lines.push("");
1113
+ // Summary
1114
+ if (regressions > 0) {
1115
+ lines.push(`${R(`⚠ ${regressions} regression(s) detected — functions removed from IR since this session`)}`);
1116
+ }
1117
+ if (additions > 0) {
1118
+ lines.push(`${G(`+ ${additions} function(s) added to IR since this session`)}`);
1119
+ }
1120
+ if (regressions === 0 && additions === 0 && fns.length > 0) {
1121
+ lines.push(`${G("✔ IR stable — all functions present in both snapshot and current IR.")}`);
1122
+ }
1123
+ // Protocol validation against snapshot
1124
+ if (session.successfulAttempt && session.snapshotId) {
1125
+ lines.push("");
1126
+ lines.push(`${C_("Protocol re-validation (snapshot IR):")}`);
1127
+ const snap = (0, semantic_snapshot_1.loadSnapshot)(session.snapshotId);
1128
+ if (snap) {
1129
+ // Build protocols from snapshot functions that had @protocol annotations
1130
+ // (we approximate from the function list — actual protocol data is in protocols.json)
1131
+ try {
1132
+ const protoPath = path.join(process.env.PROGMUNE_PROJECT_DIR || process.cwd(), "protocols.json");
1133
+ if (fs.existsSync(protoPath)) {
1134
+ const protoDef = JSON.parse(fs.readFileSync(protoPath, "utf-8"));
1135
+ const protocols = (0, ssg_validator_1.parseProtocolsFromJSON)(protoDef);
1136
+ const nsStates = new Map();
1137
+ nsStates.set("_global", "UNAUTHENTICATED");
1138
+ if (protoDef.namespaceInitialStates) {
1139
+ for (const [ns, s] of Object.entries(protoDef.namespaceInitialStates)) {
1140
+ nsStates.set(ns, s);
1141
+ }
1142
+ }
1143
+ // Pure function validation (no StateMachineValidator instance)
1144
+ const rules = new Map();
1145
+ for (const p of protocols)
1146
+ rules.set(p.function, p.protocol);
1147
+ const ruleHash = (0, ssg_validator_1.hashRules)(rules);
1148
+ const ctx = {
1149
+ ledger: [],
1150
+ currentState: (0, ssg_validator_1.rebuildState)([], nsStates),
1151
+ };
1152
+ const transitions = [];
1153
+ let valid = true;
1154
+ for (let i = 0; i < session.successfulAttempt.generatedActions.length; i++) {
1155
+ const act = session.successfulAttempt.generatedActions[i];
1156
+ if (act.kind === "call" && act.function) {
1157
+ const { valid: tValid, transition, rejection } = (0, ssg_validator_1.validateTransition)(ctx, act.function, i, rules, nsStates, ruleHash);
1158
+ transitions.push(transition);
1159
+ ctx.ledger = transitions;
1160
+ if (!tValid) {
1161
+ lines.push(` ${R("🚫")} ${act.function}: ${rejection?.missingFunctions.join(" → ") || "protocol violation"}`);
1162
+ valid = false;
1163
+ }
1164
+ else {
1165
+ ctx.currentState = transition.statesAfter;
1166
+ lines.push(` ${G("✅")} ${act.function}`);
1167
+ }
1168
+ }
1169
+ }
1170
+ // Ledger consistency check
1171
+ const consistency = (0, ssg_validator_1.checkLedgerConsistency)(transitions, nsStates);
1172
+ if (!consistency.consistent) {
1173
+ lines.push(` ${R("⚠")} Ledger consistency: ${consistency.violations.length} violation(s)`);
1174
+ valid = false;
1175
+ }
1176
+ if (valid) {
1177
+ lines.push(` ${G("✔ All actions satisfy protocol constraints against snapshot IR.")}`);
1178
+ }
1179
+ }
1180
+ }
1181
+ catch (e) {
1182
+ lines.push(` ${D("(protocol re-validation not available)")}`);
1183
+ }
1184
+ }
1185
+ }
1186
+ return lines.join("\n");
1187
+ }
1188
+ async function main() {
1189
+ const arg = process.argv[2];
1190
+ if (arg === "--genome") {
1191
+ console.log(formatGenomeSummary());
1192
+ return;
1193
+ }
1194
+ if (arg === "--learned") {
1195
+ console.log(formatLearnedPatterns());
1196
+ return;
1197
+ }
1198
+ if (arg === "--antibodies") {
1199
+ console.log(formatAntibodyStats());
1200
+ return;
1201
+ }
1202
+ if (arg === "--heatmap") {
1203
+ console.log(formatHeatmap());
1204
+ return;
1205
+ }
1206
+ if (arg === "--diff-ledgers") {
1207
+ const idA = process.argv[3];
1208
+ const idB = process.argv[4];
1209
+ if (!idA || !idB) {
1210
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts --diff-ledgers <sessionIdA> <sessionIdB>`);
1211
+ process.exit(1);
1212
+ }
1213
+ const sessions = (0, failure_corpus_1.getAllSessions)();
1214
+ const sessA = sessions.find(s => s.sessionId === idA || s.sessionId.startsWith(idA));
1215
+ const sessB = sessions.find(s => s.sessionId === idB || s.sessionId.startsWith(idB));
1216
+ if (!sessA) {
1217
+ console.error(`${R("Session A not found:")} ${idA}`);
1218
+ process.exit(1);
1219
+ }
1220
+ if (!sessB) {
1221
+ console.error(`${R("Session B not found:")} ${idB}`);
1222
+ process.exit(1);
1223
+ }
1224
+ const ledgerA = sessA.attempts.flatMap(a => a.transitions || []);
1225
+ const ledgerB = sessB.attempts.flatMap(a => a.transitions || []);
1226
+ const diff = (0, ssg_validator_1.diffLedgers)(ledgerA, ledgerB);
1227
+ console.log(`${C_("Ledger Diff")}`);
1228
+ console.log(`${D("═".repeat(50))}`);
1229
+ console.log(` A: ${D(sessA.sessionId)} (${ledgerA.length} transitions)`);
1230
+ console.log(` B: ${D(sessB.sessionId)} (${ledgerB.length} transitions)`);
1231
+ console.log("");
1232
+ if (diff.identical) {
1233
+ console.log(` ${G("✔ Ledgers are identical.")}`);
1234
+ }
1235
+ else {
1236
+ console.log(` ${G(`Unchanged: ${diff.unchanged}`)} ${R(`Only in A: ${diff.onlyInA.length}`)} ${Y(`Only in B: ${diff.onlyInB.length}`)} ${Y(`Changed: ${diff.changed.length}`)}`);
1237
+ for (const d of diff.onlyInA.slice(0, 3)) {
1238
+ console.log(` ${R("-")} @${d.index} ${d.function} ${D(d.hashA)}`);
1239
+ }
1240
+ for (const d of diff.onlyInB.slice(0, 3)) {
1241
+ console.log(` ${G("+")} @${d.index} ${d.function} ${D(d.hashB)}`);
1242
+ }
1243
+ for (const d of diff.changed.slice(0, 3)) {
1244
+ console.log(` ${Y("~")} @${d.index} ${d.function} ${D(d.hashA + " → " + d.hashB)}`);
1245
+ }
1246
+ }
1247
+ return;
1248
+ }
1249
+ if (arg === "--query-all") {
1250
+ const op = process.argv[3];
1251
+ const st = process.argv[4];
1252
+ if (!op || !st) {
1253
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts --query-all <producer|consumer> <state>`);
1254
+ process.exit(1);
1255
+ }
1256
+ if (op !== "producer" && op !== "consumer") {
1257
+ console.error(`${R("Operation must be 'producer' or 'consumer'.")}`);
1258
+ process.exit(1);
1259
+ }
1260
+ console.log(formatCrossSessionQuery(op, st));
1261
+ return;
1262
+ }
1263
+ if (arg === "--stats") {
1264
+ console.log(formatLedgerStats());
1265
+ return;
1266
+ }
1267
+ if (arg === "--snapshots") {
1268
+ console.log(formatSnapshotList());
1269
+ return;
1270
+ }
1271
+ if (arg === "--diff") {
1272
+ const snapA = process.argv[3];
1273
+ const snapB = process.argv[4];
1274
+ if (!snapA || !snapB) {
1275
+ console.log(formatSnapshotList());
1276
+ console.log(`\n${D("Usage:")} ts-node src/semantic-trace.ts --diff <snapshotIdA> <snapshotIdB>`);
1277
+ return;
1278
+ }
1279
+ console.log(formatSnapshotDiff(snapA, snapB));
1280
+ return;
1281
+ }
1282
+ if (arg === "--validate") {
1283
+ const sessionId = process.argv[3];
1284
+ if (!sessionId) {
1285
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts --validate <sessionId>`);
1286
+ console.error(`\n${D("Validates a session's IR snapshot and replays its Semantic Ledger.")}`);
1287
+ process.exit(1);
1288
+ }
1289
+ const sessionsForValidate = (0, failure_corpus_1.getAllSessions)();
1290
+ const session = sessionsForValidate.find(s => s.sessionId === sessionId || s.sessionId.startsWith(sessionId));
1291
+ if (!session) {
1292
+ console.error(`${R("Session not found:")} ${sessionId}`);
1293
+ process.exit(1);
1294
+ }
1295
+ console.log(formatSessionValidation(session));
1296
+ console.log(formatLedgerReplayValidation(session));
1297
+ return;
1298
+ }
1299
+ if (arg === "--ledger") {
1300
+ const sessionId = process.argv[3];
1301
+ if (!sessionId) {
1302
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts --ledger <sessionId>`);
1303
+ console.error(`\n${D("Replays the Semantic Ledger: rebuildState, invariants, ruleHash comparison.")}`);
1304
+ process.exit(1);
1305
+ }
1306
+ const sessionsForLedger = (0, failure_corpus_1.getAllSessions)();
1307
+ const session = sessionsForLedger.find(s => s.sessionId === sessionId || s.sessionId.startsWith(sessionId));
1308
+ if (!session) {
1309
+ console.error(`${R("Session not found:")} ${sessionId}`);
1310
+ process.exit(1);
1311
+ }
1312
+ console.log(formatLedgerReplayValidation(session));
1313
+ return;
1314
+ }
1315
+ const sessions = (0, failure_corpus_1.getAllSessions)();
1316
+ if (arg === "--states") {
1317
+ const sessionId = process.argv[3];
1318
+ if (!sessionId) {
1319
+ console.log(formatSessionSummary(sessions));
1320
+ console.log(`\n${D("Usage:")} ts-node src/semantic-trace.ts --states <sessionId>`);
1321
+ return;
1322
+ }
1323
+ const session = sessions.find(s => s.sessionId === sessionId || s.sessionId.startsWith(sessionId));
1324
+ if (!session) {
1325
+ console.error(`${R("Session not found:")} ${sessionId}`);
1326
+ process.exit(1);
1327
+ }
1328
+ console.log(formatStateTransitions(session));
1329
+ return;
1330
+ }
1331
+ if (arg === "replay") {
1332
+ const sessionId = process.argv[3];
1333
+ if (!sessionId) {
1334
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts replay <sessionId>`);
1335
+ console.error(`\n${D("Available sessions:")}`);
1336
+ for (const s of sessions) {
1337
+ console.error(` ${D(s.sessionId)} — ${s.intent}`);
1338
+ }
1339
+ process.exit(1);
1340
+ }
1341
+ const session = sessions.find(s => s.sessionId === sessionId || s.sessionId.startsWith(sessionId));
1342
+ if (!session) {
1343
+ console.error(`${R("Session not found:")} ${sessionId}`);
1344
+ console.error(`\n${D("Available sessions:")}`);
1345
+ for (const s of sessions) {
1346
+ console.error(` ${D(s.sessionId)} — ${s.intent}`);
1347
+ }
1348
+ process.exit(1);
1349
+ }
1350
+ await replaySession(session);
1351
+ return;
1352
+ }
1353
+ if (arg === "--query") {
1354
+ const sessionId = process.argv[3];
1355
+ const operation = process.argv[4];
1356
+ const operand = process.argv[5];
1357
+ if (!sessionId || !operation) {
1358
+ console.error(`${R("Usage:")} ts-node src/semantic-trace.ts --query <sessionId> <operation> [state|index]`);
1359
+ console.error(`\n${B("Operations:")}`);
1360
+ console.error(` ${D("producer <state>")} — find transitions that produce a state`);
1361
+ console.error(` ${D("consumer <state>")} — find transitions that consume a state`);
1362
+ console.error(` ${D("violations")} — list all invalid transitions`);
1363
+ console.error(` ${D("transition <index>")} — find a transition by action index`);
1364
+ console.error(` ${D("all-states")} — list all unique states in the ledger`);
1365
+ process.exit(1);
1366
+ }
1367
+ const sessionsForQuery = (0, failure_corpus_1.getAllSessions)();
1368
+ const session = sessionsForQuery.find(s => s.sessionId === sessionId || s.sessionId.startsWith(sessionId));
1369
+ if (!session) {
1370
+ console.error(`${R("Session not found:")} ${sessionId}`);
1371
+ process.exit(1);
1372
+ }
1373
+ // Collect all transitions from all attempts
1374
+ const allTransitions = session.attempts.flatMap(a => a.transitions || []);
1375
+ if (allTransitions.length === 0) {
1376
+ console.log(`${D("No ledger data in this session.")}`);
1377
+ return;
1378
+ }
1379
+ console.log(`${C_("Ledger Query")} — ${session.sessionId}`);
1380
+ console.log(`${D("═".repeat(50))}`);
1381
+ console.log(`${D(`Ledger size: ${allTransitions.length} transitions`)}`);
1382
+ console.log("");
1383
+ if (operation === "producer" || operation === "prod") {
1384
+ if (!operand) {
1385
+ console.error(`${R("Missing state name.")}`);
1386
+ process.exit(1);
1387
+ }
1388
+ const results = (0, ssg_validator_1.findProducer)(operand, allTransitions);
1389
+ if (results.length === 0) {
1390
+ console.log(` ${D(`No producer found for "${operand}"`)}`);
1391
+ }
1392
+ else {
1393
+ console.log(` ${B(`Producers of "${operand}":`)}`);
1394
+ for (const r of results) {
1395
+ console.log(` ${G("→")} ${r.transition.function}() @index=${r.index} [${D(r.namespace)}]`);
1396
+ }
1397
+ }
1398
+ }
1399
+ else if (operation === "consumer" || operation === "cons") {
1400
+ if (!operand) {
1401
+ console.error(`${R("Missing state name.")}`);
1402
+ process.exit(1);
1403
+ }
1404
+ const results = (0, ssg_validator_1.findConsumer)(operand, allTransitions);
1405
+ if (results.length === 0) {
1406
+ console.log(` ${D(`No consumer found for "${operand}"`)}`);
1407
+ }
1408
+ else {
1409
+ console.log(` ${B(`Consumers of "${operand}":`)}`);
1410
+ for (const r of results) {
1411
+ console.log(` ${Y("←")} ${r.transition.function}() @index=${r.index} [${D(r.namespace)}]`);
1412
+ }
1413
+ }
1414
+ }
1415
+ else if (operation === "violations" || operation === "viol") {
1416
+ const results = (0, ssg_validator_1.findViolations)(allTransitions);
1417
+ if (results.length === 0) {
1418
+ console.log(` ${G("No violations — all transitions are valid.")}`);
1419
+ }
1420
+ else {
1421
+ console.log(` ${R(`${results.length} violation(s):`)}`);
1422
+ for (const r of results) {
1423
+ console.log(` ${R("✖")} ${r.transition.function}() @index=${r.index} [${D(r.namespace)}]`);
1424
+ }
1425
+ }
1426
+ }
1427
+ else if (operation === "transition" || operation === "t") {
1428
+ if (!operand) {
1429
+ console.error(`${R("Missing action index.")}`);
1430
+ process.exit(1);
1431
+ }
1432
+ const idx = parseInt(operand, 10);
1433
+ if (isNaN(idx)) {
1434
+ console.error(`${R("Invalid index.")}`);
1435
+ process.exit(1);
1436
+ }
1437
+ const result = (0, ssg_validator_1.findTransition)(idx, allTransitions);
1438
+ if (!result) {
1439
+ console.log(` ${D(`No transition at index ${idx}`)}`);
1440
+ }
1441
+ else {
1442
+ const t = result.transition;
1443
+ console.log(` ${B(`Transition @${idx}:`)}`);
1444
+ console.log(` function: ${C_(t.function)}`);
1445
+ console.log(` namespace: ${D(t.namespace)}`);
1446
+ console.log(` valid: ${t.valid ? G("yes") : R("no")}`);
1447
+ console.log(` acquired: ${t.acquired.length ? G("+" + t.acquired.join(",+")) : D("(none)")}`);
1448
+ console.log(` invalidated: ${t.invalidated.length ? R("-" + t.invalidated.join(",-")) : D("(none)")}`);
1449
+ if (t.ruleHash)
1450
+ console.log(` ruleHash: ${D(t.ruleHash)}`);
1451
+ }
1452
+ }
1453
+ else if (operation === "all-states" || operation === "states") {
1454
+ const states = (0, ssg_validator_1.listAllStates)(allTransitions);
1455
+ if (states.length === 0) {
1456
+ console.log(` ${D("No states in ledger.")}`);
1457
+ }
1458
+ else {
1459
+ console.log(` ${B(`All states (${states.length}):`)}`);
1460
+ // Group by namespace
1461
+ const byNs = new Map();
1462
+ for (const s of states) {
1463
+ if (!byNs.has(s.namespace))
1464
+ byNs.set(s.namespace, []);
1465
+ byNs.get(s.namespace).push(s.state);
1466
+ }
1467
+ for (const [ns, ss] of [...byNs.entries()].sort()) {
1468
+ console.log(` ${C_(ns)}: ${ss.join(", ")}`);
1469
+ }
1470
+ }
1471
+ }
1472
+ else {
1473
+ console.error(`${R("Unknown operation:")} ${operation}`);
1474
+ console.error(`${D("Valid: producer, consumer, violations, transition, all-states")}`);
1475
+ process.exit(1);
1476
+ }
1477
+ return;
1478
+ }
1479
+ if (arg && !arg.startsWith("--")) {
1480
+ // View a specific session
1481
+ const session = sessions.find(s => s.sessionId === arg || s.sessionId.startsWith(arg));
1482
+ if (!session) {
1483
+ console.error(`${R("Session not found:")} ${arg}`);
1484
+ console.error(`\n${D("Available sessions:")}`);
1485
+ for (const s of sessions) {
1486
+ console.error(` ${D(s.sessionId)} — ${s.intent}`);
1487
+ }
1488
+ process.exit(1);
1489
+ }
1490
+ console.log(formatSessionTimeline(session));
1491
+ return;
1492
+ }
1493
+ console.log(formatSessionSummary(sessions));
1494
+ }
1495
+ if (require.main === module) {
1496
+ main().catch(console.error);
1497
+ }