pi-mega-compact 0.21.3 → 0.21.4

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 (131) hide show
  1. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.js +12 -2
  2. package/dist/extensions/mega-events/context-handler/afterCompact.js +11 -0
  3. package/dist/extensions/mega-events/context-handler/dbMirrorAppend.js +8 -0
  4. package/dist/extensions/mega-events/health-handler.js +12 -2
  5. package/dist/extensions/mega-events/session-handlers.js +1 -0
  6. package/dist/extensions/mega-pipeline/compact/run.js +11 -0
  7. package/dist/extensions/mega-runtime/helpers.js +45 -0
  8. package/dist/extensions/mega-runtime/internal-errors.js +14 -0
  9. package/dist/extensions/mega-runtime/runtime-instrumentation.js +166 -0
  10. package/dist/extensions/mega-runtime/runtime.js +27 -193
  11. package/dist/extensions/mega-runtime/state.js +1 -1
  12. package/dist/extensions/mega-runtime/widget.js +1 -1
  13. package/dist/extensions/mega-turn-store.js +5 -0
  14. package/dist/src/bridge/factory.js +15 -1
  15. package/dist/src/contextHealth.js +13 -5
  16. package/dist/src/metrics/turns.js +6 -1
  17. package/dist/src/store/sqlite/context-health-cache-poison.js +60 -0
  18. package/dist/src/store/sqlite/context-health.js +6 -48
  19. package/dist/src/store/sqlite/embedding-cache.js +4 -0
  20. package/dist/src/store/sqlite/schema.js +4 -0
  21. package/dist/src/store/turns/memory-store/admin.js +119 -0
  22. package/dist/src/store/turns/memory-store/ctx.js +28 -0
  23. package/dist/src/store/turns/memory-store/read.js +110 -0
  24. package/dist/src/store/turns/memory-store/write.js +88 -0
  25. package/dist/src/store/turns/memory-store.js +44 -273
  26. package/dist/src/store/turns/migrations.js +4 -0
  27. package/dist/src/store/turns/schema.js +1 -0
  28. package/dist/src/store/turns/sqlite-store/read.js +13 -0
  29. package/dist/src/store/turns/sqlite-store/rows.js +4 -0
  30. package/dist/src/store/turns/sqlite-store/write.js +3 -3
  31. package/dist/src/store/turns/sqlite-store.js +4 -0
  32. package/extensions/dashboard-client/dist/assets/{AdminTab-BsA8-_bX.js → AdminTab-C4Y0_UVx.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{AdminTab-BsA8-_bX.js.map → AdminTab-C4Y0_UVx.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{AreaChart-BRHEfWhc.js → AreaChart-MCWK9rn6.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{AreaChart-BRHEfWhc.js.map → AreaChart-MCWK9rn6.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{BarChart-C-M0LaFc.js → BarChart-CvSGAiWV.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{BarChart-C-M0LaFc.js.map → BarChart-CvSGAiWV.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{CacheTab-Cj3n59U3.js → CacheTab-DnMEVRro.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{CacheTab-Cj3n59U3.js.map → CacheTab-DnMEVRro.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{ConfigTab-C016XTNC.js → ConfigTab-BExuZYy2.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{ConfigTab-C016XTNC.js.map → ConfigTab-BExuZYy2.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/{EventsTab-DE29fuqe.js → EventsTab-CspsEslY.js} +2 -2
  43. package/extensions/dashboard-client/dist/assets/{EventsTab-DE29fuqe.js.map → EventsTab-CspsEslY.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/HealthTab-DiWzo2ML.js +2 -0
  45. package/extensions/dashboard-client/dist/assets/HealthTab-DiWzo2ML.js.map +1 -0
  46. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-4fJ7M4S4.js → MaintenanceTab-9NJuv3dB.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-4fJ7M4S4.js.map → MaintenanceTab-9NJuv3dB.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-CDbcK9e4.js → MemoryMapTab-YpJK1h17.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-CDbcK9e4.js.map → MemoryMapTab-YpJK1h17.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{MetricsCards-VUEcgGzo.js → MetricsCards-D2Mom1M7.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{MetricsCards-VUEcgGzo.js.map → MetricsCards-D2Mom1M7.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/MetricsTab-DqWF7wud.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/{MetricsTab-CKqJ0Zl-.js.map → MetricsTab-DqWF7wud.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{OverviewTab-9Kxo79mi.js → OverviewTab-YuRxjV9U.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{OverviewTab-9Kxo79mi.js.map → OverviewTab-YuRxjV9U.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{ReposTab-C4iveqrP.js → ReposTab-sXMrR7je.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{ReposTab-C4iveqrP.js.map → ReposTab-sXMrR7je.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{SessionsTab-DSEwkMQm.js → SessionsTab-4YCXeGNR.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{SessionsTab-DSEwkMQm.js.map → SessionsTab-4YCXeGNR.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{SetupTab-CCyWgy4O.js → SetupTab-67pZcM_W.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{SetupTab-CCyWgy4O.js.map → SetupTab-67pZcM_W.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CyD8e_e_.js → TimeSavedCard-DInjNETP.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CyD8e_e_.js.map → TimeSavedCard-DInjNETP.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/{TurnMemoryView-5tLbWkRv.js → TurnMemoryView-C3Bif8ix.js} +2 -2
  65. package/extensions/dashboard-client/dist/assets/{TurnMemoryView-5tLbWkRv.js.map → TurnMemoryView-C3Bif8ix.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/assets/TurnsTab-BUGfiANp.js +2 -0
  67. package/extensions/dashboard-client/dist/assets/{TurnsTab-C7pm92Hg.js.map → TurnsTab-BUGfiANp.js.map} +1 -1
  68. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-ObhcIyfN.js → VcStatusBadge-DKU7qz9f.js} +2 -2
  69. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-ObhcIyfN.js.map → VcStatusBadge-DKU7qz9f.js.map} +1 -1
  70. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BtHZb7o7.js → VectorCortexTab-BsVSf4xm.js} +2 -2
  71. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BtHZb7o7.js.map → VectorCortexTab-BsVSf4xm.js.map} +1 -1
  72. package/extensions/dashboard-client/dist/assets/{WikiTab-lQ4l3QIK.js → WikiTab-DZw9_Fwd.js} +2 -2
  73. package/extensions/dashboard-client/dist/assets/{WikiTab-lQ4l3QIK.js.map → WikiTab-DZw9_Fwd.js.map} +1 -1
  74. package/extensions/dashboard-client/dist/assets/{button-DhQQAJGm.js → button-BLRPN489.js} +2 -2
  75. package/extensions/dashboard-client/dist/assets/{button-DhQQAJGm.js.map → button-BLRPN489.js.map} +1 -1
  76. package/extensions/dashboard-client/dist/assets/{card-Cfhz9X31.js → card-BGkkcM4Q.js} +2 -2
  77. package/extensions/dashboard-client/dist/assets/{card-Cfhz9X31.js.map → card-BGkkcM4Q.js.map} +1 -1
  78. package/extensions/dashboard-client/dist/assets/{client-extra-CKNOGEz_.js → client-extra-0OJClxHD.js} +2 -2
  79. package/extensions/dashboard-client/dist/assets/{client-extra-CKNOGEz_.js.map → client-extra-0OJClxHD.js.map} +1 -1
  80. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-JKjK9_cB.js → generateCategoricalChart-Dl5lmrHF.js} +2 -2
  81. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-JKjK9_cB.js.map → generateCategoricalChart-Dl5lmrHF.js.map} +1 -1
  82. package/extensions/dashboard-client/dist/assets/health-lSeDFTz7.js.map +1 -1
  83. package/extensions/dashboard-client/dist/assets/{index-iuxgtzEW.js → index-CH_AD-S_.js} +3 -3
  84. package/extensions/dashboard-client/dist/assets/{index-iuxgtzEW.js.map → index-CH_AD-S_.js.map} +1 -1
  85. package/extensions/dashboard-client/dist/assets/{switch-7EHEQMSP.js → switch-BPP2-d12.js} +2 -2
  86. package/extensions/dashboard-client/dist/assets/{switch-7EHEQMSP.js.map → switch-BPP2-d12.js.map} +1 -1
  87. package/extensions/dashboard-client/dist/assets/{toggle-z1lWY4UM.js → toggle-Dez0JaMV.js} +2 -2
  88. package/extensions/dashboard-client/dist/assets/{toggle-z1lWY4UM.js.map → toggle-Dez0JaMV.js.map} +1 -1
  89. package/extensions/dashboard-client/dist/assets/{useSSE-sctOZuRM.js → useSSE-Cx2W7BTo.js} +2 -2
  90. package/extensions/dashboard-client/dist/assets/{useSSE-sctOZuRM.js.map → useSSE-Cx2W7BTo.js.map} +1 -1
  91. package/extensions/dashboard-client/dist/index.html +1 -1
  92. package/extensions/dashboard-client/src/api/health.ts +1 -0
  93. package/extensions/dashboard-client/src/tabs/HealthTab.tsx +1 -0
  94. package/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.ts +12 -2
  95. package/extensions/mega-events/context-handler/afterCompact.ts +11 -0
  96. package/extensions/mega-events/context-handler/dbMirrorAppend.ts +8 -0
  97. package/extensions/mega-events/health-handler.ts +13 -3
  98. package/extensions/mega-events/session-handlers.ts +1 -0
  99. package/extensions/mega-pipeline/compact/run.ts +11 -0
  100. package/extensions/mega-runtime/helpers.ts +46 -0
  101. package/extensions/mega-runtime/internal-errors.ts +30 -0
  102. package/extensions/mega-runtime/runtime-instrumentation.ts +195 -0
  103. package/extensions/mega-runtime/runtime.ts +29 -209
  104. package/extensions/mega-runtime/state.ts +1 -1
  105. package/extensions/mega-runtime/widget.ts +1 -1
  106. package/extensions/mega-turn-store.ts +9 -0
  107. package/package.json +2 -2
  108. package/src/bridge/factory.ts +15 -1
  109. package/src/bridge/types.ts +2 -0
  110. package/src/contextHealth.ts +26 -6
  111. package/src/metrics/turns.ts +6 -1
  112. package/src/store/sqlite/context-health-cache-poison.ts +97 -0
  113. package/src/store/sqlite/context-health.ts +12 -84
  114. package/src/store/sqlite/embedding-cache.ts +4 -0
  115. package/src/store/sqlite/schema.ts +4 -0
  116. package/src/store/turns/memory-store/admin.ts +171 -0
  117. package/src/store/turns/memory-store/ctx.ts +62 -0
  118. package/src/store/turns/memory-store/read.ts +172 -0
  119. package/src/store/turns/memory-store/write.ts +126 -0
  120. package/src/store/turns/memory-store.ts +51 -330
  121. package/src/store/turns/migrations.ts +4 -0
  122. package/src/store/turns/schema.ts +1 -0
  123. package/src/store/turns/sqlite-store/read.ts +19 -0
  124. package/src/store/turns/sqlite-store/rows.ts +5 -0
  125. package/src/store/turns/sqlite-store/write.ts +3 -2
  126. package/src/store/turns/sqlite-store.ts +5 -0
  127. package/src/store/turns/types.ts +15 -0
  128. package/extensions/dashboard-client/dist/assets/HealthTab-D4eVI8ar.js +0 -2
  129. package/extensions/dashboard-client/dist/assets/HealthTab-D4eVI8ar.js.map +0 -1
  130. package/extensions/dashboard-client/dist/assets/MetricsTab-CKqJ0Zl-.js +0 -2
  131. package/extensions/dashboard-client/dist/assets/TurnsTab-C7pm92Hg.js +0 -2
@@ -1,4 +1,4 @@
1
- import { ensureConversationIdFor, recordTurnWrite } from "../../../mega-turn-store.js";
1
+ import { ensureConversationIdFor, recordTurnWrite, turnReaderFor } from "../../../mega-turn-store.js";
2
2
  /** S43: record one turn row with the cached metrics. Best-effort + non-fatal. */
3
3
  export function recordTurnRow(event, runtime, config) {
4
4
  // S43 (per-turn tracking): record one turn row with the cached metrics so
@@ -8,10 +8,16 @@ export function recordTurnRow(event, runtime, config) {
8
8
  // instead of silently producing a blank Turns tab.
9
9
  try {
10
10
  const convId = ensureConversationIdFor(config, runtime.rt.sessionId, runtime.currentStateDir);
11
+ // S49R: store the conversation-monotonic index (MAX+1) instead of the
12
+ // per-session event.turnIndex, which restarts at 0 on resume and would
13
+ // collide with UNIQUE(conversation_id, turn_index). Carry the session
14
+ // counter as sessionTurnIndex for the raw_transcript metrics join.
15
+ const turnIndex = turnReaderFor(runtime.currentStateDir).nextTurnIndexFor(convId);
11
16
  recordTurnWrite(config, {
12
17
  conversationId: convId,
13
18
  sessionId: runtime.rt.sessionId,
14
- turnIndex: event.turnIndex,
19
+ turnIndex,
20
+ sessionTurnIndex: event.turnIndex,
15
21
  role: event.role ?? "assistant",
16
22
  endedAt: Date.now(),
17
23
  startedAt: undefined,
@@ -34,5 +40,9 @@ export function recordTurnRow(event, runtime, config) {
34
40
  error: e instanceof Error ? e.message : String(e),
35
41
  stack: e instanceof Error ? e.stack?.split("\n").slice(0, 3).join(" | ") : undefined,
36
42
  });
43
+ // Sprint H (Finding 3 / Option A): the turn-row write is an internal
44
+ // store-write failure the API-error `errorRate` ring never sees. Feed the
45
+ // separate `storeErrorRate` 6th axis.
46
+ runtime.recordInternalError("store_write");
37
47
  }
38
48
  }
@@ -48,6 +48,8 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
48
48
  }
49
49
  catch (e) {
50
50
  runtime.logger.warn("planv2-epoch-fail", { error: String(e) });
51
+ // Sprint H (Option A): checkpoint_epoch write failure.
52
+ runtime.recordInternalError("store_write");
51
53
  }
52
54
  }
53
55
  // S27 DB-mirror downstream: stamp turns, rebuild wiki, seed topics, dedup.
@@ -136,6 +138,9 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
136
138
  runtime.logger.warn("wiki_rebuild_failed", {
137
139
  error: String(wikiErr),
138
140
  });
141
+ // Sprint H (Option A): wiki rebuild writes (topic model / overrides)
142
+ // to the isolated store — internal store write.
143
+ runtime.recordInternalError("store_write");
139
144
  }
140
145
  // D1: seed the topic model from raw_transcript when context_chunks is
141
146
  // thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
@@ -202,6 +207,9 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
202
207
  runtime.logger.warn("wiki_seed_failed", {
203
208
  error: String(seedErr),
204
209
  });
210
+ // Sprint H (Option A): wiki seed rebuild writes to the isolated
211
+ // store — internal store write.
212
+ runtime.recordInternalError("store_write");
205
213
  }
206
214
  // S27 Task 6: Fire-and-forget dedup pipeline.
207
215
  // Deduplicates raw_transcript rows for the compacted range.
@@ -215,6 +223,9 @@ export async function persistEpochAndMaintain(runtime, config, ran) {
215
223
  }
216
224
  catch (e) {
217
225
  runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
226
+ // Sprint H (Option A): db-mirror downstream maintenance writes
227
+ // (stamp turns epoch / wiki / seed / dedup) — internal store writes.
228
+ runtime.recordInternalError("store_write");
218
229
  }
219
230
  }
220
231
  // VC6 Heal lifecycle emits (post-compact). VC6A: closure-optimization
@@ -76,6 +76,9 @@ export function appendMirrorAndLedger(runtime, config, messages) {
76
76
  }
77
77
  catch (e) {
78
78
  runtime.logger.warn("db-mirror-append-fail", { error: String(e) });
79
+ // Sprint H (Option A): raw_transcript / thread / tool_results write
80
+ // failure — internal store write. Feed the `storeErrorRate` axis.
81
+ runtime.recordInternalError("store_write");
79
82
  }
80
83
  }
81
84
  // VC1B (S1): canonical messages -> v2 ledger occurrences. Flag-OFF opens
@@ -87,5 +90,10 @@ export function appendMirrorAndLedger(runtime, config, messages) {
87
90
  }
88
91
  catch (e) {
89
92
  runtime.logger.warn("vc1b-ledger-append-fail", { error: String(e) });
93
+ // Sprint H (Option A): the v2 vector-cortex ledger append is a cortex
94
+ // write — this is the host-side hook for the cortex seam (the cortex
95
+ // contract forbids the store from holding a runtime handle, so the ring
96
+ // push happens here in the adapter, not inside src/vector-cortex).
97
+ runtime.recordInternalError("vector_index");
90
98
  }
91
99
  }
@@ -8,6 +8,7 @@
8
8
  *
9
9
  * PREVENT-PI-004: zero network (local TrigramEmbedder + SQLite only).
10
10
  */
11
+ import { RING_MAX } from "../mega-runtime/runtime.js";
11
12
  import { defaultEmbedder } from "../../src/embedder.js";
12
13
  import { computeOutputQuality } from "../../src/contextHealth/outputQuality.js";
13
14
  import { computeTopicDrift, computeErrorEscalation, computePrefixInstability, computeDriftScore, } from "../../src/contextHealth/drift.js";
@@ -15,7 +16,6 @@ import { computePrefixHash, checkPrefixHash, evaluateCachePoison, } from "../../
15
16
  import { computeHealthScore, recordContextHealth, } from "../../src/contextHealth.js";
16
17
  import { recordCachePoisonEvent, } from "../../src/store/sqlite/context-health.js";
17
18
  import { getHealthMitigate } from "../../src/store/sqlite/meta.js";
18
- const RING_MAX = 5;
19
19
  /** Extract assistant text from the turn_end event message. */
20
20
  function extractAssistantText(event) {
21
21
  const msg = event.message;
@@ -69,8 +69,15 @@ export function handleTurnEndHealth(event, runtime, config) {
69
69
  const prefix = computePrefixInstability(0, 5);
70
70
  drift = computeDriftScore(topic, error, prefix);
71
71
  }
72
- // Error rate sub-score (1 = no errors)
72
+ // Error rate sub-score (1 = no errors) — API-retry errors only.
73
73
  const errorScore = computeErrorEscalation(runtime.recentErrorCategories);
74
+ // Sprint H (B2): store-error sub-score (1 = no store-write failures).
75
+ // Distinct from errorScore — internal store/service-write failures
76
+ // (turn rows, recall, dbMirror, ledger, epoch, stats, memory consolidate,
77
+ // compact persist, vector index, embedder, migration) never reach the
78
+ // API-retry errorRate ring. Mirrors computeErrorEscalation: 1 - (n/RING_MAX).
79
+ const recentInternalCount = Math.min(runtime.recentInternalErrors.length, RING_MAX);
80
+ const storeErrorScore = 1 - recentInternalCount / RING_MAX;
74
81
  // Cache health (from perf-handler)
75
82
  const cacheHealth = runtime.rt._lastCacheHealthScore ?? 1.0;
76
83
  // Cache poison sub-score
@@ -113,6 +120,7 @@ export function handleTurnEndHealth(event, runtime, config) {
113
120
  errorRate: errorScore,
114
121
  cacheHealth,
115
122
  cachePoison,
123
+ storeErrorRate: storeErrorScore,
116
124
  };
117
125
  const composite = computeHealthScore(sub);
118
126
  // Persist
@@ -126,6 +134,7 @@ export function handleTurnEndHealth(event, runtime, config) {
126
134
  cacheHealth,
127
135
  cachePoison,
128
136
  composite,
137
+ storeErrorScore,
129
138
  modelId: runtime.currentModel?.modelId,
130
139
  repetitionRatio,
131
140
  coherenceScore,
@@ -137,6 +146,7 @@ export function handleTurnEndHealth(event, runtime, config) {
137
146
  drift,
138
147
  outputQuality,
139
148
  errorRate: errorScore,
149
+ storeErrorRate: storeErrorScore,
140
150
  cacheHealth,
141
151
  cachePoison,
142
152
  turnIndex: event.turnIndex,
@@ -90,6 +90,7 @@ export function registerSessionHandlers(pi, runtime, config) {
90
90
  }
91
91
  catch (e) {
92
92
  runtime.logger.warn("db-auto-maintain-fail", { error: String(e) });
93
+ runtime.recordInternalError("store_write");
93
94
  }
94
95
  runtime.dashboard.event("session_start", {
95
96
  reason: event.reason,
@@ -130,6 +130,9 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
130
130
  logDaily(sid, "compact", result.checkpointId, saved, runtime.currentStateDir);
131
131
  }
132
132
  catch {
133
+ // Sprint H (Option A): session-activity / daily-log write is an internal
134
+ // store-write failure — feed the separate `storeErrorRate` axis.
135
+ runtime.recordInternalError("store_write");
133
136
  /* non-fatal: stats bookkeeping only */
134
137
  }
135
138
  // S21.2: best-effort consolidation of near-duplicate memories for this repo.
@@ -145,10 +148,14 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
145
148
  if (n > 0)
146
149
  runtime.pushTicker(`${C.green}∫${C.reset} consolidated ${n} memory dup${n === 1 ? "" : "s"}`);
147
150
  }, () => {
151
+ // Sprint H (Option A): memory-consolidation write failure.
152
+ runtime.recordInternalError("store_write");
148
153
  /* swallow: consolidate failures must never surface to the user */
149
154
  });
150
155
  }
151
156
  catch {
157
+ // Sprint H (Option A): memory-consolidation write failure (sync throw).
158
+ runtime.recordInternalError("store_write");
152
159
  /* non-fatal */
153
160
  }
154
161
  }
@@ -215,6 +222,8 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
215
222
  }
216
223
  }
217
224
  catch {
225
+ // Sprint H (Option A): RAPTOR tree-refresh write failure.
226
+ runtime.recordInternalError("vector_index");
218
227
  /* non-fatal: tree refresh never blocks a compaction */
219
228
  }
220
229
  }
@@ -228,6 +237,8 @@ function doCompact(view, keepFrom, opts, sid, config, pi, ctx, runtime) {
228
237
  const latest = all.find((cp) => cp.checkpointId === result.checkpointId);
229
238
  if (latest?.embedding) {
230
239
  void indexUpsertEmbedding(repoKey(runtime.currentStateDir), sid, latest.checkpointId, latest.embedding).catch(() => {
240
+ // Sprint H (Option A): async global vector-index upsert failure.
241
+ runtime.recordInternalError("vector_index");
231
242
  /* non-fatal: index refresh never blocks a compaction */
232
243
  });
233
244
  }
@@ -8,6 +8,7 @@
8
8
  import { join, dirname } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { readFileSync } from "node:fs";
11
+ import { normalizeSessionId } from "../../src/store.js";
11
12
  // ── Public string constants ────────────────────────────────────────────────
12
13
  // Exported via the barrel — consumers (mega-events.ts, mega-pipeline.ts) use
13
14
  // these keys to register widgets/markers with pi.
@@ -38,3 +39,47 @@ export function ownVersion() {
38
39
  CACHED_VERSION = v;
39
40
  return v;
40
41
  }
42
+ /**
43
+ * createSessionRuntime() — the default per-session runtime state.
44
+ *
45
+ * Extracted from runtime.ts (delegate-shell split) so the MegaRuntime class
46
+ * stays a field-declarations + 1-line-delegate shell. Returns a fresh
47
+ * SessionRuntime for each session (reset on session_start / session_tree).
48
+ * Mirrors the neuralwatt-mcr per-session closure.
49
+ */
50
+ export function createSessionRuntime() {
51
+ return {
52
+ sessionId: normalizeSessionId(undefined),
53
+ persistedThisSession: false,
54
+ lastCheckpointId: undefined,
55
+ lastCompactedFrom: 0,
56
+ lastCompactedTokens: 0,
57
+ dedupSkips: 0,
58
+ dedupAttempts: 0,
59
+ tokensSaved: 0,
60
+ lastCompactAt: null,
61
+ lastRecallAt: null,
62
+ lastInjectAt: null,
63
+ _prevCacheHitPct: null,
64
+ _lastCacheHealthScore: undefined,
65
+ lastNativeCompactAt: null,
66
+ compactCount: 0,
67
+ recallInjections: 0,
68
+ cacheHitTokens: 0,
69
+ lengthStopPending: false,
70
+ errorRetryCount: 0,
71
+ errorRetryUntil: 0,
72
+ consecutiveErrors: 0,
73
+ lastErrorRetryAt: 0,
74
+ retryNudgePending: false,
75
+ errorRetrySessionCount: 0,
76
+ lastErrorText: undefined,
77
+ errorTextRepeatCount: 0,
78
+ poisonedAdviseSent: false,
79
+ providerOutageAdvised: false,
80
+ poisonedCompactSignatures: new Set(),
81
+ recallInjectedThisTurn: false,
82
+ poisonedCount: 0,
83
+ extensionInitiatedTurn: false,
84
+ };
85
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * RING_MAX — the cap for the rolling health ring buffers
3
+ * (`recentTurnEmbeddings`, `recentErrorCategories`, `recentInternalErrors`).
4
+ * Defined here (with the ring writer) and re-exported from runtime.ts so the
5
+ * ring + its writer live together; health-handler.ts imports it.
6
+ */
7
+ export const RING_MAX = 5;
8
+ /** Push a category into the internal-error ring. Mirrors `recentErrorCategories`. */
9
+ export function recordInternalErrorImpl(rt, category) {
10
+ rt.recentInternalErrors.push(category);
11
+ if (rt.recentInternalErrors.length > RING_MAX) {
12
+ rt.recentInternalErrors.shift();
13
+ }
14
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * DIAG counters for the "team run doesn't relieve context" investigation.
3
+ * Plain integers, incremented at the three compaction decision points. They
4
+ * let a headless test drive the real event handlers and assert the firing
5
+ * cadence without scraping log files. Inert in production (the live-trim and
6
+ * before-compact probes also emit logger.info, but these counters are always
7
+ * updated and cost nothing).
8
+ */
9
+ export class RuntimeInstrumentation {
10
+ diagLiveTrimFires = 0; // context handler returned a trimmed view
11
+ diagLiveTrimReplays = 0; // v0.8.6: trim view returned via cached replay (skipped re-compact)
12
+ diagBeforeCompactFires = 0; // session_before_compact handler entered
13
+ diagBeforeCompactSupplied = 0; // session_before_compact supplied our trim
14
+ diagAgentEndIdle = 0; // agent_end with activeAgents===0
15
+ diagAgentEndDurable = 0; // agent_end fired ctx.compact() (mid-run durable trim)
16
+ diagAgentEndDurableSkipRecent = 0; // agent_end skipped ctx.compact() — compaction in last 10s (race guard)
17
+ // Per-skip-path counters for the team-run diagnosis.
18
+ diagCtxFastGate = 0; // returned at token fast-gate (below threshold)
19
+ diagCtxNoCompact = 0; // autoCompactCheck().shouldCompact === false
20
+ diagCtxDebounce = 0; // debounceUntil not yet elapsed
21
+ diagCtxRunSkipped = 0; // runCompact() returned skipped
22
+ diagCtxCutNull = 0; // computeLiveTrimCut returned null (anchor/boundary)
23
+ diagCtxThrown = 0; // live-trim try threw (caught)
24
+ // Context health instrumentation (v0.12): rolling ring buffers for
25
+ // drift detection + cache poison Layer 1 hash baseline.
26
+ recentTurnEmbeddings = [];
27
+ recentErrorCategories = [];
28
+ lastPrefixHash = null;
29
+ lastErrorCategory = null;
30
+ // Sprint H (Finding 3): a SEPARATE internal-error ring fed by explicit
31
+ // `recordInternalError(category)` calls at each store/service-write failure
32
+ // emit site (Option A — NOT a central events.log filter). This captures
33
+ // internal store-write failures which the API-error `errorRate` ring never
34
+ // sees. The health-handler computes a distinct `storeErrorRate` 6th axis.
35
+ // Mirrors `recentErrorCategories` / `lastErrorCategory` exactly (cap = RING_MAX).
36
+ recentInternalErrors = [];
37
+ /**
38
+ * S26 capture instrumentation: the "model_snapshots empty → $0.00 cost card"
39
+ * bug was invisible because captureModel swallowed the DB write in a silent
40
+ * `catch {}`. These always-updated counters (zero cost) let a headless test or
41
+ * a live capture tell whether captureModel ran and whether the snapshot landed.
42
+ */
43
+ diagCaptureModelCalls = 0; // captureModel entered with a populated ctx.model
44
+ diagCaptureModelFails = 0; // recordModelSnapshot threw → model_snapshots stays empty
45
+ // ── Live display / cache-stability state (moved from runtime.ts shell) ────
46
+ // v0.8.6 cache-stability: the cached live-trim view for the current
47
+ // compaction epoch. Set after a fresh runCompact + computeLiveTrimCut, and
48
+ // replayed verbatim on subsequent gated context events in the SAME epoch
49
+ // (same checkpointId) so the provider KV-cache prefix stays stable instead
50
+ // of being invalidated by a freshly regenerated summary + sentinel every
51
+ // fire. Invalidated on session restart (resetRuntime) and on any native
52
+ // durable compaction (session_compact) that truncates the transcript.
53
+ trimCache = null;
54
+ debounceUntil = 0;
55
+ // S16: debounce for the agent_end resume nudge (avoid busy-loops).
56
+ resumeNudgeUntil = 0;
57
+ // Agent tracking for real-time widget updates
58
+ activeAgents = 0;
59
+ currentTurn = 0;
60
+ // S33: transient MEGA CACHE flare flag (armed by the turn_end scoring hook
61
+ // when cachePct > 100). Copied into widgetData.megaCacheFlare on the next
62
+ // snapshot() so the widget renders the oopsie gag, then reset (one cycle).
63
+ megaCacheFlare = false;
64
+ /** v0.8.3: ambient effect state for animated panel borders keyed off
65
+ * status transitions (level-up, mega-cache overshoot, achievement unlock,
66
+ * compaction start). Threaded into widgetData as `activeEffect`; the widget
67
+ * computes the per-frame phase from startedAt vs Date.now() (non-expired).
68
+ * Null when idle/expired. */
69
+ activeEffect = null;
70
+ megaCacheFlarePct = 0;
71
+ levelUpFlare = false;
72
+ lastLevel = 0;
73
+ // S35: transient achievement-unlock flare (armed by the scoring hooks after
74
+ // evaluateAndUnlockAchievements returns newly-unlocked titles). Copied into
75
+ // widgetData.achievementFlare on the next snapshot() so the widget renders the
76
+ // unlock toast, then reset (one cycle — mirrors megaCacheFlare/levelUpFlare).
77
+ achievementFlare = false;
78
+ achievementFlareTitles = [];
79
+ // S33: last cumulative dedup-collapsed count seen by the session_compact
80
+ // hook, so we only record the DELTA as the dedupe score (leaderboard sums).
81
+ lastDedupCollapsed = 0;
82
+ // Recall block produced by auto-inline (resume/branch) that the next
83
+ // before_agent_start should prepend to the system prompt. Unset after use.
84
+ pendingRecallBlock;
85
+ // S21: memory recall block, parallel to pendingRecallBlock. Same one-shot
86
+ // semantics; composed with the checkpoint block in before_agent_start.
87
+ pendingMemoryRecallBlock;
88
+ statusKey; // current status text for dashboard
89
+ // Active model/provider (for real cost estimation). Captured from ctx.model
90
+ // on model_select + session_start; persisted to SQL so cost + the dashboard
91
+ // can read it without a live ctx.
92
+ currentModel;
93
+ // Live "what it's doing right now" timestamp, used for the fresh-window.
94
+ lastActivityAt = 0;
95
+ // Live per-tier dedup trace (Phase 1): e.g. "L0 ✓ → L1 ✓ → L2 0.91 → stored".
96
+ // Built from the store's sync onTier callback during a compaction so the user
97
+ // watches each tier evaluate in real time. Cleared once the outcome settles.
98
+ tierTrace;
99
+ // Phase 3 — standout toolbar state.
100
+ // Recall/activity ticker: a small ring buffer (≤5) of recent compact/recall
101
+ // events so the widget shows a live history instead of a single last action.
102
+ ticker = [];
103
+ TICKER_MAX = 5;
104
+ // Pulsing status: set true while a compaction is in flight, cleared on result.
105
+ pulsing = false;
106
+ // S21.2: set by `applyMemoryOps` when a memory add/replace/remove lands in
107
+ // the current compaction. The pipeline reads this after a successful compact
108
+ // to decide whether to fire `consolidateMemories` (skip the work entirely
109
+ // when no memory rows changed).
110
+ memoriesTouchedThisCompaction = 0;
111
+ // Rolling "saved" goal for the progress bar — grows as we save more, so the
112
+ // bar always has a meaningful denominator (never sits at 100% forever).
113
+ savedGoal = 50_000;
114
+ // Last explain-why line (dedup reason / anchor-kept / superseded), surfaced
115
+ // while fresh.
116
+ lastWhy = undefined;
117
+ // v0.8.8 Perf dashboard instrumentation: turn/provider start timestamps +
118
+ // the 5s cpu/mem interval handle (one per MegaRuntime, cleared in dispose()).
119
+ perfTurnStart = 0;
120
+ perfProviderStart = 0;
121
+ perfCpuInterval = null;
122
+ perfCpuBaseline;
123
+ // Context tracking for the dashboard (updated in the context handler).
124
+ lastCtxTokens = null;
125
+ lastCtxPercent = null;
126
+ lastCtxWindow = 0;
127
+ // Latest computed widget payload (recomputed per snapshot, rendered per frame).
128
+ widgetData = null;
129
+ // v0.8.5: material-change signature from the last full snapshot() body. When
130
+ // the next snapshot()'s signature matches, the expensive recompute (6 sync
131
+ // SQLite opens) + writeFileSync(dashboard.json) are skipped — only the
132
+ // (already-registered) widget factory is refreshed. Kills the per-event
133
+ // main-thread block during typing/idle streaming with no material change.
134
+ lastSnapshotSig = null;
135
+ lastHeartbeatAt = 0;
136
+ // v0.8.5: bumped whenever the cached game-state memo is evicted (bumpGameState
137
+ // for in-process /mega-game writes, the fs.watch callback for cross-process
138
+ // dashboard-server writes, and bindRepo on repo switch) so the snapshot gate
139
+ // invalidates and the widget re-reads theme/mode after the change.
140
+ gameStateBump = 0;
141
+ // Cached cross-repo drift status (recomputed at most every 30s — it opens the
142
+ // machine-wide registry DB, so we don't want to do it on every render frame).
143
+ driftCache = null;
144
+ // S31: cached game-mode state (game_mode_on/theme/tui_display_mode). Lazily
145
+ // read from the game_state SQLite row on the first widget render, then
146
+ // memoized until bumpGameState() evicts it (called by /mega-game after a
147
+ // write) so the widget picks up theme/mode/level changes live without
148
+ // re-querying the DB on every render frame.
149
+ cachedGameState;
150
+ // S32: fs.watch on the current repo's sqlite.db so cross-process writes
151
+ // (e.g. the dashboard server's PUT /api/game-state, which runs as a detached
152
+ // child with no MegaRuntime ref) evict the cached game-state memo. Without
153
+ // this, /mega-game's in-process bumpGameState() is the only eviction trigger
154
+ // and the widget would keep showing stale theme/mode/toggle after a dashboard
155
+ // edit until a restart. The watcher tracks currentStateDir — closed + re-opened
156
+ // by ensureGameStateWatcher() on every bindRepo repo switch. Non-fatal: any
157
+ // fs.watch failure (missing file / platform issue) is swallowed; the next
158
+ // getCachedGameState() snapshot re-queries the DB anyway.
159
+ gameStateWatcher;
160
+ gameStateWatchDir;
161
+ // P2: the last ExtensionContext handed to snapshot()/renderWidget(), stashed
162
+ // so the fs.watch game-state callback can force a widget re-render without
163
+ // a context event (cross-process dashboard edits while pi is idle). Cleared
164
+ // implicitly on construction (undefined → watcher skips until first snap).
165
+ lastWidgetCtx;
166
+ }