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,165 @@
1
+ /**
2
+ * vector-cortex-ledger.ts — VC1B occurrence-ledger writer wiring (S1).
3
+ *
4
+ * Wires ONLY the `LedgerWriter` capability into message ingestion: each
5
+ * canonical message that flows through the compaction pipeline becomes an
6
+ * occurrence in the v2 ledger. The wiring is writer-only (never reader/admin
7
+ * here — the dashboard GET owns the reader), matching the capability-gated
8
+ * CONTRACTS §Store rule. A tool RESULT occurrence references exactly one
9
+ * earlier call via `toolCallId` (the ledger enforces EVT_TOOL_CALL_MISSING).
10
+ *
11
+ * When MEGACOMPACT_VC1B is OFF the seam opens NO ledger DB at all — and even if
12
+ * a caller already holds a store, its write path is inert (S2 flag-gate in
13
+ * store.ts) — so the OFF behavior is byte-identical to the pre-VC1B predecessor.
14
+ *
15
+ * Local-only (PREVENT-PI-004), no `any` (PREVENT-011), no console.log (events
16
+ * go through the ledger emit seam); non-fatal — a ledger write failure never
17
+ * breaks the agent loop.
18
+ */
19
+ import { createHash } from "node:crypto";
20
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
21
+ import { VC1B_ENABLED } from "../../src/config/vector-cortex.js";
22
+ import {
23
+ createLedgerStore,
24
+ type LedgerWriter,
25
+ } from "../../src/vector-cortex/ledger/store.js";
26
+
27
+ /** A single canonical message mapped to a ledger occurrence input. */
28
+ export interface LedgerMessageInput {
29
+ readonly session: string;
30
+ readonly seq: bigint;
31
+ readonly eventId: string;
32
+ readonly kind: string;
33
+ readonly toolCallId?: string;
34
+ readonly sourceBytes: Uint8Array;
35
+ }
36
+
37
+ /** The writer handle handed to ingestion. */
38
+ export interface LedgerWriterHandle {
39
+ readonly writer: LedgerWriter;
40
+ readonly close: () => void;
41
+ }
42
+
43
+ /** Open the ledger writer for ingestion, or null when VC1B is disabled. */
44
+ export function openLedgerWriter(stateDir: string): LedgerWriterHandle | null {
45
+ if (!VC1B_ENABLED()) return null;
46
+ const store = createLedgerStore({ stateDir });
47
+ return { writer: store.writer(), close: () => store.close() };
48
+ }
49
+
50
+ /**
51
+ * Append one occurrence for a canonical message. `kind` is the neutral kind;
52
+ * when `toolCallId` is present the ledger enforces exactly-one reference to an
53
+ * earlier call. Flag-OFF (null handle) and the writer's own inert path are
54
+ * no-ops. Non-fatal: never throws to the loop — a failure is surfaced as
55
+ * `{ ok: false, code }` so the caller can log the reason (Q02).
56
+ */
57
+ export function appendLedgerMessage(
58
+ handle: LedgerWriterHandle,
59
+ input: LedgerMessageInput,
60
+ ): { ok: boolean; code?: string } {
61
+ try {
62
+ const res = handle.writer.append(input);
63
+ return res.ok ? { ok: true } : { ok: false, code: res.code };
64
+ } catch (e) {
65
+ return { ok: false, code: String(e) };
66
+ }
67
+ }
68
+
69
+ /** Structured logger sink for seam append failures (wired by the extension). */
70
+ export interface LedgerAppendLogger {
71
+ readonly warn: (event: string, fields: Record<string, unknown>) => void;
72
+ }
73
+
74
+ /**
75
+ * Append one occurrence per canonical message in `messages` (session-scoped,
76
+ * sequence = 1-based index). Opens the writer, appends each, closes the handle.
77
+ * Returns the number of accepted occurrences (0 when disabled OR when every
78
+ * append was a non-fatal no-op). This is the S1 ingestion seam.
79
+ *
80
+ * Monotonic-prefix assumption (Q02): the FIRST accepted append establishes the
81
+ * per-session high-water, and each subsequent append must carry `seq =
82
+ * highWater + 1`. Append order here follows `messages` array order with 1-based
83
+ * indices, so a shorter/mid-removal/reordered `messages` list after a prior
84
+ * taller run (rewind/fork) can drive `seq` backwards and be rejected with
85
+ * `EVT_SEQ_REGRESSION`. Such appends fail on the ledger and, without `onFailure`,
86
+ * are swallowed silently — so the caller should pass `onFailure` to log them.
87
+ */
88
+ export function appendMessagesToLedger(
89
+ stateDir: string,
90
+ sessionId: string,
91
+ messages: AgentMessage[],
92
+ onFailure?: Readonly<LedgerAppendLogger>,
93
+ ): number {
94
+ const ledger = openLedgerWriter(stateDir);
95
+ if (!ledger) return 0;
96
+ try {
97
+ let accepted = 0;
98
+ for (let i = 0; i < messages.length; i++) {
99
+ const input = messageToLedgerInput(messages[i]!, sessionId, i);
100
+ const res = appendLedgerMessage(ledger, input);
101
+ if (res.ok) {
102
+ accepted++;
103
+ } else if (onFailure) {
104
+ onFailure.warn("vc1b-ledger-append-skip", {
105
+ session: sessionId,
106
+ seq: input.seq.toString(),
107
+ eventId: input.eventId,
108
+ kind: input.kind,
109
+ reason: res.code ?? "unknown",
110
+ });
111
+ }
112
+ }
113
+ return accepted;
114
+ } finally {
115
+ ledger.close();
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Map an AgentMessage to a ledger occurrence input. `eventId` is the stable
121
+ * content digest so re-observed identical messages are (event_id,digest)-deduped;
122
+ * `kind` mirrors the canonical role. `toolCallId` is intentionally NOT set here:
123
+ * pi discriminates messages by `role` only and the tool-call id lives in
124
+ * variant-specific `.content`/`.tool_calls` we must not reach into, so the
125
+ * exactly-one tool back-edge (EVT_TOOL_CALL_MISSING) is exercised at the
126
+ * store/acceptance level and the full live mapping is deferred to the VC1
127
+ * producer-wiring sprint.
128
+ */
129
+ export function messageToLedgerInput(
130
+ msg: AgentMessage,
131
+ session: string,
132
+ indexInSession: number,
133
+ ): LedgerMessageInput {
134
+ const m = msg as { role?: string; id?: string };
135
+ const text = messageText(msg);
136
+ const role = m.role ?? "unknown";
137
+ const digest = `sha256:${createHash("sha256").update(text).digest("hex")}`;
138
+ return {
139
+ session,
140
+ seq: BigInt(indexInSession + 1),
141
+ eventId: m.id ?? digest,
142
+ kind: role,
143
+ sourceBytes: new TextEncoder().encode(text),
144
+ };
145
+ }
146
+
147
+ /** Best-effort text extraction from an AgentMessage (string or part array). */
148
+ function messageText(msg: AgentMessage): string {
149
+ const content = (msg as { content?: unknown }).content;
150
+ if (content == null) return "";
151
+ if (typeof content === "string") return content;
152
+ if (Array.isArray(content)) {
153
+ return content
154
+ .map((p) => {
155
+ const part = p as { type?: string; text?: string };
156
+ return typeof part.text === "string" ? part.text : "";
157
+ })
158
+ .join("\n");
159
+ }
160
+ if (typeof content === "object") {
161
+ const maybe = (content as Record<string, unknown>).text;
162
+ if (typeof maybe === "string") return maybe;
163
+ }
164
+ return "";
165
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * vector-cortex-safety.ts — VC0C live safety envelope (VC0C, task 4 + 5).
3
+ *
4
+ * Owns the live triad selection BEFORE provider invocation: select mode A
5
+ * (optimized/learned), then independent mode B (deterministic local spool
6
+ * deriving directly from authority), then unchanged mode C (continuity, not
7
+ * semantic completeness — C uses only the exact current transcript and reports
8
+ * that limitation). A manual reset clears cooldown but NEVER evidence.
9
+ *
10
+ * This adapter composes the resilience seams (`resilience/breaker.ts`,
11
+ * `resilience/spool.ts`, `resilience/emit.ts`) into the health/reset API the
12
+ * dashboard owns (`GET /api/vector-cortex/health`, admin
13
+ * `POST /api/vector-cortex/breakers/reset`). It is the pi-runtime-adjacent shell;
14
+ * all durable state is owned by the src/ resilience modules. Non-fatal: any
15
+ * breaker/spool noise degrades to mode C (unchanged host transcript), and the
16
+ * agent loop is never broken.
17
+ *
18
+ * Local-only (PREVENT-PI-004); no `any` (PREVENT-011); no console.log — events
19
+ * go through the injected resilience reporter / Logger.
20
+ *
21
+ * LIVENESS HONESTY (VC0C-Q01/Q06): the breaker composed here is PER-PROCESS /
22
+ * IN-MEMORY and EPHEMERAL — `createVectorCortexSafety` builds a fresh instance on
23
+ * every dashboard request (GET /health, POST /reset). There is NO persistent
24
+ * breaker runtime and NO live producer wiring (the real circuit-breaker that runs
25
+ * around the actual compaction loop is DEFERRED to the producer-wiring sprint,
26
+ * carried VC0B-I08 -> VC0D). Consequently GET /health always reflects a brand-new
27
+ * CLOSED_A instance and POST /reset mutates an instance that vanishes when the
28
+ * request returns: the endpoints are ILLUSTRATIVE until VC0D wires a persistent
29
+ * instance. The health payload therefore carries `stateSource:"ephemeral"` so the
30
+ * dashboard/README never present it as a live breaker. Frontier-frozen / spool-lag
31
+ * are owned by the DURABLE spool but have no live per-session handle here, so they
32
+ * are surfaced as static/non-live until VC0D (with authorityOutage mirrored from
33
+ * the host context when supplied).
34
+ */
35
+
36
+ import { join } from "node:path";
37
+ import { createResilienceReporter, type ResilienceReporter } from "../../src/vector-cortex/resilience/emit.js";
38
+ import { createBreaker } from "../../src/vector-cortex/resilience/breaker.js";
39
+ import { createSpool, type Spool } from "../../src/vector-cortex/resilience/spool.js";
40
+ import type { BreakerRecord, Mode, TriadResult } from "../../src/vector-cortex/resilience/types.js";
41
+ import { BREAKER_WINDOW_MS, VC0C_ENABLED } from "../../src/config/vector-cortex.js";
42
+
43
+ /** Daily/health context the safety adapter needs from its host. */
44
+ export interface VectorCortexSafetyContext {
45
+ /** State directory hosting the durable breaker/spool state. */
46
+ readonly stateDir: string;
47
+ /** Monotonic clock for windows/cooldowns (fake-clock testable). */
48
+ readonly now?: () => number;
49
+ /** Wall-clock supplier for record timestamps (default ISO now). */
50
+ readonly wallNow?: () => string;
51
+ /** True while the mode-A authority (SQLite ledger) is in OUTAGE. */
52
+ readonly authorityOutage?: () => boolean;
53
+ }
54
+
55
+ /** Health-card aggregate (dashboard contract). */
56
+ export interface VectorCortexHealthSummary {
57
+ readonly enabled: boolean;
58
+ readonly mode: Mode;
59
+ readonly state: string;
60
+ readonly subsystem: string;
61
+ readonly sinceMs: number;
62
+ readonly reason?: string;
63
+ readonly windowMs: number;
64
+ readonly probeCount: number;
65
+ readonly backoffDelayMs: number;
66
+ readonly frontierFrozen: boolean;
67
+ readonly authorityOutage: boolean;
68
+ readonly spoolLag: number;
69
+ readonly attempts: number;
70
+ readonly failures: number;
71
+ readonly p95Ms: number;
72
+ readonly failureRate: number;
73
+ readonly updatedAt: string;
74
+ /** "ephemeral" => per-process/in-memory breaker; "live" => persistent (VC0D). */
75
+ readonly stateSource: "ephemeral" | "live";
76
+ }
77
+
78
+ export interface TriadProvider<T> {
79
+ readonly session: string;
80
+ readonly subsystem: string;
81
+ readonly inputDigest: string;
82
+ /** Mode A — optimized/learned. */
83
+ readonly runA: () => T;
84
+ /** Mode B — deterministic local spool, derives directly from authority. */
85
+ readonly runB: () => T;
86
+ /** Mode C — unchanged current transcript (continuity, NOT completeness). */
87
+ readonly runC: () => T;
88
+ readonly validate: (v: T) => boolean;
89
+ }
90
+
91
+ export interface VectorCortexSafety {
92
+ /**
93
+ * Select A, then independent B, then unchanged C BEFORE provider invocation.
94
+ * Demotes on live failure; the selected mode's output is the only thing served
95
+ * (probe output is never served).
96
+ */
97
+ select<T>(provider: TriadProvider<T>): TriadResult<T>;
98
+ /** Reader-only aggregate for GET /api/vector-cortex/health. */
99
+ health(): VectorCortexHealthSummary;
100
+ /** The mode-B durable spool (append before provider; drain on recovery). */
101
+ readonly spool: Spool;
102
+ /** Admin reset: clears cooldown, never evidence. Returns the new record. */
103
+ reset(subsystem: string): BreakerRecord;
104
+ /** Manual halt with a required reason (authority/digest/causal corruption). */
105
+ halt(reason: string): BreakerRecord;
106
+ }
107
+
108
+ /** Build the live safety envelope, wiring the emit seam into the breaker. */
109
+ export function createVectorCortexSafety(
110
+ ctx: VectorCortexSafetyContext,
111
+ emit?: (event: string, fields: Record<string, unknown>) => void,
112
+ ): VectorCortexSafety {
113
+ const reporter: ResilienceReporter = createResilienceReporter(emit);
114
+ const wallNow = ctx.wallNow ?? (() => new Date().toISOString());
115
+ const breaker = createBreaker({ now: ctx.now, reporter, wallNow });
116
+ const spool = createSpool({
117
+ dir: join(ctx.stateDir, "spool"),
118
+ authorityOutage: ctx.authorityOutage,
119
+ // Wire the resilience emit seam (incl. vector_cortex_frontier_frozen) into
120
+ // the mode-B spool so a real authority-frontier freeze is observable.
121
+ reporter,
122
+ });
123
+
124
+ return {
125
+ spool,
126
+ select<T>(provider: TriadProvider<T>): TriadResult<T> {
127
+ const { subsystem, inputDigest, runA, runB, runC, validate } = provider;
128
+ // Thin delegation to the breaker: it selects the highest healthy mode
129
+ // (A, else independent B, else unchanged C) BEFORE provider invocation and
130
+ // records the attempt/trip. Across invocations A-failure demotes to B and
131
+ // B-failure demotes to C (continuity — unchanged transcript).
132
+ return breaker.execute(
133
+ subsystem,
134
+ inputDigest,
135
+ { A: runA, B: runB, C: runC },
136
+ validate,
137
+ );
138
+ },
139
+
140
+ health(): VectorCortexHealthSummary {
141
+ const rec = breaker.snapshot("provider");
142
+ const enabled = VC0C_ENABLED();
143
+ // LIVENESS HONESTY (VC0C-Q01/Q06): this breaker is created fresh per request
144
+ // and is ephemeral — declare it explicitly so the dashboard never presents it
145
+ // as a live breaker. `authorityOutage` is mirrored from the host context when
146
+ // supplied (otherwise false). `frontierFrozen` (rec.frozenFrontier) and
147
+ // `spoolLag` are owned by the DURABLE spool, which has no live per-session
148
+ // handle here — they stay static/no-op until VC0D wires a persistent breaker
149
+ // instance; stateSource:"ephemeral" is the signal that they are not live.
150
+ return {
151
+ enabled,
152
+ mode: rec.state === "MANUAL_HALT" ? "C" : rec.state === "CLOSED_A" ? "A" : "B",
153
+ state: rec.state,
154
+ subsystem: "provider",
155
+ sinceMs: rec.transitionedAtMs,
156
+ reason: rec.manualReason,
157
+ windowMs: BREAKER_WINDOW_MS,
158
+ probeCount: rec.probeCount,
159
+ backoffDelayMs: rec.retryDelayMs,
160
+ frontierFrozen: rec.frozenFrontier,
161
+ authorityOutage: ctx.authorityOutage?.() ?? false,
162
+ spoolLag: 0,
163
+ attempts: rec.attempts,
164
+ failures: rec.failures,
165
+ p95Ms: rec.p95Ms,
166
+ failureRate: rec.failureRate,
167
+ updatedAt: wallNow(),
168
+ stateSource: "ephemeral",
169
+ };
170
+ },
171
+
172
+ reset(subsystem: string): BreakerRecord {
173
+ return breaker.reset(subsystem);
174
+ },
175
+
176
+ halt(reason: string): BreakerRecord {
177
+ return breaker.manualHalt(reason);
178
+ },
179
+ };
180
+ }
181
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.16.3",
3
+ "version": "0.17.1",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -47,6 +47,7 @@
47
47
  "clean": "rm -rf dist",
48
48
  "prebuild": "npm run clean",
49
49
  "build": "tsc -p tsconfig.json",
50
+ "postbuild": "node scripts/vector-cortex-publish-acceptance.mjs",
50
51
  "build:dashboard": "cd extensions/dashboard-client && npx vite build",
51
52
  "test:dashboard-smoke": "node scripts/dashboard-tab-smoke.mjs",
52
53
  "lint": "tsc --noEmit && node scripts/guardrails-scan.mjs && node scripts/semantic-scan.mjs",
@@ -0,0 +1,98 @@
1
+ /**
2
+ * config/vector-cortex.ts — vector-cortex feature flags + breaker/triad constants.
3
+ *
4
+ * Every sprint ships one positive `MEGACOMPACT_<SPRINT>` flag, default ON and
5
+ * `=0`/`_DISABLED` off. Flag-OFF is byte-identical to the predecessor sprint's
6
+ * behavior (for VC0A: mode C — observer absent, zero evaluation writes).
7
+ *
8
+ * The breaker/triad constants (TRIAD_RESILIENCE.md) live here so VC0C consumes
9
+ * them without re-declaring the ownership boundary. Pi-agnostic, dependency-free.
10
+ */
11
+
12
+ /** Positive sprint flag: `=0` or `_DISABLED=true` disables (default ON). */
13
+ function sprintFlag(name: string): boolean {
14
+ const v = process.env[name];
15
+ if (v === "0" || v === "false") return false;
16
+ const disabled = process.env[name + "_DISABLED"];
17
+ if (disabled === "true" || disabled === "1") return false;
18
+ return true;
19
+ }
20
+
21
+ /** VC0A — baseline observability (MetricEventV1 / AnnotationV1). Default ON. */
22
+ export const VC0A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC0A");
23
+
24
+ /**
25
+ * VC0B — replay correctness (ReplayCutV2 / ReplayReportV2, M3 effective-cut-v2).
26
+ * Default ON. `MEGACOMPACT_VC0B=0` disables and is byte-identical to the
27
+ * predecessor (legacy capped-replay behavior preserved; the v2 cut/replay is
28
+ * only consulted on the vector-cortex path).
29
+ */
30
+ export const VC0B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC0B");
31
+
32
+ /**
33
+ * VC1A — canonical byte events (EventV2 / EventCodec).
34
+ * Default ON. `MEGACOMPACT_VC1A=0` disables and is byte-identical to the
35
+ * predecessor (mode C: ledger absent, current transcript codec unchanged).
36
+ * The single real consumer is the ledger emit seam (`ledger/emit.ts`): flag OFF
37
+ * gates zero observability writes.
38
+ */
39
+ export const VC1A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC1A");
40
+
41
+ /**
42
+ * VC1B — occurrence ledger + tool identity + compat journal (LedgerReader/
43
+ * Writer/Admin, CompatJournalV1, M2 occurrence-v2 migration).
44
+ * Default ON. `MEGACOMPACT_VC1B=0` disables and is byte-identical to the
45
+ * predecessor (mode C: the neutral occurrence ledger is not written, no
46
+ * journal rows, zero `vector_cortex_occurrence_appended` emissions). The real
47
+ * consumers are the ledger write integration seam and the compat-journal
48
+ * switch seam.
49
+ */
50
+ export const VC1B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC1B");
51
+
52
+ /**
53
+ * VC0C — live safety envelope (TriadResult / Breaker / KillDecision + durable
54
+ * spool). Default ON. `MEGACOMPACT_VC0C=0` disables and is byte-identical to
55
+ * the predecessor (mode C: selected before provider invocation, unchanged host
56
+ * transcript, breaker/spool idle and emitting nothing). The single real
57
+ * consumer is the resilience emit seam + the safety adapter's triad selection.
58
+ */
59
+ export const VC0C_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC0C");
60
+
61
+ /**
62
+ * VC1C — cross-language conformance v2 (FixtureManifestV2 / DowngradeReport /
63
+ * MinHashV2 + M4 minhash-v2 migration).
64
+ * Default ON. `MEGACOMPACT_VC1C=0` disables and is byte-identical to the
65
+ * predecessor (mode C: a v2 conformance runner that accepts authority fixtures
66
+ * and the manifest validator idle; the sync dedup scan stays on the v1 path;
67
+ * zero `vector_cortex_*` VC1C emissions). The real consumers are the conformance
68
+ * emit seam, the minhash-v2 backfill seam and the downgrade-export seam.
69
+ */
70
+ export const VC1C_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC1C");
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Breaker state machine constants (TRIAD_RESILIENCE.md §breaker).
74
+ // Rolled numbers for one 60s window; VC0C consumes these at its breaker seam.
75
+ // ---------------------------------------------------------------------------
76
+
77
+ /** Rolling eligibility window (milliseconds). */
78
+ export const BREAKER_WINDOW_MS = 60_000;
79
+ /** Minimum attempts before a breaker may trip or promote. */
80
+ export const BREAKER_MIN_ATTEMPTS = 20;
81
+ /** Performance trip: ≥ this many failures in window, or ≥ this fraction. */
82
+ export const BREAKER_PERF_FAILURES = 5;
83
+ export const BREAKER_PERF_FAILURE_RATE = 0.1;
84
+ /** Correctness trip trips on the first correctness failure. */
85
+ export const BREAKER_CORRECTNESS_FAILURES = 1;
86
+ /** Cooldown before an open breaker may probe (milliseconds). */
87
+ export const BREAKER_COOLDOWN_MS = 30_000;
88
+ /** Consecutive successful probes required to advance a state. */
89
+ export const BREAKER_PROBE_COUNT = 3;
90
+ /** Exponential retry base: 30s * 2^attempt, capped, ±10% jitter. */
91
+ export const BREAKER_RETRY_BASE_MS = 30_000;
92
+ export const BREAKER_RETRY_CAP_MS = 15 * 60_000;
93
+ export const BREAKER_RETRY_JITTER = 0.1;
94
+ /** Promotion hysteresis: failure rate must be < this and p95 within budget. */
95
+ export const BREAKER_HYSTERESIS_FAILURE_RATE = 0.02;
96
+ export const BREAKER_HYSTERESIS_BUDGET_P95_MS = 50;
97
+ /** Minimum healthy residence before a further promotion (milliseconds). */
98
+ export const BREAKER_MIN_HEALTHY_RESIDENCE_MS = 5 * 60_000;
package/src/config.ts CHANGED
@@ -143,3 +143,31 @@ export const RAG_HYDE_ENABLED = (): boolean =>
143
143
 
144
144
  /** Spec 1: vbrainstorm visual design migration for the dashboard. */
145
145
  export const NEW_UI = (): boolean => ragEnabled("MEGACOMPACT_NEW_UI");
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // Vector-cortex flags + breaker constants (VC0A+). Positive sprint flags,
149
+ // default ON, `=0`/`_DISABLED` off. Re-exported from src/config/vector-cortex.ts
150
+ // so root consumers share one source of truth.
151
+ // ---------------------------------------------------------------------------
152
+
153
+ export {
154
+ VC0A_ENABLED,
155
+ VC0B_ENABLED,
156
+ VC1A_ENABLED,
157
+ VC0C_ENABLED,
158
+ VC1B_ENABLED,
159
+ VC1C_ENABLED,
160
+ BREAKER_WINDOW_MS,
161
+ BREAKER_MIN_ATTEMPTS,
162
+ BREAKER_PERF_FAILURES,
163
+ BREAKER_PERF_FAILURE_RATE,
164
+ BREAKER_CORRECTNESS_FAILURES,
165
+ BREAKER_COOLDOWN_MS,
166
+ BREAKER_PROBE_COUNT,
167
+ BREAKER_RETRY_BASE_MS,
168
+ BREAKER_RETRY_CAP_MS,
169
+ BREAKER_RETRY_JITTER,
170
+ BREAKER_HYSTERESIS_FAILURE_RATE,
171
+ BREAKER_HYSTERESIS_BUDGET_P95_MS,
172
+ BREAKER_MIN_HEALTHY_RESIDENCE_MS,
173
+ } from "./config/vector-cortex.js";
@@ -0,0 +1,78 @@
1
+ /**
2
+ * l1-lsh-v2.ts — Locality-Sensitive Hashing banding over MinHashV2 signatures
3
+ * (VC1C, M4 minhash-v2).
4
+ *
5
+ * Splits the frozen 2048-byte v2 signature (256 x u64 LE slots) into 64 bands
6
+ * of FOUR u64 values each. Each band yields a deterministic bucket key derived
7
+ * from its 4 u64 little-endian bytes (32 bytes) hashed with a 64-bit FNV-1a,
8
+ * scoped by session id and the frozen v2 version tag so buckets never collide
9
+ * across sessions or the v1 path. Deterministic: same (sessionId,
10
+ * signatureBytes) -> same 64 bucket keys, every run, every language.
11
+ *
12
+ * Mixed v1/v2 comparison and bucket mixing is REJECTED upstream with
13
+ * `MINHASH_VERSION_MISMATCH` (see minhash-v2 migration); this module only ever
14
+ * bands a v2 signature.
15
+ *
16
+ * Pure compute, no deps, no storage, no network (PREVENT-PI-004 / PREVENT-011).
17
+ */
18
+
19
+ import {
20
+ MINHASH_VERSION,
21
+ NUM_HASHES_V2,
22
+ U64_BYTES,
23
+ } from "./l1-minhash-v2.js";
24
+
25
+ /** Number of bands (frozen). */
26
+ export const BANDS_V2 = 64 as const;
27
+
28
+ /** u64 slots per band (frozen): 64 * 4 = 256 total slots. */
29
+ export const VALUES_PER_BAND_V2 = 4 as const;
30
+
31
+ /** Band byte length: 4 u64 LE = 32 bytes. */
32
+ export const BAND_BYTES_V2 = VALUES_PER_BAND_V2 * U64_BYTES;
33
+
34
+ /** Total signature byte length this scheme expects (256 * 8 = 2048). */
35
+ export const SIGNATURE_BYTES_EXPECTED_V2 = NUM_HASHES_V2 * U64_BYTES;
36
+
37
+ const MASK64 = 0xffffffffffffffffn;
38
+
39
+ /** 64-bit FNV-1a over a byte buffer. */
40
+ function fnv1a64Bytes(buf: Uint8Array): bigint {
41
+ let h = 0xcbf29ce484222325n;
42
+ for (let i = 0; i < buf.length; i++) {
43
+ h ^= BigInt(buf[i] ?? 0);
44
+ h = (h * 0x100000001b3n) & MASK64;
45
+ }
46
+ return h;
47
+ }
48
+
49
+ /**
50
+ * Compute the 64 LSH bucket keys for a v2 signature within a session. `bytes`
51
+ * is the 2048-byte little-endian signature (see encodeSignatureV2). Each bucket
52
+ * key is the hex of an 8-byte little-endian FNV-1a-64 over the band's 32 bytes
53
+ * prefixed by `<sessionId>|v2|band-` — so the "bucket bytes" are deterministic
54
+ * and reproducible across languages.
55
+ */
56
+ export function lshBandsV2(
57
+ bytes: Uint8Array,
58
+ sessionId: string,
59
+ version: number = MINHASH_VERSION,
60
+ ): string[] {
61
+ if (bytes.length !== SIGNATURE_BYTES_EXPECTED_V2) {
62
+ throw new Error(
63
+ `lshBandsV2: expected ${SIGNATURE_BYTES_EXPECTED_V2} signature bytes, got ${bytes.length}`,
64
+ );
65
+ }
66
+ const keys: string[] = [];
67
+ const prefix = Buffer.from(`${sessionId}|v${version}|`, "utf8");
68
+ for (let band = 0; band < BANDS_V2; band++) {
69
+ const start = band * BAND_BYTES_V2;
70
+ const bandBytes = bytes.slice(start, start + BAND_BYTES_V2);
71
+ const combined = Buffer.concat([prefix, Buffer.from(bandBytes)]);
72
+ const h = fnv1a64Bytes(combined);
73
+ const out = Buffer.allocUnsafe(U64_BYTES);
74
+ out.writeBigUInt64LE(h, 0);
75
+ keys.push(`b${band}:${out.toString("hex")}`);
76
+ }
77
+ return keys;
78
+ }