pi-mega-compact 0.20.22 → 0.20.24
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/resolve-snapshot.js +42 -28
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +2 -0
- package/dist/extensions/dashboard-server/routes-setup.js +4 -1
- package/dist/extensions/dashboard-server/routes-vector-cortex-crystals.js +11 -3
- package/dist/extensions/dashboard-server/routes-vector-cortex-diagnostics.js +7 -2
- package/dist/extensions/dashboard-server/routes-vector-cortex-economics.js +1 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-heal.js +18 -6
- package/dist/extensions/dashboard-server/routes-vector-cortex-policy.js +1 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-reconstruct.js +10 -3
- package/dist/extensions/dashboard-server/routes-vector-cortex-repair.js +13 -5
- package/dist/extensions/dashboard-server/routes-vector-cortex-shards.js +12 -4
- package/dist/extensions/dashboard-server/vc-event-counts.js +63 -0
- package/dist/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.js +15 -4
- package/dist/extensions/mega-events/context-handler/afterCompact.js +57 -4
- package/dist/extensions/mega-events/context-handler/dbMirrorAppend.js +35 -7
- package/dist/extensions/mega-events/context-handler/pipelineRun.js +33 -0
- package/dist/extensions/mega-events/context-handler/tailResult.js +45 -12
- package/dist/extensions/mega-runtime/dashboard-snapshot.js +9 -6
- package/dist/extensions/mega-runtime/runtime-snapshot.js +2 -0
- package/dist/extensions/mega-runtime/vc-observer.js +98 -0
- package/dist/src/cache-stripe-impl.js +52 -214
- package/dist/src/cache-stripe-score.js +115 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-BkfB-LSQ.js → AreaChart-BzEedilo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-BkfB-LSQ.js.map → AreaChart-BzEedilo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-Cs1kogko.js → BarChart-CzAVg1_J.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-Cs1kogko.js.map → BarChart-CzAVg1_J.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-BZgaguGr.js → CacheTab-D2-rzTuX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-BZgaguGr.js.map → CacheTab-D2-rzTuX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-BFbkI_MO.js → EventsTab-DB7g1Szy.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-BFbkI_MO.js.map → EventsTab-DB7g1Szy.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-CvlOENCX.js → HealthTab-Cvkmi-R3.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-CvlOENCX.js.map → HealthTab-Cvkmi-R3.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CtBuz2qL.js → MaintenanceTab-g_udcOO7.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CtBuz2qL.js.map → MaintenanceTab-g_udcOO7.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-K4775S4d.js → MemoryMapTab-DAjBaf8P.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-K4775S4d.js.map → MemoryMapTab-DAjBaf8P.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DVGcFInz.js → MetricsTab-13dYYocB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-DVGcFInz.js.map → MetricsTab-13dYYocB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-4LmW5ZCl.js → OverviewTab-CLpCyLvx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-4LmW5ZCl.js.map → OverviewTab-CLpCyLvx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-StebchgQ.js → ReposTab-EdAqUrwG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-StebchgQ.js.map → ReposTab-EdAqUrwG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C3D_XAkX.js → SessionsTab-C21ZuOL_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C3D_XAkX.js.map → SessionsTab-C21ZuOL_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-CP7lE3L_.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CP7lE3L_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CTPi_AAW.js → TimeSavedCard-DZ3QR8qt.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CTPi_AAW.js.map → TimeSavedCard-DZ3QR8qt.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DSOGcY5Q.js → TurnsTab-CNchE5rD.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DSOGcY5Q.js.map → TurnsTab-CNchE5rD.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-OMW8_RFf.js → VectorCortexTab-B3WuPeyn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-OMW8_RFf.js.map → VectorCortexTab-B3WuPeyn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-Db-qFDdg.js → WikiTab-BIe5Z9Nc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-Db-qFDdg.js.map → WikiTab-BIe5Z9Nc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-BF4UgBAD.js → button-BrVreSt5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-BF4UgBAD.js.map → button-BrVreSt5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-XmXoYQqB.js → card-D9F4wbqs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-XmXoYQqB.js.map → card-D9F4wbqs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Be8hM1aU.js → generateCategoricalChart-mkdzCnMP.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Be8hM1aU.js.map → generateCategoricalChart-mkdzCnMP.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-NXDgILxv.js → index-CtlmOlj1.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-NXDgILxv.js.map → index-CtlmOlj1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-kUZCrbia.js → switch-BXmp5iwA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-kUZCrbia.js.map → switch-BXmp5iwA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-DEe5mCwF.js → toggle-BgawNwW9.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-DEe5mCwF.js.map → toggle-BgawNwW9.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-BlCyLqge.js → useSSE-DZKX73Ea.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BlCyLqge.js.map → useSSE-DZKX73Ea.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/tabs/SetupTab/CustomEndpointSection.tsx +65 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +19 -108
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetupStyles.ts +69 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +5 -3
- package/extensions/dashboard-server/api-contracts/setup.ts +4 -3
- package/extensions/dashboard-server/api-contracts/vector-cortex-cache.ts +5 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-diagnostics.ts +2 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-economics.ts +2 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex-policy.ts +2 -0
- package/extensions/dashboard-server/resolve-snapshot.ts +42 -28
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +12 -0
- package/extensions/dashboard-server/routes-setup.ts +3 -1
- package/extensions/dashboard-server/routes-vector-cortex-crystals.ts +12 -3
- package/extensions/dashboard-server/routes-vector-cortex-diagnostics.ts +8 -2
- package/extensions/dashboard-server/routes-vector-cortex-economics.ts +1 -0
- package/extensions/dashboard-server/routes-vector-cortex-heal.ts +19 -6
- package/extensions/dashboard-server/routes-vector-cortex-policy.ts +1 -0
- package/extensions/dashboard-server/routes-vector-cortex-reconstruct.ts +11 -3
- package/extensions/dashboard-server/routes-vector-cortex-repair.ts +14 -5
- package/extensions/dashboard-server/routes-vector-cortex-shards.ts +13 -4
- package/extensions/dashboard-server/vc-event-counts.ts +67 -0
- package/extensions/mega-dashboard.ts +2 -0
- package/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.ts +13 -4
- package/extensions/mega-events/context-handler/afterCompact.ts +69 -4
- package/extensions/mega-events/context-handler/dbMirrorAppend.ts +39 -7
- package/extensions/mega-events/context-handler/pipelineRun.ts +39 -0
- package/extensions/mega-events/context-handler/tailResult.ts +56 -15
- package/extensions/mega-runtime/dashboard-snapshot.ts +12 -6
- package/extensions/mega-runtime/runtime-snapshot.ts +6 -0
- package/extensions/mega-runtime/vc-observer.ts +120 -0
- package/package.json +1 -1
- package/src/cache-stripe-impl.ts +73 -277
- package/src/cache-stripe-score.ts +170 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-BTBGyppF.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-BTBGyppF.js.map +0 -1
|
@@ -8,16 +8,14 @@
|
|
|
8
8
|
* Resolution order (the launch dir is the OWNer of this dashboard):
|
|
9
9
|
* 1. The launch stateDir's OWN dashboard.json — the pi process that launched
|
|
10
10
|
* this dashboard server is the session you are coding in, so its snapshot
|
|
11
|
-
* is "this session" by definition.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* the launch dir has no live snapshot yet (e.g. dashboard launched before
|
|
20
|
-
* any compaction wrote dashboard.json).
|
|
11
|
+
* is "this session" by definition. It must be fresh (updatedAt within
|
|
12
|
+
* STALE_MS) to win; otherwise the launch dir's pi process has exited or
|
|
13
|
+
* stopped snapshotting, and showing its stale data as "this session" is
|
|
14
|
+
* misleading. When stale, fall through to the most-recently-active repo.
|
|
15
|
+
* 2. Most recently seen repo (by last_seen in repo_registry) whose
|
|
16
|
+
* dashboard.json exists and has a non-null updatedAt — this includes the
|
|
17
|
+
* launch dir via the registry, so an exited-but-recent launch session
|
|
18
|
+
* still appears.
|
|
21
19
|
* 3. The static launch stateDir's dashboard.json (original behavior).
|
|
22
20
|
*/
|
|
23
21
|
import { existsSync } from "node:fs";
|
|
@@ -25,14 +23,29 @@ import { join } from "node:path";
|
|
|
25
23
|
import { createRequire } from "node:module";
|
|
26
24
|
import { readSnapshot } from "./snapshot.js";
|
|
27
25
|
import { getIndexDir } from "./index-reader.js";
|
|
26
|
+
/** Snapshots older than this are stale — the owning pi session has exited or
|
|
27
|
+
* stopped snapshotting. 5 minutes covers the slowest possible context event
|
|
28
|
+
* cadence + debounce + snapshot throttle. */
|
|
29
|
+
const STALE_MS = 5 * 60 * 1000;
|
|
30
|
+
/** Age of a snapshot's updatedAt in ms. Returns Infinity for invalid dates. */
|
|
31
|
+
function snapshotAgeMs(updatedAt) {
|
|
32
|
+
if (!updatedAt)
|
|
33
|
+
return Infinity;
|
|
34
|
+
const t = Date.parse(updatedAt);
|
|
35
|
+
if (Number.isNaN(t))
|
|
36
|
+
return Infinity;
|
|
37
|
+
return Date.now() - t;
|
|
38
|
+
}
|
|
28
39
|
const require = createRequire(import.meta.url);
|
|
29
40
|
/**
|
|
30
|
-
* Find the most recently active
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
41
|
+
* Find the most recently active repo's stateDir by scanning the repo registry
|
|
42
|
+
* for the repo with the highest last_seen whose dashboard.json exists and has
|
|
43
|
+
* a non-null updatedAt. Unlike the old `mostRecentOtherRepoStateDir`, this
|
|
44
|
+
* does NOT exclude the launch dir — when the launch dir's snapshot is stale
|
|
45
|
+
* but its registry entry has a recent last_seen (e.g. session just exited),
|
|
46
|
+
* it should still be eligible.
|
|
34
47
|
*/
|
|
35
|
-
function
|
|
48
|
+
function mostRecentActiveRepoStateDir(_launchStateDir) {
|
|
36
49
|
const indexPath = join(getIndexDir(), "index.sqlite");
|
|
37
50
|
if (!existsSync(indexPath))
|
|
38
51
|
return null;
|
|
@@ -43,9 +56,8 @@ function mostRecentOtherRepoStateDir(launchStateDir) {
|
|
|
43
56
|
const rows = db
|
|
44
57
|
.prepare(`SELECT state_dir, last_seen FROM repo_registry
|
|
45
58
|
WHERE state_dir IS NOT NULL AND last_seen IS NOT NULL
|
|
46
|
-
AND state_dir != @launch
|
|
47
59
|
ORDER BY last_seen DESC`)
|
|
48
|
-
.all(
|
|
60
|
+
.all();
|
|
49
61
|
for (const r of rows) {
|
|
50
62
|
const dashPath = join(r.state_dir, "dashboard.json");
|
|
51
63
|
if (!existsSync(dashPath))
|
|
@@ -70,24 +82,26 @@ function mostRecentOtherRepoStateDir(launchStateDir) {
|
|
|
70
82
|
}
|
|
71
83
|
}
|
|
72
84
|
/**
|
|
73
|
-
* Resolve the best snapshot to serve.
|
|
74
|
-
*
|
|
85
|
+
* Resolve the best snapshot to serve. The launch dir wins when its snapshot is
|
|
86
|
+
* fresh; when stale (or missing) the most recently active repo wins instead.
|
|
75
87
|
*/
|
|
76
88
|
export function resolveSnapshot(staticSnapshotPath, staticStateDir) {
|
|
77
|
-
// 1. The launch dir's OWN snapshot is "this session" —
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
89
|
+
// 1. The launch dir's OWN snapshot is "this session" — but only when it's
|
|
90
|
+
// fresh (updated within STALE_MS). A stale launch-dir snapshot means
|
|
91
|
+
// the pi process that owned it has exited or stopped snapshotting; serving
|
|
92
|
+
// its frozen data as "this session" is misleading. Fall through to the
|
|
93
|
+
// most-recently-active repo so the user sees the session that is actually
|
|
94
|
+
// running.
|
|
82
95
|
if (existsSync(staticSnapshotPath)) {
|
|
83
96
|
const launchSnap = readSnapshot(staticSnapshotPath);
|
|
84
|
-
if (launchSnap.updatedAt) {
|
|
97
|
+
if (launchSnap.updatedAt && snapshotAgeMs(launchSnap.updatedAt) < STALE_MS) {
|
|
85
98
|
return { snapshot: launchSnap, stateDir: staticStateDir };
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
|
-
// 2. Fall back to the most recently active OTHER repo (launch dir
|
|
89
|
-
// live snapshot yet).
|
|
90
|
-
|
|
101
|
+
// 2. Fall back to the most recently active OTHER repo (launch dir stale or
|
|
102
|
+
// had no live snapshot yet). The registry includes the launch dir too,
|
|
103
|
+
// so a recently-exited launch session can still appear.
|
|
104
|
+
const activeDir = mostRecentActiveRepoStateDir(staticStateDir);
|
|
91
105
|
if (activeDir) {
|
|
92
106
|
const activePath = join(activeDir, "dashboard.json");
|
|
93
107
|
const snap = readSnapshot(activePath);
|
|
@@ -50,6 +50,8 @@ export const SETTINGS = [
|
|
|
50
50
|
boolFlag("MEGACOMPACT_MEMORY_GRAPH", "Memory Graph", "Dashboard-oriented memory graph traversal", true),
|
|
51
51
|
boolFlag("MEGACOMPACT_HYDE", "HyDE", "Generate hypothetical answer via LLM, embed it, RRF-fuse", true, true),
|
|
52
52
|
boolFlag("MEGACOMPACT_NEW_UI", "New Dashboard UI", "Tailwind + shadcn visual design (sidebar, glass panels)", true),
|
|
53
|
+
boolDirect("MEGACOMPACT_MESSAGE_SEPARATION", "Message Separation (P2)", "PLAN_V2: split conversation thread from tool results to grow stable cache prefix", false),
|
|
54
|
+
boolDirect("MEGACOMPACT_CACHE_STRIPING", "Cache Striping (P3)", "PLAN_V2: order stable context by stability score so durable chunks lead the prompt", false),
|
|
53
55
|
],
|
|
54
56
|
},
|
|
55
57
|
{
|
|
@@ -193,6 +193,7 @@ export function handleSetupDetect(req, res, _ctx) {
|
|
|
193
193
|
// ---------------------------------------------------------------------------
|
|
194
194
|
const OLLAMA_DEFAULT_URL = "http://localhost:11434/api/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
|
|
195
195
|
const LLAMA_DEFAULT_URL = "http://localhost:8080/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
|
|
196
|
+
const ONNX_DEFAULT_URL = "http://localhost:8081/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch — TEI / ONNX embedding server
|
|
196
197
|
function readJsonBody(req, cb) {
|
|
197
198
|
let body = "";
|
|
198
199
|
let tooBig = false;
|
|
@@ -237,7 +238,7 @@ export function handleSetupConfigure(req, res, ctx) {
|
|
|
237
238
|
}
|
|
238
239
|
const body = parsed.value;
|
|
239
240
|
const embedder = body.embedder;
|
|
240
|
-
if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram" && embedder !== "custom") {
|
|
241
|
+
if (embedder !== "ollama" && embedder !== "llama" && embedder !== "trigram" && embedder !== "custom" && embedder !== "onnx") {
|
|
241
242
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
242
243
|
res.end(JSON.stringify({ error: "invalid_embedder" }));
|
|
243
244
|
return;
|
|
@@ -249,6 +250,8 @@ export function handleSetupConfigure(req, res, ctx) {
|
|
|
249
250
|
resolvedUrl = typeof url === "string" && url ? url : OLLAMA_DEFAULT_URL;
|
|
250
251
|
else if (embedder === "llama")
|
|
251
252
|
resolvedUrl = typeof url === "string" && url ? url : LLAMA_DEFAULT_URL;
|
|
253
|
+
else if (embedder === "onnx")
|
|
254
|
+
resolvedUrl = typeof url === "string" && url ? url : ONNX_DEFAULT_URL;
|
|
252
255
|
else if (embedder === "custom") {
|
|
253
256
|
// Third-party / remote endpoint. Requires a URL; opts in to the
|
|
254
257
|
// non-loopback allowlist so embeddingConfigFromEnv() accepts it.
|
|
@@ -25,13 +25,19 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { VC7A_ENABLED } from "../../src/config.js";
|
|
27
27
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
28
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
29
|
+
// Actual events emitted by src/vector-cortex/cache/crystal-emit.ts.
|
|
30
|
+
const CRYSTAL_EVENTS = [
|
|
31
|
+
"vector_cortex_crystal_written",
|
|
32
|
+
"vector_cortex_crystal_collision",
|
|
33
|
+
];
|
|
28
34
|
/**
|
|
29
35
|
* Reader-only GET /api/vector-cortex/cache-crystals (VC7A).
|
|
30
36
|
*
|
|
31
37
|
* Counts, byte volumes, and CRY_* codes only — a static reader-only aggregate
|
|
32
38
|
* seam with the same shape as the VC6A/VC6B/VC6C handlers.
|
|
33
39
|
*/
|
|
34
|
-
export function handleVectorCortexCrystals(req, res,
|
|
40
|
+
export function handleVectorCortexCrystals(req, res, ctx) {
|
|
35
41
|
const url = req.url ?? "";
|
|
36
42
|
const path = url.split("?")[0] ?? url;
|
|
37
43
|
if (path !== "/api/vector-cortex/cache-crystals")
|
|
@@ -41,6 +47,7 @@ export function handleVectorCortexCrystals(req, res, _ctx) {
|
|
|
41
47
|
return true;
|
|
42
48
|
}
|
|
43
49
|
const enabled = VC7A_ENABLED();
|
|
50
|
+
const counts = countVcEvents(ctx.stateDir, CRYSTAL_EVENTS);
|
|
44
51
|
// Flag-off routes to mode C: with VC7A off nothing is served from the crystal
|
|
45
52
|
// cache, which is exactly the spec's "cache bypass" outcome. Reporting A (hit)
|
|
46
53
|
// or B (fresh render forced by a miss) would imply a cache path that is not
|
|
@@ -49,16 +56,17 @@ export function handleVectorCortexCrystals(req, res, _ctx) {
|
|
|
49
56
|
const body = {
|
|
50
57
|
enabled,
|
|
51
58
|
mode,
|
|
52
|
-
crystalCount:
|
|
59
|
+
crystalCount: vcCount(counts, "vector_cortex_crystal_written"),
|
|
53
60
|
totalBytes: 0,
|
|
54
61
|
hits: 0,
|
|
55
62
|
misses: 0,
|
|
56
63
|
hitBytes: 0,
|
|
57
64
|
writes: 0,
|
|
58
65
|
duplicateWrites: 0,
|
|
59
|
-
collisions:
|
|
66
|
+
collisions: vcCount(counts, "vector_cortex_crystal_collision"),
|
|
60
67
|
lastFailure: null,
|
|
61
68
|
updatedAt: new Date().toISOString(),
|
|
69
|
+
deferredReason: "crystal_store_not_instantiated_v0_20_23",
|
|
62
70
|
};
|
|
63
71
|
sendJson(res, 200, body);
|
|
64
72
|
return true;
|
|
@@ -27,13 +27,16 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { VC7C_ENABLED } from "../../src/config.js";
|
|
29
29
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
30
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
31
|
+
// Actual events emitted by src/vector-cortex/cache/diagnostics-emit.ts.
|
|
32
|
+
const DIAGNOSTICS_EVENTS = ["vector_cortex_cache_serve_blocked"];
|
|
30
33
|
/**
|
|
31
34
|
* Reader-only GET /api/vector-cortex/cache-diagnostics (VC7C).
|
|
32
35
|
*
|
|
33
36
|
* Per-miss-class counts, breaker state, and CACHE and M5 codes only — a static
|
|
34
37
|
* reader-only aggregate seam with the same shape as the VC7B economics handler.
|
|
35
38
|
*/
|
|
36
|
-
export function handleVectorCortexDiagnostics(req, res,
|
|
39
|
+
export function handleVectorCortexDiagnostics(req, res, ctx) {
|
|
37
40
|
const url = req.url ?? "";
|
|
38
41
|
const path = url.split("?")[0] ?? url;
|
|
39
42
|
if (path !== "/api/vector-cortex/cache-diagnostics")
|
|
@@ -43,6 +46,7 @@ export function handleVectorCortexDiagnostics(req, res, _ctx) {
|
|
|
43
46
|
return true;
|
|
44
47
|
}
|
|
45
48
|
const enabled = VC7C_ENABLED();
|
|
49
|
+
const counts = countVcEvents(ctx.stateDir, DIAGNOSTICS_EVENTS);
|
|
46
50
|
// Flag-off routes to mode C: with VC7C off the diagnostics/breaker reporter is
|
|
47
51
|
// suppressed, so no cache serve is attested here and the surface reports the
|
|
48
52
|
// all-cache bypass outcome. Reporting A (crystal served) or B (fresh render
|
|
@@ -58,10 +62,11 @@ export function handleVectorCortexDiagnostics(req, res, _ctx) {
|
|
|
58
62
|
requestMisses: 0,
|
|
59
63
|
generationMisses: 0,
|
|
60
64
|
unknownMisses: 0,
|
|
61
|
-
serveBlocked:
|
|
65
|
+
serveBlocked: vcCount(counts, "vector_cortex_cache_serve_blocked"),
|
|
62
66
|
breakerState: "closed",
|
|
63
67
|
lastFailure: null,
|
|
64
68
|
updatedAt: new Date().toISOString(),
|
|
69
|
+
deferredReason: "cache_classifier_not_wired_v0_20_23",
|
|
65
70
|
};
|
|
66
71
|
sendJson(res, 200, body);
|
|
67
72
|
return true;
|
|
@@ -21,8 +21,18 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { VC6A_ENABLED, VC6B_ENABLED } from "../../src/config.js";
|
|
23
23
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
24
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
25
|
+
// Actual event names emitted by src/vector-cortex/heal/emit.ts + restore-emit.ts.
|
|
26
|
+
const CLOSURE_EVENTS = [
|
|
27
|
+
"vector_cortex_closure_optimized",
|
|
28
|
+
"vector_cortex_closure_proof_rejected",
|
|
29
|
+
];
|
|
30
|
+
const RESTORE_EVENTS = [
|
|
31
|
+
"vector_cortex_source_restored",
|
|
32
|
+
"vector_cortex_restore_digest_rejected",
|
|
33
|
+
];
|
|
24
34
|
/** Reader-only GET /api/vector-cortex/closure-proof (VC6A). */
|
|
25
|
-
export function handleVectorCortexClosureProof(req, res,
|
|
35
|
+
export function handleVectorCortexClosureProof(req, res, ctx) {
|
|
26
36
|
const url = req.url ?? "";
|
|
27
37
|
const path = url.split("?")[0] ?? url;
|
|
28
38
|
if (path !== "/api/vector-cortex/closure-proof")
|
|
@@ -32,13 +42,14 @@ export function handleVectorCortexClosureProof(req, res, _ctx) {
|
|
|
32
42
|
return true;
|
|
33
43
|
}
|
|
34
44
|
const enabled = VC6A_ENABLED();
|
|
45
|
+
const counts = countVcEvents(ctx.stateDir, CLOSURE_EVENTS);
|
|
35
46
|
// Flag-off routes to mode B (conservative closure, no reduction) per spec.
|
|
36
47
|
const mode = enabled ? "A" : "B";
|
|
37
48
|
const body = {
|
|
38
49
|
enabled,
|
|
39
50
|
mode,
|
|
40
|
-
optimizations:
|
|
41
|
-
proofRejections:
|
|
51
|
+
optimizations: vcCount(counts, "vector_cortex_closure_optimized"),
|
|
52
|
+
proofRejections: vcCount(counts, "vector_cortex_closure_proof_rejected"),
|
|
42
53
|
retainedEdgeTotal: 0,
|
|
43
54
|
removedEdgeTotal: 0,
|
|
44
55
|
conservativeTraversalTotal: 0,
|
|
@@ -56,7 +67,7 @@ export function handleVectorCortexClosureProof(req, res, _ctx) {
|
|
|
56
67
|
* seam (same shape as the VC6A handler): there is no payload endpoint and never
|
|
57
68
|
* will be, so no restored bytes/span ids/node ids/ledger text can leak here.
|
|
58
69
|
*/
|
|
59
|
-
export function handleVectorCortexRestore(req, res,
|
|
70
|
+
export function handleVectorCortexRestore(req, res, ctx) {
|
|
60
71
|
const url = req.url ?? "";
|
|
61
72
|
const path = url.split("?")[0] ?? url;
|
|
62
73
|
if (path !== "/api/vector-cortex/restore")
|
|
@@ -66,6 +77,7 @@ export function handleVectorCortexRestore(req, res, _ctx) {
|
|
|
66
77
|
return true;
|
|
67
78
|
}
|
|
68
79
|
const enabled = VC6B_ENABLED();
|
|
80
|
+
const counts = countVcEvents(ctx.stateDir, RESTORE_EVENTS);
|
|
69
81
|
// Flag-off routes to mode C: with VC6B off there is no exact-restoration path
|
|
70
82
|
// at all, so the honest OFF view is the disclose-loss mode (old context is
|
|
71
83
|
// omitted rather than inferred) — mirroring how VC6A's OFF view reports the
|
|
@@ -74,10 +86,10 @@ export function handleVectorCortexRestore(req, res, _ctx) {
|
|
|
74
86
|
const body = {
|
|
75
87
|
enabled,
|
|
76
88
|
mode,
|
|
77
|
-
restoreAttempts:
|
|
89
|
+
restoreAttempts: vcCount(counts, "vector_cortex_source_restored"),
|
|
78
90
|
restoredCount: 0,
|
|
79
91
|
missingCount: 0,
|
|
80
|
-
digestRejections:
|
|
92
|
+
digestRejections: vcCount(counts, "vector_cortex_restore_digest_rejected"),
|
|
81
93
|
lastRejection: null,
|
|
82
94
|
updatedAt: new Date().toISOString(),
|
|
83
95
|
};
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { VC4C_ENABLED } from "../../src/config.js";
|
|
10
10
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
11
|
-
|
|
11
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
12
|
+
// Closure attempt/rejection events emitted by src/vector-cortex/heal/emit.ts.
|
|
13
|
+
const RECONSTRUCT_EVENTS = [
|
|
14
|
+
"vector_cortex_closure_optimized",
|
|
15
|
+
"vector_cortex_closure_proof_rejected",
|
|
16
|
+
];
|
|
17
|
+
export function handleVectorCortexReconstruct(req, res, ctx) {
|
|
12
18
|
const url = req.url ?? "";
|
|
13
19
|
const path = url.split("?")[0] ?? url;
|
|
14
20
|
if (path !== "/api/vector-cortex/reconstruct")
|
|
@@ -18,10 +24,11 @@ export function handleVectorCortexReconstruct(req, res, _ctx) {
|
|
|
18
24
|
return true;
|
|
19
25
|
}
|
|
20
26
|
const enabled = VC4C_ENABLED();
|
|
27
|
+
const counts = countVcEvents(ctx.stateDir, RECONSTRUCT_EVENTS);
|
|
21
28
|
const body = {
|
|
22
29
|
enabled,
|
|
23
|
-
closureAttempts:
|
|
24
|
-
closureRejections:
|
|
30
|
+
closureAttempts: vcCount(counts, "vector_cortex_closure_optimized"),
|
|
31
|
+
closureRejections: vcCount(counts, "vector_cortex_closure_proof_rejected"),
|
|
25
32
|
validatedCount: 0,
|
|
26
33
|
invalidatedCount: 0,
|
|
27
34
|
spanTotal: 0,
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { VC6C_ENABLED } from "../../src/config.js";
|
|
24
24
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
25
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
26
|
+
// Actual event names emitted by src/vector-cortex/heal/repair-emit.ts.
|
|
27
|
+
const REPAIR_EVENTS = [
|
|
28
|
+
"vector_cortex_repair_planned",
|
|
29
|
+
"vector_cortex_repair_pointer_switched",
|
|
30
|
+
"vector_cortex_repair_backoff",
|
|
31
|
+
];
|
|
25
32
|
/**
|
|
26
33
|
* Reader-only GET /api/vector-cortex/repair (VC6C).
|
|
27
34
|
*
|
|
@@ -30,7 +37,7 @@ import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
|
30
37
|
* never will be, so no subsystem bytes, gap ranges, high-water marks, or root
|
|
31
38
|
* digests can leak here.
|
|
32
39
|
*/
|
|
33
|
-
export function handleVectorCortexRepair(req, res,
|
|
40
|
+
export function handleVectorCortexRepair(req, res, ctx) {
|
|
34
41
|
const url = req.url ?? "";
|
|
35
42
|
const path = url.split("?")[0] ?? url;
|
|
36
43
|
if (path !== "/api/vector-cortex/repair")
|
|
@@ -40,6 +47,7 @@ export function handleVectorCortexRepair(req, res, _ctx) {
|
|
|
40
47
|
return true;
|
|
41
48
|
}
|
|
42
49
|
const enabled = VC6C_ENABLED();
|
|
50
|
+
const counts = countVcEvents(ctx.stateDir, REPAIR_EVENTS);
|
|
43
51
|
// Flag-off routes to mode C: with VC6C off no self-healing controller runs at
|
|
44
52
|
// all, so neither the targeted rebuild (mode A) nor the full deterministic
|
|
45
53
|
// rebuild (mode B) path is available. Mode C is exactly the spec's "derived
|
|
@@ -50,10 +58,10 @@ export function handleVectorCortexRepair(req, res, _ctx) {
|
|
|
50
58
|
const body = {
|
|
51
59
|
enabled,
|
|
52
60
|
mode,
|
|
53
|
-
repairAttempts:
|
|
54
|
-
repairsPlanned:
|
|
55
|
-
pointersSwitched:
|
|
56
|
-
backoffs:
|
|
61
|
+
repairAttempts: vcCount(counts, "vector_cortex_repair_planned"),
|
|
62
|
+
repairsPlanned: vcCount(counts, "vector_cortex_repair_planned"),
|
|
63
|
+
pointersSwitched: vcCount(counts, "vector_cortex_repair_pointer_switched"),
|
|
64
|
+
backoffs: vcCount(counts, "vector_cortex_repair_backoff"),
|
|
57
65
|
lastBackoffMs: null,
|
|
58
66
|
lastFailure: null,
|
|
59
67
|
updatedAt: new Date().toISOString(),
|
|
@@ -19,10 +19,16 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { VC4A_ENABLED } from "../../src/config.js";
|
|
21
21
|
import { sendJson } from "./routes-vector-cortex-shared.js";
|
|
22
|
+
import { countVcEvents, vcCount } from "./vc-event-counts.js";
|
|
23
|
+
// Actual events emitted by src/vector-cortex/shards/manifest.ts. VC4A has no
|
|
24
|
+
// per-tier (semantic/exact) write event — the manifest build is the single
|
|
25
|
+
// shard-write signal — so semanticCount is wired to it and exactCount stays 0
|
|
26
|
+
// until a per-tier write event exists.
|
|
27
|
+
const SHARD_EVENTS = ["vector_cortex_shard_manifest_built"];
|
|
22
28
|
/**
|
|
23
29
|
* Reader-only GET /api/vector-cortex/shards (VC4A).
|
|
24
30
|
*/
|
|
25
|
-
export function handleVectorCortexShards(req, res,
|
|
31
|
+
export function handleVectorCortexShards(req, res, ctx) {
|
|
26
32
|
const url = req.url ?? "";
|
|
27
33
|
const path = url.split("?")[0] ?? url;
|
|
28
34
|
if (path !== "/api/vector-cortex/shards")
|
|
@@ -33,11 +39,13 @@ export function handleVectorCortexShards(req, res, _ctx) {
|
|
|
33
39
|
return true;
|
|
34
40
|
}
|
|
35
41
|
const enabled = VC4A_ENABLED();
|
|
42
|
+
const counts = countVcEvents(ctx.stateDir, SHARD_EVENTS);
|
|
36
43
|
const body = {
|
|
37
44
|
enabled,
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
|
|
45
|
+
// The manifest-build event is the only VC4A shard-write signal; semanticCount
|
|
46
|
+
// reflects manifests built and exactCount stays 0 (no per-tier write event
|
|
47
|
+
// distinguishes exact shards in events.log yet).
|
|
48
|
+
semanticCount: vcCount(counts, "vector_cortex_shard_manifest_built"),
|
|
41
49
|
exactCount: 0,
|
|
42
50
|
byteTotal: 0,
|
|
43
51
|
protectedByteTotal: 0,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/vc-event-counts.ts — lightweight events.log tail reader for
|
|
3
|
+
* the Vector Cortex dashboard routes.
|
|
4
|
+
*
|
|
5
|
+
* The VC event reporters in `src/vector-cortex/*` emit structured JSON events
|
|
6
|
+
* (one per line) into the per-repo `events.log`. Instead of the dashboard
|
|
7
|
+
* hardcoding zero for aggregate counters, this module reads the event tail and
|
|
8
|
+
* counts real occurrences of named events. It is the single shared seam so every
|
|
9
|
+
* route stays a small, thin consumer and the counting logic lives in one place
|
|
10
|
+
* (extensions/ 400-line soft-as-hard split trigger).
|
|
11
|
+
*
|
|
12
|
+
* NEVER throws: a missing/unreadable file degrades to an empty Map, malformed
|
|
13
|
+
* lines are skipped silently, and only the `.event` string field is inspected —
|
|
14
|
+
* no payload, bytes, span ids, digests, or ledger text ever leaves this module
|
|
15
|
+
* (SECURITY_PRIVACY, reader-only aggregate).
|
|
16
|
+
*
|
|
17
|
+
* Guardrails: PREVENT-PI-004 (local in-process file read only), PREVENT-011
|
|
18
|
+
* (no `any`).
|
|
19
|
+
*/
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { readFileSync } from "node:fs";
|
|
22
|
+
/**
|
|
23
|
+
* Count occurrences of the given named events within the last `maxLines` of the
|
|
24
|
+
* per-repo events.log adjacent to `stateDir`. Returns a Map keyed by event name;
|
|
25
|
+
* a missing/unreadable log or zero matching lines yields an empty Map. Best-effort
|
|
26
|
+
* and non-fatal by construction (matches the non-fatal-stores invariant).
|
|
27
|
+
*/
|
|
28
|
+
export function countVcEvents(stateDir, eventNames, maxLines = 10000) {
|
|
29
|
+
const counts = new Map();
|
|
30
|
+
let raw;
|
|
31
|
+
try {
|
|
32
|
+
raw = readFileSync(join(stateDir, "events.log"), "utf-8");
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Missing or unreadable log → nothing to count, never throw.
|
|
36
|
+
return counts;
|
|
37
|
+
}
|
|
38
|
+
// Walk only the tail: split into lines and keep the last `maxLines`.
|
|
39
|
+
const lines = raw.split("\n");
|
|
40
|
+
const start = Math.max(0, lines.length - maxLines);
|
|
41
|
+
const wanted = new Set(eventNames);
|
|
42
|
+
for (let i = start; i < lines.length; i++) {
|
|
43
|
+
const line = lines[i];
|
|
44
|
+
if (line.length === 0)
|
|
45
|
+
continue;
|
|
46
|
+
let ev = null;
|
|
47
|
+
try {
|
|
48
|
+
ev = JSON.parse(line);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Malformed line — skip silently, never break the reader.
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (typeof ev?.event === "string" && wanted.has(ev.event)) {
|
|
55
|
+
counts.set(ev.event, (counts.get(ev.event) ?? 0) + 1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return counts;
|
|
59
|
+
}
|
|
60
|
+
/** Read a value from an event-count map, defaulting to 0 when absent. */
|
|
61
|
+
export function vcCount(counts, name) {
|
|
62
|
+
return counts.get(name) ?? 0;
|
|
63
|
+
}
|
|
@@ -10,12 +10,23 @@ export function cacheStripe(event, runtime, config) {
|
|
|
10
10
|
const currentTurn = event.turnIndex;
|
|
11
11
|
const embedder = defaultEmbedder();
|
|
12
12
|
// (a) Extract text from the assistant's response for topic embedding.
|
|
13
|
+
// pi's assistant content may be a plain string OR an array of parts.
|
|
14
|
+
// Discriminate by type and only reach into `.text` after confirming the
|
|
15
|
+
// part is an object carrying a string `.text` — never assume shape.
|
|
13
16
|
let textToEmbed = "";
|
|
14
17
|
const msg = event.message;
|
|
15
|
-
if (msg.role === "assistant"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
if (msg.role === "assistant") {
|
|
19
|
+
const c = msg.content;
|
|
20
|
+
if (typeof c === "string") {
|
|
21
|
+
textToEmbed = c;
|
|
22
|
+
}
|
|
23
|
+
else if (Array.isArray(c)) {
|
|
24
|
+
for (const part of c) {
|
|
25
|
+
if (part && typeof part === "object" && "text" in part) {
|
|
26
|
+
const t = part.text;
|
|
27
|
+
if (typeof t === "string")
|
|
28
|
+
textToEmbed += t + " ";
|
|
29
|
+
}
|
|
19
30
|
}
|
|
20
31
|
}
|
|
21
32
|
}
|
|
@@ -15,14 +15,20 @@ import { openTurnStore } from "../../../src/store/turns/connection.js";
|
|
|
15
15
|
import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, applyOverridesAfterRebuild, applyFullOverridesAfterRebuild, } from "../../../src/topics/index.js";
|
|
16
16
|
import { assignNewMemoriesIncremental } from "../../../src/wiki/index.js";
|
|
17
17
|
import { TrigramEmbedder } from "../../../src/embedder.js";
|
|
18
|
+
import { reportClosureOptimized } from "../../../src/vector-cortex/heal/emit.js";
|
|
19
|
+
import { reportRepairPlanned } from "../../../src/vector-cortex/heal/repair-emit.js";
|
|
20
|
+
import { VC6A_ENABLED, VC6C_ENABLED } from "../../../src/config/vector-cortex.js";
|
|
18
21
|
/**
|
|
19
22
|
* Persist the checkpoint_epoch, stamp turns, rebuild the auto-wiki, seed the
|
|
20
23
|
* topic model, and dedup — gated on dbMirror. Non-fatal end-to-end.
|
|
21
24
|
*/
|
|
22
25
|
export async function persistEpochAndMaintain(runtime, config, ran) {
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
+
// PLAN_V2 cache-striping epoch row. buildCacheOptimizedPrompt's stripe
|
|
27
|
+
// lookup reads the most-recent checkpoint_epochs row, so emit it whenever
|
|
28
|
+
// PLAN_V2 flags are live. Separate from the legacy dbMirror block below so
|
|
29
|
+
// PLAN_V2 can run with dbMirror OFF (flag-on is a genuine additive; flag-OFF
|
|
30
|
+
// = byte-identical to the predecessor, since this block no-ops then).
|
|
31
|
+
if (config.dbMirror || config.messageSeparation || config.cacheStriping) {
|
|
26
32
|
try {
|
|
27
33
|
const db = openStore(runtime.currentStateDir);
|
|
28
34
|
const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
|
|
@@ -37,11 +43,27 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
|
|
|
37
43
|
createdAt: Date.now(),
|
|
38
44
|
};
|
|
39
45
|
writeCheckpointEpoch(db, epoch);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
runtime.logger.warn("planv2-epoch-fail", { error: String(e) });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// S27 DB-mirror downstream: stamp turns, rebuild wiki, seed topics, dedup.
|
|
52
|
+
// Remains on `config.dbMirror` only — these are DB-mirror maintenance and
|
|
53
|
+
// must NOT run for PLAN_V2-only configurations.
|
|
54
|
+
if (config.dbMirror) {
|
|
55
|
+
try {
|
|
56
|
+
const db = openStore(runtime.currentStateDir);
|
|
57
|
+
const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
|
|
58
|
+
// epoch + writeCheckpointEpoch moved to the PLAN_V2 block above (it
|
|
59
|
+
// gates the wider set of flags); reuse epochIdFor(cpId) here so the
|
|
60
|
+
// stamps below land in the same epoch row.
|
|
61
|
+
const epochId = epochIdFor(cpId);
|
|
40
62
|
// S50B: link this session's turns to the epoch that just compacted
|
|
41
63
|
// them (compression-by-conversation-epoch metrics). Isolated-store
|
|
42
64
|
// only; best-effort + non-fatal.
|
|
43
65
|
try {
|
|
44
|
-
stampTurnsEpochFor(config, runtime.rt.sessionId,
|
|
66
|
+
stampTurnsEpochFor(config, runtime.rt.sessionId, epochId, runtime.currentStateDir);
|
|
45
67
|
}
|
|
46
68
|
catch {
|
|
47
69
|
/* non-fatal: epoch stamping never breaks compaction */
|
|
@@ -193,4 +215,35 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
|
|
|
193
215
|
runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
|
|
194
216
|
}
|
|
195
217
|
}
|
|
218
|
+
// VC6 Heal lifecycle emits (post-compact). Wiring stubs — dashboard graph +
|
|
219
|
+
// event counts move; real gap detection/rebuild is a future sprint.
|
|
220
|
+
// VC6A: closure-optimization savings from the compact token delta.
|
|
221
|
+
const savings = Math.max(0, (ran.result.originalTokenEstimate ?? 0) - (ran.result.tokenEstimate ?? 0));
|
|
222
|
+
if (VC6A_ENABLED()) {
|
|
223
|
+
try {
|
|
224
|
+
reportClosureOptimized((name, payload) => runtime.appendEvent(name, payload), {
|
|
225
|
+
sessionId: runtime.rt.sessionId,
|
|
226
|
+
removed: 0,
|
|
227
|
+
retained: ran.result.compactedFrom,
|
|
228
|
+
savings,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
/* non-fatal: VC6A heal emit never breaks compaction */
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// VC6C: repair-planner placeholder (no real gap detection yet).
|
|
236
|
+
if (VC6C_ENABLED()) {
|
|
237
|
+
try {
|
|
238
|
+
reportRepairPlanned((name, payload) => runtime.appendEvent(name, payload), {
|
|
239
|
+
subsystem: "post_compact",
|
|
240
|
+
generation: 1,
|
|
241
|
+
backoffMs: 0,
|
|
242
|
+
gapSize: 0,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
/* non-fatal: VC6C heal emit never breaks compaction */
|
|
247
|
+
}
|
|
248
|
+
}
|
|
196
249
|
}
|