pi-mega-compact 0.16.3 → 0.17.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 (207) hide show
  1. package/dist/config/vector-cortex.js +91 -0
  2. package/dist/dedup/digest.js +30 -0
  3. package/dist/dedup/l1-lsh-v2.js +60 -0
  4. package/dist/dedup/l1-lsh.js +52 -0
  5. package/dist/dedup/l1-minhash-v2.js +193 -0
  6. package/dist/dedup/l1-minhash.js +91 -0
  7. package/dist/dedup/l1-verify.js +54 -0
  8. package/dist/dedup/mmr.js +45 -0
  9. package/dist/dedup/normalize.js +39 -0
  10. package/dist/dedup/raptor/buildHistory.js +164 -0
  11. package/dist/dedup/raptor/guardrails.js +83 -0
  12. package/dist/dedup/raptor/incremental.js +304 -0
  13. package/dist/dedup/raptor/index.js +190 -0
  14. package/dist/dedup/raptor/kmeans.js +152 -0
  15. package/dist/dedup/raptor/multilevel.js +184 -0
  16. package/dist/dedup/raptor/retrieval.js +93 -0
  17. package/dist/dedup/raptor/summarizer.js +86 -0
  18. package/dist/dedup/raptor/tree.js +202 -0
  19. package/dist/dedup/topk.js +60 -0
  20. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +30 -0
  21. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +4 -14
  22. package/dist/extensions/dashboard-server/api-contracts/vector-cortex.js +12 -0
  23. package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +11 -0
  24. package/dist/extensions/dashboard-server/routes-vector-cortex.js +292 -0
  25. package/dist/extensions/dashboard-server/routes.js +1 -0
  26. package/dist/extensions/dashboard-server/server.js +9 -1
  27. package/dist/extensions/mega-events/context-handler.js +11 -0
  28. package/dist/extensions/mega-runtime/vector-cortex-ledger.js +131 -0
  29. package/dist/extensions/mega-runtime/vector-cortex-safety.js +100 -0
  30. package/dist/src/config/vector-cortex.js +91 -0
  31. package/dist/src/config.js +6 -0
  32. package/dist/src/dedup/l1-lsh-v2.js +60 -0
  33. package/dist/src/dedup/l1-minhash-v2.js +193 -0
  34. package/dist/src/dedup/normalize.js +1 -1
  35. package/dist/src/vector-cortex/conformance/emit.js +46 -0
  36. package/dist/src/vector-cortex/conformance/manifest.js +235 -0
  37. package/dist/src/vector-cortex/conformance/runner.js +111 -0
  38. package/dist/src/vector-cortex/conformance/triadB-reader.js +95 -0
  39. package/dist/src/vector-cortex/eval/annotations.js +41 -0
  40. package/dist/src/vector-cortex/eval/metrics.js +86 -0
  41. package/dist/src/vector-cortex/eval/observer.js +61 -0
  42. package/dist/src/vector-cortex/eval/persist.js +67 -0
  43. package/dist/src/vector-cortex/eval/reader.js +29 -0
  44. package/dist/src/vector-cortex/eval/types.js +33 -0
  45. package/dist/src/vector-cortex/ledger/adapter.js +55 -0
  46. package/dist/src/vector-cortex/ledger/compat-journal.js +206 -0
  47. package/dist/src/vector-cortex/ledger/emit.js +53 -0
  48. package/dist/src/vector-cortex/ledger/event-codec.js +72 -0
  49. package/dist/src/vector-cortex/ledger/event-codecB.js +76 -0
  50. package/dist/src/vector-cortex/ledger/sqlite.js +200 -0
  51. package/dist/src/vector-cortex/ledger/store.js +184 -0
  52. package/dist/src/vector-cortex/ledger/types.js +52 -0
  53. package/dist/src/vector-cortex/ledger/validator.js +117 -0
  54. package/dist/src/vector-cortex/migrations/effective-cut-v2.js +103 -0
  55. package/dist/src/vector-cortex/migrations/minhash-v2.js +209 -0
  56. package/dist/src/vector-cortex/migrations/occurrence-v2.js +139 -0
  57. package/dist/src/vector-cortex/replay/cut.js +123 -0
  58. package/dist/src/vector-cortex/replay/emit.js +58 -0
  59. package/dist/src/vector-cortex/replay/replay.js +260 -0
  60. package/dist/src/vector-cortex/replay/replayB.js +73 -0
  61. package/dist/src/vector-cortex/replay/types.js +52 -0
  62. package/dist/src/vector-cortex/resilience/breaker-core.js +359 -0
  63. package/dist/src/vector-cortex/resilience/breaker.js +12 -0
  64. package/dist/src/vector-cortex/resilience/emit.js +56 -0
  65. package/dist/src/vector-cortex/resilience/spool-core.js +347 -0
  66. package/dist/src/vector-cortex/resilience/spool.js +12 -0
  67. package/dist/src/vector-cortex/resilience/types.js +32 -0
  68. package/dist/vector-cortex/conformance/emit.js +46 -0
  69. package/dist/vector-cortex/conformance/manifest.js +235 -0
  70. package/dist/vector-cortex/conformance/runner.js +111 -0
  71. package/dist/vector-cortex/conformance/triadB-reader.js +95 -0
  72. package/dist/vector-cortex/eval/annotations.js +41 -0
  73. package/dist/vector-cortex/eval/metrics.js +86 -0
  74. package/dist/vector-cortex/eval/observer.js +61 -0
  75. package/dist/vector-cortex/eval/persist.js +67 -0
  76. package/dist/vector-cortex/eval/reader.js +29 -0
  77. package/dist/vector-cortex/eval/types.js +33 -0
  78. package/dist/vector-cortex/ledger/adapter.js +55 -0
  79. package/dist/vector-cortex/ledger/compat-journal.js +206 -0
  80. package/dist/vector-cortex/ledger/emit.js +53 -0
  81. package/dist/vector-cortex/ledger/event-codec.js +72 -0
  82. package/dist/vector-cortex/ledger/event-codecB.js +76 -0
  83. package/dist/vector-cortex/ledger/sqlite.js +200 -0
  84. package/dist/vector-cortex/ledger/store.js +184 -0
  85. package/dist/vector-cortex/ledger/types.js +52 -0
  86. package/dist/vector-cortex/ledger/validator.js +117 -0
  87. package/dist/vector-cortex/migrations/effective-cut-v2.js +103 -0
  88. package/dist/vector-cortex/migrations/minhash-v2.js +209 -0
  89. package/dist/vector-cortex/migrations/occurrence-v2.js +139 -0
  90. package/dist/vector-cortex/replay/cut.js +123 -0
  91. package/dist/vector-cortex/replay/emit.js +58 -0
  92. package/dist/vector-cortex/replay/replay.js +260 -0
  93. package/dist/vector-cortex/replay/replayB.js +73 -0
  94. package/dist/vector-cortex/replay/types.js +52 -0
  95. package/dist/vector-cortex/resilience/breaker-core.js +359 -0
  96. package/dist/vector-cortex/resilience/breaker.js +12 -0
  97. package/dist/vector-cortex/resilience/emit.js +56 -0
  98. package/dist/vector-cortex/resilience/spool-core.js +347 -0
  99. package/dist/vector-cortex/resilience/spool.js +12 -0
  100. package/dist/vector-cortex/resilience/types.js +32 -0
  101. package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js → AreaChart-BQXFF7UI.js} +2 -2
  102. package/extensions/dashboard-client/dist/assets/{AreaChart-Y_X0Bbjd.js.map → AreaChart-BQXFF7UI.js.map} +1 -1
  103. package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js → BarChart-BVtoz9Eg.js} +2 -2
  104. package/extensions/dashboard-client/dist/assets/{BarChart-B9XDb-Ob.js.map → BarChart-BVtoz9Eg.js.map} +1 -1
  105. package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js → CacheTab-trI2TIGy.js} +2 -2
  106. package/extensions/dashboard-client/dist/assets/{CacheTab-BUGVb1G1.js.map → CacheTab-trI2TIGy.js.map} +1 -1
  107. package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js → EventsTab-CNUbk9__.js} +2 -2
  108. package/extensions/dashboard-client/dist/assets/{EventsTab-dOqLYTsy.js.map → EventsTab-CNUbk9__.js.map} +1 -1
  109. package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js → HealthTab-K-bd_CM-.js} +2 -2
  110. package/extensions/dashboard-client/dist/assets/{HealthTab-c2vezKg1.js.map → HealthTab-K-bd_CM-.js.map} +1 -1
  111. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js → MaintenanceTab-CoEioKzx.js} +2 -2
  112. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-bQYHIcdx.js.map → MaintenanceTab-CoEioKzx.js.map} +1 -1
  113. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js → MemoryMapTab-CJo24ulv.js} +2 -2
  114. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-2L8pH6y2.js.map → MemoryMapTab-CJo24ulv.js.map} +1 -1
  115. package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js → MetricsTab-DCNlQWWP.js} +2 -2
  116. package/extensions/dashboard-client/dist/assets/{MetricsTab-CzUx1jpo.js.map → MetricsTab-DCNlQWWP.js.map} +1 -1
  117. package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js → OverviewTab-CQQlyIQ6.js} +2 -2
  118. package/extensions/dashboard-client/dist/assets/{OverviewTab-eCNoaclv.js.map → OverviewTab-CQQlyIQ6.js.map} +1 -1
  119. package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js → ReposTab-Cqm82_yn.js} +2 -2
  120. package/extensions/dashboard-client/dist/assets/{ReposTab-tb0IW3NF.js.map → ReposTab-Cqm82_yn.js.map} +1 -1
  121. package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js → SessionsTab-A8xTAdET.js} +2 -2
  122. package/extensions/dashboard-client/dist/assets/{SessionsTab-C-IoLw5h.js.map → SessionsTab-A8xTAdET.js.map} +1 -1
  123. package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js → SetupTab-CqaSgaZl.js} +2 -2
  124. package/extensions/dashboard-client/dist/assets/{SetupTab-BvmFi8gf.js.map → SetupTab-CqaSgaZl.js.map} +1 -1
  125. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js → TimeSavedCard-C_f3q8GR.js} +2 -2
  126. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DBH-cOlA.js.map → TimeSavedCard-C_f3q8GR.js.map} +1 -1
  127. package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js → TurnsTab-BEsafACo.js} +2 -2
  128. package/extensions/dashboard-client/dist/assets/{TurnsTab-DBMgmvnX.js.map → TurnsTab-BEsafACo.js.map} +1 -1
  129. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js +2 -0
  130. package/extensions/dashboard-client/dist/assets/VectorCortexTab-DD1CMK80.js.map +1 -0
  131. package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js → WikiTab-Bf01M2_Z.js} +2 -2
  132. package/extensions/dashboard-client/dist/assets/{WikiTab-1LcQrXk3.js.map → WikiTab-Bf01M2_Z.js.map} +1 -1
  133. package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js → button-BEJPTk_E.js} +2 -2
  134. package/extensions/dashboard-client/dist/assets/{button-DtEsZTUE.js.map → button-BEJPTk_E.js.map} +1 -1
  135. package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js → card-DK1V382s.js} +2 -2
  136. package/extensions/dashboard-client/dist/assets/{card-DcfTmw-4.js.map → card-DK1V382s.js.map} +1 -1
  137. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js → generateCategoricalChart-CRtaPphL.js} +2 -2
  138. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BsIxUDyw.js.map → generateCategoricalChart-CRtaPphL.js.map} +1 -1
  139. package/extensions/dashboard-client/dist/assets/{index-B93cewiX.js → index-CB6BslE4.js} +34 -29
  140. package/extensions/dashboard-client/dist/assets/index-CB6BslE4.js.map +1 -0
  141. package/extensions/dashboard-client/dist/assets/index-CfvziyBi.css +1 -0
  142. package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js → switch-C4FV6B9k.js} +2 -2
  143. package/extensions/dashboard-client/dist/assets/{switch-Bowd7jCD.js.map → switch-C4FV6B9k.js.map} +1 -1
  144. package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js → toggle-GBmeENMd.js} +2 -2
  145. package/extensions/dashboard-client/dist/assets/{toggle-Bo7kJZ4u.js.map → toggle-GBmeENMd.js.map} +1 -1
  146. package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js → useSSE-BOKZGSn1.js} +2 -2
  147. package/extensions/dashboard-client/dist/assets/{useSSE-zNhb0c3u.js.map → useSSE-BOKZGSn1.js.map} +1 -1
  148. package/extensions/dashboard-client/dist/index.html +2 -2
  149. package/extensions/dashboard-client/src/App.tsx +2 -0
  150. package/extensions/dashboard-client/src/api/vector-cortex.ts +54 -0
  151. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +272 -0
  152. package/extensions/dashboard-client/src/tabs/registry.ts +4 -1
  153. package/extensions/dashboard-client/src/types/vector-cortex.ts +84 -0
  154. package/extensions/dashboard-client/tsconfig.json +1 -1
  155. package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +67 -0
  156. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +4 -21
  157. package/extensions/dashboard-server/api-contracts/index.ts +3 -0
  158. package/extensions/dashboard-server/api-contracts/vector-cortex.ts +136 -0
  159. package/extensions/dashboard-server/routes-rag-settings-helpers.ts +41 -0
  160. package/extensions/dashboard-server/routes-vector-cortex.ts +332 -0
  161. package/extensions/dashboard-server/routes.ts +6 -0
  162. package/extensions/dashboard-server/server.ts +8 -0
  163. package/extensions/mega-events/context-handler.ts +16 -0
  164. package/extensions/mega-runtime/vector-cortex-ledger.ts +165 -0
  165. package/extensions/mega-runtime/vector-cortex-safety.ts +181 -0
  166. package/package.json +2 -1
  167. package/src/config/vector-cortex.ts +98 -0
  168. package/src/config.ts +28 -0
  169. package/src/dedup/l1-lsh-v2.ts +78 -0
  170. package/src/dedup/l1-minhash-v2.ts +221 -0
  171. package/src/dedup/normalize.ts +1 -1
  172. package/src/store/sqlite/game-scores.ts +2 -1
  173. package/src/vector-cortex/conformance/emit.ts +56 -0
  174. package/src/vector-cortex/conformance/manifest.ts +298 -0
  175. package/src/vector-cortex/conformance/runner.ts +165 -0
  176. package/src/vector-cortex/conformance/triadB-reader.ts +110 -0
  177. package/src/vector-cortex/eval/annotations.ts +70 -0
  178. package/src/vector-cortex/eval/metrics.ts +113 -0
  179. package/src/vector-cortex/eval/observer.ts +86 -0
  180. package/src/vector-cortex/eval/persist.ts +73 -0
  181. package/src/vector-cortex/eval/reader.ts +45 -0
  182. package/src/vector-cortex/eval/types.ts +89 -0
  183. package/src/vector-cortex/ledger/adapter.ts +71 -0
  184. package/src/vector-cortex/ledger/compat-journal.ts +234 -0
  185. package/src/vector-cortex/ledger/emit.ts +86 -0
  186. package/src/vector-cortex/ledger/event-codec.ts +79 -0
  187. package/src/vector-cortex/ledger/event-codecB.ts +87 -0
  188. package/src/vector-cortex/ledger/sqlite.ts +265 -0
  189. package/src/vector-cortex/ledger/store.ts +380 -0
  190. package/src/vector-cortex/ledger/types.ts +141 -0
  191. package/src/vector-cortex/ledger/validator.ts +124 -0
  192. package/src/vector-cortex/migrations/effective-cut-v2.ts +149 -0
  193. package/src/vector-cortex/migrations/minhash-v2.ts +263 -0
  194. package/src/vector-cortex/migrations/occurrence-v2.ts +192 -0
  195. package/src/vector-cortex/replay/cut.ts +169 -0
  196. package/src/vector-cortex/replay/emit.ts +89 -0
  197. package/src/vector-cortex/replay/replay.ts +308 -0
  198. package/src/vector-cortex/replay/replayB.ts +97 -0
  199. package/src/vector-cortex/replay/types.ts +145 -0
  200. package/src/vector-cortex/resilience/breaker-core.ts +444 -0
  201. package/src/vector-cortex/resilience/breaker.ts +22 -0
  202. package/src/vector-cortex/resilience/emit.ts +99 -0
  203. package/src/vector-cortex/resilience/spool-core.ts +411 -0
  204. package/src/vector-cortex/resilience/spool.ts +22 -0
  205. package/src/vector-cortex/resilience/types.ts +158 -0
  206. package/extensions/dashboard-client/dist/assets/index-B93cewiX.js.map +0 -1
  207. package/extensions/dashboard-client/dist/assets/index-C_tCbOI0.css +0 -1
