progmune-runtime 2.0.4 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) 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/README.md +108 -54
  7. package/demo-project/auth.ts +55 -0
  8. package/demo-project/tsconfig.json +8 -0
  9. package/dist/ab-stats.js +11 -0
  10. package/dist/acl-breakdown.js +13 -0
  11. package/dist/action-runtime.js +1 -0
  12. package/dist/all-sessions.js +11 -0
  13. package/dist/antibody-stats.js +11 -0
  14. package/dist/audit.js +222 -0
  15. package/dist/benchmark-count.js +7 -0
  16. package/dist/benchmark-full.js +17 -0
  17. package/dist/benchmark-pass-rate.js +54 -0
  18. package/dist/benchmark-report.js +67 -0
  19. package/dist/benchmark-save.js +62 -0
  20. package/dist/benchmark-status.js +15 -0
  21. package/dist/branch-ledger.js +393 -0
  22. package/dist/branch-tree-count.js +14 -0
  23. package/dist/check.js +506 -0
  24. package/dist/common-fixpath.js +12 -0
  25. package/dist/constraint-types.js +12 -0
  26. package/dist/deterministic-replay.js +283 -0
  27. package/dist/emitter.js +143 -12
  28. package/dist/exec-metrics.js +11 -0
  29. package/dist/execute.js +251 -0
  30. package/dist/extract-ir.js +592 -5
  31. package/dist/failure-collector.js +163 -0
  32. package/dist/failure-corpus.js +507 -35
  33. package/dist/failure-report.js +11 -0
  34. package/dist/failures.js +11 -0
  35. package/dist/fast-path-hits.js +13 -0
  36. package/dist/feedback.js +10 -3
  37. package/dist/file-lock.js +82 -0
  38. package/dist/find-session.js +10 -0
  39. package/dist/fingerprint-list.js +15 -0
  40. package/dist/gen-history-log.js +13 -0
  41. package/dist/generate.js +2 -1
  42. package/dist/generate_500.js +4 -2
  43. package/dist/genome.js +11 -0
  44. package/dist/heatmap-data.js +11 -0
  45. package/dist/heatmap.js +11 -0
  46. package/dist/immune-reporter.js +34 -22
  47. package/dist/ir-utils.js +18 -0
  48. package/dist/learned.js +11 -0
  49. package/dist/ledger-registry.js +252 -0
  50. package/dist/llm.js +46 -2
  51. package/dist/load-benchmarks.js +47 -0
  52. package/dist/main.js +2 -1
  53. package/dist/mcp-server.mjs +445 -43
  54. package/dist/memory-layer.js +54 -13
  55. package/dist/metrics.js +11 -0
  56. package/dist/obs-web.js +561 -0
  57. package/dist/p0_ssg_demo.js +255 -40
  58. package/dist/planner.js +996 -80
  59. package/dist/protocol-registry.js +112 -0
  60. package/dist/recent-session.js +12 -0
  61. package/dist/repair-proposal.js +363 -0
  62. package/dist/runtime-invariants.js +170 -0
  63. package/dist/runtime-types.js +117 -0
  64. package/dist/runtime.js +1 -0
  65. package/dist/search-planner.js +39 -9
  66. package/dist/semantic-snapshot.js +157 -0
  67. package/dist/semantic-trace.js +1497 -0
  68. package/dist/semantic-validator.js +3 -2
  69. package/dist/semantic_guard_test.js +2 -1
  70. package/dist/session-utils.js +19 -0
  71. package/dist/sessions.js +11 -0
  72. package/dist/ssg-validator.js +666 -20
  73. package/dist/svl-distribution.js +11 -0
  74. package/dist/terminal-status.js +11 -0
  75. package/dist/test_failure_corpus.js +3 -1
  76. package/dist/token-savings.js +11 -0
  77. package/dist/total-repairs.js +12 -0
  78. package/dist/unresolved-count.js +12 -0
  79. package/dist/utils.js +2 -0
  80. package/dist/valid-fingerprints.js +13 -0
  81. package/dist/validator.js +118 -60
  82. package/dist/verify-fps.js +11 -0
  83. package/dist/verify-ledgers.js +11 -0
  84. package/docs/whitepaper-style.css +77 -0
  85. package/docs/whitepaper-v2.1.md +609 -0
  86. package/docs/whitepaper-v2.2.md +1064 -0
  87. package/docs/whitepaper-v2.2.pdf +0 -0
  88. package/fly.toml +1 -1
  89. package/package.json +13 -4
  90. package/protocols.json +131 -11
  91. package/public/dashboard.html +119 -0
  92. package/server/hub.js +84 -12
  93. package/test/replay-golden/sess_1780063202050_mgeld.json +9 -0
  94. package/test/replay-golden/sess_1780064032560_gocld.json +354 -0
  95. package/test/replay-golden/sess_1780064413331_s2709.json +606 -0
  96. package/test/replay-golden/sess_1780064792710_y3avo.json +614 -0
  97. package/test/replay-golden.ts +84 -0
  98. package/test_benchmark.js +165 -0
  99. package/test_comprehensive.mjs +638 -0
  100. package/test_concurrency.js +129 -0
  101. package/test_ir_robustness.js +85 -0
  102. package/test_semantic_contracts.js +269 -0
  103. package/test_ssg_stress.js +156 -0
  104. package/test_svl3.js +58 -0
  105. package/tsconfig.json +1 -1
  106. package/.env.example +0 -3
  107. package/.progmune_memory/episodic.json +0 -186
  108. package/.progmune_memory/fingerprints.json +0 -7
  109. package/.progmune_memory/opt_in.json +0 -4
  110. package/immune_hub_data/2026-05-14.json +0 -50
