pi-mega-compact 0.4.4 → 0.4.6

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 (69) hide show
  1. package/dist/extensions/dashboard-server.js +450 -0
  2. package/dist/extensions/dashboard-server.test.js +111 -0
  3. package/dist/extensions/error-patterns.js +115 -0
  4. package/dist/extensions/mega-compact.js +782 -0
  5. package/dist/extensions/mega-compact.test.js +328 -0
  6. package/dist/extensions/openclaw-mega-compact.js +291 -0
  7. package/dist/src/adapt.js +106 -0
  8. package/dist/src/boundary.js +88 -0
  9. package/dist/src/boundary.test.js +53 -0
  10. package/dist/src/canary.js +118 -0
  11. package/dist/src/compact.js +250 -0
  12. package/dist/src/compact.test.js +78 -0
  13. package/dist/src/config/dedup.js +81 -0
  14. package/dist/src/config.js +12 -0
  15. package/dist/src/dedup/dedup.test.js +41 -0
  16. package/dist/src/dedup/digest.js +30 -0
  17. package/dist/src/dedup/l1-lsh.js +52 -0
  18. package/dist/src/dedup/l1-minhash.js +91 -0
  19. package/dist/src/dedup/l1-verify.js +54 -0
  20. package/dist/src/dedup/l1.test.js +50 -0
  21. package/dist/src/dedup/mmr.js +45 -0
  22. package/dist/src/dedup/normalize.js +39 -0
  23. package/dist/src/dedup/raptor/guardrails.js +83 -0
  24. package/dist/src/dedup/raptor/index.js +94 -0
  25. package/dist/src/dedup/raptor/kmeans.js +152 -0
  26. package/dist/src/dedup/raptor/raptor.test.js +205 -0
  27. package/dist/src/dedup/raptor/retrieval.js +81 -0
  28. package/dist/src/dedup/raptor/summarizer.js +85 -0
  29. package/dist/src/dedup/raptor/tree.js +177 -0
  30. package/dist/src/dedup/sprint12.test.js +219 -0
  31. package/dist/src/dedup/topk.js +60 -0
  32. package/dist/src/dedup-engine.test.js +447 -0
  33. package/dist/src/e2e.test.js +698 -0
  34. package/dist/src/embedder.js +102 -0
  35. package/dist/src/engine.js +137 -0
  36. package/dist/src/engine.test.js +111 -0
  37. package/dist/src/extractive.js +209 -0
  38. package/dist/src/extractive.test.js +130 -0
  39. package/dist/src/httpEmbedder.js +143 -0
  40. package/dist/src/log.js +47 -0
  41. package/dist/src/log.test.js +42 -0
  42. package/dist/src/minilm.js +92 -0
  43. package/dist/src/monitoring.js +131 -0
  44. package/dist/src/ratio.bench.test.js +897 -0
  45. package/dist/src/recall.integration.test.js +77 -0
  46. package/dist/src/recall.js +60 -0
  47. package/dist/src/recall.test.js +50 -0
  48. package/dist/src/sprint14.test.js +219 -0
  49. package/dist/src/store/backfill.js +189 -0
  50. package/dist/src/store/bloom.js +114 -0
  51. package/dist/src/store/compression.js +177 -0
  52. package/dist/src/store/compression.test.js +67 -0
  53. package/dist/src/store/integrity.js +44 -0
  54. package/dist/src/store/migrate.js +79 -0
  55. package/dist/src/store/migrate.test.js +139 -0
  56. package/dist/src/store/sprint10.test.js +186 -0
  57. package/dist/src/store/sqlite.js +574 -0
  58. package/dist/src/store.js +115 -0
  59. package/dist/src/store.test.js +142 -0
  60. package/dist/src/supersede.js +68 -0
  61. package/dist/src/supersede.test.js +36 -0
  62. package/dist/src/tokens.js +31 -0
  63. package/dist/src/types.js +8 -0
  64. package/dist/src/types.test.js +9 -0
  65. package/dist/src/vectorStore.js +465 -0
  66. package/dist/src/vectorStore.test.js +479 -0
  67. package/dist/src/wordpiece.js +129 -0
  68. package/extensions/mega-compact.ts +9 -3
  69. package/package.json +4 -2
