maxpool 1.19.8 → 1.20.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxpool",
3
- "version": "1.19.8",
3
+ "version": "1.20.1",
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",
@@ -124,8 +124,12 @@ const DEFAULT_SCHEDULER = {
124
124
  // CONCURRENCY HEADROOM for the request (an at-cap route cannot serve without
125
125
  // deepening the congestion). Congestion-based, not presence-based: an idle provider
126
126
  // or reserve account keeps serving and no unlock fires — critical becomes relief
127
- // exactly when the fleet is out of headroom, and never preempts an idle route
128
- // (cost is also ABOVE reserve's attainable max ~19, pinning the ordering).
127
+ // exactly when the fleet is out of headroom, and never preempts an idle route.
128
+ // Ordering vs reserve: reserve's attainable max is floor(5) + band(≤8) + weekly
129
+ // scarcity(≤6) ≈ 19, PLUS utilization's weekly term (≤3, 2026-09-16) ⇒ up to ~22 —
130
+ // this 21 sits above a lightly-priced reserve but can sit BELOW a maxed one. The
131
+ // X3 pin holds for the idle-reserve case (0.90 ⇒ ~10-19); if that regresses, raise
132
+ // this to 24 (see critical-unlock.test.js X3).
129
133
  // -1 disables; 0 = unlock only when every route is at cap.
130
134
  criticalPressureUnlockRoutes: 0,
131
135
  criticalPressureCost: 21,
@@ -147,6 +151,13 @@ const DEFAULT_SCHEDULER = {
147
151
  capPenaltyWeight: 10, // steep penalty per unit of in-flight depth past D (throttle safety floor)
148
152
  paceCostWeight: 1.5, // soft de-preference of accounts burning ahead of pace (was the ×6 term)
149
153
  utilizationWeight: 3, // RAW utilization cost — drives load balancing in the mid-range
154
+ // WEEKLY-AWARE SCORING (2026-09-16): when true, _rawUtilization also folds in the
155
+ // WEEKLY utilization (unified7d / providerWk), not just the 5h session. Before this,
156
+ // a Claude account at 89% weekly with a freshly-reset 5h window scored as CHEAP —
157
+ // weekly-burning accounts kept winning the lease all day (backtest: 62%→35% mean
158
+ // weekly burn once weekly-aware). Boolean; default ON was chosen because the
159
+ // pre-flag behavior is the bug this fixes.
160
+ weeklyAwareScoring: true,
150
161
  scarcityWeight: 6, // legacy; superseded by paceCostWeight (kept so old configs don't error)
151
162
  // Reserve-account OVERFLOW model. A weekly-RESERVE account (util 0.85-0.95) used to
152
163
  // sit idle behind a healthy-only first pass; now it's eligible in the first pass but
@@ -2692,7 +2703,7 @@ export class AccountManager {
2692
2703
  * _accountScarcity but WITHOUT the elapsed-fraction discount. This is the signal
2693
2704
  * the load balancer needs: an account at 80% is more expensive than one at 10%,
2694
2705
  * full stop. */
2695
- _rawUtilization(account) {
2706
+ _rawUtilization(account, now = Date.now()) {
2696
2707
  const q = account?.quota;
2697
2708
  if (!q) return 0;
2698
2709
  // SESSION windows use raw utilization — headroom is consumed immediately and an
@@ -2708,6 +2719,24 @@ export class AccountManager {
2708
2719
  if (q.tokensLimit != null && q.tokensLimit > 0 && q.tokensRemaining != null) {
2709
2720
  util = Math.max(util, 1 - q.tokensRemaining / q.tokensLimit);
2710
2721
  }
2722
+ // WEEKLY-AWARE (2026-09-16): fold the WEEKLY number in too, behind its own
2723
+ // flag — via _windowScarcity (reset-aware), NEVER raw. v1 of this block used
2724
+ // raw max(), which fixed the 89%-weekly-wins-all-day bug but broke the
2725
+ // near-reset contracts that predate it: the use-it-or-lose-it pin, the
2726
+ // preReset drain (X2/X5), and S10's flag-off parity. Pace-adjusted, a
2727
+ // 60%-weekly account mid-window adds (0.60 − elapsedFrac) here at weight 3
2728
+ // ON TOP of the paceCost's weight-1.5 copy — doubling the weekly steering
2729
+ // signal (the actual fix) while capacity dying at reset stays free (the
2730
+ // invariant the older tests pin). Unknown/absent reset → face value, same as
2731
+ // _accountScarcity. Turn the flag off to restore session-only exactly.
2732
+ if (this.scheduler.weeklyAwareScoring !== false) {
2733
+ if (q.unified7d != null) {
2734
+ util = Math.max(util, this._windowScarcity(q.unified7d, q.unified7dReset, WEEK_MS, now));
2735
+ }
2736
+ if (q.providerWk != null) {
2737
+ util = Math.max(util, this._windowScarcity(q.providerWk, q.providerWkReset, WEEK_MS, now));
2738
+ }
2739
+ }
2711
2740
  return util;
2712
2741
  }
2713
2742
 
package/src/tui.js CHANGED
@@ -977,6 +977,11 @@ export class TUI {
977
977
  // mode — under balance/prefer-* the mode itself controls eligibility. Still
978
978
  // safe to set (it'll apply if you switch back to sticky).
979
979
  this._cycleProviderClaudeFallback(k === 'g' ? 'zai' : 'kimi');
980
+ } else if (k === 'w' || k === 'W') {
981
+ // WEEKLY-AWARE SCORING (2026-09-16): fold weekly utilization into the routing
982
+ // score, not just the 5h session. Without it, an account at 89% weekly with a
983
+ // fresh session window scores as cheap and keeps winning all day.
984
+ this._toggleWeeklyAware();
980
985
  } else if (k === 'esc' || k === 'q') {
981
986
  this.mode = 'normal';
982
987
  }
@@ -1066,6 +1071,32 @@ export class TUI {
1066
1071
  : `Peak cap: bench a GLM account once it passes ${Math.round(next * 100)}% of its weekly quota`);
1067
1072
  }
1068
1073
 
1074
+ /** Toggle weekly-aware routing for the whole fleet. One scheduler flag — when OFF the
1075
+ * score sees only the 5h session (the pre-2026-09-16 behavior); when ON the weekly
1076
+ * number is folded in, so a nearly-exhausted account loses to a fresh one at ALL
1077
+ * hours, not just after its session window resets. */
1078
+ async _toggleWeeklyAware() {
1079
+ const next = this.am.scheduler.weeklyAwareScoring === false;
1080
+ this.am.scheduler.weeklyAwareScoring = next;
1081
+ const sched = { ...(this.config.scheduler || {}) };
1082
+ sched.weeklyAwareScoring = next;
1083
+ this.config.scheduler = sched;
1084
+ try {
1085
+ await this.saveConfig(this.config);
1086
+ } catch (e) {
1087
+ // Roll back both the live flag and the mirror so an unsaved toggle can't
1088
+ // silently revert on the next reload — same pattern as the sibling
1089
+ // _cycleProviderClaudeFallback (tui.js).
1090
+ this.am.scheduler.weeklyAwareScoring = !next;
1091
+ this.config.scheduler = sched.weeklyAwareScoring === next ? { ...sched, weeklyAwareScoring: !next } : sched;
1092
+ this._addLog(`Could not save: ${e.message}`);
1093
+ return;
1094
+ }
1095
+ this._addLog(next
1096
+ ? 'Weekly-aware routing: ON — accounts near their weekly limit rank last, all day'
1097
+ : 'Weekly-aware routing: OFF — score sees only the 5h session window again');
1098
+ }
1099
+
1069
1100
  async _cycleRoutingMode() {
1070
1101
  const modes = TUI.ROUTING_MODES;
1071
1102
  const cur = this.am.scheduler?.routingMode || 'sticky';
@@ -2369,7 +2400,8 @@ export class TUI {
2369
2400
  const now = st?.inPeak ? red(' NOW') : '';
2370
2401
  const dep = ps.depreference ? yellow('GLM last') : cyan('normal');
2371
2402
  const cap = ps.cap >= 1 ? 'off' : ps.cap === 0 ? 'never' : `${Math.round(ps.cap * 100)}%`;
2372
- peakPart = ` ${dim('│')} ${bold(' d ')}Peak${now}: ${dep} ${bold(' c ')}cap ${cyan(cap)}`;
2403
+ const wk = this.am.scheduler.weeklyAwareScoring === false ? yellow('5h-only') : cyan('weekly');
2404
+ peakPart = ` ${dim('│')} ${bold(' d ')}Peak${now}: ${dep} ${bold(' c ')}cap ${cyan(cap)} ${bold(' w ')}score:${wk}`;
2373
2405
  }
2374
2406
  return ` ${bold('f')} Routing: ${cyan(mode.label)} ↻${provPart}${peakPart} ${bold('p')} Preference ${bold('Esc')} Back`;
2375
2407
  }