@lmzhen/dsh-evolution-replay 0.3.67 → 0.3.68

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/lib/index.js CHANGED
@@ -88,7 +88,7 @@ function comparePlans(plans, weights = DEFAULT_WEIGHTS) {
88
88
  report: scored.map(({ plan, score }) => `${plan.policyId}: ${score.toFixed(1)} (${plan.acceptedOps} accepted, ${plan.rejectedOps} rejected${(plan.executionFailures ?? 0) > 0 ? `, ${plan.executionFailures} failed${plan.executionError !== void 0 ? `: ${plan.executionError}` : ""}` : ""})`).join("\n")
89
89
  };
90
90
  }
91
- var EvolutionReplayDriver = class {
91
+ var EvolutionReplayDriver = class EvolutionReplayDriver {
92
92
  plans = [];
93
93
  maxPlans;
94
94
  /** V25-01 (v25): backfill-once latch — see {@link EvolutionReplayDriver.backfill}. */
@@ -96,8 +96,18 @@ var EvolutionReplayDriver = class {
96
96
  /** V26-05 (v25): plan ids recorded live BEFORE the backfill settled. A
97
97
  * plan-applied landing inside the one-shot `loadActivity` read window is
98
98
  * recorded live AND persisted into the sidecar the backfill is reading —
99
- * `backfill()` drops those ids so the event is not counted twice. */
99
+ * `backfill()` drops those ids so the event is not counted twice.
100
+ *
101
+ * V27 INS-05: the set is BOUNDED. `backfill()` is the only place that cleared
102
+ * it, so a sidecar load that never succeeded (the inject callback's catch
103
+ * warns and does not retry until the io dependency is replaced) let every
104
+ * live plan id accumulate for the process lifetime. Past
105
+ * PRE_BACKFILL_ID_CAP the oldest ids are dropped: the dedupe window is then
106
+ * finite, and a dropped duplicate can at worst repeat an entry inside the
107
+ * `maxPlans` window instead of growing memory without bound. */
100
108
  preBackfillIds = /* @__PURE__ */ new Set();
109
+ /** Upper bound on {@link EvolutionReplayDriver.preBackfillIds} (V27 INS-05). */
110
+ static PRE_BACKFILL_ID_CAP = 4096;
101
111
  weights;
102
112
  constructor(config = {}, warn = () => {}) {
103
113
  const maxPlans = clampedNumber(config.maxPlans ?? 50, 50, { min: 1 });
@@ -111,7 +121,14 @@ var EvolutionReplayDriver = class {
111
121
  }
112
122
  }
113
123
  record(plan) {
114
- if (!this.backfilled) this.preBackfillIds.add(plan.planId);
124
+ if (!this.backfilled) {
125
+ this.preBackfillIds.add(plan.planId);
126
+ while (this.preBackfillIds.size > EvolutionReplayDriver.PRE_BACKFILL_ID_CAP) {
127
+ const oldest = this.preBackfillIds.keys().next().value;
128
+ if (oldest === void 0) break;
129
+ this.preBackfillIds.delete(oldest);
130
+ }
131
+ }
115
132
  const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
116
133
  const countOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
117
134
  const memoryApplied = count(plan.memoryApplied);
@@ -73,8 +73,18 @@ export declare class EvolutionReplayDriver {
73
73
  /** V26-05 (v25): plan ids recorded live BEFORE the backfill settled. A
74
74
  * plan-applied landing inside the one-shot `loadActivity` read window is
75
75
  * recorded live AND persisted into the sidecar the backfill is reading —
76
- * `backfill()` drops those ids so the event is not counted twice. */
76
+ * `backfill()` drops those ids so the event is not counted twice.
77
+ *
78
+ * V27 INS-05: the set is BOUNDED. `backfill()` is the only place that cleared
79
+ * it, so a sidecar load that never succeeded (the inject callback's catch
80
+ * warns and does not retry until the io dependency is replaced) let every
81
+ * live plan id accumulate for the process lifetime. Past
82
+ * PRE_BACKFILL_ID_CAP the oldest ids are dropped: the dedupe window is then
83
+ * finite, and a dropped duplicate can at worst repeat an entry inside the
84
+ * `maxPlans` window instead of growing memory without bound. */
77
85
  private readonly preBackfillIds;
86
+ /** Upper bound on {@link EvolutionReplayDriver.preBackfillIds} (V27 INS-05). */
87
+ private static readonly PRE_BACKFILL_ID_CAP;
78
88
  private readonly weights;
79
89
  constructor(config?: Config, warn?: (message: string) => void);
80
90
  record(plan: EvolutionPlanAppliedEvent): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-replay",
3
3
  "description": "Replay/A-B evaluation primitives for evolution plans (community build)",
4
- "version": "0.3.67",
4
+ "version": "0.3.68",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,8 +31,8 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-activity": "^0.3.67",
35
- "@lmzhen/dsh-evolution-core": "^0.3.67"
34
+ "@lmzhen/dsh-evolution-activity": "^0.3.68",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.68"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
43
- "@lmzhen/dsh-evolution-activity": "^0.3.67",
44
- "@lmzhen/dsh-evolution-core": "^0.3.67"
43
+ "@lmzhen/dsh-evolution-activity": "^0.3.68",
44
+ "@lmzhen/dsh-evolution-core": "^0.3.68"
45
45
  }
46
46
  }