@@ -0,0 +1,186 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { VectorStore } from "../vectorStore.js";
7
+ import { normalize } from "../dedup/normalize.js";
8
+ import { openBloom, closeBloom } from "./bloom.js";
9
+ import { backfillContentHashes, isBackfillComplete } from "./backfill.js";
10
+ import { checkSessionIntegrity, checkAllIntegrity } from "./integrity.js";
11
+ import { openStore, closeStore, upsertCheckpoint, saveSessionState, loadSessionState } from "./sqlite.js";
12
+ const baseTmp = mkdtempSync(join(tmpdir(), "mc-s10-"));
13
+ let counter = 0;
14
+ function store(opts = {}) {
15
+ const dir = join(baseTmp, `run-${counter++}`);
16
+ return { s: new VectorStore({ dedupSim: opts.dedupSim ?? 0.9, stateDir: dir }), dir };
17
+ }
18
+ // --- L0 normalization upgrade (case/whitespace/ANSI collapse) --------------
19
+ test("Sprint 10 L0: case/whitespace/ANSI variants dedup to one row", () => {
20
+ const { s } = store();
21
+ const variants = ["user reviewed the auth module and merged the PR", " USER REVIEWED the AUTH module and MERGED the PR ", "USER REVIEWED THE AUTH MODULE AND MERGED THE PR"];
22
+ let added = 0;
23
+ for (const v of variants) {
24
+ const r = s.add({ sessionId: "sess_norm", summary: "x", regionText: v, timestamp: added + 1 });
25
+ if (!r.deduped)
26
+ added++;
27
+ }
28
+ assert.equal(s.list("sess_norm").length, 1);
29
+ });
30
+ test("normalize case-folds so Foo/foo/FOO are equal", () => {
31
+ assert.equal(normalize("Foo Bar"), normalize("foo bar"));
32
+ assert.equal(normalize("FOO BAR"), normalize("foo bar"));
33
+ });
34
+ test("normalize strips ANSI before hashing", () => {
35
+ assert.equal(normalize("err\x1b[31m fatal\x1b[0m"), normalize("err fatal"));
36
+ });
37
+ // --- Bloom accelerator ------------------------------------------------------
38
+ test("bloom miss short-circuits the scan; hit is confirmed by query", () => {
39
+ const { s, dir } = store();
40
+ const raw = "the region text under test for bloom behavior";
41
+ s.add({ sessionId: "sess_bloom", summary: "x", regionText: raw, timestamp: 1 });
42
+ const bloom = openBloom(dir);
43
+ // content_hash for `raw` is present → hit path must confirm via query and dedup.
44
+ assert.equal(bloom.maybeHas("this-key-is-not-present"), false); // definitive miss
45
+ const r2 = s.add({ sessionId: "sess_bloom", summary: "x", regionText: raw, timestamp: 2 });
46
+ assert.equal(r2.deduped, true);
47
+ assert.equal(r2.reason, "contentHash");
48
+ });
49
+ test("bloom persists to disk and reloads warm", () => {
50
+ const dir = join(baseTmp, `run-${counter++}`);
51
+ const s1 = new VectorStore({ stateDir: dir });
52
+ s1.add({ sessionId: "sess_persist", summary: "x", regionText: "persisted region", timestamp: 1 });
53
+ closeBloom(dir); // evict cache so the next open reads from disk
54
+ const s2 = new VectorStore({ stateDir: dir });
55
+ const r = s2.add({ sessionId: "sess_persist", summary: "x", regionText: "persisted region", timestamp: 2 });
56
+ assert.equal(r.deduped, true);
57
+ });
58
+ // --- Atomic write + QA #13 timeout degrade ---------------------------------
59
+ test("duplicate add is idempotent (no partial rows, single checkpoint)", () => {
60
+ const { s } = store();
61
+ const raw = "idempotent region content for atomicity check";
62
+ const a = s.add({ sessionId: "sess_atom", summary: "x", regionText: raw, timestamp: 1 });
63
+ const b = s.add({ sessionId: "sess_atom", summary: "x", regionText: raw, timestamp: 2 });
64
+ assert.equal(a.deduped, false);
65
+ assert.equal(b.deduped, true);
66
+ assert.equal(s.list("sess_atom").length, 1);
67
+ });
68
+ // --- Backfill orchestrator -------------------------------------------------
69
+ test("backfill populates null content_hash rows and is idempotent", () => {
70
+ const dir = join(baseTmp, `run-${counter++}`);
71
+ openStore(dir);
72
+ // Seed two rows with null content_hash via direct upsert (simulating legacy data).
73
+ const cp = (id, summary) => ({
74
+ checkpointId: id,
75
+ sessionId: "sess_bf",
76
+ summary,
77
+ keyDecisions: [],
78
+ nextSteps: [],
79
+ filesModified: [],
80
+ tokenEstimate: 0,
81
+ regionHash: "r",
82
+ embedding: [0, 0, 0],
83
+ timestamp: 1,
84
+ });
85
+ upsertCheckpoint(cp("chkpt_001", "alpha summary"), dir);
86
+ upsertCheckpoint(cp("chkpt_002", "beta summary"), dir);
87
+ const r1 = backfillContentHashes(dir);
88
+ assert.equal(r1.updated, 2);
89
+ assert.equal(r1.processed, 2);
90
+ assert.equal(isBackfillComplete(dir), true);
91
+ // Second run is a no-op (idempotent): no rows left to process.
92
+ const r2 = backfillContentHashes(dir);
93
+ assert.equal(r2.processed, 0);
94
+ });
95
+ test("backfill resolves a content_hash collision keeping the oldest row", () => {
96
+ const dir = join(baseTmp, `run-${counter++}`);
97
+ openStore(dir);
98
+ // Both rows share the same normalized summary → same content_hash.
99
+ const cp = (id) => ({
100
+ checkpointId: id,
101
+ sessionId: "sess_dup",
102
+ summary: "identical normalized summary text",
103
+ keyDecisions: [],
104
+ nextSteps: [],
105
+ filesModified: [],
106
+ tokenEstimate: 0,
107
+ regionHash: "r",
108
+ embedding: [0, 0, 0],
109
+ timestamp: 1,
110
+ });
111
+ upsertCheckpoint(cp("chkpt_001"), dir);
112
+ upsertCheckpoint(cp("chkpt_002"), dir);
113
+ const r = backfillContentHashes(dir);
114
+ assert.equal(r.duplicatesResolved, 1);
115
+ assert.equal(r.updated, 1);
116
+ });
117
+ // --- Integrity checks ------------------------------------------------------
118
+ test("integrity flags a tampered storedRegionHashes set", () => {
119
+ const dir = join(baseTmp, `run-${counter++}`);
120
+ const s = new VectorStore({ stateDir: dir });
121
+ s.add({ sessionId: "sess_int", summary: "x", regionText: "integrity region one", timestamp: 1 });
122
+ s.add({ sessionId: "sess_int", summary: "y", regionText: "integrity region two", timestamp: 2 });
123
+ const okReport = checkSessionIntegrity("sess_int", dir);
124
+ assert.equal(okReport.ok, true); // consistent after normal adds
125
+ // Simulate tampering: the sentinel stores a region hash the checkpoints lack.
126
+ const db = openStore(dir);
127
+ db.prepare("UPDATE session_state SET stored_region_hashes = ? WHERE session_id = ?").run(JSON.stringify(["deadbeefcafe0000"]), "sess_int");
128
+ const tampered = checkSessionIntegrity("sess_int", dir);
129
+ assert.equal(tampered.ok, false);
130
+ assert.equal(tampered.regionHashMismatch, true);
131
+ });
132
+ test("integrity detects an orphan injectedCheckpointId", () => {
133
+ const dir = join(baseTmp, `run-${counter++}`);
134
+ const s = new VectorStore({ stateDir: dir });
135
+ s.add({ sessionId: "sess_orphan", summary: "x", regionText: "orphan region", timestamp: 1 });
136
+ // Manually inject a dangling id into session state (SQLite-backed).
137
+ const st = loadSessionState("sess_orphan", dir);
138
+ st.injectedCheckpointIds.push("chkpt_999");
139
+ saveSessionState("sess_orphan", st, dir);
140
+ const report = checkSessionIntegrity("sess_orphan", dir);
141
+ assert.equal(report.ok, false);
142
+ assert.deepEqual(report.orphanInjectedIds, ["chkpt_999"]);
143
+ });
144
+ test("checkAllIntegrity covers every session", () => {
145
+ const dir = join(baseTmp, `run-${counter++}`);
146
+ const s = new VectorStore({ stateDir: dir });
147
+ s.add({ sessionId: "sess_a", summary: "x", regionText: "a region", timestamp: 1 });
148
+ s.add({ sessionId: "sess_b", summary: "y", regionText: "b region", timestamp: 1 });
149
+ const reports = checkAllIntegrity(dir);
150
+ assert.equal(reports.length, 2);
151
+ assert.ok(reports.every((r) => r.ok));
152
+ });
153
+ // --- schema migration (v0.4.2: original_token_estimate) -------------------
154
+ test("Sprint 10 migration: pre-0.4.2 db gains original_token_estimate and repoStats works", () => {
155
+ const dir = join(baseTmp, `run-${counter++}`);
156
+ // Simulate a v0.4.1-era store: openStore() builds the full current schema,
157
+ // then drop the original_token_estimate column that 0.4.2 added. CREATE TABLE
158
+ // IF NOT EXISTS is a no-op on an existing table, which is exactly why the
159
+ // shipped v0.4.2 crashed at runtime on old repos ("no such column").
160
+ const db = openStore(dir);
161
+ db.exec("ALTER TABLE context_chunks DROP COLUMN original_token_estimate;");
162
+ closeStore(dir);
163
+ // Re-open through the real code path — must ALTER the column in, not crash.
164
+ const vs = new VectorStore({ dedupSim: 0.9, stateDir: dir });
165
+ vs.add({
166
+ sessionId: "sess_mig",
167
+ summary: "legacy region",
168
+ regionText: "some region text to compact",
169
+ tokenEstimate: 100,
170
+ originalTokenEstimate: 500,
171
+ timestamp: 1,
172
+ });
173
+ const repo = vs.repoStats();
174
+ // No "no such column" crash = migration succeeded; totals reflect the new col.
175
+ assert.equal(repo.checkpointCount, 1);
176
+ assert.equal(repo.originalTokens, 500, "originalTokens read from migrated column");
177
+ // Re-open a second time to prove idempotency (column already exists).
178
+ closeStore(dir);
179
+ const vs2 = new VectorStore({ dedupSim: 0.9, stateDir: dir });
180
+ assert.equal(vs2.repoStats().originalTokens, 500, "stable across re-open");
181
+ });
182
+ // --- cleanup ---------------------------------------------------------------
183
+ test("Sprint 10 cleanup", () => {
184
+ closeStore(baseTmp);
185
+ rmSync(baseTmp, { recursive: true, force: true });
186
+ });