maxpool 1.12.0 → 1.13.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.12.0",
3
+ "version": "1.13.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",
@@ -1134,7 +1134,10 @@ export class AccountManager {
1134
1134
  // disappears (without this, OAuth cycles essentially never close: red-team 2026-08-22).
1135
1135
  if (q.unified5h != null && q.unified5hReset && now >= q.unified5hReset) {
1136
1136
  console.log(`[Maxpool] Account "${account.name}" session quota reset`);
1137
- this.capacity?.closeCycle?.(account.name, 'ses', q.unified5hReset, { resetAt: q.unified5hReset });
1137
+ // TANK: q.unified5h is still the CLOSING window's fullness here — the nulls below
1138
+ // come after. Snapshot into the cycle before the rollover wipes it.
1139
+ this.capacity?.closeCycle?.(account.name, 'ses', q.unified5hReset,
1140
+ { resetAt: q.unified5hReset, finalUtilization: q.unified5h });
1138
1141
  q.unified5h = null;
1139
1142
  q.unified5hReset = null;
1140
1143
  changed = true;
@@ -1142,7 +1145,8 @@ export class AccountManager {
1142
1145
  }
1143
1146
  if (q.unified7d != null && q.unified7dReset && now >= q.unified7dReset) {
1144
1147
  console.log(`[Maxpool] Account "${account.name}" weekly quota reset`);
1145
- this.capacity?.closeCycle?.(account.name, 'wk', q.unified7dReset, { resetAt: q.unified7dReset });
1148
+ this.capacity?.closeCycle?.(account.name, 'wk', q.unified7dReset,
1149
+ { resetAt: q.unified7dReset, finalUtilization: q.unified7d });
1146
1150
  q.unified7d = null;
1147
1151
  q.unified7dReset = null;
1148
1152
  q.unifiedStatus = null;
@@ -2667,7 +2671,7 @@ export class AccountManager {
2667
2671
  * in-window) and criticalPeakUnlock is enabled. Default off.
2668
2672
  * Precedence prereset > pressure > peak: the cheaper drain wins.
2669
2673
  */
2670
- _criticalUnlock(account, requestInfo = {}, excludedIndexes = new Set(), pressureCache = null, now = Date.now()) {
2674
+ _criticalUnlock(account, requestInfo = {}, excludedIndexes = new Set(), _pressureCache = null, now = Date.now()) {
2671
2675
  const state = this._weeklyRawState(account);
2672
2676
  if (state !== 'critical') return null;
2673
2677
 
@@ -2736,7 +2740,7 @@ export class AccountManager {
2736
2740
  * - pressure/peak: a flat cost ABOVE reserve's attainable max, so critical is
2737
2741
  * relief for a LOADED last route and never preempts an idle reserve.
2738
2742
  */
2739
- _criticalCost(account, now = Date.now(), unlock = null, weeklyState = this._weeklyRawState(account)) {
2743
+ _criticalCost(account, _now = Date.now(), unlock = null, weeklyState = this._weeklyRawState(account)) {
2740
2744
  if (weeklyState !== 'critical') return 0;
2741
2745
  if (!unlock) return 0;
2742
2746
  if (unlock.reason === 'prereset') {
@@ -2915,10 +2919,14 @@ export class AccountManager {
2915
2919
  const account = this.accounts[accountIndex];
2916
2920
  if (!account || !usage) return;
2917
2921
  const q = account.quota;
2918
- // CAPACITY LEDGER: prev stamps, so a probe observing the window ADVANCE closes
2919
- // the old cycle (the OAuth twin of the applyProviderUsage hook).
2922
+ // CAPACITY LEDGER: prev stamps AND prev utilizations, so a probe observing the
2923
+ // window ADVANCE closes the old cycle with the OLD window's tank reading —
2924
+ // snapshot BEFORE the writes below clobber the fields with the new window's
2925
+ // values (the OAuth twin of the applyProviderUsage hook).
2920
2926
  const prevSesReset = q.unified5hReset;
2921
2927
  const prevWkReset = q.unified7dReset;
2928
+ const prevSesUtil = q.unified5h;
2929
+ const prevWkUtil = q.unified7d;
2922
2930
 
2923
2931
  if (usage.fiveHour) {
2924
2932
  if (usage.fiveHour.utilization != null) q.unified5h = clamp01(usage.fiveHour.utilization);
@@ -2928,8 +2936,8 @@ export class AccountManager {
2928
2936
  if (usage.sevenDay.utilization != null) q.unified7d = clamp01(usage.sevenDay.utilization);
2929
2937
  if (usage.sevenDay.resetAt != null) q.unified7dReset = usage.sevenDay.resetAt;
2930
2938
  }
2931
- this.noteCapacityWindowAdvance(account.name, 'ses', prevSesReset, usage.fiveHour?.resetAt);
2932
- this.noteCapacityWindowAdvance(account.name, 'wk', prevWkReset, usage.sevenDay?.resetAt);
2939
+ this.noteCapacityWindowAdvance(account.name, 'ses', prevSesReset, usage.fiveHour?.resetAt, prevSesUtil);
2940
+ this.noteCapacityWindowAdvance(account.name, 'wk', prevWkReset, usage.sevenDay?.resetAt, prevWkUtil);
2933
2941
  // Utilization readings feed the capacity ESTIMATE. The probe path passes per-window
2934
2942
  // marks so the DELTA method can difference consecutive readings.
2935
2943
  this.capacity.noteUtilizationObserved(Date.now(), [
@@ -3046,11 +3054,14 @@ export class AccountManager {
3046
3054
  const account = this.accounts[accountIndex];
3047
3055
  if (!account || !usage) return;
3048
3056
  const q = account.quota;
3049
- // CAPACITY LEDGER: snapshot the previous reset stamps so a probe observing the
3050
- // window ADVANCE (new stamp) closes the capacity cycle at the old boundary —
3051
- // covers windows whose old stamp was never learned (clock-close can't fire).
3057
+ // CAPACITY LEDGER: snapshot the previous reset stamps AND utilizations so a probe
3058
+ // observing the window ADVANCE (new stamp) closes the capacity cycle at the old
3059
+ // boundary WITH the old window's tank reading — covers windows whose old stamp
3060
+ // was never learned (clock-close can't fire). Snapshot before the writes below.
3052
3061
  const prevSesReset = q.providerSesReset;
3053
3062
  const prevWkReset = q.providerWkReset;
3063
+ const prevSesUtil = q.providerSes;
3064
+ const prevWkUtil = q.providerWk;
3054
3065
  if (usage.error) {
3055
3066
  // Distinguish "no pollable quota" (Kimi) from a transient probe failure.
3056
3067
  // Never clear existing values on a transient error — let them age into the
@@ -3078,8 +3089,8 @@ export class AccountManager {
3078
3089
  q.weeklyAbsent = true;
3079
3090
  }
3080
3091
  q.lastProbeOkAt = Date.now();
3081
- this.noteCapacityWindowAdvance(account.name, 'ses', prevSesReset, usage.ses?.resetAt);
3082
- this.noteCapacityWindowAdvance(account.name, 'wk', prevWkReset, usage.wk?.resetAt);
3092
+ this.noteCapacityWindowAdvance(account.name, 'ses', prevSesReset, usage.ses?.resetAt, prevSesUtil);
3093
+ this.noteCapacityWindowAdvance(account.name, 'wk', prevWkReset, usage.wk?.resetAt, prevWkUtil);
3083
3094
  this.capacity.noteUtilizationObserved(Date.now(), [
3084
3095
  { name: account.name, window: 'ses', utilization: usage.ses?.utilization },
3085
3096
  { name: account.name, window: 'wk', utilization: usage.wk?.utilization },
@@ -3277,6 +3288,24 @@ export class AccountManager {
3277
3288
  return this.capacity.estimateFromUtilization(a.name, window, util) || null;
3278
3289
  }
3279
3290
 
3291
+ /** Measured TANK for an account+window: capacity, not delivery. Prefers completed
3292
+ * cycles (tokens ÷ closing utilization, averaged); falls back to the live open
3293
+ * window's estimate so a row is useful from minute one instead of reading
3294
+ * "no completed cycle yet" while the vendor is plainly reporting a percentage. */
3295
+ capacityTank(accountIndex, window) {
3296
+ const a = this.accounts[accountIndex];
3297
+ if (!a) return null;
3298
+ const measured = this.capacity.tankStats(a.name, window);
3299
+ if (measured) return { ...measured, source: 'cycles' };
3300
+ const est = this.capacityEstimate(accountIndex, window);
3301
+ if (!est) return null;
3302
+ return {
3303
+ avg: est.tokens, last: est.tokens, n: 0, exact: est.lowerBound ? 0 : 1,
3304
+ bounded: est.lowerBound ? 1 : 0, lowerBound: Boolean(est.lowerBound),
3305
+ source: 'live', utilization: est.utilization, method: est.method, fresh: est.fresh,
3306
+ };
3307
+ }
3308
+
3280
3309
  accrueCapacity(accountIndex, { input = 0, output = 0 } = {}) {
3281
3310
  const account = this.accounts[accountIndex];
3282
3311
  if (!account) return;
@@ -3289,6 +3318,18 @@ export class AccountManager {
3289
3318
  this.capacity.accrue(account.name, { input, output }, undefined, windows);
3290
3319
  }
3291
3320
 
3321
+ /** The vendor's CURRENT fullness reading for a window — the tank numerator's
3322
+ * denominator. Returns null when unreadable (a null reading divides nothing and
3323
+ * must never coerce to 0, which would make tank = Infinity). */
3324
+ _windowUtilization(account, window) {
3325
+ const q = account?.quota;
3326
+ if (!q) return null;
3327
+ const v = account.type === 'provider'
3328
+ ? (window === 'wk' ? q.providerWk : q.providerSes)
3329
+ : (window === 'wk' ? q.unified7d : q.unified5h);
3330
+ return Number.isFinite(v) && v >= 0 ? v : null;
3331
+ }
3332
+
3292
3333
  /** Close any window cycle whose reset time has passed — CLOCK-AUTHORITATIVE, so a
3293
3334
  * stale or dead probe can never leave a cycle open and mis-attribute the next
3294
3335
  * window's tokens to it (pre-mortem M5; worst case is the no-weekly account whose
@@ -3332,7 +3373,14 @@ export class AccountManager {
3332
3373
  // here as well (round-2) made a prober-first notice silently swallow all of
3333
3374
  // those whenever the sweep won the race (red-team round 3, RT3-1).
3334
3375
  if (resetAt && now >= resetAt) {
3335
- this.capacity.closeCycle(a.name, win, resetAt, { resetAt });
3376
+ this.capacity.closeCycle(a.name, win, resetAt, {
3377
+ resetAt,
3378
+ // TANK: the vendor's own fullness for the window we are closing. Read it
3379
+ // BEFORE _clearExpiredQuotas nulls it — this sweep runs first by design
3380
+ // (see the close-only note above), which is exactly why the reading is
3381
+ // still the CLOSING window's and not the new one's.
3382
+ finalUtilization: this._windowUtilization(a, win),
3383
+ });
3336
3384
  }
3337
3385
  }
3338
3386
  }
@@ -3340,7 +3388,7 @@ export class AccountManager {
3340
3388
 
3341
3389
  /** Close a cycle because a probe observed the window ADVANCE (a new reset stamp) —
3342
3390
  * covers the case where the old stamp was never learned. */
3343
- noteCapacityWindowAdvance(accountName, window, prevResetAt, nextResetAt) {
3391
+ noteCapacityWindowAdvance(accountName, window, prevResetAt, nextResetAt, prevUtilization = null) {
3344
3392
  if (!prevResetAt || !nextResetAt) return;
3345
3393
  // TWO guards, both learned from live data (2026-08-23):
3346
3394
  // 1. PAST stamp = a probe that answered late (its window rolled mid-request) or
@@ -3361,7 +3409,15 @@ export class AccountManager {
3361
3409
  // expired) — endedAt is always within [start, now].
3362
3410
  const boundary = Math.min(nextResetAt, nowMs);
3363
3411
  if (boundary - prevResetAt < WINDOW_ADVANCE_EPSILON_MS) return;
3364
- this.capacity.closeCycle(accountName, window, boundary, { resetAt: prevResetAt });
3412
+ // TANK: the CLOSING window's own fullness, passed in by the caller. It must be the
3413
+ // caller's SNAPSHOT, never a re-read here: both probe paths write the new window's
3414
+ // utilization into the quota fields before calling us, so re-reading would divide
3415
+ // the old window's tokens by the NEW window's percentage — a silently wrong tank
3416
+ // on exactly the rollover this path exists to catch.
3417
+ this.capacity.closeCycle(accountName, window, boundary, {
3418
+ resetAt: prevResetAt,
3419
+ finalUtilization: Number.isFinite(prevUtilization) && prevUtilization >= 0 ? prevUtilization : null,
3420
+ });
3365
3421
  }
3366
3422
 
3367
3423
  /**
@@ -199,8 +199,15 @@ export class CapacityLedger {
199
199
 
200
200
  /** Close the open cycle for a window (M5: clock-authoritative — the close is keyed
201
201
  * on `endedAt`, which the caller derives from the reset stamp or the clock, and the
202
- * cycle keeps its own book regardless of probe health). No-op if none open. */
203
- closeCycle(name, window, endedAt = this._now(), { resetAt = null } = {}) {
202
+ * cycle keeps its own book regardless of probe health). No-op if none open.
203
+ *
204
+ * TANK (2026-08-25, owner-directed): the closed row records `finalUtilization` —
205
+ * the vendor's own fullness reading for the window at close. tank = tokens ÷ util
206
+ * is the CAPACITY of the plan, as distinct from the tokens we happened to deliver.
207
+ * Delivery measures demand; tank measures the plan. Both are recorded; the UI
208
+ * decides which to show. Recording happens on a best-effort basis here (the ledger
209
+ * keeps its own book — the caller passes the reading in, it does not poll). */
210
+ closeCycle(name, window, endedAt = this._now(), { resetAt = null, finalUtilization = null } = {}) {
204
211
  const rec = this._accounts.get(name);
205
212
  if (!rec || !rec[window]?.open) return null;
206
213
  const open = rec[window].open;
@@ -221,7 +228,10 @@ export class CapacityLedger {
221
228
  // Fold ONLY a complete tail: folding a partial/disabled tail would flip the
222
229
  // flags on the prior legitimate observation and ERASE it from the averages
223
230
  // (round 3, RT3-2) — strictly worse than leaving a tiny excluded cycle.
231
+ // The fold ALSO takes the tail's tank reading if the prior row lacks one —
232
+ // same boundary, same window, so the later reading is simply fresher.
224
233
  prev.tokens += open.tokensSoFar;
234
+ if (prev.finalUtilization == null && finalUtilization != null) prev.finalUtilization = finalUtilization;
225
235
  rec[window].open = null;
226
236
  return prev;
227
237
  }
@@ -232,6 +242,12 @@ export class CapacityLedger {
232
242
  complete: open.complete,
233
243
  disabledDuring: open.disabledDuring,
234
244
  ...(open.partialReason ? { partialReason: open.partialReason } : {}),
245
+ ...(finalUtilization != null ? { finalUtilization } : {}),
246
+ // Carried onto the closed row because tankStats needs it: a cycle observed from
247
+ // its window START yields an EXACT tank; one we joined late yields a lower bound
248
+ // (we only counted the tokens that flowed through maxpool, while the vendor's
249
+ // percentage counts everything). Dropping it here made every tank read "bounded".
250
+ ...(open.windowStartedAt != null ? { windowStartedAt: open.windowStartedAt } : {}),
235
251
  resetAt,
236
252
  });
237
253
  if (rec[window].closed.length > MAX_CYCLES_PER_WINDOW) rec[window].closed.shift();
@@ -366,6 +382,48 @@ export class CapacityLedger {
366
382
  * ABSENCE (present in dayKeys, absent from days) — and with MAX_DAY_BUCKETS=10 an
367
383
  * idle day no longer even evicts; only real activity ages out. `partial` is true
368
384
  * when any bucket in the window is flagged partial — the figure is ≤ observed. */
385
+ /** TANK STATS — the CAPACITY of the plan, from the owner's own formula:
386
+ * tank = tokens delivered ÷ utilization at close, per cycle, averaged across
387
+ * cycles (2026-08-25, owner-directed). This measures the plan, not the demand:
388
+ * a cycle that delivered 812k at 96% and one that delivered 51k at 6% both say
389
+ * "~846k tank". Delivered-only averages (windowStats) measure demand and stay
390
+ * available separately.
391
+ *
392
+ * Guards, because the raw formula lies in two ways:
393
+ * - We only count tokens that flowed THROUGH maxpool; a cycle whose vendor util
394
+ * includes spend we never saw (joined mid-window, or usage outside the proxy)
395
+ * yields a tank ≥ the truth but not equal to it. Only a cycle observed from its
396
+ * window start is exact; later ones are marked `lowerBound`.
397
+ * - Vendors report whole percents. At 3% full, 1pp of rounding = 33% error, so a
398
+ * reading below MIN_UTIL is excluded (rounding-dominated) rather than folded
399
+ * into the average as fake precision.
400
+ * Returns { avg, exact, n, bounded, last } or null when no usable readings. */
401
+ tankStats(name, window) {
402
+ const rec = this._accounts.get(name);
403
+ const floor = (this._readFloorOverride ?? READ_FLOOR_MS)[window] ?? 0;
404
+ const usable = (rec?.[window]?.closed || []).filter(c =>
405
+ c.complete && !c.disabledDuring
406
+ && Number.isFinite(c.finalUtilization)
407
+ && c.finalUtilization >= 0.05
408
+ && (c.endedAt - c.startedAt) >= floor - 1_000);
409
+ if (!usable.length) return null;
410
+ let sum = 0, exact = 0, bounded = 0;
411
+ for (const c of usable) {
412
+ const observedFromStart = c.startedAt != null && c.windowStartedAt != null
413
+ && c.startedAt <= c.windowStartedAt + 60_000;
414
+ sum += c.tokens / c.finalUtilization;
415
+ if (observedFromStart) exact++; else bounded++;
416
+ }
417
+ const last = usable[usable.length - 1];
418
+ return {
419
+ avg: Math.round(sum / usable.length),
420
+ exact, bounded,
421
+ n: usable.length,
422
+ last: Math.round(last.tokens / last.finalUtilization),
423
+ lowerBound: bounded > 0 && exact === 0,
424
+ };
425
+ }
426
+
369
427
  rollingThroughput(name, days = 7) {
370
428
  const rec = this._accounts.get(name);
371
429
  if (!rec) return { tokens: 0, partial: false };
package/src/tui.js CHANGED
@@ -2031,7 +2031,7 @@ export class TUI {
2031
2031
  const ledger = this.am.capacity;
2032
2032
  const title = win === 'wk' ? 'Weekly (7d) capacity' : 'Session (5h) capacity';
2033
2033
  out.push('');
2034
- out.push(` ${bold(title)} ${dim('— tokens delivered per completed cycle, per account')}`);
2034
+ out.push(` ${bold(title)} ${dim('— how many tokens each account can deliver per window')}`);
2035
2035
  out.push('');
2036
2036
 
2037
2037
  if (!ledger) { out.push(yellow(' Capacity ledger unavailable on this worker.')); return out; }
@@ -2039,15 +2039,19 @@ export class TUI {
2039
2039
  // Narrow terminals: drop trailing columns rather than let fitLine chop a number
2040
2040
  // mid-digit (at W=80 the full 6-column row is 82+ chars — every row silently lost
2041
2041
  // its last two cells). The dropped ones are the aggregates, not the observations.
2042
- const ALL_COLS = ['Last', 'Prev', 'Prev-1', 'Avg 3', 'Avg 10', 'All time'];
2043
- const CW = 9;
2042
+ // CAPACITY (tank) is the headline: tokens ÷ the vendor's own fullness at close,
2043
+ // per cycle. That measures the PLAN. The delivered-token columns measure DEMAND —
2044
+ // useful, but they were the headline before 2026-08-25 and read as capacity, which
2045
+ // is why an account that simply went unused looked small.
2046
+ const ALL_COLS = ['Capacity', 'Used now', 'Last cyc', 'Avg cyc'];
2047
+ const CW = 10;
2044
2048
  const nameW = 12;
2045
2049
  let COLS = ALL_COLS;
2046
- while (COLS.length > 1 && (nameW + PROVIDER_W + 2 + COLS.length * CW + 14) > W) {
2050
+ while (COLS.length > 1 && (nameW + PROVIDER_W + 2 + COLS.length * CW + 16) > W) {
2047
2051
  COLS = COLS.slice(0, -1);
2048
2052
  }
2049
2053
  const header = ' ' + 'Account'.padEnd(nameW) + ' ' + 'Provider'.padEnd(PROVIDER_W) + ' '
2050
- + COLS.map(c => c.padStart(CW)).join('') + ' Cycles';
2054
+ + COLS.map(c => c.padStart(CW)).join('') + ' Basis';
2051
2055
  out.push(dimUnderline(fitLine(header, W)));
2052
2056
 
2053
2057
  let anyData = false;
@@ -2065,14 +2069,16 @@ export class TUI {
2065
2069
  // capacity). 33.6 five-hour windows fit in 7 days — the user's own
2066
2070
  // approximation ("from the session limits"), shipped as a ceiling, never a cap.
2067
2071
  const t = ledger.rollingThroughput(a.name, 7);
2068
- const ses = ledger.windowStats(a.name, 'ses');
2069
2072
  const windowsPerWk = (7 * 24) / 5;
2070
2073
  anyData = anyData || t.tokens > 0;
2071
2074
  const vol = t.tokens > 0 ? formatTokens(t.tokens) : '--';
2072
- // The ceiling needs a measured session capacity; without one it would multiply
2073
- // a guess — show the volume alone rather than fabricate the headline.
2074
- const ceiling = ses ? ` · ≈${formatTokens(Math.round(windowsPerWk * ses.avg10))}/wk ceiling`
2075
- + dim(` (${windowsPerWk.toFixed(0)} sessions × ${formatTokens(ses.avg10)})`) : '';
2075
+ // The ceiling needs a measured session TANK (capacity, not avg delivery) —
2076
+ // multiplying an old avg-delivery number understates a demand-limited account.
2077
+ const sesTank = this.am.capacityTank?.(i, 'ses');
2078
+ const ceiling = sesTank
2079
+ ? ` · ≈${formatTokens(Math.round(windowsPerWk * sesTank.avg))}/wk ceiling`
2080
+ + dim(` (${windowsPerWk.toFixed(0)} × ${formatTokens(sesTank.avg)} per 5h)`)
2081
+ : '';
2076
2082
  // Always disclose the window's age boundary: today is unfinished, so the 7d
2077
2083
  // figure grows through the day; a genuinely partial day adds the ≤-observed floor.
2078
2084
  const note = t.partial
@@ -2083,54 +2089,60 @@ export class TUI {
2083
2089
  continue;
2084
2090
  }
2085
2091
  const st = ledger.windowStats(a.name, win);
2086
- if (!st) {
2087
- // No completed cycle yet — but the vendor's own fullness reading still yields
2088
- // an ESTIMATE (tokens seen ÷ utilization): useful from minute one, honest about
2089
- // being an estimate. `~` marks it; a measured column replaces it after the first
2090
- // full window. A stale-util caveat only when we cannot prove same-window.
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`) : '';
2098
- if (est) {
2099
- anyData = true;
2100
- const caveat = est.fresh ? '' : ' (utilization reading may be from the previous window)';
2101
- // ≥ = absolute method on a window we joined late: the true tank is at least
2102
- // this. No ≥ when the delta method fired — it is join-independent, or the
2103
- // window was observed from its start.
2104
- const op = est.lowerBound ? '≥' : '~';
2105
- const via = est.method === 'delta'
2106
- ? `Δ ${(est.utilization * 100).toFixed(0)}% full` : `${(est.utilization * 100).toFixed(0)}% full`;
2107
- out.push(' ' + name + ' ' + prov + ' ' + cyan(op + formatTokens(est.tokens).padStart(CW - 1))
2108
- + dim(` est from ${via}${caveat} — measured after this window completes`) + nowTag);
2109
- } else {
2110
- out.push(' ' + name + ' ' + prov + ' ' + dim('no completed cycle yet') + nowTag);
2111
- }
2092
+ let tank = this.am.capacityTank?.(i, win);
2093
+ const nowOpen = ledger.openCycle(a.name, win);
2094
+ const util = this.am._windowUtilization?.(a, win);
2095
+ // A reading we cannot prove is from THIS window must not badge the capacity
2096
+ // number as "live" — it may describe the previous window entirely (the estimate
2097
+ // still renders; the basis line just stops claiming freshness it can't prove).
2098
+ if (tank?.source === 'live' && tank.fresh === false) tank = null;
2099
+
2100
+ // A row with NEITHER a tank nor any delivery has genuinely nothing to say. Say
2101
+ // WHY in the account's own terms — "no completed cycle yet" was true and useless
2102
+ // (reported 2026-08-25: an account sitting at 99% weekly rendered that line).
2103
+ if (!tank && !st && !(nowOpen?.tokensSoFar > 0)) {
2104
+ const why = util == null
2105
+ ? 'no quota reading from this provider'
2106
+ : util > 0
2107
+ ? `${(util * 100).toFixed(0)}% used, but no traffic through maxpool to measure with`
2108
+ : 'window empty — nothing used yet';
2109
+ out.push(' ' + name + ' ' + prov + ' ' + dim(why));
2112
2110
  continue;
2113
2111
  }
2114
2112
  anyData = true;
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 };
2116
- const cells = COLS.map(c => formatTokens(all[c]).padStart(CW)).join('');
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);
2113
+
2114
+ // Capacity: measured tank, or the live in-window estimate. `~` = estimate from an
2115
+ // open window; `≥` = we joined the window late, so the vendor's percentage counts
2116
+ // spend maxpool never saw and the true tank is at least this.
2117
+ const capCell = tank
2118
+ ? (tank.lowerBound ? '≥' : tank.source === 'live' ? '~' : ' ') + formatTokens(tank.avg)
2119
+ : '--';
2120
+ const usedNow = nowOpen?.tokensSoFar > 0 ? formatTokens(nowOpen.tokensSoFar) : '--';
2121
+ const cellsByName = {
2122
+ Capacity: capCell,
2123
+ 'Used now': usedNow,
2124
+ 'Last cyc': st ? formatTokens(st.last) : '--',
2125
+ 'Avg cyc': st ? formatTokens(st.avg10) : '--',
2126
+ };
2127
+ const cells = COLS.map(c => cellsByName[c].padStart(CW)).join('');
2128
+
2129
+ // Basis: how the capacity number was arrived at, in one short phrase. Never a
2130
+ // bare count — "3" told the reader nothing about what it was counting.
2131
+ const basis = !tank ? dim('no capacity reading yet')
2132
+ : tank.source === 'cycles'
2133
+ ? dim(`${tank.n} full ${tank.n === 1 ? 'window' : 'windows'}`)
2134
+ : dim(`live · ${((tank.utilization ?? 0) * 100).toFixed(0)}% used`);
2135
+ const pct = util != null && tank?.source !== 'live' ? dim(` (${(util * 100).toFixed(0)}% full now)`) : '';
2136
+ out.push(' ' + name + ' ' + prov + ' ' + cyan(cells) + ' ' + basis + pct);
2121
2137
  }
2122
2138
 
2123
2139
  out.push('');
2124
2140
  if (!anyData) {
2125
- // Fresh install: the page is honest about WHY it is empty and WHEN it fills,
2126
- // instead of showing zeros that read like an account delivering nothing.
2127
- out.push(' ' + yellow('No completed cycles yet.') + dim(
2128
- win === 'wk'
2129
- ? ' A weekly figure appears after an account\'s 7d window resets once.'
2130
- : ' A session figure appears after an account\'s 5h window resets once.'));
2131
- }
2132
- out.push(' ' + dim('A cycle counts only if maxpool ran for all of it and the account stayed enabled.'));
2133
- out.push(' ' + dim('~ = estimated; ≥ = at least; Δ = exact-by-difference; ≈/wk = session-rate ceiling; ▸ = live this window.'));
2141
+ out.push(' ' + yellow('Nothing to measure yet.')
2142
+ + dim(' Capacity needs traffic through maxpool plus a quota reading from the provider.'));
2143
+ }
2144
+ out.push(' ' + dim('Capacity = tokens delivered ÷ how full the provider said the window was.'));
2145
+ out.push(' ' + dim('~ = from the window still running · ≥ = at least this (maxpool joined the window late).'));
2134
2146
  return out;
2135
2147
  }
2136
2148