pi-mega-compact 0.11.3 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
- package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
- package/dist/extensions/dashboard-server/index-reader.js +6 -2
- package/dist/extensions/dashboard-server/routes-cache.js +115 -55
- package/dist/extensions/dashboard-server/routes-memory.js +51 -0
- package/dist/extensions/dashboard-server/routes-repo.js +2 -2
- package/dist/extensions/dashboard-server/routes-setup.js +162 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +7 -1
- package/dist/extensions/mega-commands.js +189 -1
- package/dist/extensions/mega-config.js +3 -0
- package/dist/extensions/mega-events/agent-handlers.js +41 -6
- package/dist/extensions/mega-events/compact-handlers.js +1 -0
- package/dist/extensions/mega-events/context-handler.js +37 -92
- package/dist/extensions/mega-events/context-hwm.js +51 -0
- package/dist/extensions/mega-events/error-classifier.js +118 -128
- package/dist/extensions/mega-events/mirror-append.js +107 -0
- package/dist/extensions/mega-events/outage-advisor.js +59 -0
- package/dist/extensions/mega-events/perf-handler.js +51 -1
- package/dist/extensions/mega-events/recall-tail.js +59 -0
- package/dist/extensions/mega-events/session-handlers.js +15 -8
- package/dist/extensions/mega-runtime/reset-runtime.js +6 -0
- package/dist/extensions/mega-runtime/runtime.js +7 -0
- package/dist/src/embedder.js +41 -2
- package/dist/src/memoryStats.js +75 -0
- package/dist/src/prefix-break.js +43 -0
- package/dist/src/pricing.js +1 -1
- package/dist/src/store/sqlite/perf-samples.js +144 -16
- package/dist/src/store/turns/memory-store.js +8 -0
- package/dist/src/store/turns/sqlite-store.js +14 -3
- package/dist/src/store/turns/types.js +18 -1
- package/dist/src/store/vectorIndex.js +26 -5
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-BoL7qBOJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-BoL7qBOJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/AchievementsTab-BFDE3HYc.js +2 -0
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-BFDE3HYc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-DDFE-ckA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-DDFE-ckA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-B6UxZ7PM.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-B6UxZ7PM.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js → GameTab-DehUX-KE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-DehUX-KE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-0GWRt4wn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-0GWRt4wn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-C3rwMVsN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-C3rwMVsN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-39O9_x5j.js +2 -0
- package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-39O9_x5j.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-DXDTCi3r.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-DXDTCi3r.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BAw972BV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BAw972BV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-Cf5mGIdl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-Cf5mGIdl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{index-BX0bcgLu.js → index-4gQ7auad.js} +10 -10
- package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-DNgMuyP6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-DNgMuyP6.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +4 -0
- package/extensions/dashboard-client/src/api/client.ts +14 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
- package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +1 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +355 -0
- package/extensions/dashboard-client/tsconfig.json +3 -2
- package/extensions/dashboard-client/vite.config.ts +2 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +36 -3
- package/extensions/dashboard-server/api-contracts/index.ts +7 -0
- package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
- package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
- package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
- package/extensions/dashboard-server/api-contracts/setup.ts +58 -0
- package/extensions/dashboard-server/index-reader.ts +138 -121
- package/extensions/dashboard-server/routes-cache.ts +161 -85
- package/extensions/dashboard-server/routes-memory.ts +63 -0
- package/extensions/dashboard-server/routes-repo.ts +36 -36
- package/extensions/dashboard-server/routes-setup.ts +181 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +6 -0
- package/extensions/mega-commands.ts +211 -1
- package/extensions/mega-config.ts +18 -0
- package/extensions/mega-events/agent-handlers.ts +44 -5
- package/extensions/mega-events/compact-handlers.ts +1 -0
- package/extensions/mega-events/context-handler.ts +45 -110
- package/extensions/mega-events/context-hwm.ts +85 -0
- package/extensions/mega-events/error-classifier.ts +156 -124
- package/extensions/mega-events/mirror-append.ts +155 -0
- package/extensions/mega-events/outage-advisor.ts +79 -0
- package/extensions/mega-events/perf-handler.ts +79 -5
- package/extensions/mega-events/recall-tail.ts +88 -0
- package/extensions/mega-events/session-handlers.ts +14 -7
- package/extensions/mega-runtime/helpers.ts +14 -0
- package/extensions/mega-runtime/reset-runtime.ts +6 -0
- package/extensions/mega-runtime/runtime.ts +7 -0
- package/package.json +5 -2
- package/src/embedder.ts +42 -2
- package/src/memoryStats.ts +107 -0
- package/src/prefix-break.ts +83 -0
- package/src/pricing.ts +2 -2
- package/src/store/sqlite/perf-samples.ts +215 -22
- package/src/store/turns/memory-store.ts +10 -1
- package/src/store/turns/sqlite-store.ts +27 -15
- package/src/store/turns/types.ts +21 -0
- package/src/store/vectorIndex.ts +33 -4
- package/dist/extensions/conflict-scan.test.js +0 -115
- package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
- package/dist/extensions/dashboard-server/html.test.js +0 -52
- package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
- package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
- package/dist/extensions/dashboard-server/server.test.js +0 -120
- package/dist/extensions/dashboard-server-s32.test.js +0 -181
- package/dist/extensions/dashboard-server.test.js +0 -339
- package/dist/extensions/mega-cache-replay.test.js +0 -400
- package/dist/extensions/mega-compact-s38.test.js +0 -820
- package/dist/extensions/mega-compact.test.js +0 -1112
- package/dist/extensions/mega-events.test.js +0 -47
- package/dist/extensions/mega-game-cmds.test.js +0 -163
- package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
- package/dist/extensions/mega-runtime/state.test.js +0 -266
- package/dist/extensions/mega-runtime/widget.test.js +0 -343
- package/dist/extensions/mega-shutdown-widget.test.js +0 -121
- package/dist/extensions/mega-teamrun.test.js +0 -156
- package/dist/extensions/mega-trim.test.js +0 -58
- package/dist/extensions/mega-turn-store.test.js +0 -68
- package/dist/src/boundary.test.js +0 -170
- package/dist/src/compact.test.js +0 -78
- package/dist/src/config/themes.test.js +0 -94
- package/dist/src/dedup/dedup.test.js +0 -41
- package/dist/src/dedup/l1.test.js +0 -50
- package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
- package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
- package/dist/src/dedup/raptor/multilevel.test.js +0 -238
- package/dist/src/dedup/raptor/promote.test.js +0 -69
- package/dist/src/dedup/raptor/raptor.test.js +0 -248
- package/dist/src/dedup/raptor/retrieval.test.js +0 -95
- package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
- package/dist/src/dedup/sprint12.test.js +0 -219
- package/dist/src/dedup-engine.test.js +0 -472
- package/dist/src/driftDetection.test.js +0 -87
- package/dist/src/e2e.test.js +0 -698
- package/dist/src/engine.test.js +0 -111
- package/dist/src/extractive.test.js +0 -147
- package/dist/src/fork.test.js +0 -81
- package/dist/src/game/scoring.test.js +0 -98
- package/dist/src/httpEmbedder.test.js +0 -277
- package/dist/src/importance.test.js +0 -372
- package/dist/src/intent.test.js +0 -78
- package/dist/src/log.test.js +0 -42
- package/dist/src/mechanical-fix.test.js +0 -65
- package/dist/src/memory.test.js +0 -70
- package/dist/src/memoryConsolidate.test.js +0 -38
- package/dist/src/memoryOps.test.js +0 -129
- package/dist/src/memoryRecall.test.js +0 -171
- package/dist/src/memoryRoundtrip.test.js +0 -137
- package/dist/src/metrics/turns.test.js +0 -152
- package/dist/src/mirror/mirror.test.js +0 -185
- package/dist/src/raptor-inject-summaries.test.js +0 -162
- package/dist/src/ratio.bench.test.js +0 -897
- package/dist/src/recall.integration.test.js +0 -77
- package/dist/src/recall.test.js +0 -379
- package/dist/src/sprint14.test.js +0 -219
- package/dist/src/sprint4x-rag-verification.test.js +0 -93
- package/dist/src/store/compression.test.js +0 -139
- package/dist/src/store/memoryIndex.test.js +0 -51
- package/dist/src/store/migrate.test.js +0 -139
- package/dist/src/store/pgOpenGuard.test.js +0 -74
- package/dist/src/store/phase01.test.js +0 -81
- package/dist/src/store/phase04.test.js +0 -54
- package/dist/src/store/sprint10.test.js +0 -186
- package/dist/src/store/sqlite/game-achievements.test.js +0 -67
- package/dist/src/store/sqlite/game-scores.test.js +0 -106
- package/dist/src/store/sqlite/game-state.test.js +0 -76
- package/dist/src/store/sqlite/global-index.test.js +0 -136
- package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
- package/dist/src/store/sqlite/perf-samples.test.js +0 -146
- package/dist/src/store/sqlite/raptor.test.js +0 -106
- package/dist/src/store/sqlite/turns.test.js +0 -183
- package/dist/src/store/sqlite.cachehit.test.js +0 -55
- package/dist/src/store/sqlite.dbmaint.test.js +0 -158
- package/dist/src/store/sqlite.dbmirror.test.js +0 -184
- package/dist/src/store/turns/contract-compliance.test.js +0 -428
- package/dist/src/store/turns/memory-store.test.js +0 -9
- package/dist/src/store/turns/migrations.test.js +0 -138
- package/dist/src/store/turns/sqlite-store.test.js +0 -144
- package/dist/src/store/vectorIndex.test.js +0 -123
- package/dist/src/store.test.js +0 -161
- package/dist/src/supersede.test.js +0 -36
- package/dist/src/topics/cluster.test.js +0 -150
- package/dist/src/topics/store.test.js +0 -117
- package/dist/src/types.test.js +0 -9
- package/dist/src/vector-search-cache.test.js +0 -157
- package/dist/src/vectorStore.test.js +0 -479
- package/dist/src/wiki.test.js +0 -171
- package/extensions/conflict-scan.test.ts +0 -129
- package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
- package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
- package/extensions/dashboard-server/html.test.ts +0 -62
- package/extensions/dashboard-server/perf-server.test.ts +0 -101
- package/extensions/dashboard-server/routes-cache.test.ts +0 -302
- package/extensions/dashboard-server/server.test.ts +0 -131
- package/extensions/dashboard-server-s32.test.ts +0 -195
- package/extensions/dashboard-server.test.ts +0 -382
- package/extensions/mega-cache-replay.test.ts +0 -526
- package/extensions/mega-compact-s38.test.ts +0 -872
- package/extensions/mega-compact.test.ts +0 -1509
- package/extensions/mega-events.test.ts +0 -55
- package/extensions/mega-game-cmds.test.ts +0 -197
- package/extensions/mega-runtime/snapshot.test.ts +0 -139
- package/extensions/mega-runtime/state.test.ts +0 -262
- package/extensions/mega-runtime/widget.test.ts +0 -468
- package/extensions/mega-shutdown-widget.test.ts +0 -141
- package/extensions/mega-teamrun.test.ts +0 -176
- package/extensions/mega-trim.test.ts +0 -64
- package/extensions/mega-turn-store.test.ts +0 -108
- package/src/boundary.test.ts +0 -187
- package/src/compact.test.ts +0 -99
- package/src/config/themes.test.ts +0 -116
- package/src/dedup/dedup.test.ts +0 -46
- package/src/dedup/l1.test.ts +0 -57
- package/src/dedup/raptor/buildHistory.test.ts +0 -353
- package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
- package/src/dedup/raptor/multilevel.test.ts +0 -325
- package/src/dedup/raptor/promote.test.ts +0 -82
- package/src/dedup/raptor/raptor.test.ts +0 -297
- package/src/dedup/raptor/retrieval.test.ts +0 -118
- package/src/dedup/raptor/serve-gate.test.ts +0 -348
- package/src/dedup/sprint12.test.ts +0 -242
- package/src/dedup-engine.test.ts +0 -670
- package/src/driftDetection.test.ts +0 -100
- package/src/e2e.test.ts +0 -843
- package/src/engine.test.ts +0 -123
- package/src/extractive.test.ts +0 -174
- package/src/fork.test.ts +0 -94
- package/src/game/scoring.test.ts +0 -103
- package/src/httpEmbedder.test.ts +0 -286
- package/src/importance.test.ts +0 -538
- package/src/intent.test.ts +0 -87
- package/src/log.test.ts +0 -47
- package/src/mechanical-fix.test.ts +0 -70
- package/src/memory.test.ts +0 -92
- package/src/memoryConsolidate.test.ts +0 -47
- package/src/memoryOps.test.ts +0 -148
- package/src/memoryRecall.test.ts +0 -194
- package/src/memoryRoundtrip.test.ts +0 -155
- package/src/metrics/turns.test.ts +0 -165
- package/src/mirror/mirror.test.ts +0 -240
- package/src/raptor-inject-summaries.test.ts +0 -228
- package/src/ratio.bench.test.ts +0 -1316
- package/src/recall.integration.test.ts +0 -96
- package/src/recall.test.ts +0 -467
- package/src/sprint14.test.ts +0 -245
- package/src/sprint4x-rag-verification.test.ts +0 -119
- package/src/store/compression.test.ts +0 -168
- package/src/store/memoryIndex.test.ts +0 -61
- package/src/store/migrate.test.ts +0 -158
- package/src/store/pgOpenGuard.test.ts +0 -89
- package/src/store/phase01.test.ts +0 -88
- package/src/store/phase04.test.ts +0 -58
- package/src/store/sprint10.test.ts +0 -214
- package/src/store/sqlite/game-achievements.test.ts +0 -80
- package/src/store/sqlite/game-scores.test.ts +0 -132
- package/src/store/sqlite/game-state.test.ts +0 -89
- package/src/store/sqlite/global-index.test.ts +0 -222
- package/src/store/sqlite/mechanical-fix.test.ts +0 -162
- package/src/store/sqlite/perf-samples.test.ts +0 -169
- package/src/store/sqlite/raptor.test.ts +0 -139
- package/src/store/sqlite/turns.test.ts +0 -218
- package/src/store/sqlite.cachehit.test.ts +0 -68
- package/src/store/sqlite.dbmaint.test.ts +0 -193
- package/src/store/sqlite.dbmirror.test.ts +0 -229
- package/src/store/turns/contract-compliance.test.ts +0 -562
- package/src/store/turns/memory-store.test.ts +0 -15
- package/src/store/turns/migrations.test.ts +0 -161
- package/src/store/turns/sqlite-store.test.ts +0 -161
- package/src/store/vectorIndex.test.ts +0 -140
- package/src/store.test.ts +0 -191
- package/src/supersede.test.ts +0 -42
- package/src/topics/cluster.test.ts +0 -176
- package/src/topics/store.test.ts +0 -132
- package/src/types.test.ts +0 -10
- package/src/vector-search-cache.test.ts +0 -190
- package/src/vectorStore.test.ts +0 -533
- package/src/wiki.test.ts +0 -217
package/src/e2e.test.ts
DELETED
|
@@ -1,843 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* e2e.test.ts — comprehensive end-to-end pipeline tests.
|
|
3
|
-
*
|
|
4
|
-
* Exercises the full compaction → storage → dedup → recall pipeline across
|
|
5
|
-
* 12 scenarios. Each test is self-contained with its own temp store.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { test } from "node:test";
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
import { VectorStore, computeRegionHash, vectorList, vectorSemDedup, vectorWasInjected, vectorMarkInjected, vectorTopSimilar, vectorStats, vectorSearch } from "./vectorStore.js";
|
|
14
|
-
import { compactSession, recall, supersededCount } from "./engine.js";
|
|
15
|
-
import { loadDedupConfig, type DedupConfigShape } from "./config/dedup.js";
|
|
16
|
-
import { defaultEmbedder } from "./embedder.js";
|
|
17
|
-
import { decompressSmart } from "./store.js";
|
|
18
|
-
import {
|
|
19
|
-
upsertCheckpoint,
|
|
20
|
-
closeStore,
|
|
21
|
-
} from "./store/sqlite.js";
|
|
22
|
-
import type { EngineMessage } from "./types.js";
|
|
23
|
-
import type { StoredCheckpoint } from "./store.js";
|
|
24
|
-
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Temp dir management — each store() gets its own isolated state dir.
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
const baseTmp = mkdtempSync(join(tmpdir(), "mc-e2e-"));
|
|
30
|
-
let counter = 0;
|
|
31
|
-
|
|
32
|
-
function storeDir(): string {
|
|
33
|
-
return join(baseTmp, `run-${counter++}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function store(over: Partial<DedupConfigShape> = {}): VectorStore {
|
|
37
|
-
const dir = storeDir();
|
|
38
|
-
const config: DedupConfigShape = { ...loadDedupConfig(), ...over };
|
|
39
|
-
return new VectorStore({ stateDir: dir, config });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function msg(role: EngineMessage["role"], text: string, toolName?: string, input?: string, output?: string): EngineMessage {
|
|
43
|
-
return toolName
|
|
44
|
-
? { role, text, toolName, input: input ?? text, output: output ?? text }
|
|
45
|
-
: { role, text };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Seed a checkpoint directly into SQLite (bypasses online dedup tiers). */
|
|
49
|
-
function seedDirect(dir: string, sessionId: string, rows: { id: string; text: string; tok: number; ts?: number }[]): void {
|
|
50
|
-
const e = defaultEmbedder();
|
|
51
|
-
for (const r of rows) {
|
|
52
|
-
const cp: StoredCheckpoint = {
|
|
53
|
-
checkpointId: r.id,
|
|
54
|
-
sessionId,
|
|
55
|
-
summary: r.text,
|
|
56
|
-
keyDecisions: [],
|
|
57
|
-
nextSteps: [],
|
|
58
|
-
filesModified: [],
|
|
59
|
-
tokenEstimate: r.tok,
|
|
60
|
-
regionHash: computeRegionHash(r.text),
|
|
61
|
-
embedding: e.embed(r.text),
|
|
62
|
-
timestamp: r.ts ?? 1,
|
|
63
|
-
};
|
|
64
|
-
upsertCheckpoint(cp, dir);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
// 1. Full Compaction Pipeline (SUPERSEDE → COLLAPSE → CLUSTER)
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
|
-
|
|
72
|
-
test("1. Full compaction pipeline: SUPERSEDE → COLLAPSE → CLUSTER", () => {
|
|
73
|
-
const s = store();
|
|
74
|
-
const SESS = "sess_full_pipeline";
|
|
75
|
-
|
|
76
|
-
// Build a realistic 20+ message conversation with file reads, edits,
|
|
77
|
-
// user questions, and assistant responses with tool calls.
|
|
78
|
-
const messages: EngineMessage[] = [
|
|
79
|
-
msg("user", "read src/server.ts to understand the current setup"),
|
|
80
|
-
msg("assistant", "Reading src/server.ts", "Read", "src/server.ts", "const server = createServer(...)"),
|
|
81
|
-
msg("user", "the server has a memory leak, let's fix it"),
|
|
82
|
-
msg("assistant", "I see the leak in src/server.ts:42 — the event listeners are not cleaned up", "Edit"),
|
|
83
|
-
msg("user", "edit src/server.ts to remove the listeners on cleanup"),
|
|
84
|
-
msg("assistant", "Edited src/server.ts:42 — added cleanup() to remove all listeners", "Edit"),
|
|
85
|
-
msg("user", "now read src/router.ts"),
|
|
86
|
-
msg("assistant", "Reading src/router.ts", "Read", "src/router.ts", "export const router = new Map()"),
|
|
87
|
-
msg("user", "the router is missing the /health endpoint"),
|
|
88
|
-
msg("assistant", "I'll add a /health endpoint to src/router.ts", "Edit"),
|
|
89
|
-
msg("user", "also read src/middleware.ts for the auth check"),
|
|
90
|
-
msg("assistant", "Reading src/middleware.ts", "Read", "src/middleware.ts", "function authMiddleware(req, res, next) {...}"),
|
|
91
|
-
msg("user", "the auth middleware should use JWT instead of session cookies"),
|
|
92
|
-
msg("assistant", "Refactoring src/middleware.ts to use JWT verification", "Edit"),
|
|
93
|
-
msg("user", "add tests for the new JWT auth in src/auth.test.ts"),
|
|
94
|
-
msg("assistant", "Created src/auth.test.ts with 5 test cases for JWT validation", "Edit"),
|
|
95
|
-
msg("user", "run the tests to make sure everything passes"),
|
|
96
|
-
msg("assistant", "Running npm test", "Bash", "npm test", "All 5 auth tests passed"),
|
|
97
|
-
msg("user", "great, now let's deploy this"),
|
|
98
|
-
msg("assistant", "Deploying to staging environment", "Bash", "npm run deploy", "Deployed to staging"),
|
|
99
|
-
msg("user", "check the staging logs for any errors"),
|
|
100
|
-
msg("assistant", "Checking staging logs", "Bash", "kubectl logs", "No errors detected"),
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
// Compact the older portion (keep last 4 messages verbatim).
|
|
104
|
-
const r = compactSession({ sessionId: SESS, messages, keepFrom: 18, timestamp: 100 }, s);
|
|
105
|
-
|
|
106
|
-
// Verify: not skipped
|
|
107
|
-
assert.equal(r.skipped, false, "compaction should not be skipped");
|
|
108
|
-
|
|
109
|
-
// Verify: summary is non-empty
|
|
110
|
-
assert.ok(r.summary.length > 0, "summary should be produced by COLLAPSE");
|
|
111
|
-
|
|
112
|
-
// Verify: regionHash is computed
|
|
113
|
-
assert.ok(r.regionHash.length > 0, "regionHash should be computed");
|
|
114
|
-
assert.match(r.regionHash, /^[0-9a-f]{16}$/, "regionHash is 16-hex SHA-256 prefix");
|
|
115
|
-
|
|
116
|
-
// Verify: SUPERSEDE dropped obsolete file reads (the first reads of
|
|
117
|
-
// server.ts, router.ts, middleware.ts are superseded by later edits)
|
|
118
|
-
const compactable = messages.slice(0, 18);
|
|
119
|
-
const superseded = supersededCount(compactable);
|
|
120
|
-
assert.ok(superseded >= 1, `at least 1 superseded file read, got ${superseded}`);
|
|
121
|
-
|
|
122
|
-
// Verify: checkpoint persisted
|
|
123
|
-
assert.ok(r.checkpointId, "checkpointId should be set");
|
|
124
|
-
assert.match(r.checkpointId!, /^chkpt_001$/);
|
|
125
|
-
|
|
126
|
-
// Verify: checkpoint is searchable via vectorSearch(store, )
|
|
127
|
-
const hits = vectorSearch(s, SESS, "server.ts memory leak JWT auth", 5);
|
|
128
|
-
assert.ok(hits.length > 0, "checkpoint should be searchable");
|
|
129
|
-
assert.equal(hits[0].checkpoint.checkpointId, r.checkpointId);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
// 2. Multi-Session Dedup (L0 exact hash)
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
|
-
|
|
136
|
-
test("2. Multi-session dedup: identical content in same session detected by L0", () => {
|
|
137
|
-
const s = store();
|
|
138
|
-
|
|
139
|
-
// First compaction — stores a checkpoint
|
|
140
|
-
const messagesA: EngineMessage[] = [
|
|
141
|
-
msg("user", "read src/database.ts and fix the connection pooling"),
|
|
142
|
-
msg("assistant", "Fixed connection pool in src/database.ts", "Edit"),
|
|
143
|
-
msg("user", "add a retry mechanism for failed queries"),
|
|
144
|
-
msg("assistant", "Added retry logic in src/database.ts:85", "Edit"),
|
|
145
|
-
];
|
|
146
|
-
|
|
147
|
-
const rA = compactSession({ sessionId: "sess_multi_a", messages: messagesA, keepFrom: 4, timestamp: 1 }, s);
|
|
148
|
-
assert.equal(rA.deduped, false, "first compaction should not be deduped");
|
|
149
|
-
assert.ok(rA.checkpointId);
|
|
150
|
-
|
|
151
|
-
// Same session, identical content — L0 exact hash should detect the duplicate
|
|
152
|
-
const messagesB: EngineMessage[] = [
|
|
153
|
-
msg("user", "read src/database.ts and fix the connection pooling"),
|
|
154
|
-
msg("assistant", "Fixed connection pool in src/database.ts", "Edit"),
|
|
155
|
-
msg("user", "add a retry mechanism for failed queries"),
|
|
156
|
-
msg("assistant", "Added retry logic in src/database.ts:85", "Edit"),
|
|
157
|
-
];
|
|
158
|
-
|
|
159
|
-
const rB = compactSession({ sessionId: "sess_multi_a", messages: messagesB, keepFrom: 4, timestamp: 2 }, s);
|
|
160
|
-
|
|
161
|
-
// L0 exact hash dedup should catch this — same regionText → same regionHash
|
|
162
|
-
assert.equal(rB.deduped, true, "second identical compaction should be deduped by L0");
|
|
163
|
-
assert.ok(rB.dedupReason === "regionHash" || rB.dedupReason === "contentHash",
|
|
164
|
-
`dedup reason should be L0 (regionHash or contentHash), got ${rB.dedupReason}`);
|
|
165
|
-
|
|
166
|
-
// Search should still return the checkpoint
|
|
167
|
-
const hits = vectorSearch(s, "sess_multi_a", "database connection pooling", 5);
|
|
168
|
-
assert.ok(hits.length > 0, "search returns the deduped result");
|
|
169
|
-
assert.equal(hits[0].checkpoint.checkpointId, rA.checkpointId);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// ---------------------------------------------------------------------------
|
|
173
|
-
// 3. Near-Duplicate Detection (L1 MinHash/LSH)
|
|
174
|
-
// ---------------------------------------------------------------------------
|
|
175
|
-
|
|
176
|
-
test("3. Near-duplicate detection: L1 MinHash/LSH catches one-word edits that L0 misses", () => {
|
|
177
|
-
// Disable L2 so we isolate L1 behavior
|
|
178
|
-
const s = store({ L2_ENABLED: false });
|
|
179
|
-
const SESS = "sess_l1_e2e";
|
|
180
|
-
|
|
181
|
-
// First conversation
|
|
182
|
-
const r1 = s.add({
|
|
183
|
-
sessionId: SESS,
|
|
184
|
-
summary: "user reviewed the authentication module and merged the pull request",
|
|
185
|
-
regionText: "user reviewed the authentication module and merged the pull request on github after ci passed",
|
|
186
|
-
timestamp: 1,
|
|
187
|
-
});
|
|
188
|
-
assert.equal(r1.deduped, false);
|
|
189
|
-
|
|
190
|
-
// Near-duplicate: a few word changes that L0 exact hash misses
|
|
191
|
-
const r2 = s.add({
|
|
192
|
-
sessionId: SESS,
|
|
193
|
-
summary: "user reviewed the authentication module and merged the pull request",
|
|
194
|
-
regionText: "user reviewed the authentication module and merged the pull requests on github after ci passed",
|
|
195
|
-
timestamp: 2,
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
// L1 should catch the near-dup
|
|
199
|
-
assert.equal(r2.deduped, true, "L1 should catch the near-duplicate");
|
|
200
|
-
assert.equal(r2.reason, "l1MinHash", "dedup reason should be l1MinHash");
|
|
201
|
-
assert.equal(vectorList(s,SESS).length, 1, "only one checkpoint stored");
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("3b. Negative: L1 does NOT collapse genuinely different content", () => {
|
|
205
|
-
const s = store({ L2_ENABLED: false });
|
|
206
|
-
const SESS = "sess_l1_neg";
|
|
207
|
-
|
|
208
|
-
s.add({
|
|
209
|
-
sessionId: SESS,
|
|
210
|
-
summary: "database migration",
|
|
211
|
-
regionText: "the database migration added three new indexes to the users table for faster lookups",
|
|
212
|
-
timestamp: 1,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const r2 = s.add({
|
|
216
|
-
sessionId: SESS,
|
|
217
|
-
summary: "frontend dark mode",
|
|
218
|
-
regionText: "the frontend added a dark mode toggle with css custom properties for theming",
|
|
219
|
-
timestamp: 2,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
assert.equal(r2.deduped, false, "distinct content should not be deduped");
|
|
223
|
-
assert.equal(vectorList(s,SESS).length, 2, "both checkpoints stored");
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// ---------------------------------------------------------------------------
|
|
227
|
-
// 4. Semantic Dedup (L2 cosine)
|
|
228
|
-
// ---------------------------------------------------------------------------
|
|
229
|
-
|
|
230
|
-
test("4. Semantic dedup: L2 cosine catches highly similar content that L0/L1 miss", () => {
|
|
231
|
-
const s = store();
|
|
232
|
-
const SESS = "sess_l2_e2e";
|
|
233
|
-
|
|
234
|
-
// First conversation about authentication and session tokens
|
|
235
|
-
const r1 = s.add({
|
|
236
|
-
sessionId: SESS,
|
|
237
|
-
summary: "user authentication and session token management",
|
|
238
|
-
regionText: "user authentication and session token management login validation session expiry handling secure cookie management",
|
|
239
|
-
timestamp: 1,
|
|
240
|
-
});
|
|
241
|
-
assert.equal(r1.deduped, false);
|
|
242
|
-
|
|
243
|
-
// Second conversation — nearly identical with a few word swaps
|
|
244
|
-
// L0 won't catch (different text), L1 might not catch (too many word changes)
|
|
245
|
-
// L2 cosine on trigram embeddings should catch this high-similarity paraphrase
|
|
246
|
-
const r2 = s.add({
|
|
247
|
-
sessionId: SESS,
|
|
248
|
-
summary: "user authentication and session token management login validation",
|
|
249
|
-
regionText: "user authentication and session token management login validation session expiry handling secure cookie configuration",
|
|
250
|
-
timestamp: 2,
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
// L2 semantic cosine should catch this high-similarity paraphrase
|
|
254
|
-
assert.equal(r2.deduped, true, "L2 should catch the high-similarity paraphrase");
|
|
255
|
-
assert.ok(r2.reason === "contentSimilarity" || r2.reason === "l1MinHash",
|
|
256
|
-
`dedup reason should be L2 contentSimilarity or L1 l1MinHash, got ${r2.reason}`);
|
|
257
|
-
assert.equal(vectorList(s,SESS).length, 1, "only one checkpoint after semantic dedup");
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test("4b. MMR diversifies search results", () => {
|
|
261
|
-
const s = store();
|
|
262
|
-
const SESS = "sess_mmr_e2e";
|
|
263
|
-
|
|
264
|
-
// Store several checkpoints — some near-identical, some distinct.
|
|
265
|
-
// Use sufficiently different text to avoid L1/L2 dedup collapse.
|
|
266
|
-
const regions = [
|
|
267
|
-
"the parser handles tokenization of source code files with lexical analysis",
|
|
268
|
-
"the database uses a b-tree index for fast lookups on the users table",
|
|
269
|
-
"the frontend renders a virtualized list for large datasets with lazy loading",
|
|
270
|
-
"the api gateway implements rate limiting with a token bucket throttling algorithm",
|
|
271
|
-
];
|
|
272
|
-
|
|
273
|
-
for (let i = 0; i < regions.length; i++) {
|
|
274
|
-
s.add({
|
|
275
|
-
sessionId: SESS,
|
|
276
|
-
summary: `topic_${i}`,
|
|
277
|
-
regionText: regions[i],
|
|
278
|
-
timestamp: i + 1,
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Search for parser-related content — should return relevant results
|
|
283
|
-
const hits = vectorSearch(s, SESS, "parser tokenization source code files", 4);
|
|
284
|
-
assert.ok(hits.length >= 1, "should return at least one result");
|
|
285
|
-
|
|
286
|
-
// The top hit should be the parser checkpoint
|
|
287
|
-
assert.ok(hits[0].checkpoint.summary.includes("topic_0"), "top hit is the parser topic");
|
|
288
|
-
|
|
289
|
-
// MMR should provide diversity — not all results should be near-identical
|
|
290
|
-
// (with 4 distinct topics, we should get variety in the results)
|
|
291
|
-
const summaries = hits.map((h) => h.checkpoint.summary);
|
|
292
|
-
const uniqueSummaries = new Set(summaries);
|
|
293
|
-
assert.ok(uniqueSummaries.size >= 2, "MMR provides diverse results");
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
// ---------------------------------------------------------------------------
|
|
297
|
-
// 5. SemDeDup Offline Cleanup
|
|
298
|
-
// ---------------------------------------------------------------------------
|
|
299
|
-
|
|
300
|
-
test("5. SemDeDup offline cleanup: redundant rows marked removed, not deleted", () => {
|
|
301
|
-
const dir = storeDir();
|
|
302
|
-
const s = new VectorStore({ stateDir: dir, config: { ...loadDedupConfig() } });
|
|
303
|
-
const SESS = "sess_semdedup";
|
|
304
|
-
|
|
305
|
-
// Seed multiple checkpoints with varying similarity directly into SQLite
|
|
306
|
-
// to bypass online dedup (SemDeDup's real job is offline cleanup)
|
|
307
|
-
seedDirect(dir, SESS, [
|
|
308
|
-
{ id: "chkpt_001", text: "the cache stores parsed ast nodes for fast lookup and retrieval", tok: 100, ts: 1 },
|
|
309
|
-
{ id: "chkpt_002", text: "the cache stores parsed ast nodes for fast lookup and retrieval and reuse", tok: 900, ts: 2 },
|
|
310
|
-
{ id: "chkpt_003", text: "the frontend uses a virtualized list for rendering large datasets efficiently", tok: 500, ts: 3 },
|
|
311
|
-
]);
|
|
312
|
-
|
|
313
|
-
// Run SemDeDup with threshold that catches the near-identical pair
|
|
314
|
-
const removed = vectorSemDedup(s,SESS, 0.85);
|
|
315
|
-
assert.equal(removed, 1, "one redundant row should be marked removed");
|
|
316
|
-
|
|
317
|
-
// Verify: the lower-tokenEstimate row is the one removed
|
|
318
|
-
const all = vectorList(s,SESS);
|
|
319
|
-
const dropped = all.find((c) => c.dedupStatus === "removed");
|
|
320
|
-
assert.ok(dropped, "a row should have dedup_status='removed'");
|
|
321
|
-
assert.equal(dropped!.checkpointId, "chkpt_001", "lower tokenEstimate row removed");
|
|
322
|
-
assert.equal(dropped!.dedupStatus, "removed");
|
|
323
|
-
|
|
324
|
-
// Verify: search excludes removed rows (3 total, 1 removed → 2 active)
|
|
325
|
-
const hits = vectorSearch(s, SESS, "cache parsed ast nodes frontend virtualized list", 10);
|
|
326
|
-
assert.equal(hits.length, 2, "search excludes the removed row, returns 2 active");
|
|
327
|
-
assert.ok(hits.every((h) => h.checkpoint.dedupStatus !== "removed"), "no removed rows in search");
|
|
328
|
-
|
|
329
|
-
// Verify: idempotent re-run removes nothing new
|
|
330
|
-
const secondRun = vectorSemDedup(s,SESS, 0.85);
|
|
331
|
-
assert.equal(secondRun, 0, "idempotent re-run removes nothing new");
|
|
332
|
-
|
|
333
|
-
closeStore(dir);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// ---------------------------------------------------------------------------
|
|
337
|
-
// 6. Recall + Inline with Dedup Sentinel
|
|
338
|
-
// ---------------------------------------------------------------------------
|
|
339
|
-
|
|
340
|
-
test("6. Recall + inline with dedup sentinel: injected checkpoints are skipped", () => {
|
|
341
|
-
const s = store();
|
|
342
|
-
const SESS = "sess_recall";
|
|
343
|
-
|
|
344
|
-
// Compact a session
|
|
345
|
-
const messages: EngineMessage[] = [
|
|
346
|
-
msg("user", "investigated src/vectorStore.ts to understand the dedup cascade"),
|
|
347
|
-
msg("assistant", "Found the L0, L1, L2 tiers in src/vectorStore.ts", "Read"),
|
|
348
|
-
msg("user", "now document the dedup pipeline in README.md"),
|
|
349
|
-
msg("assistant", "Updated README.md with full dedup documentation", "Edit"),
|
|
350
|
-
];
|
|
351
|
-
|
|
352
|
-
const r = compactSession({ sessionId: SESS, messages, keepFrom: 4, timestamp: 1 }, s);
|
|
353
|
-
assert.ok(r.checkpointId);
|
|
354
|
-
|
|
355
|
-
// Recall with a relevant query — should return the checkpoint
|
|
356
|
-
const first = recall({ sessionId: SESS, query: "vectorStore dedup cascade", limit: 5, skipInjected: true }, s);
|
|
357
|
-
assert.equal(first.newHits.length, 1, "first recall should find the checkpoint");
|
|
358
|
-
assert.equal(first.hits.length, 1);
|
|
359
|
-
|
|
360
|
-
// Mark it injected
|
|
361
|
-
const cpId = first.hits[0].checkpoint.checkpointId;
|
|
362
|
-
vectorMarkInjected(s,SESS, cpId);
|
|
363
|
-
|
|
364
|
-
// Recall again — should skip the injected checkpoint
|
|
365
|
-
const second = recall({ sessionId: SESS, query: "vectorStore dedup cascade", limit: 5, skipInjected: true }, s);
|
|
366
|
-
assert.equal(second.newHits.length, 0, "injected checkpoint should be skipped (dedup sentinel)");
|
|
367
|
-
|
|
368
|
-
// Without skipInjected, hits still surface
|
|
369
|
-
assert.equal(second.hits.length, 1, "hits still surface without skipInjected");
|
|
370
|
-
|
|
371
|
-
// Verify wasInjected
|
|
372
|
-
assert.equal(vectorWasInjected(s,SESS, cpId), true, "wasInjected returns true for injected checkpoint");
|
|
373
|
-
assert.equal(vectorWasInjected(s,SESS, "chkpt_999"), false, "wasInjected returns false for non-injected");
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
// ---------------------------------------------------------------------------
|
|
377
|
-
// 7. topSimilar
|
|
378
|
-
// ---------------------------------------------------------------------------
|
|
379
|
-
|
|
380
|
-
test("7. topSimilar: returns n most cosine-similar checkpoints", () => {
|
|
381
|
-
const s = store();
|
|
382
|
-
const SESS = "sess_topsim";
|
|
383
|
-
|
|
384
|
-
// Store several checkpoints with varying topics
|
|
385
|
-
const regions = [
|
|
386
|
-
"the compiler optimized the hot loop with loop unrolling and inlining",
|
|
387
|
-
"the database added a covering index to speed up queries on the users table",
|
|
388
|
-
"the frontend introduced a virtualized list for large tables with lazy rendering",
|
|
389
|
-
"the api added rate limiting using a token bucket algorithm for throttling",
|
|
390
|
-
"the worker pool now backpressures when the queue is overloaded with tasks",
|
|
391
|
-
];
|
|
392
|
-
|
|
393
|
-
for (let i = 0; i < regions.length; i++) {
|
|
394
|
-
s.add({
|
|
395
|
-
sessionId: SESS,
|
|
396
|
-
summary: `topic_${i}`,
|
|
397
|
-
regionText: regions[i],
|
|
398
|
-
timestamp: i + 1,
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Call topSimilar(3)
|
|
403
|
-
const hits = vectorTopSimilar(s,SESS, 3);
|
|
404
|
-
assert.ok(hits.length <= 3, "should respect n limit");
|
|
405
|
-
assert.ok(hits.length > 0, "should return results");
|
|
406
|
-
|
|
407
|
-
// Verify self-exclusion: the most recent checkpoint should not be in results
|
|
408
|
-
const all = vectorList(s,SESS);
|
|
409
|
-
const ordered = [...all].sort((a, b) => a.checkpointId.localeCompare(b.checkpointId));
|
|
410
|
-
const current = ordered[ordered.length - 1];
|
|
411
|
-
assert.ok(!hits.some((h) => h.checkpoint.checkpointId === current.checkpointId), "current checkpoint excluded");
|
|
412
|
-
|
|
413
|
-
// Verify scores are descending
|
|
414
|
-
for (let i = 1; i < hits.length; i++) {
|
|
415
|
-
assert.ok(hits[i - 1].score >= hits[i].score, "scores should be descending");
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
test("7b. topSimilar respects n limit strictly", () => {
|
|
420
|
-
const s = store();
|
|
421
|
-
const SESS = "sess_topsim_limit";
|
|
422
|
-
|
|
423
|
-
// Use sufficiently distinct texts to avoid L1 dedup collapse
|
|
424
|
-
const regions = [
|
|
425
|
-
"the compiler optimizer unrolls loops and inlines function calls for speed",
|
|
426
|
-
"the database engine uses a covering b-tree index to accelerate lookups",
|
|
427
|
-
"the frontend framework virtualizes large lists with lazy rendering and recycling",
|
|
428
|
-
"the api gateway throttles requests using a token bucket rate limiting algorithm",
|
|
429
|
-
"the worker pool applies backpressure when the task queue exceeds capacity limits",
|
|
430
|
-
];
|
|
431
|
-
|
|
432
|
-
for (let i = 0; i < regions.length; i++) {
|
|
433
|
-
s.add({
|
|
434
|
-
sessionId: SESS,
|
|
435
|
-
summary: `c${i}`,
|
|
436
|
-
regionText: regions[i],
|
|
437
|
-
timestamp: i + 1,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const hits = vectorTopSimilar(s,SESS, 2);
|
|
442
|
-
assert.equal(hits.length, 2, "n limit respected");
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
test("7c. topSimilar returns empty for sessions with 0 or 1 checkpoints", () => {
|
|
446
|
-
const s = store();
|
|
447
|
-
assert.deepEqual(vectorTopSimilar(s,"sess_empty", 5), []);
|
|
448
|
-
s.add({ sessionId: "sess_one", summary: "solo", regionText: "only checkpoint here", timestamp: 1 });
|
|
449
|
-
assert.deepEqual(vectorTopSimilar(s,"sess_one", 5), []);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
// ---------------------------------------------------------------------------
|
|
453
|
-
// 8. Compression Round-Trip
|
|
454
|
-
// ---------------------------------------------------------------------------
|
|
455
|
-
|
|
456
|
-
test("8. Compression round-trip: decompression produces original content", () => {
|
|
457
|
-
const s = store();
|
|
458
|
-
const SESS = "sess_compress";
|
|
459
|
-
|
|
460
|
-
// Store a checkpoint with a realistic region text
|
|
461
|
-
const originalText = [
|
|
462
|
-
"user asked to read src/server.ts",
|
|
463
|
-
"assistant read src/server.ts and found a memory leak at line 42",
|
|
464
|
-
"user asked to fix the leak by removing unused event listeners",
|
|
465
|
-
"assistant edited src/server.ts to add cleanup() call in the shutdown handler",
|
|
466
|
-
"user asked to add tests for the cleanup logic",
|
|
467
|
-
"assistant created src/server.test.ts with three test cases",
|
|
468
|
-
].join("\n");
|
|
469
|
-
|
|
470
|
-
s.add({
|
|
471
|
-
sessionId: SESS,
|
|
472
|
-
summary: "fixed memory leak in server.ts and added tests",
|
|
473
|
-
regionText: originalText,
|
|
474
|
-
tokenEstimate: 500,
|
|
475
|
-
timestamp: 1,
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// Retrieve and verify decompression
|
|
479
|
-
const cp = vectorList(s,SESS)[0];
|
|
480
|
-
assert.ok(cp.compressedOriginal instanceof Buffer, "compressedOriginal is a Buffer");
|
|
481
|
-
|
|
482
|
-
const restored = decompressSmart(cp.compressedOriginal as Buffer).toString("utf-8");
|
|
483
|
-
assert.equal(restored, originalText, "decompression produces the original content");
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
test("8b. Compression round-trip with different content sizes", () => {
|
|
487
|
-
const s = store();
|
|
488
|
-
const SESS = "sess_compress_sizes";
|
|
489
|
-
|
|
490
|
-
// Small text (under 512 bytes → raw tier)
|
|
491
|
-
const small = "small region text about a minor fix";
|
|
492
|
-
s.add({ sessionId: SESS, summary: "small", regionText: small, timestamp: 1 });
|
|
493
|
-
|
|
494
|
-
// Medium text (512B–4KB → gzip level 1)
|
|
495
|
-
const medium = "medium region text with more detail. ".repeat(50);
|
|
496
|
-
s.add({ sessionId: SESS, summary: "medium", regionText: medium, timestamp: 2 });
|
|
497
|
-
|
|
498
|
-
// Large text (>4KB → gzip level 6 or brotli)
|
|
499
|
-
const large = "detailed region text with lots of context about the codebase. ".repeat(200);
|
|
500
|
-
s.add({ sessionId: SESS, summary: "large", regionText: large, timestamp: 3 });
|
|
501
|
-
|
|
502
|
-
const checkpoints = vectorList(s,SESS);
|
|
503
|
-
assert.equal(checkpoints.length, 3);
|
|
504
|
-
|
|
505
|
-
// Verify each round-trips correctly
|
|
506
|
-
const texts = [small, medium, large];
|
|
507
|
-
for (let i = 0; i < 3; i++) {
|
|
508
|
-
const cp = checkpoints[i];
|
|
509
|
-
assert.ok(cp.compressedOriginal instanceof Buffer);
|
|
510
|
-
const restored = decompressSmart(cp.compressedOriginal as Buffer).toString("utf-8");
|
|
511
|
-
assert.equal(restored, texts[i], `content ${i} round-trips correctly`);
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
// ---------------------------------------------------------------------------
|
|
516
|
-
// 9. Store Stats and Metrics
|
|
517
|
-
// ---------------------------------------------------------------------------
|
|
518
|
-
|
|
519
|
-
test("9. Store stats and metrics reflect actual state after compactions", () => {
|
|
520
|
-
const s = store();
|
|
521
|
-
const SESS = "sess_stats_e2e";
|
|
522
|
-
|
|
523
|
-
// Compact three different conversations
|
|
524
|
-
const conv1: EngineMessage[] = [
|
|
525
|
-
msg("user", "read src/index.ts and refactor the imports"),
|
|
526
|
-
msg("assistant", "Refactored imports in src/index.ts", "Edit"),
|
|
527
|
-
];
|
|
528
|
-
const r1 = compactSession({ sessionId: SESS, messages: conv1, keepFrom: 2, timestamp: 1 }, s);
|
|
529
|
-
assert.equal(r1.deduped, false);
|
|
530
|
-
|
|
531
|
-
const conv2: EngineMessage[] = [
|
|
532
|
-
msg("user", "fix the type errors in src/types.ts"),
|
|
533
|
-
msg("assistant", "Fixed type errors in src/types.ts", "Edit"),
|
|
534
|
-
];
|
|
535
|
-
const r2 = compactSession({ sessionId: SESS, messages: conv2, keepFrom: 2, timestamp: 2 }, s);
|
|
536
|
-
assert.equal(r2.deduped, false);
|
|
537
|
-
|
|
538
|
-
const conv3: EngineMessage[] = [
|
|
539
|
-
msg("user", "add unit tests for the new utility functions"),
|
|
540
|
-
msg("assistant", "Added tests in src/utils.test.ts", "Edit"),
|
|
541
|
-
];
|
|
542
|
-
const r3 = compactSession({ sessionId: SESS, messages: conv3, keepFrom: 2, timestamp: 3 }, s);
|
|
543
|
-
assert.equal(r3.deduped, false);
|
|
544
|
-
|
|
545
|
-
// Get stats
|
|
546
|
-
const st = vectorStats(s,SESS);
|
|
547
|
-
assert.equal(st.checkpointCount, 3, "three checkpoints stored");
|
|
548
|
-
assert.ok(st.totalTokenEstimate > 0, "totalTokenEstimate should be positive");
|
|
549
|
-
assert.equal(st.lastCheckpointId, "chkpt_003", "last checkpoint id correct");
|
|
550
|
-
assert.ok(st.lastSummary && st.lastSummary.length > 0, "last summary is non-empty");
|
|
551
|
-
assert.equal(st.injectedCount, 0, "no injections yet");
|
|
552
|
-
assert.equal(st.dedupHitRate, 0, "dedupHitRate is 0 with no injections");
|
|
553
|
-
|
|
554
|
-
// Mark one injected and re-check
|
|
555
|
-
vectorMarkInjected(s,SESS, "chkpt_001");
|
|
556
|
-
const st2 = vectorStats(s,SESS);
|
|
557
|
-
assert.equal(st2.injectedCount, 1, "one injection tracked");
|
|
558
|
-
assert.ok(Math.abs(st2.dedupHitRate - 1 / 3) < 1e-9, "dedupHitRate = injected/checkpoints");
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
test("9b. Stats on empty session returns zeros", () => {
|
|
562
|
-
const s = store();
|
|
563
|
-
const st = vectorStats(s,"sess_nothing");
|
|
564
|
-
assert.equal(st.checkpointCount, 0);
|
|
565
|
-
assert.equal(st.totalTokenEstimate, 0);
|
|
566
|
-
assert.equal(st.lastCheckpointId, undefined);
|
|
567
|
-
assert.equal(st.lastSummary, undefined);
|
|
568
|
-
assert.equal(st.dedupHitRate, 0);
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
// ---------------------------------------------------------------------------
|
|
572
|
-
// 10. Concurrent Sessions
|
|
573
|
-
// ---------------------------------------------------------------------------
|
|
574
|
-
|
|
575
|
-
test("10. Concurrent sessions: no cross-contamination", () => {
|
|
576
|
-
const s = store();
|
|
577
|
-
|
|
578
|
-
// Three different sessions with distinct content
|
|
579
|
-
const sessions = [
|
|
580
|
-
{ id: "sess_concurrent_a", msgs: [
|
|
581
|
-
msg("user", "work on the authentication module in src/auth.ts"),
|
|
582
|
-
msg("assistant", "Updated src/auth.ts with JWT validation", "Edit"),
|
|
583
|
-
]},
|
|
584
|
-
{ id: "sess_concurrent_b", msgs: [
|
|
585
|
-
msg("user", "optimize the database queries in src/db.ts"),
|
|
586
|
-
msg("assistant", "Added covering indexes in src/db.ts", "Edit"),
|
|
587
|
-
]},
|
|
588
|
-
{ id: "sess_concurrent_c", msgs: [
|
|
589
|
-
msg("user", "fix the rendering bug in src/canvas.ts"),
|
|
590
|
-
msg("assistant", "Fixed the canvas rendering loop in src/canvas.ts", "Edit"),
|
|
591
|
-
]},
|
|
592
|
-
];
|
|
593
|
-
|
|
594
|
-
// Compact all three "simultaneously" (sequentially but back-to-back)
|
|
595
|
-
const results = sessions.map((sess) =>
|
|
596
|
-
compactSession({ sessionId: sess.id, messages: sess.msgs, keepFrom: 2, timestamp: 1 }, s),
|
|
597
|
-
);
|
|
598
|
-
|
|
599
|
-
// Each session has its own checkpoint
|
|
600
|
-
results.forEach((r, i) => {
|
|
601
|
-
assert.equal(r.skipped, false, `session ${i} should compact`);
|
|
602
|
-
assert.equal(r.deduped, false, `session ${i} should not be deduped (distinct content)`);
|
|
603
|
-
assert.ok(r.checkpointId);
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
// Verify: each session has exactly one checkpoint
|
|
607
|
-
sessions.forEach((sess) => {
|
|
608
|
-
const cps = vectorList(s,sess.id);
|
|
609
|
-
assert.equal(cps.length, 1, `${sess.id} should have 1 checkpoint`);
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
// Verify: search in one session doesn't return another session's checkpoints
|
|
613
|
-
const hitsA = vectorSearch(s, "sess_concurrent_a", "authentication JWT", 5);
|
|
614
|
-
assert.ok(hitsA.every((h) => h.checkpoint.sessionId === "sess_concurrent_a"),
|
|
615
|
-
"search in A returns only A's checkpoints");
|
|
616
|
-
|
|
617
|
-
const hitsB = vectorSearch(s, "sess_concurrent_b", "database queries indexes", 5);
|
|
618
|
-
assert.ok(hitsB.every((h) => h.checkpoint.sessionId === "sess_concurrent_b"),
|
|
619
|
-
"search in B returns only B's checkpoints");
|
|
620
|
-
|
|
621
|
-
const hitsC = vectorSearch(s, "sess_concurrent_c", "canvas rendering bug", 5);
|
|
622
|
-
assert.ok(hitsC.every((h) => h.checkpoint.sessionId === "sess_concurrent_c"),
|
|
623
|
-
"search in C returns only C's checkpoints");
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
// ---------------------------------------------------------------------------
|
|
627
|
-
// 11. Edge Cases
|
|
628
|
-
// ---------------------------------------------------------------------------
|
|
629
|
-
|
|
630
|
-
test("11a. Empty session (no messages) — compactSession should skip", () => {
|
|
631
|
-
const s = store();
|
|
632
|
-
const r = compactSession({ sessionId: "sess_empty_msgs", messages: [], keepFrom: 0, timestamp: 1 }, s);
|
|
633
|
-
assert.equal(r.skipped, true, "empty session should be skipped");
|
|
634
|
-
assert.equal(r.summary, "");
|
|
635
|
-
assert.equal(r.regionHash, "");
|
|
636
|
-
assert.equal(vectorList(s,"sess_empty_msgs").length, 0);
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
test("11b. Single message session — should skip or handle gracefully", () => {
|
|
640
|
-
const s = store();
|
|
641
|
-
const r = compactSession({
|
|
642
|
-
sessionId: "sess_single_msg",
|
|
643
|
-
messages: [msg("user", "hello world")],
|
|
644
|
-
keepFrom: 0,
|
|
645
|
-
timestamp: 1,
|
|
646
|
-
}, s);
|
|
647
|
-
// With keepFrom=0, the single message is compactable, so it should work
|
|
648
|
-
// but produce a minimal summary
|
|
649
|
-
assert.ok(r.skipped === true || r.skipped === false, "should not throw");
|
|
650
|
-
if (!r.skipped) {
|
|
651
|
-
assert.ok(r.checkpointId);
|
|
652
|
-
}
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
test("11c. Very large region text — should still compact and store", () => {
|
|
656
|
-
const s = store();
|
|
657
|
-
const SESS = "sess_large";
|
|
658
|
-
|
|
659
|
-
// Build a large conversation with many messages
|
|
660
|
-
const messages: EngineMessage[] = [];
|
|
661
|
-
for (let i = 0; i < 50; i++) {
|
|
662
|
-
messages.push(msg("user", `read src/module_${i}.ts and review the implementation of feature ${i}`));
|
|
663
|
-
messages.push(msg("assistant", `Reviewed src/module_${i}.ts — feature ${i} looks good with minor issues`, "Read"));
|
|
664
|
-
messages.push(msg("user", `fix the issues in src/module_${i}.ts`));
|
|
665
|
-
messages.push(msg("assistant", `Fixed issues in src/module_${i}.ts`, "Edit"));
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
const r = compactSession({ sessionId: SESS, messages, keepFrom: 8, timestamp: 1 }, s);
|
|
669
|
-
assert.equal(r.skipped, false, "large conversation should compact");
|
|
670
|
-
assert.ok(r.checkpointId, "checkpoint created");
|
|
671
|
-
assert.ok(r.summary.length > 0, "summary produced");
|
|
672
|
-
|
|
673
|
-
// Verify it's searchable
|
|
674
|
-
const hits = vectorSearch(s, SESS, "module feature fix review", 3);
|
|
675
|
-
assert.ok(hits.length > 0, "large checkpoint is searchable");
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
test("11d. Unicode and emoji content — should normalize and hash correctly", () => {
|
|
679
|
-
const s = store();
|
|
680
|
-
const SESS = "sess_unicode";
|
|
681
|
-
|
|
682
|
-
const messages: EngineMessage[] = [
|
|
683
|
-
msg("user", "read src/本地化.ts and fix the 中文 translation issues 🌏"),
|
|
684
|
-
msg("assistant", "Fixed translations in src/本地化.ts — updated 中文 strings and emoji handling 🌏✅", "Edit"),
|
|
685
|
-
msg("user", "add support for 日本語 and 한국어 locales too"),
|
|
686
|
-
msg("assistant", "Added 日本語 and 한국어 locale support in src/本地化.ts 🌏✅🇯🇵🇰🇷", "Edit"),
|
|
687
|
-
];
|
|
688
|
-
|
|
689
|
-
const r = compactSession({ sessionId: SESS, messages, keepFrom: 4, timestamp: 1 }, s);
|
|
690
|
-
assert.equal(r.skipped, false, "unicode conversation should compact");
|
|
691
|
-
assert.ok(r.regionHash.length > 0, "regionHash computed for unicode content");
|
|
692
|
-
|
|
693
|
-
// Verify the checkpoint exists and is searchable
|
|
694
|
-
const hits = vectorSearch(s, SESS, "中文 translation 本地化", 3);
|
|
695
|
-
assert.ok(hits.length > 0, "unicode checkpoint is searchable");
|
|
696
|
-
|
|
697
|
-
// Verify regionHash is deterministic for the same unicode content
|
|
698
|
-
const r2 = compactSession({ sessionId: SESS, messages, keepFrom: 4, timestamp: 2 }, s);
|
|
699
|
-
assert.equal(r2.deduped, true, "identical unicode content should be deduped");
|
|
700
|
-
assert.equal(r.regionHash, r2.regionHash, "regionHash is deterministic for unicode");
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
test("11e. All messages in preserve-recent window — nothing to compact", () => {
|
|
704
|
-
const s = store();
|
|
705
|
-
const messages: EngineMessage[] = [
|
|
706
|
-
msg("user", "first message"),
|
|
707
|
-
msg("assistant", "first response", "Edit"),
|
|
708
|
-
msg("user", "second message"),
|
|
709
|
-
msg("assistant", "second response", "Edit"),
|
|
710
|
-
];
|
|
711
|
-
|
|
712
|
-
// keepFrom = 0 → compactable slice is empty (everything is "preserved")
|
|
713
|
-
const r = compactSession({
|
|
714
|
-
sessionId: "sess_all_preserved",
|
|
715
|
-
messages,
|
|
716
|
-
keepFrom: 0,
|
|
717
|
-
timestamp: 1,
|
|
718
|
-
}, s);
|
|
719
|
-
assert.equal(r.skipped, true, "should skip when keepFrom=0 (nothing to compact)");
|
|
720
|
-
assert.equal(vectorList(s,"sess_all_preserved").length, 0, "no checkpoints stored");
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
// ---------------------------------------------------------------------------
|
|
724
|
-
// 12. Feature Flag Toggling
|
|
725
|
-
// ---------------------------------------------------------------------------
|
|
726
|
-
|
|
727
|
-
test("12a. L0_ENABLED=false — L0 does not collapse exact dups", () => {
|
|
728
|
-
// Disable all tiers so no dedup happens at all
|
|
729
|
-
const s = store({ L0_ENABLED: false, L1_ENABLED: false, L2_ENABLED: false });
|
|
730
|
-
const SESS = "sess_l0_off";
|
|
731
|
-
|
|
732
|
-
// Use different regionText for each add to avoid the SQLite content_hash
|
|
733
|
-
// unique constraint (which fires regardless of L0 flag since the hash is
|
|
734
|
-
// always computed). When L0 is disabled, the dedup cascade skips the
|
|
735
|
-
// hash check, but the DB constraint is structural.
|
|
736
|
-
const r1 = s.add({
|
|
737
|
-
sessionId: SESS,
|
|
738
|
-
summary: "first checkpoint about the parser",
|
|
739
|
-
regionText: "the parser tokenizes the input into a stream of tokens for the compiler version one",
|
|
740
|
-
timestamp: 1,
|
|
741
|
-
});
|
|
742
|
-
const r2 = s.add({
|
|
743
|
-
sessionId: SESS,
|
|
744
|
-
summary: "second checkpoint about the parser",
|
|
745
|
-
regionText: "the parser tokenizes the input into a stream of tokens for the compiler version two",
|
|
746
|
-
timestamp: 2,
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
assert.equal(r1.deduped, false);
|
|
750
|
-
// With L0 off (and L1/L2 off too), near-dup should NOT be collapsed
|
|
751
|
-
assert.equal(r2.deduped, false, "L0 disabled → near-dup not collapsed");
|
|
752
|
-
assert.equal(vectorList(s,SESS).length, 2, "both checkpoints stored when L0 is off");
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
test("12b. MARK_ONLY_L1=true — L1 records but does not collapse", () => {
|
|
756
|
-
// Disable L2 to isolate L1 behavior
|
|
757
|
-
const s = store({ L1_ENABLED: true, MARK_ONLY_L1: true, L2_ENABLED: false });
|
|
758
|
-
const SESS = "sess_mark_only_l1";
|
|
759
|
-
|
|
760
|
-
const r1 = s.add({
|
|
761
|
-
sessionId: SESS,
|
|
762
|
-
summary: "user worked on the parser optimization",
|
|
763
|
-
regionText: "the parser optimized the hot loop with aggressive inlining",
|
|
764
|
-
timestamp: 1,
|
|
765
|
-
});
|
|
766
|
-
const r2 = s.add({
|
|
767
|
-
sessionId: SESS,
|
|
768
|
-
summary: "user worked on the parser optimization",
|
|
769
|
-
regionText: "the parser optimized the hot loop with aggressive inlinings",
|
|
770
|
-
timestamp: 2,
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
assert.equal(r1.deduped, false);
|
|
774
|
-
// MARK_ONLY_L1 → L1 detects the near-dup but does NOT collapse
|
|
775
|
-
assert.equal(r2.deduped, false, "MARK_ONLY_L1 → not collapsed");
|
|
776
|
-
assert.equal(vectorList(s,SESS).length, 2, "both checkpoints stored (mark only)");
|
|
777
|
-
|
|
778
|
-
// Both should be active (not removed)
|
|
779
|
-
const all = vectorList(s,SESS);
|
|
780
|
-
assert.ok(all.every((c) => c.dedupStatus === "active"), "both rows active under MARK_ONLY");
|
|
781
|
-
});
|
|
782
|
-
|
|
783
|
-
test("12c. L2_ENABLED=false — L2 skipped but L0/L1 still work", () => {
|
|
784
|
-
const s = store({ L2_ENABLED: false });
|
|
785
|
-
const SESS = "sess_l2_off";
|
|
786
|
-
|
|
787
|
-
// L0 should still catch exact dups
|
|
788
|
-
s.add({
|
|
789
|
-
sessionId: SESS,
|
|
790
|
-
summary: "auth module work",
|
|
791
|
-
regionText: "the auth module validates the session token and refreshes it on each request",
|
|
792
|
-
timestamp: 1,
|
|
793
|
-
});
|
|
794
|
-
const r2 = s.add({
|
|
795
|
-
sessionId: SESS,
|
|
796
|
-
summary: "auth module work",
|
|
797
|
-
regionText: "the auth module validates the session token and refreshes it on each request",
|
|
798
|
-
timestamp: 2,
|
|
799
|
-
});
|
|
800
|
-
assert.equal(r2.deduped, true, "L0 still catches exact dup with L2 off");
|
|
801
|
-
assert.equal(r2.reason, "contentHash", "L0 contentHash still fires");
|
|
802
|
-
|
|
803
|
-
// L1 should still catch near-dups
|
|
804
|
-
const r3 = s.add({
|
|
805
|
-
sessionId: SESS,
|
|
806
|
-
summary: "auth module work variant",
|
|
807
|
-
regionText: "the auth module validates the session tokens and refreshes them on each requests",
|
|
808
|
-
timestamp: 3,
|
|
809
|
-
});
|
|
810
|
-
assert.equal(r3.deduped, true, "L1 still catches near-dup with L2 off");
|
|
811
|
-
assert.equal(r3.reason, "l1MinHash", "L1 MinHash still fires");
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
test("12d. All tiers disabled — nothing deduped, everything stored", () => {
|
|
815
|
-
const s = store({ L0_ENABLED: false, L1_ENABLED: false, L2_ENABLED: false });
|
|
816
|
-
const SESS = "sess_all_off";
|
|
817
|
-
|
|
818
|
-
// Use different regionText to avoid SQLite content_hash unique constraint
|
|
819
|
-
const r1 = s.add({
|
|
820
|
-
sessionId: SESS,
|
|
821
|
-
summary: "alpha",
|
|
822
|
-
regionText: "alpha region text about the compiler optimization pipeline first pass",
|
|
823
|
-
timestamp: 1,
|
|
824
|
-
});
|
|
825
|
-
const r2 = s.add({
|
|
826
|
-
sessionId: SESS,
|
|
827
|
-
summary: "alpha",
|
|
828
|
-
regionText: "alpha region text about the compiler optimization pipeline second pass",
|
|
829
|
-
timestamp: 2,
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
assert.equal(r1.deduped, false);
|
|
833
|
-
assert.equal(r2.deduped, false, "all tiers off → nothing deduped");
|
|
834
|
-
assert.equal(vectorList(s,SESS).length, 2, "both stored");
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
// ---------------------------------------------------------------------------
|
|
838
|
-
// Cleanup
|
|
839
|
-
// ---------------------------------------------------------------------------
|
|
840
|
-
|
|
841
|
-
test("E2E cleanup", () => {
|
|
842
|
-
rmSync(baseTmp, { recursive: true, force: true });
|
|
843
|
-
});
|