@@ -0,0 +1,86 @@
1
+ /**
2
+ * summarizer.ts — per-cluster summary for the RAPTOR tree (Sprint 13, Phase 6).
3
+ *
4
+ * Default: pure extractive (deterministic, zero network, zero model) reusing
5
+ * extractive.ts. Optional: a LOCAL Ollama model (llama3.2:3b by default) when
6
+ * MEGACOMPACT_RAPTOR_MODEL is set — localhost only, same PREVENT-PI-004
7
+ * exception class as HttpEmbedder/the dashboard. No remote API is ever called.
8
+ *
9
+ * The summarizer returns structured text + a token estimate. Faithfulness is
10
+ * enforced downstream by guardrails.ts — this module only produces candidates.
11
+ */
12
+ import { extractiveSummarize } from "../../extractive.js";
13
+ import { estimateBlockTokens } from "../../tokens.js";
14
+ import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: localhost-only user-spawned Ollama server (BYO local model, never remote)
15
+ /** The local Ollama endpoint (loopback). Read lazily so tests can avoid it. */
16
+ function ollamaEndpoint() {
17
+ const model = process.env.MEGACOMPACT_RAPTOR_MODEL;
18
+ if (!model)
19
+ return null;
20
+ const base = process.env.MEGACOMPACT_RAPTOR_URL ?? "http://127.0.0.1:11434"; // guardrails-allow PREVENT-PI-004: loopback-only Ollama endpoint for local RAPTOR summarization
21
+ // Guard: only loopback is permitted (remote Ollama would violate PREVENT-PI-004).
22
+ if (!/^https?:\/\/(localhost|127\.0\.0\.1)([:/]|$)/.test(base)) {
23
+ throw new Error(`MEGACOMPACT_RAPTOR_URL must be localhost/127.0.0.1 (got ${base}). ` +
24
+ `Remote Ollama is not allowed (PREVENT-PI-004).`);
25
+ }
26
+ return { url: `${base}/api/generate`, model };
27
+ }
28
+ /**
29
+ * Extractive summarization of a cluster's source messages. Deterministic and
30
+ * fully local — the on-by-default path.
31
+ */
32
+ export function extractiveClusterSummary(messages) {
33
+ const s = extractiveSummarize(messages);
34
+ return { summary: s.topicSummary, tokenEstimate: s.tokenEstimate };
35
+ }
36
+ /**
37
+ * Build a summary for one cluster of source messages.
38
+ *
39
+ * Uses local Ollama when MEGACOMPACT_RAPTOR_MODEL is set (localhost-only);
40
+ * otherwise falls back to deterministic extractive. The `fetch` is a localhost
41
+ * call inside the PREVENT-PI-004 exception — annotated accordingly.
42
+ */
43
+ export function summarizeCluster(messages) {
44
+ const ollama = ollamaEndpoint();
45
+ if (!ollama)
46
+ return extractiveClusterSummary(messages);
47
+ return ollamaSummarize(messages, ollama);
48
+ }
49
+ function ollamaSummarize(messages, ollama) {
50
+ // The fetch below is localhost-only (loopback Ollama) — the PREVENT-PI-004
51
+ // sanctioned local-model exceptions (same class as /dashboard, HttpEmbedder).
52
+ const prompt = messages.map((m) => `${m.role}: ${m.text}`).join("\n");
53
+ // Synchronous bridge: spawnSync an inline worker so the call blocks without
54
+ // deadlocking fetch (mirrors HttpEmbedder — Atomics.wait on main thread would
55
+ // hang). A blocked main thread cannot pump the socket.
56
+ const WORKER = String.raw `
57
+ const url = process.env.R_URL, model = process.env.R_MODEL, prompt = process.env.R_PROMPT;
58
+ try {
59
+ const r = await fetch(url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ model, prompt, stream: false }) }); // guardrails-allow PREVENT-PI-004: localhost-only user-spawned Ollama server (BYO local model, never remote)
60
+ const j = await r.json();
61
+ process.stdout.write(JSON.stringify({ ok: r.ok, text: j.response || "" }));
62
+ } catch (e) {
63
+ process.stdout.write(JSON.stringify({ ok: false, error: String(e && e.message ? e.message : e) }));
64
+ }
65
+ `;
66
+ const res = spawnSync(process.execPath, ["-e", WORKER], {
67
+ encoding: "utf8",
68
+ timeout: 30_000,
69
+ env: { ...process.env, R_URL: ollama.url, R_MODEL: ollama.model, R_PROMPT: prompt },
70
+ });
71
+ let parsed = { ok: false, error: "no response" };
72
+ if (typeof res.stdout === "string" && res.stdout.length > 0) {
73
+ try {
74
+ parsed = JSON.parse(res.stdout);
75
+ }
76
+ catch {
77
+ parsed = { ok: false, error: "bad json" };
78
+ }
79
+ }
80
+ if (!parsed.ok || !parsed.text) {
81
+ // Ollama unavailable → deterministic extractive fallback (never fail the build).
82
+ return extractiveClusterSummary(messages);
83
+ }
84
+ const summary = parsed.text.trim();
85
+ return { summary, tokenEstimate: estimateBlockTokens(summary) };
86
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * tree.ts — RAPTOR hierarchical summary-tree builder (Sprint 13, Phase 6).
3
+ *
4
+ * Builds a multi-level tree of summary nodes over leaf chunks: leaves are the
5
+ * original regions; each higher level summarizes clusters of the level below
6
+ * until a single root remains. QA ops: a wall-clock budget guard — on exhaustion
7
+ * we build an extractive fallback root. <10 leaves → a single summary node.
8
+ *
9
+ * Node model (kept simple + flat): every RaptorNode stores the LIST OF LEAF IDS
10
+ * it ultimately covers in `children` (not a mix of node/leaf ids). So the node
11
+ * map holds ONLY internal summary nodes — never per-leaf wrappers — which is
12
+ * what makes RAPTOR consolidate (nodes.size << leaves) and makes retrieval's
13
+ * leaf walk trivial.
14
+ *
15
+ * PREVENT-PI-004: no network here. summarizeCluster() may call a localhost
16
+ * Ollama (annotated in summarizer.ts); extractive is the default.
17
+ */
18
+ import { kmeanspp, meanVector } from "./kmeans.js";
19
+ import { summarizeCluster } from "./summarizer.js";
20
+ import { applyHallucinationGuardrails, sourceTokenSet } from "./guardrails.js";
21
+ const DEFAULT_BUDGET_MS = 5000;
22
+ const DEFAULT_CLUSTERS = 5;
23
+ function defaultNextId(level, index) {
24
+ return `r${level}_${index}`;
25
+ }
26
+ function summarizeInto(item, centroid, embedder, consistencyThreshold) {
27
+ let summary = summarizeCluster(item.messages);
28
+ const guard = applyHallucinationGuardrails({
29
+ summary: summary.summary,
30
+ sources: item.sources,
31
+ centroid,
32
+ embedder,
33
+ sourceTokens: sourceTokenSet(item.sources),
34
+ consistencyThreshold,
35
+ });
36
+ if (guard.marker === "extractive_fallback") {
37
+ summary = summarizeCluster(item.messages); // deterministic extractive text
38
+ }
39
+ return {
40
+ summary: summary.summary,
41
+ tokenEstimate: summary.tokenEstimate,
42
+ qualityMarker: guard.marker === "extractive_fallback" ? "low" : guard.marker,
43
+ };
44
+ }
45
+ /**
46
+ * Build a RAPTOR tree from leaf chunks. Synchronous; guarded by an elapsed-time
47
+ * budget. Returns a tree whose `nodes` map holds ONLY internal summary nodes.
48
+ */
49
+ export function buildRaptorTree(leaves, opts) {
50
+ const embedder = opts.embedder;
51
+ const budgetMs = opts.budgetMs ?? DEFAULT_BUDGET_MS;
52
+ const clustersPerLevel = opts.clustersPerLevel ?? DEFAULT_CLUSTERS;
53
+ const nextId = opts.nextId ?? defaultNextId;
54
+ const now = opts.now ?? (() => Date.now());
55
+ const start = now();
56
+ const within = () => now() - start <= budgetMs;
57
+ const nodes = new Map();
58
+ // <10 leaves → single summary root (no hierarchy needed).
59
+ if (leaves.length < 10) {
60
+ const item = {
61
+ id: "root",
62
+ parentId: null,
63
+ embedding: meanVector(leaves.map((l) => l.embedding)),
64
+ leafIds: leaves.map((l) => l.id),
65
+ messages: leaves.flatMap((l) => l.messages),
66
+ sources: leaves.map((l) => l.sourceText),
67
+ };
68
+ const centroid = item.embedding;
69
+ const { summary, tokenEstimate, qualityMarker } = summarizeInto(item, centroid, embedder, opts.consistencyThreshold);
70
+ const rootId = nextId(0, 0);
71
+ nodes.set(rootId, {
72
+ id: rootId,
73
+ level: 0,
74
+ parentId: null,
75
+ children: item.leafIds,
76
+ summary,
77
+ embedding: centroid,
78
+ qualityMarker,
79
+ tokenEstimate,
80
+ });
81
+ return { nodes, rootId, levels: 1, timedOut: false };
82
+ }
83
+ let currentLevel = leaves.map((l) => ({
84
+ id: l.id,
85
+ parentId: null,
86
+ embedding: l.embedding,
87
+ leafIds: [l.id],
88
+ messages: l.messages,
89
+ sources: [l.sourceText],
90
+ }));
91
+ let level = 0;
92
+ while (currentLevel.length > 1) {
93
+ if (!within())
94
+ return extractiveFallbackRoot(leaves, nodes, nextId);
95
+ // Once we're down to a handful of items, collapse them all into one root.
96
+ // (k === currentLevel.length would make every item its own singleton
97
+ // cluster and never shrink — an infinite loop until the budget blows.)
98
+ if (currentLevel.length <= clustersPerLevel) {
99
+ const merged = {
100
+ id: "merge",
101
+ parentId: null,
102
+ embedding: meanVector(currentLevel.map((c) => c.embedding)),
103
+ leafIds: currentLevel.flatMap((c) => c.leafIds),
104
+ messages: currentLevel.flatMap((c) => c.messages),
105
+ sources: currentLevel.flatMap((c) => c.sources),
106
+ };
107
+ const centroid = merged.embedding;
108
+ const { summary, tokenEstimate, qualityMarker } = summarizeInto(merged, centroid, embedder, opts.consistencyThreshold);
109
+ const rootId = nextId(level + 1, 0);
110
+ nodes.set(rootId, {
111
+ id: rootId,
112
+ level: level + 1,
113
+ parentId: null,
114
+ children: merged.leafIds,
115
+ summary,
116
+ embedding: centroid,
117
+ qualityMarker,
118
+ tokenEstimate,
119
+ });
120
+ // Populate parentId for the internal nodes being merged into this root.
121
+ // currentLevel items with ids in `nodes` are internal summary nodes (level
122
+ // >= 1); raw leaf ids are not in `nodes` and are correctly skipped.
123
+ for (const c of currentLevel) {
124
+ const child = nodes.get(c.id);
125
+ if (child && child.id !== rootId && child.parentId === null) {
126
+ child.parentId = rootId;
127
+ }
128
+ }
129
+ return { nodes, rootId, levels: level + 2, timedOut: false };
130
+ }
131
+ const k = Math.max(1, Math.min(clustersPerLevel, currentLevel.length));
132
+ const clustered = kmeanspp(currentLevel.map((c) => c.embedding), k, { seed: 0x1234 + level });
133
+ const groups = Array.from({ length: clustered.k }, () => []);
134
+ clustered.assignments.forEach((c, i) => groups[c].push(currentLevel[i]));
135
+ const nextLevel = [];
136
+ for (let g = 0; g < groups.length; g++) {
137
+ const group = groups[g];
138
+ if (group.length === 0)
139
+ continue;
140
+ const merged = {
141
+ id: nextId(level + 1, g),
142
+ parentId: null,
143
+ embedding: clustered.centroids[g],
144
+ leafIds: group.flatMap((c) => c.leafIds),
145
+ messages: group.flatMap((c) => c.messages),
146
+ sources: group.flatMap((c) => c.sources),
147
+ };
148
+ const { summary, tokenEstimate, qualityMarker } = summarizeInto(merged, merged.embedding, embedder, opts.consistencyThreshold);
149
+ nodes.set(merged.id, {
150
+ id: merged.id,
151
+ level: level + 1,
152
+ parentId: null,
153
+ children: merged.leafIds,
154
+ summary,
155
+ embedding: merged.embedding,
156
+ qualityMarker,
157
+ tokenEstimate,
158
+ });
159
+ // Populate parentId for the internal nodes being absorbed into this
160
+ // parent summary. Group members with ids in `nodes` are internal summary
161
+ // nodes (level >= 1); raw leaf ids are not in `nodes` (per-leaf wrappers
162
+ // are intentionally absent) and are correctly skipped — leaf→summary
163
+ // walks go through the parent's `children` list instead.
164
+ for (const c of group) {
165
+ const child = nodes.get(c.id);
166
+ if (child && child.id !== merged.id) {
167
+ child.parentId = merged.id;
168
+ }
169
+ }
170
+ nextLevel.push(merged);
171
+ }
172
+ currentLevel = nextLevel;
173
+ level++;
174
+ }
175
+ const root = currentLevel[0];
176
+ const rootId = root ? root.id : null;
177
+ return {
178
+ nodes,
179
+ rootId,
180
+ levels: level + 1,
181
+ timedOut: false,
182
+ };
183
+ }
184
+ /**
185
+ * Budget-exceeded fallback: build a single deterministic extractive root over
186
+ * all leaves and mark it low quality. Keeps a valid (if shallow) tree.
187
+ */
188
+ function extractiveFallbackRoot(leaves, nodes, nextId) {
189
+ const summary = summarizeCluster(leaves.flatMap((l) => l.messages));
190
+ const rootId = nextId(99, 0);
191
+ nodes.set(rootId, {
192
+ id: rootId,
193
+ level: 99,
194
+ parentId: null,
195
+ children: leaves.map((l) => l.id),
196
+ summary: summary.summary,
197
+ embedding: meanVector(leaves.map((l) => l.embedding)),
198
+ qualityMarker: "low",
199
+ tokenEstimate: summary.tokenEstimate,
200
+ });
201
+ return { nodes, rootId, levels: 100, timedOut: true };
202
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * topk.ts — min-heap based top-K selection (Sprint 12, QA #4).
3
+ *
4
+ * Replaces the O(N log N) full `.sort()` in search() with an O(N log k) heap,
5
+ * which matters once a session holds thousands of checkpoints. Generic over any
6
+ * scored item with a numeric `score`.
7
+ *
8
+ * Pure, no deps, no network (PREVENT-PI-004).
9
+ */
10
+ /**
11
+ * Return the `k` highest-scoring items (stable insertion order on ties).
12
+ * O(N log k) — a bounded min-heap of size k.
13
+ */
14
+ export function topK(items, k) {
15
+ if (k <= 0)
16
+ return [];
17
+ if (items.length <= k)
18
+ return [...items].sort((a, b) => b.score - a.score);
19
+ // Min-heap of the current top-k, stored as a flat array of Scored<T>.
20
+ const heap = [];
21
+ const push = (e) => {
22
+ heap.push(e);
23
+ let i = heap.length - 1;
24
+ while (i > 0) {
25
+ const parent = (i - 1) >> 1;
26
+ if (heap[parent].score <= heap[i].score)
27
+ break;
28
+ [heap[parent], heap[i]] = [heap[i], heap[parent]];
29
+ i = parent;
30
+ }
31
+ };
32
+ const siftDown = (start) => {
33
+ let i = start;
34
+ for (;;) {
35
+ const l = 2 * i + 1;
36
+ const r = 2 * i + 2;
37
+ let smallest = i;
38
+ if (l < heap.length && heap[l].score < heap[smallest].score)
39
+ smallest = l;
40
+ if (r < heap.length && heap[r].score < heap[smallest].score)
41
+ smallest = r;
42
+ if (smallest === i)
43
+ break;
44
+ [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
45
+ i = smallest;
46
+ }
47
+ };
48
+ for (const it of items) {
49
+ if (heap.length < k) {
50
+ push(it);
51
+ }
52
+ else if (it.score > heap[0].score) {
53
+ // Replace the current minimum with this better-scoring item, then sift
54
+ // it down to restore the min-heap invariant.
55
+ heap[0] = it;
56
+ siftDown(0);
57
+ }
58
+ }
59
+ return heap.sort((a, b) => b.score - a.score);
60
+ }
@@ -0,0 +1,30 @@
1
+ /** Additive endpoint entries spread into the ENDPOINTS registry. */
2
+ export const EXTRA_ENDPOINTS = {
3
+ // ─── Per-model compaction thresholds (S52 / v0.16.1) ───────────────
4
+ /** GET /api/model-thresholds — List known models + their thresholds. */
5
+ modelThresholds: {
6
+ method: "GET",
7
+ path: "/api/model-thresholds",
8
+ description: "Every known model (from model_snapshots) with its per-model threshold override (or defaults).",
9
+ },
10
+ // ─── RAG Metrics (Sprint H2) ──────────────────────────────────────
11
+ /** GET /api/rag-metrics — HyDE + recall-quality telemetry aggregates. */
12
+ ragMetrics: {
13
+ method: "GET",
14
+ path: "/api/rag-metrics",
15
+ description: "HyDE invocation + recall-quality telemetry: flags, totals, recent turns, and daily series.",
16
+ },
17
+ // ─── Vector Cortex (VC0A) ────────────────────────────────────────
18
+ /** GET /api/vector-cortex/evaluation — reader-only eval aggregate (VC0A). */
19
+ vectorCortexEvaluation: {
20
+ method: "GET",
21
+ path: "/api/vector-cortex/evaluation",
22
+ description: "Reader-only vector-cortex evaluation summary: latency histogram + per-mode sample counts (never payloads).",
23
+ },
24
+ /** GET /api/vector-cortex/ledger — reader-only occurrence ledger view (VC1B). */
25
+ vectorCortexLedger: {
26
+ method: "GET",
27
+ path: "/api/vector-cortex/ledger",
28
+ description: "Reader-only occurrence-ledger identity view: seq/eventId/kind/digest + high-water (never source payloads).",
29
+ },
30
+ };
@@ -1,3 +1,4 @@
1
+ import { EXTRA_ENDPOINTS } from "./registry-ext.js";
1
2
  // ─── ENDPOINTS Registry ─────────────────────────────────────────────────────
2
3
  /**
3
4
  * Central registry of all 14 dashboard API endpoints. Each entry is an
@@ -290,18 +291,7 @@ export const ENDPOINTS = {
290
291
  path: "/api/rag-settings",
291
292
  description: "Update RAG feature flag states by writing _DISABLED env vars to .mega-compact.env.",
292
293
  },
293
- // ─── RAG Metrics (Sprint H2) ──────────────────────────────────────
294
- /** GET /api/rag-metrics HyDE + recall-quality telemetry aggregates. */
295
- ragMetrics: {
296
- method: "GET",
297
- path: "/api/rag-metrics",
298
- description: "HyDE invocation + recall-quality telemetry: flags, totals, recent turns, and daily series.",
299
- },
300
- // ─── Per-model compaction thresholds (S52 / v0.16.1) ───────────────
301
- /** GET /api/model-thresholds — List known models + their thresholds. */
302
- modelThresholds: {
303
- method: "GET",
304
- path: "/api/model-thresholds",
305
- description: "Every known model (from model_snapshots) with its per-model threshold override (or defaults).",
306
- },
294
+ // ─── Additive groups (rag-metrics, thresholds, vector-cortex) live in
295
+ // ─── registry-ext.ts so this registry stays under the 500-line limit.
296
+ ...EXTRA_ENDPOINTS,
307
297
  };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * api-contracts/vector-cortex.ts — vector-cortex dashboard API contracts.
3
+ *
4
+ * Owned by the vector-cortex sprints. VC0A ships only the reader-only aggregate
5
+ * `GET /api/vector-cortex/evaluation`. VC0C adds the breaker health endpoint
6
+ * and reset mutation into this SAME file — keep entries small and additive so
7
+ * the file stays within extension limits (400 soft / 500 hard).
8
+ *
9
+ * PREVENT-PI-004: type definitions only, no network code.
10
+ * PREVENT-011: no `any` type.
11
+ */
12
+ export {};
@@ -129,6 +129,17 @@ export const SETTINGS = [
129
129
  num("MEGACOMPACT_EMBED_CACHE", "Embed Cache Size", "Embedding cache entries (0 = disabled)", 256, 0, 10000),
130
130
  ],
131
131
  },
132
+ {
133
+ name: "Vector Cortex",
134
+ settings: [
135
+ boolDirect("MEGACOMPACT_VC0A", "VC0A Baseline Observability", "Structured evaluation observer (MetricEventV1 + latency histogram). OFF = mode C, byte-identical to predecessor.", true),
136
+ boolDirect("MEGACOMPACT_VC0B", "VC0B Replay Correctness", "ReplayCutV2 effective-cut (min of boundary-safe/commit/capture high-water + pair retreat + anchor floor) and M3 effective-cut-v2 migration. OFF = legacy capped replay, byte-identical.", true),
137
+ boolDirect("MEGACOMPACT_VC1A", "VC1A Canonical Byte Events", "EventV2 byte-authority ledger codec (original bytes + SHA-256, strict UTF-8, derived NFC) and canonical validator (EVT_DIGEST_MISMATCH / EVT_UTF8_TAG_INVALID / EVT_DUPLICATE_ID). OFF = mode C, transcript codec unchanged, byte-identical.", true),
138
+ boolDirect("MEGACOMPACT_VC1B", "VC1B Occurrence Ledger + Tool Identity", "Neutral occurrence ledger (LedgerReader/Writer/Admin + CompatJournalV1): per-session monotonic seq, tool result references one earlier call, uniqueness by (eventId,digest) only, and the M2 copy-validate-switch downgrade journal. OFF = mode C, ledger unwritten, byte-identical.", true),
139
+ boolDirect("MEGACOMPACT_VC0C", "VC0C Live Safety Envelope", "TriadResult/Breaker live circuit breaker (60s window, 20 attempts, 30s cooldown, 3 probes, 5min healthy residence) + durable spool before provider invocation; manual reset clears cooldown but never evidence. OFF = mode C, unchanged transcript, byte-identical.", true),
140
+ boolDirect("MEGACOMPACT_VC1C", "VC1C Cross-Language Conformance v2", "FixtureManifestV2 canonical manifest validator + DowngradeReport deterministic downgrade export + MinHashV2 exact big-integer signatures and the M4 copy/validate/switch minhash-v2 migration (seed table frozen, cross-language byte-exact). OFF = mode C, v1 sync dedup scan unchanged, byte-identical.", true),
141
+ ],
142
+ },
132
143
  {
133
144
  name: "Cost API",
134
145
  settings: [