maxpool 1.10.2 → 1.10.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
4
4
  "description": "Multi-account Claude Code proxy with adaptive, rate-aware load balancing across Claude accounts",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -3010,7 +3010,11 @@ export class AccountManager {
3010
3010
  * cycle is no longer a truthful capacity observation — flag it partial (B2/SC6).
3011
3011
  * It still displays; it is excluded from averages. */
3012
3012
  restoreCapacityState(payload, now = Date.now(), downtimeMs = null) {
3013
+ // Preserve the test seam across the ledger swap (fromSerialized returns a fresh
3014
+ // instance; without this the zero-floor harness override dies on any restore).
3015
+ const floorOverride = this.capacity?._readFloorOverride ?? null;
3013
3016
  this.capacity = CapacityLedger.fromSerialized(payload);
3017
+ this.capacity._readFloorOverride = floorOverride;
3014
3018
  // Partial is keyed on MAXPOOL'S OWN downtime, NEVER on the account's last request:
3015
3019
  // an account parked >10min mid-cycle is normal fleet rotation, and keying on its
3016
3020
  // last request discarded valid observations on every reload (red-team F3). The
@@ -31,6 +31,10 @@ const SCHEMA_VERSION = 3;
31
31
  // Two closes this far apart are the SAME boundary observed twice (a clock-close and a
32
32
  // stamp-advance racing across the boundary second), not two windows.
33
33
  const SAME_BOUNDARY_MS = 5_000;
34
+
35
+ // The minimum span of a COMPLETE cycle per window (80% of nominal): a real one is
36
+ // flagged partial by the writer, so a complete cycle below this is corrupt history.
37
+ const READ_FLOOR_MS = { ses: 4 * 3600_000, wk: 5 * 86400_000 };
34
38
  const MAX_CYCLES_PER_WINDOW = 50;
35
39
  const MAX_DAY_BUCKETS = 10;
36
40
 
@@ -54,6 +58,9 @@ export class CapacityLedger {
54
58
  // Cleared per account+window once that window's first boundary is behind us.
55
59
  this._joinedMidWindow = false;
56
60
  this._utilObservedAt = 0; // last utilization-reading arrival (see estimateFromUtilization)
61
+ // Test seam ONLY: real-window fixtures are laborious for every close-cycle test,
62
+ // so tests may zero the read floor. Production never touches this.
63
+ this._readFloorOverride = null;
57
64
  }
58
65
 
59
66
  /** Restore from a serialized payload (state.json). Tolerant: unknown schemaVersion →
@@ -324,7 +331,20 @@ export class CapacityLedger {
324
331
  * are observations, not capacity). */
325
332
  windowStats(name, window) {
326
333
  const rec = this._accounts.get(name);
327
- const closed = (rec?.[window]?.closed || []).filter(c => c.complete && !c.disabledDuring);
334
+ // READ-TIME FLOOR. A cycle marked complete + never-disabled but spanning far less
335
+ // than its window is junk from a writer bug — the live ledger held a 0.5-second /
336
+ // 588-token "cycle" (clock-close and stamp-advance racing at one boundary, the fold
337
+ // refused on an endedAt mismatch) and it dragged this account's Avg3 down ~188k.
338
+ // Unlike the WRITE-time floor I tried first (reverted: it punished accounts that
339
+ // were merely idle early in their window), at read time a genuinely short cycle is
340
+ // already flagged complete:false by the writer — so a complete sub-floor cycle is
341
+ // definitionally corrupt, never a real observation.
342
+ const floor = (this._readFloorOverride ?? READ_FLOOR_MS)[window] ?? 0;
343
+ // >= floor, with a 1s tolerance for the accrue-vs-close clock race (an accrue can
344
+ // stamp Date.now() a tick AFTER the close computed its boundary, making a 0-span
345
+ // cycle read as -1ms — found by debugging a D2 failure that only reproduced in-file).
346
+ const closed = (rec?.[window]?.closed || []).filter(c =>
347
+ c.complete && !c.disabledDuring && (c.endedAt - c.startedAt) >= floor - 1_000);
328
348
  if (!closed.length) return null;
329
349
  const avg = (arr) => arr.length ? Math.round(arr.reduce((a, b) => a + b, 0) / arr.length) : null;
330
350
  const tokens = closed.map(c => c.tokens);