pi-mega-compact 0.21.0 → 0.21.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.
@@ -35,6 +35,30 @@ export const ReductionValidator = {
35
35
  return { effective, liveBefore, liveAfter };
36
36
  },
37
37
  };
38
+ /**
39
+ * Disarm the ThrashGuard — clears the persisted `blocked_until` so subsequent
40
+ * compactions are not refused. Called when a compaction is judged EFFECTIVE
41
+ * (the thrash condition is over) and on session start (so a stale guard from a
42
+ * prior session cannot suppress the next session's compactions).
43
+ *
44
+ * Best-effort: any failure is swallowed (never blocks on a store fault).
45
+ */
46
+ export function disarmThrashGuard(stateDir, logger, emit) {
47
+ try {
48
+ setMetaNumber(THRASH_BLOCKED_KEY, 0, stateDir);
49
+ setMetaNumber(THRASH_BASELINE_KEY, 0, stateDir);
50
+ logger?.info("thrasguard_disarmed", { reason: "effective_or_reset" });
51
+ try {
52
+ emit?.("thrasguard_disarmed", { reason: "effective_or_reset" });
53
+ }
54
+ catch {
55
+ /* non-fatal */
56
+ }
57
+ }
58
+ catch {
59
+ /* non-fatal: best-effort meta write */
60
+ }
61
+ }
38
62
  /**
39
63
  * Arm the ThrashGuard after an ineffective compaction. Persists:
40
64
  * - `thrasguard.baseline_tokens` = the live currentTokens at this (post-fire)
@@ -201,6 +225,16 @@ export function evaluatePendingReduction(runtime, currentTokens, config) {
201
225
  : undefined;
202
226
  armThrashGuard(currentTokens, config.thrashRearmPct, runtime.effectiveThreshold, runtime.currentStateDir, runtime.logger, emit);
203
227
  }
228
+ else {
229
+ // Effective compaction — the thrash condition is over. Disarm the guard
230
+ // so it does not block legitimate subsequent compactions (the bug: without
231
+ // this, `blocked_until` from the prior ineffective fire persists and blocks
232
+ // the now-smaller window from ever re-firing).
233
+ const emit = typeof runtime.appendEvent === "function"
234
+ ? runtime.appendEvent.bind(runtime)
235
+ : undefined;
236
+ disarmThrashGuard(runtime.currentStateDir, runtime.logger, emit);
237
+ }
204
238
  }
205
239
  catch {
206
240
  /* non-fatal */
@@ -5,6 +5,7 @@ import { doRecall, doRecallAsync } from "../mega-pipeline.js";
5
5
  import { recallMemoriesAndInline } from "../../src/recall.js";
6
6
  import { vectorStats } from "../../src/vectorStore.js";
7
7
  import { openTurnStore } from "../../src/store/turns/connection.js";
8
+ import { disarmThrashGuard } from "./context-handler/thrashGuard.js";
8
9
  import { openIntentQueue } from "../../src/intent.js";
9
10
  /** Register session lifecycle event handlers. */
10
11
  export function registerSessionHandlers(pi, runtime, config) {
@@ -15,6 +16,17 @@ export function registerSessionHandlers(pi, runtime, config) {
15
16
  });