@@ -0,0 +1,393 @@
1
+ "use strict";
2
+ /**
3
+ * Phase 4: Branch Ledger (P1)
4
+ *
5
+ * Upgrades the semantic ledger from linear to tree-structured.
6
+ * Supports fork/merge for future Repair Planner, alternative plans,
7
+ * and counterfactual replay.
8
+ *
9
+ * A Branch is a named sequence of state transitions with a parent reference.
10
+ * The full execution is a tree of branches rooted at a single "root" branch.
11
+ *
12
+ * Backward compatible: existing linear ledgers auto-wrap as single-branch root.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.generateBranchId = generateBranchId;
16
+ exports.createRootBranch = createRootBranch;
17
+ exports.createBranch = createBranch;
18
+ exports.forkBranch = forkBranch;
19
+ exports.mergeBranches = mergeBranches;
20
+ exports.flattenBranch = flattenBranch;
21
+ exports.getBranchPath = getBranchPath;
22
+ exports.replayBranch = replayBranch;
23
+ exports.buildBranchMap = buildBranchMap;
24
+ exports.findRootBranch = findRootBranch;
25
+ exports.findChildBranches = findChildBranches;
26
+ exports.describeBranchTree = describeBranchTree;
27
+ exports.evaluateBranches = evaluateBranches;
28
+ exports.wrapAsBranch = wrapAsBranch;
29
+ exports.unwrapBranchTree = unwrapBranchTree;
30
+ const ssg_validator_1 = require("./ssg-validator");
31
+ const runtime_invariants_1 = require("./runtime-invariants");
32
+ const protocol_registry_1 = require("./protocol-registry");
33
+ // ── Pure Functions ──
34
+ /** Generate a unique branch ID. */
35
+ /** @requires BRANCH_TREE @produces BRANCH_ID */
36
+ function generateBranchId() {
37
+ return `br_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
38
+ }
39
+ /** Create the root branch of a new execution tree. */
40
+ /** Create the root branch of an execution tree. */
41
+ /** @requires TRANSITIONS @produces ROOT_BRANCH */
42
+ function createRootBranch(transitions = []) {
43
+ const id = generateBranchId();
44
+ return {
45
+ id,
46
+ rootId: id,
47
+ transitions,
48
+ reason: "root",
49
+ createdAt: Date.now(),
50
+ };
51
+ }
52
+ /**
53
+ * Create a CHILD branch (parent → child relationship).
54
+ *
55
+ * Tree structure:
56
+ * root
57
+ * └── child (parentId = root.id)
58
+ *
59
+ * The child starts with an independent transition sequence. It does NOT
60
+ * inherit any transitions from the parent — it begins empty or with
61
+ * the given initialTransitions. The parent's state at creation time is
62
+ * the child's implicit starting state; use forkBranch() if you need to
63
+ * share a prefix of transitions.
64
+ *
65
+ * Use createBranch when:
66
+ * - Creating an alternative implementation from scratch
67
+ * - The child has no shared history with the parent beyond the parent's
68
+ * final state
69
+ */
70
+ /** Create a child branch from a parent branch. */
71
+ /** @requires PARENT_BRANCH @produces CHILD_BRANCH */
72
+ function createBranch(parent, reason = "alternative", initialTransitions = []) {
73
+ const id = generateBranchId();
74
+ return {
75
+ id,
76
+ parentId: parent.id,
77
+ rootId: parent.rootId,
78
+ transitions: initialTransitions,
79
+ reason,
80
+ createdAt: Date.now(),
81
+ };
82
+ }
83
+ /**
84
+ * Fork a branch at a specific transition index, creating a SIBLING branch.
85
+ *
86
+ * Sibling semantics (NOT child):
87
+ * parent
88
+ * ├── original (branch, truncated at splitIndex, marked "abandoned")
89
+ * └── forked (NEW sibling — same parentId as original, NOT a child of original)
90
+ *
91
+ * Tree structure BEFORE fork:
92
+ * ... → parent → branch
93
+ *
94
+ * Tree structure AFTER fork:
95
+ * ... → parent
96
+ * ├── original (abandoned — only transitions[0..splitIndex])
97
+ * └── forked (repair_attempt — transitions[splitIndex+1..end])
98
+ *
99
+ * Both share the same parent. The forked branch inherits the COMMON PREFIX
100
+ * (transitions 0..splitIndex) implicitly through the tree path — flattenBranch()
101
+ * will walk parent → forked and include parent's + forked's transitions.
102
+ *
103
+ * Use forkBranch when:
104
+ * - A violation is detected at splitIndex and you want to try a fix
105
+ * - The prefix up to splitIndex is valid and should be preserved
106
+ * - You want to keep the original as evidence (abandoned, not deleted)
107
+ *
108
+ * Use createBranch when:
109
+ * - Starting a completely fresh alternative from the parent's final state
110
+ */
111
+ /** Fork a branch at a split index creating a sibling repair branch. */
112
+ /** @requires BRANCH @produces FORKED_BRANCHES */
113
+ function forkBranch(branch, splitIndex, reason = "repair_attempt") {
114
+ const sharedTransitions = branch.transitions.slice(0, splitIndex + 1);
115
+ const remainingTransitions = branch.transitions.slice(splitIndex + 1);
116
+ const original = {
117
+ ...branch,
118
+ transitions: sharedTransitions,
119
+ outcome: "abandoned",
120
+ };
121
+ const forked = {
122
+ id: generateBranchId(),
123
+ parentId: branch.parentId, // sibling — same parent
124
+ rootId: branch.rootId,
125
+ transitions: remainingTransitions,
126
+ reason,
127
+ createdAt: Date.now(),
128
+ };
129
+ // Ontology: verify all split transitions are internally consistent
130
+ for (const t of [...sharedTransitions, ...remainingTransitions]) {
131
+ if (t.valid)
132
+ try {
133
+ (0, runtime_invariants_1.assertDeltaConsistency)(t);
134
+ }
135
+ catch { }
136
+ }
137
+ return { original, forked };
138
+ }
139
+ /** Merge multiple branches into one.
140
+ * Takes the successful path: concatenates transitions from each branch
141
+ * in the order they appear in the tree path.
142
+ * Returns null if no branches have transitions. */
143
+ /** Merge multiple branches into one unified branch. */
144
+ /** @requires BRANCH_LIST @produces MERGED_BRANCH */
145
+ function mergeBranches(branches) {
146
+ const validBranches = branches.filter(b => b.transitions.length > 0);
147
+ if (validBranches.length === 0)
148
+ return null;
149
+ // Sort by creation time to preserve causal order
150
+ const sorted = [...validBranches].sort((a, b) => a.createdAt - b.createdAt);
151
+ const first = sorted[0];
152
+ const merged = {
153
+ id: generateBranchId(),
154
+ rootId: first.rootId,
155
+ transitions: [],
156
+ reason: "merge",
157
+ createdAt: Date.now(),
158
+ };
159
+ // Deduplicate transitions by index (keep first occurrence)
160
+ const seenIndices = new Set();
161
+ for (const branch of sorted) {
162
+ for (const t of branch.transitions) {
163
+ if (!seenIndices.has(t.actionIndex)) {
164
+ seenIndices.add(t.actionIndex);
165
+ merged.transitions.push(t);
166
+ }
167
+ }
168
+ }
169
+ // Sort by actionIndex
170
+ merged.transitions.sort((a, b) => a.actionIndex - b.actionIndex);
171
+ return merged;
172
+ }
173
+ /** Flatten a branch and all its ancestors into a single linear transition sequence.
174
+ * This is the bridge between the tree model and existing linear-only consumers
175
+ * (checkLedgerConsistency, hashLedger, etc.). */
176
+ /** Flatten a branch tree into a linear transition sequence. */
177
+ /** @requires BRANCH_TREE @produces TRANSITIONS */
178
+ function flattenBranch(branch, allBranches) {
179
+ const path = getBranchPath(branch, allBranches);
180
+ const allTransitions = [];
181
+ const seenIndices = new Set();
182
+ for (const b of path) {
183
+ for (const t of b.transitions) {
184
+ // In case of index collision (forked branches), keep the later branch's version
185
+ if (seenIndices.has(t.actionIndex)) {
186
+ // Replace the earlier transition with this one
187
+ const existingIdx = allTransitions.findIndex(existing => existing.actionIndex === t.actionIndex);
188
+ if (existingIdx >= 0) {
189
+ allTransitions[existingIdx] = t;
190
+ }
191
+ }
192
+ else {
193
+ seenIndices.add(t.actionIndex);
194
+ allTransitions.push(t);
195
+ }
196
+ }
197
+ }
198
+ return allTransitions.sort((a, b) => a.actionIndex - b.actionIndex);
199
+ }
200
+ /** Get the path from root to a given branch (inclusive). */
201
+ /** Get the path from root to a target branch. */
202
+ /** @requires BRANCH @produces BRANCH_PATH */
203
+ function getBranchPath(branch, allBranches) {
204
+ const path = [];
205
+ let current = branch;
206
+ while (current) {
207
+ path.unshift(current);
208
+ if (current.parentId) {
209
+ current = allBranches.get(current.parentId);
210
+ }
211
+ else {
212
+ current = undefined;
213
+ }
214
+ }
215
+ return path;
216
+ }
217
+ /** Replay a branch tree: rebuild state across all ancestor branches
218
+ * and verify every transition is valid. */
219
+ /** Replay a branch tree verifying all transitions. */
220
+ /** @requires BRANCH_TREE @produces REPLAY_RESULT */
221
+ function replayBranch(branch, allBranches, namespaceInitialStates = (0, protocol_registry_1.getNsInit)()) {
222
+ const path = getBranchPath(branch, allBranches);
223
+ const pathIds = path.map(b => b.id);
224
+ // Collect all transitions in tree order
225
+ const allTransitions = flattenBranch(branch, allBranches);
226
+ // Check validity
227
+ let valid = true;
228
+ let violationIndex;
229
+ let violationBranch;
230
+ for (const t of allTransitions) {
231
+ if (!t.valid) {
232
+ valid = false;
233
+ violationIndex = t.actionIndex;
234
+ // Find which branch contains this transition
235
+ for (const b of path) {
236
+ if (b.transitions.some(bt => bt.actionIndex === t.actionIndex)) {
237
+ violationBranch = b.id;
238
+ break;
239
+ }
240
+ }
241
+ break;
242
+ }
243
+ }
244
+ const finalState = allTransitions.length > 0
245
+ ? (0, ssg_validator_1.rebuildState)(allTransitions, namespaceInitialStates)
246
+ : {};
247
+ return {
248
+ branchId: branch.id,
249
+ path: pathIds,
250
+ finalState,
251
+ totalTransitions: allTransitions.length,
252
+ valid,
253
+ violationIndex,
254
+ violationBranch,
255
+ };
256
+ }
257
+ /** Build a branch lookup map from an array of branches. */
258
+ /** Build a lookup map from a branch array. */
259
+ /** @requires BRANCH_LIST @produces BRANCH_MAP */
260
+ function buildBranchMap(branches) {
261
+ const map = new Map();
262
+ for (const b of branches) {
263
+ map.set(b.id, b);
264
+ }
265
+ return map;
266
+ }
267
+ /** Find the root branch of a tree. */
268
+ /** Find the root branch of a tree. */
269
+ /** @requires BRANCH_LIST @produces ROOT_BRANCH */
270
+ function findRootBranch(branches) {
271
+ return branches.find(b => !b.parentId);
272
+ }
273
+ /** Find all child branches of a given parent. */
274
+ /** @requires PARENT_BRANCH @produces CHILD_BRANCHES */
275
+ function findChildBranches(parent, allBranches) {
276
+ const children = [];
277
+ for (const b of allBranches.values()) {
278
+ if (b.parentId === parent.id) {
279
+ children.push(b);
280
+ }
281
+ }
282
+ return children;
283
+ }
284
+ /** Get the full branch tree as a human-readable structure. */
285
+ /** Format a branch tree as human-readable text. */
286
+ /** @requires BRANCH_TREE @produces DESCRIPTION */
287
+ function describeBranchTree(root, allBranches, indent = 0) {
288
+ const prefix = " ".repeat(indent);
289
+ let result = `${prefix}${root.id.slice(0, 12)} [${root.reason}] (${root.transitions.length} tx, outcome: ${root.outcome || "open"})\n`;
290
+ const children = findChildBranches(root, allBranches);
291
+ for (const child of children) {
292
+ result += describeBranchTree(child, allBranches, indent + 1);
293
+ }
294
+ return result;
295
+ }
296
+ /** Evaluate all branches in a tree, score them, and return the recommended winner.
297
+ * Scoring: replay +50, zero violations +30, success outcome +20.
298
+ * Highest score wins. Ties go to the smaller branch (fewer transitions). */
299
+ /** Score all branches in a tree and return the recommended winner. */
300
+ /** @requires BRANCH_TREE @produces BRANCH_SCORES */
301
+ function evaluateBranches(branches, namespaceInitialStates = new Map([["_global", "UNAUTHENTICATED"]])) {
302
+ if (branches.length === 0)
303
+ return { scores: [], winner: null };
304
+ const map = buildBranchMap(branches);
305
+ const scores = [];
306
+ for (const branch of branches) {
307
+ const tx = flattenBranch(branch, map);
308
+ const validCount = tx.filter(t => t.valid).length;
309
+ const invalidCount = tx.filter(t => !t.valid).length;
310
+ let replayPassed = false;
311
+ try {
312
+ const replay = replayBranch(branch, map, namespaceInitialStates);
313
+ replayPassed = replay.valid;
314
+ }
315
+ catch {
316
+ replayPassed = false;
317
+ }
318
+ let score = 0;
319
+ if (replayPassed)
320
+ score += 50;
321
+ if (invalidCount === 0)
322
+ score += 30;
323
+ if (branch.outcome === "success")
324
+ score += 20;
325
+ let recommendation = "";
326
+ if (score >= 90)
327
+ recommendation = "Recommended — clean execution";
328
+ else if (score >= 70)
329
+ recommendation = "Acceptable — minor issues";
330
+ else if (score >= 50)
331
+ recommendation = "Needs review — violations present";
332
+ else
333
+ recommendation = "Rejected — replay failed or significant violations";
334
+ scores.push({
335
+ branchId: branch.id,
336
+ reason: branch.reason,
337
+ outcome: branch.outcome || "open",
338
+ transitionCount: tx.length,
339
+ validCount,
340
+ violationCount: invalidCount,
341
+ replayPassed,
342
+ score,
343
+ recommendation,
344
+ });
345
+ }
346
+ // Sort: highest score first, ties broken by fewer transitions
347
+ scores.sort((a, b) => b.score - a.score || a.transitionCount - b.transitionCount);
348
+ // Winner is the first one that passed replay
349
+ const winner = scores.find(s => s.replayPassed) || scores[0] || null;
350
+ return { scores, winner };
351
+ }
352
+ /** Wrap a linear transition array as a single root branch (backward compat). */
353
+ /** Wrap linear transitions as a single root branch. */
354
+ /** @requires TRANSITIONS @produces ROOT_BRANCH */
355
+ function wrapAsBranch(transitions) {
356
+ const b = createRootBranch(transitions);
357
+ b.outcome = transitions.length > 0
358
+ ? (transitions.every(t => t.valid) ? "success" : "violation")
359
+ : "success";
360
+ return b;
361
+ }
362
+ /** Unwrap a branch tree to the linear transition list.
363
+ * For backward compatibility: flattens the "winning" path (first successful leaf). */
364
+ /** Unwrap a branch tree to a flat transition list. */
365
+ /** @requires BRANCH_LIST @produces TRANSITIONS */
366
+ function unwrapBranchTree(branches) {
367
+ if (branches.length === 0)
368
+ return [];
369
+ const map = buildBranchMap(branches);
370
+ const root = findRootBranch(branches);
371
+ if (!root)
372
+ return [];
373
+ // Find the first successful leaf
374
+ const successfulLeaf = findSuccessfulLeaf(root, map);
375
+ if (successfulLeaf) {
376
+ return flattenBranch(successfulLeaf, map);
377
+ }
378
+ // Fallback: flatten the root
379
+ return flattenBranch(root, map);
380
+ }
381
+ function findSuccessfulLeaf(branch, allBranches) {
382
+ if (branch.outcome === "success") {
383
+ // Check if any children are also successful (prefer children)
384
+ const children = findChildBranches(branch, allBranches);
385
+ for (const child of children) {
386
+ const leaf = findSuccessfulLeaf(child, allBranches);
387
+ if (leaf)
388
+ return leaf;
389
+ }
390
+ return branch;
391
+ }
392
+ return undefined;
393
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.main = main;
4
+ // @progmune-generated session=sess_1780343627181_k5xw4 timestamp=2026-06-01T19:53:48.655Z ruleHash=9dec68bc2995e92a
5
+ // Generated with IR constraint: 389 functions, 17 protocol rules
6
+ const failure_corpus_1 = require("./failure-corpus");
7
+ const branch_ledger_1 = require("./branch-ledger");
8
+ function main() {
9
+ const sessions = (0, failure_corpus_1.getAllSessions)();
10
+ const root = (0, branch_ledger_1.findRootBranch)(sessions);
11
+ const children = (0, branch_ledger_1.findChildBranches)(root, {});
12
+ return children;
13
+ }
14
+ main();