maxpool 1.11.0 → 1.12.0

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.11.0",
3
+ "version": "1.12.0",
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",
@@ -161,6 +161,27 @@ const DEFAULT_SCHEDULER = {
161
161
  reserveConcurrencyTarget: 2, // tighter in-flight cap for reserve (capPenalty bites at inflight>2 ⇒ load fans out
162
162
  // across the fleet before any single reserve account is dogpiled toward a 429)
163
163
  spreadShareWeight: 3, // multiplies an account's share of recent fleet load (0..1)
164
+ // FAST-REFILL DISCOUNT (2026-08-25). The two LOAD-BALANCING terms — utilizationCost
165
+ // and paceCost — price a window by how FULL it is, never by how much absolute
166
+ // headroom it holds or how soon it refills. So "17% of a 5h window that refills 33.6x
167
+ // a week" is priced identically to "17% of a weekly window that refills once", and an
168
+ // account whose only cap is a fast-refilling session never pulls ahead of one guarding
169
+ // a scarce weekly budget. That is the whole reason the fleet's largest-capacity
170
+ // account sat at ~17% of fleet traffic (measured 2026-08-25) while four Claude
171
+ // accounts ran at weekly 1.0.
172
+ //
173
+ // The discount is a MULTIPLIER on those two terms only — never a flat bonus. A flat
174
+ // bonus would drive an idle account's total NEGATIVE (idle floor is concurrency×2 = 2),
175
+ // below the entire band structure that reserveFloorCost:5 / criticalPressureCost:21
176
+ // assume is non-negative. A multiplier in [0,1] cannot: it only ever REMOVES cost that
177
+ // is already there, so the total stays ≥ the concurrency floor and every safety term
178
+ // (concurrency, capPenalty, reserve, critical, ramp, failures) is untouched.
179
+ //
180
+ // It also DECAYS: at session util 0 the discount is full, and it is gone by
181
+ // fastRefillFadeUtil — so as the fast window fills, the account converges back to
182
+ // normal pricing and the fleet re-balances smoothly instead of flapping at a cliff.
183
+ fastRefillDiscount: 0.6, // 0 = off (full cost), 0.6 = discount up to 60% of the two balancing terms
184
+ fastRefillFadeUtil: 0.65, // discount reaches 0 at this session utilization (weeklySoftThreshold)
164
185
  recoveryRampWeight: 4, // decaying penalty applied to a just-recovered account
165
186
  recoveryRampMs: 5 * 60_000, // how long the post-recovery ramp lasts
166
187
  spreadWindowMs: 15 * 60_000, // rolling window used to measure recent per-account load
@@ -250,6 +271,13 @@ const FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
250
271
  const PERSISTED_QUOTA_FIELDS = [
251
272
  'unified5h', 'unified7d', 'unified5hReset', 'unified7dReset', 'unifiedStatus', 'scopedWeekly',
252
273
  'tokensLimit', 'tokensRemaining', 'requestsLimit', 'requestsRemaining', 'resetsAt',
274
+ // Plan identity, not a utilization: a successful probe's "no weekly window" is
275
+ // positive knowledge (2026-08-06). Without persisting it, every restart clears the
276
+ // flag and the fast-refill discount (plus the TUI "Wk none" rendering) silently
277
+ // drops until the next probe sweep re-learns it. The probe still rewrites it on
278
+ // every successful sweep, so a plan change heals on the same cadence.
279
+ 'weeklyAbsent', 'providerSes', 'providerSesReset', 'providerWk', 'providerWkReset',
280
+ 'providerQuotaSource', 'lastProbeOkAt',
253
281
  ];
254
282
 
255
283
  function clampRetryAfterSeconds(value) {
@@ -2487,7 +2515,11 @@ export class AccountManager {
2487
2515
 
2488
2516
  // Burn-pace COST only (demoted from the old dominant scarcity×6 term): a
2489
2517
  // soft de-preference of accounts burning ahead of an even pace. Never a bench.
2490
- const paceCost = this._accountScarcity(account, now) * this.scheduler.paceCostWeight;
2518
+ // FAST-REFILL DISCOUNT: applied to the pace and utilization terms (and only
2519
+ // those) for an account whose only cap is a fast-refilling session window —
2520
+ // see the DEFAULT_SCHEDULER block for the full rationale.
2521
+ const refillMult = this._fastRefillMultiplier(account);
2522
+ const paceCost = this._accountScarcity(account, now) * this.scheduler.paceCostWeight * refillMult;
2491
2523
 
2492
2524
  // RAW utilization cost — direct, not pace-adjusted. The pace cost above discounts
2493
2525
  // by how far into the window you are, so an account at 80% with 2h left is only
@@ -2495,7 +2527,7 @@ export class AccountManager {
2495
2527
  // benching, but wrong for load balancing: an account at 80% should be clearly less
2496
2528
  // attractive than one at 10% even if both are "on pace". Measured 2026-08-10: cc at
2497
2529
  // 80% scored 52.30 vs glm at 10% at 52.15 — a 0.15 gap drowned by round-robin.
2498
- const utilizationCost = this._rawUtilization(account) * this.scheduler.utilizationWeight;
2530
+ const utilizationCost = this._rawUtilization(account) * this.scheduler.utilizationWeight * refillMult;
2499
2531
 
2500
2532
  // Per-model weekly de-preference: an account whose scoped weekly for THIS
2501
2533
  // request's model (e.g. Fable) is high-but-not-exhausted is a poor pick for
@@ -2722,6 +2754,39 @@ export class AccountManager {
2722
2754
  return this._criticalUnlock(account, { profile: 'claude' }, new Set(), null, now);
2723
2755
  }
2724
2756
 
2757
+ /**
2758
+ * FAST-REFILL MULTIPLIER — 1.0 (no change) or a discount in (0,1) for an account
2759
+ * whose ONLY cap is a fast-refilling session window. The predicate is exactly the
2760
+ * one the TUI already renders ("Wk none"): a provider whose quota poll succeeded
2761
+ * and carried NO weekly window (positive knowledge the plan has none — measured
2762
+ * 2026-08-06, z.ai `max` returns one TOKENS_LIMIT unit 3 = 5h and no unit-6 weekly).
2763
+ *
2764
+ * The discount is LINEARLY FADED to 0 by session utilization: full at 0%, gone at
2765
+ * fastRefillFadeUtil. So the preference this grants decays as the window fills and
2766
+ * the account converges back to normal pricing — no cliff, no flap. At util ≥ fade
2767
+ * point the multiplier is exactly 1, making the term byte-identical to pre-2026-08-25
2768
+ * behaviour by construction.
2769
+ *
2770
+ * Rationale (why a weeklyAbsent account at all): its window refills 33.6× per week
2771
+ * vs a weekly window's 1×, so equal FULLNESS does not mean equal VALUE — capacity
2772
+ * that expires unused every 5h is worth spending faster than capacity that guards a
2773
+ * whole week. This is the use-it-or-lose-it principle _windowScarcity already applies
2774
+ * WITHIN a window, extended across window KINDS. It is a discount on balancing terms
2775
+ * only — never a flat bonus (a flat bonus drives the total negative, under the
2776
+ * non-negative band structure reserveFloorCost/criticalPressureCost were calibrated
2777
+ * against), and never on safety terms (concurrency, capPenalty, reserve, critical).
2778
+ */
2779
+ _fastRefillMultiplier(account) {
2780
+ const disc = this.scheduler.fastRefillDiscount;
2781
+ if (!(disc > 0)) return 1; // feature off → multiplier 1
2782
+ if (!(account?.type === 'provider' && account.quota?.weeklyAbsent)) return 1;
2783
+ const fade = this.scheduler.fastRefillFadeUtil;
2784
+ const ses = clamp01(account.quota.providerSes ?? 0);
2785
+ if (ses >= fade) return 1;
2786
+ // 1 at ses=0 → 1-disc at ses=0; linear to 1 at ses=fade
2787
+ return 1 - disc * (1 - ses / Math.max(1e-6, fade));
2788
+ }
2789
+
2725
2790
  _reserveCost(account, now = Date.now(), weeklyState = this._weeklyRawState(account)) {
2726
2791
  if (weeklyState !== 'reserve') return 0;
2727
2792
  const q = account.quota;
@@ -3974,6 +4039,22 @@ export class AccountManager {
3974
4039
  safetyMaxActivePerAccount: this.scheduler.safetyMaxActivePerAccount,
3975
4040
  safetyMaxGlobalActive: this.scheduler.safetyMaxGlobalActive,
3976
4041
  peak: this.peakSummary(),
4042
+ // FAST-REFILL visibility (2026-08-25): monitors must be able to assert the
4043
+ // discount is ARMED (config > 0) and, per eligible account, the multiplier
4044
+ // actually being applied — a flag that can never show "inert" is not a
4045
+ // monitorable feature. Mirrors the peak block's shape.
4046
+ fastRefill: {
4047
+ enabled: this.scheduler.fastRefillDiscount > 0,
4048
+ discount: this.scheduler.fastRefillDiscount,
4049
+ fadeUtil: this.scheduler.fastRefillFadeUtil,
4050
+ accounts: this.accounts
4051
+ .filter(a => a.type === 'provider' && a.quota?.weeklyAbsent)
4052
+ .map(a => ({
4053
+ name: a.name,
4054
+ sesUtilization: clamp01(a.quota.providerSes ?? 0),
4055
+ multiplier: Number(this._fastRefillMultiplier(a).toFixed(3)),
4056
+ })),
4057
+ },
3977
4058
  },
3978
4059
  upstreamThrottle: {
3979
4060
  active: this._isUpstreamThrottleBlocking(),
package/src/tui.js CHANGED
@@ -1961,6 +1961,13 @@ export class TUI {
1961
1961
  if (tier === 2) note += ` ${yellow(`peak·capped ${Math.round((wu ?? 0) * 100)}%`)}`;
1962
1962
  else if (tier === 1) note += wu == null ? ` ${dim('peak·cap n/a')}` : ` ${yellow('peak')}`;
1963
1963
  }
1964
+ // FAST-REFILL tag (2026-08-25): mirrors the router's own _fastRefillMultiplier —
1965
+ // the label cannot disagree with routing because it reads the same predicate.
1966
+ // Only shown when a discount is actually applied (< 1).
1967
+ if (a.quota?.weeklyAbsent && this.am._fastRefillMultiplier) {
1968
+ const m = this.am._fastRefillMultiplier(a);
1969
+ if (m < 1) note += ` ${cyan(`fast·refill ×${m.toFixed(2)}`)}`;
1970
+ }
1964
1971
  } else if (q.providerQuotaSource === 'console-only') {
1965
1972
  sesCell = emptyBar('n/a', bw);
1966
1973
  wkCell = emptyBar('n/a', bw);
@@ -2082,6 +2089,12 @@ export class TUI {
2082
2089
  // being an estimate. `~` marks it; a measured column replaces it after the first
2083
2090
  // full window. A stale-util caveat only when we cannot prove same-window.
2084
2091
  const est = this.am.capacityEstimate?.(i, win);
2092
+ // LIVE now-column: the open cycle is the only number that moves between window
2093
+ // closes, and without it the page read as frozen (reported 2026-08-25: "they
2094
+ // don't seem to be updating at all"). Rendered on every row that has one.
2095
+ const nowOpen = ledger.openCycle(a.name, win);
2096
+ const nowTag = nowOpen && nowOpen.tokensSoFar > 0
2097
+ ? ' ' + yellow(`▸ ${formatTokens(nowOpen.tokensSoFar)} this window`) : '';
2085
2098
  if (est) {
2086
2099
  anyData = true;
2087
2100
  const caveat = est.fresh ? '' : ' (utilization reading may be from the previous window)';
@@ -2092,16 +2105,19 @@ export class TUI {
2092
2105
  const via = est.method === 'delta'
2093
2106
  ? `Δ ${(est.utilization * 100).toFixed(0)}% full` : `${(est.utilization * 100).toFixed(0)}% full`;
2094
2107
  out.push(' ' + name + ' ' + prov + ' ' + cyan(op + formatTokens(est.tokens).padStart(CW - 1))
2095
- + dim(` est from ${via}${caveat} — measured after this window completes`));
2108
+ + dim(` est from ${via}${caveat} — measured after this window completes`) + nowTag);
2096
2109
  } else {
2097
- out.push(' ' + name + ' ' + prov + ' ' + dim('no completed cycle yet'));
2110
+ out.push(' ' + name + ' ' + prov + ' ' + dim('no completed cycle yet') + nowTag);
2098
2111
  }
2099
2112
  continue;
2100
2113
  }
2101
2114
  anyData = true;
2102
2115
  const all = { Last: st.last, Prev: st.prev, 'Prev-1': st.prev1, 'Avg 3': st.avg3, 'Avg 10': st.avg10, 'All time': st.allTime };
2103
2116
  const cells = COLS.map(c => formatTokens(all[c]).padStart(CW)).join('');
2104
- out.push(' ' + name + ' ' + prov + ' ' + cells + ' ' + dim(String(st.cycles)));
2117
+ const nowOpen = ledger.openCycle(a.name, win);
2118
+ const nowTag = nowOpen && nowOpen.tokensSoFar > 0
2119
+ ? ' ' + yellow(`▸ ${formatTokens(nowOpen.tokensSoFar)}`) : '';
2120
+ out.push(' ' + name + ' ' + prov + ' ' + cells + ' ' + dim(String(st.cycles)) + nowTag);
2105
2121
  }
2106
2122
 
2107
2123
  out.push('');
@@ -2114,7 +2130,7 @@ export class TUI {
2114
2130
  : ' A session figure appears after an account\'s 5h window resets once.'));
2115
2131
  }
2116
2132
  out.push(' ' + dim('A cycle counts only if maxpool ran for all of it and the account stayed enabled.'));
2117
- out.push(' ' + dim('~ = estimated from utilization; ≥ = at least this (window joined late); Δ = exact-by-difference; ≈/wk ceiling = session rate, not a cap.'));
2133
+ out.push(' ' + dim('~ = estimated; ≥ = at least; Δ = exact-by-difference; ≈/wk = session-rate ceiling; ▸ = live this window.'));
2118
2134
  return out;
2119
2135
  }
2120
2136