16
17
  pi.on("session_start", async (event, ctx) => {
17
18
  runtime.resetRuntime(ctx.sessionManager.getSessionId());
19
+ // Disarm the ThrashGuard on session start so a stale `blocked_until` from a
20
+ // prior session cannot suppress this session's compactions. Bind FIRST:
21
+ // currentStateDir defaults to the global dir until bindRepo resolves the
22
+ // per-repo <repo>/.pi/mega-compact store, and the guard arms in the
23
+ // PER-REPO store — disarming before the bind would clear the wrong (global)
24
+ // dir after a process restart. Gated on the umbrella so flag-OFF stays
25
+ // byte-identical (no meta writes).
26
+ if (config.threeWayFailback) {
27
+ runtime.bindRepo(ctx.cwd);
28
+ disarmThrashGuard(runtime.currentStateDir);
29
+ }
18
30
  runtime.captureModel(ctx); // best-effort: ctx.model may be set by session start
19
31
  runtime.setStatus(ctx, config.auto ? "mega-compact: ready" : "mega-compact: manual only");
20
32
  // S21: clear any stale memory block from a prior session.
@@ -62,6 +62,33 @@ export const ReductionValidator = {
62
62
  },
63
63
  };
64
64
 
65
+ /**
66
+ * Disarm the ThrashGuard — clears the persisted `blocked_until` so subsequent
67
+ * compactions are not refused. Called when a compaction is judged EFFECTIVE
68
+ * (the thrash condition is over) and on session start (so a stale guard from a
69
+ * prior session cannot suppress the next session's compactions).
70
+ *
71
+ * Best-effort: any failure is swallowed (never blocks on a store fault).
72
+ */
73
+ export function disarmThrashGuard(
74
+ stateDir: string,
75
+ logger?: { info(event: string, fields?: Record<string, unknown>): void },
76
+ emit?: (event: string, fields: Record<string, unknown>) => void,
77
+ ): void {
78
+ try {
79
+ setMetaNumber(THRASH_BLOCKED_KEY, 0, stateDir);
80
+ setMetaNumber(THRASH_BASELINE_KEY, 0, stateDir);
81
+ logger?.info("thrasguard_disarmed", { reason: "effective_or_reset" });
82
+ try {
83
+ emit?.("thrasguard_disarmed", { reason: "effective_or_reset" });
84
+ } catch {
85
+ /* non-fatal */
86
+ }
87
+ } catch {
88
+ /* non-fatal: best-effort meta write */
89
+ }
90
+ }
91
+
65
92
  /**
66
93
  * Arm the ThrashGuard after an ineffective compaction. Persists:
67
94
  * - `thrasguard.baseline_tokens` = the live currentTokens at this (post-fire)
@@ -245,6 +272,16 @@ export function evaluatePendingReduction(
245
272
  runtime.logger,
246
273
  emit,
247
274
  );
275
+ } else {
276
+ // Effective compaction — the thrash condition is over. Disarm the guard
277
+ // so it does not block legitimate subsequent compactions (the bug: without
278
+ // this, `blocked_until` from the prior ineffective fire persists and blocks
279
+ // the now-smaller window from ever re-firing).
280
+ const emit =
281
+ typeof runtime.appendEvent === "function"
282
+ ? runtime.appendEvent.bind(runtime)
283
+ : undefined;
284
+ disarmThrashGuard(runtime.currentStateDir, runtime.logger, emit);
248
285
  }
249
286
  } catch {
250
287
  /* non-fatal */
@@ -16,6 +16,7 @@ import { doRecall, doRecallAsync } from "../mega-pipeline.js";
16
16
  import { recallMemoriesAndInline } from "../../src/recall.js";
17
17
  import { vectorStats } from "../../src/vectorStore.js";
18
18
  import { openTurnStore } from "../../src/store/turns/connection.js";
19
+ import { disarmThrashGuard } from "./context-handler/thrashGuard.js";
19
20
  import { openIntentQueue } from "../../src/intent.js";
20
21
  import type { MegaConfig } from "../mega-config.js";
21
22
 
@@ -33,6 +34,17 @@ export function registerSessionHandlers(
33
34
 
34
35
  pi.on("session_start", async (event, ctx) => {
35
36
  runtime.resetRuntime(ctx.sessionManager.getSessionId());
37
+ // Disarm the ThrashGuard on session start so a stale `blocked_until` from a
38
+ // prior session cannot suppress this session's compactions. Bind FIRST:
39
+ // currentStateDir defaults to the global dir until bindRepo resolves the
40
+ // per-repo <repo>/.pi/mega-compact store, and the guard arms in the
41
+ // PER-REPO store — disarming before the bind would clear the wrong (global)
42
+ // dir after a process restart. Gated on the umbrella so flag-OFF stays
43
+ // byte-identical (no meta writes).
44
+ if (config.threeWayFailback) {
45
+ runtime.bindRepo(ctx.cwd);
46
+ disarmThrashGuard(runtime.currentStateDir);
47
+ }
36
48
  runtime.captureModel(ctx); // best-effort: ctx.model may be set by session start
37
49
  runtime.setStatus(
38
50
  ctx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.21.0",
3
+ "version": "0.21.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",