maxpool 1.24.24 → 1.24.25
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 +1 -1
- package/src/account-manager.js +1 -1
- package/src/capacity-ledger.js +64 -7
- package/src/tui.js +13 -5
package/package.json
CHANGED
package/src/account-manager.js
CHANGED
|
@@ -3728,7 +3728,7 @@ export class AccountManager {
|
|
|
3728
3728
|
spannedDays.add(new Date(now).toISOString().slice(0, 10));
|
|
3729
3729
|
for (const name of this.capacity.accounts()) {
|
|
3730
3730
|
if (this.capacity.openCycle(name, 'ses') || this.capacity.openCycle(name, 'wk')) {
|
|
3731
|
-
this.capacity.markPartial(name);
|
|
3731
|
+
this.capacity.markPartial(name, { reason: 'maxpool-downtime' });
|
|
3732
3732
|
}
|
|
3733
3733
|
for (const day of spannedDays) this.capacity.markDayPartial(name, day);
|
|
3734
3734
|
}
|
package/src/capacity-ledger.js
CHANGED
|
@@ -43,6 +43,14 @@ const READ_FLOOR_MS = { ses: 4 * 3600_000, wk: 5 * 86400_000 };
|
|
|
43
43
|
// in-window estimate must apply the same floor; one guarding without the other is how
|
|
44
44
|
// the absurd number reached the screen in the first place.
|
|
45
45
|
export const TANK_MIN_UTIL = 0.05;
|
|
46
|
+
|
|
47
|
+
// Nominal window length. A closed cycle much LONGER than its window swallowed a
|
|
48
|
+
// rollover it never saw (measured live 2026-10-13: "weekly" cycles of 11.9d-14d,
|
|
49
|
+
// "5h" cycles of 7-8h) — two tanks' tokens over one tank's percentage. Not an
|
|
50
|
+
// observation of one window; excluded from tank stats.
|
|
51
|
+
const WINDOW_MS = { ses: 5 * 3600_000, wk: 7 * 86400_000 };
|
|
52
|
+
const WINDOW_CEIL_FACTOR = 1.25;
|
|
53
|
+
|
|
46
54
|
const MAX_CYCLES_PER_WINDOW = 50;
|
|
47
55
|
const MAX_DAY_BUCKETS = 10;
|
|
48
56
|
|
|
@@ -190,7 +198,7 @@ export class CapacityLedger {
|
|
|
190
198
|
|
|
191
199
|
/** Mark the open cycles as partial (maxpool was down / an account was disabled).
|
|
192
200
|
* Called by the boot path when a gap is detected (B2), and by the disable hook. */
|
|
193
|
-
markPartial(name, { disabled = false } = {}) {
|
|
201
|
+
markPartial(name, { disabled = false, reason = null } = {}) {
|
|
194
202
|
const rec = this._accounts.get(name);
|
|
195
203
|
if (!rec) return;
|
|
196
204
|
for (const w of ['ses', 'wk']) {
|
|
@@ -200,8 +208,15 @@ export class CapacityLedger {
|
|
|
200
208
|
// account out of rotation. Setting both for a disable made the disabled flag
|
|
201
209
|
// query-redundant and therefore untested (red-team F6-1) — each now excludes on
|
|
202
210
|
// its own, and each is pinned by its own test.
|
|
211
|
+
// `reason` ('maxpool-downtime', 'no-weekly-plan', …) rides along for display;
|
|
212
|
+
// a bare-false (reason null) keeps the historic shape. It is NEVER
|
|
213
|
+
// 'pre-v3-unverified' — that reason alone means "never trust this row"
|
|
214
|
+
// (see tankStats' reason gate).
|
|
203
215
|
if (disabled) rec[w].open.disabledDuring = true;
|
|
204
|
-
else
|
|
216
|
+
else {
|
|
217
|
+
rec[w].open.complete = false;
|
|
218
|
+
if (reason != null && !rec[w].open.partialReason) rec[w].open.partialReason = reason;
|
|
219
|
+
}
|
|
205
220
|
}
|
|
206
221
|
}
|
|
207
222
|
|
|
@@ -219,6 +234,15 @@ export class CapacityLedger {
|
|
|
219
234
|
const rec = this._accounts.get(name);
|
|
220
235
|
if (!rec || !rec[window]?.open) return null;
|
|
221
236
|
const open = rec[window].open;
|
|
237
|
+
// The closing window's fullness is the HIGHEST reading the cycle saw, never
|
|
238
|
+
// merely the latest: fullness only rises inside a window, so a caller's reading
|
|
239
|
+
// BELOW the peak is the next window's, arrived before this close ran (measured
|
|
240
|
+
// live 2026-10-13: kira closed a 3.1M-token week at "3% full" ⇒ a 105M tank —
|
|
241
|
+
// the reading was the freshly-reset NEXT week's).
|
|
242
|
+
if (Number.isFinite(open.peakUtilization)
|
|
243
|
+
&& !(Number.isFinite(finalUtilization) && finalUtilization >= open.peakUtilization)) {
|
|
244
|
+
finalUtilization = open.peakUtilization;
|
|
245
|
+
}
|
|
222
246
|
// ONE CYCLE PER BOUNDARY CLOSURE — the structural backstop for the two-closer race
|
|
223
247
|
// (round-2 F1). If both closers observe the SAME reset stamp within the same
|
|
224
248
|
// rollover moment, the second close's tokens are a straddling tail of that same
|
|
@@ -332,9 +356,15 @@ export class CapacityLedger {
|
|
|
332
356
|
if (!marks) return;
|
|
333
357
|
this._utilMarks = this._utilMarks || new Map();
|
|
334
358
|
for (const m of marks) {
|
|
335
|
-
if (!(m.utilization
|
|
359
|
+
if (!Number.isFinite(m.utilization) || m.utilization < 0) continue;
|
|
336
360
|
const open = this.openCycle(m.name, m.window);
|
|
337
361
|
if (!open) continue;
|
|
362
|
+
// PEAK: fullness only rises inside one window, so the highest reading a cycle
|
|
363
|
+
// saw is its closing fullness (closeCycle prefers it over a later, lower one).
|
|
364
|
+
if (!Number.isFinite(open.peakUtilization) || m.utilization > open.peakUtilization) {
|
|
365
|
+
open.peakUtilization = Math.min(1, m.utilization);
|
|
366
|
+
}
|
|
367
|
+
if (!(m.utilization < 1)) continue;
|
|
338
368
|
const key = `${m.name}:${m.window}`;
|
|
339
369
|
const prev = this._utilMarks.get(key);
|
|
340
370
|
// Keep the OLDEST usable mark within this cycle: a wider span means a larger
|
|
@@ -409,8 +439,24 @@ export class CapacityLedger {
|
|
|
409
439
|
tankStats(name, window) {
|
|
410
440
|
const rec = this._accounts.get(name);
|
|
411
441
|
const floor = (this._readFloorOverride ?? READ_FLOOR_MS)[window] ?? 0;
|
|
442
|
+
// TANK READING SET (2026-10-13): partial cycles COUNT here. The strict
|
|
443
|
+
// `complete` gate was written for demand stats and quietly deleted every
|
|
444
|
+
// weekly observation — a 7d window outlives every maxpool restart/sleep, so
|
|
445
|
+
// restoreCapacityState's >60s downtime check marked nearly all of them
|
|
446
|
+
// partial and the Weekly (7d) page read "--" everywhere (owner report
|
|
447
|
+
// 2026-10-13). For TANK math a gap is already handled: tokens ÷ vendor % is
|
|
448
|
+
// a lower bound whenever spend was unseen, and exact/bounded/lowerBound
|
|
449
|
+
// exist to say so. Still excluded, hard: disabledDuring (operator benched
|
|
450
|
+
// the account — not a capacity observation) and `pre-v3-unverified` (the
|
|
451
|
+
// ONE reason that means "never trust this row").
|
|
412
452
|
const closed = (rec?.[window]?.closed || []).filter(c =>
|
|
413
|
-
|
|
453
|
+
!c.disabledDuring
|
|
454
|
+
&& c.partialReason !== 'pre-v3-unverified'
|
|
455
|
+
&& (c.endedAt - c.startedAt) >= floor - 1_000
|
|
456
|
+
// CEILING: a cycle far longer than its window swallowed a rollover it never
|
|
457
|
+
// saw — two tanks' tokens over one tank's percentage (see WINDOW_CEIL_FACTOR).
|
|
458
|
+
&& (this._readFloorOverride != null
|
|
459
|
+
|| (c.endedAt - c.startedAt) <= WINDOW_MS[window] * WINDOW_CEIL_FACTOR));
|
|
414
460
|
// PHYSICAL FLOOR: a tank can never be smaller than the most tokens ever
|
|
415
461
|
// delivered in one complete window — every token we count is a vendor token
|
|
416
462
|
// (C ≤ V ≤ tank), so maxDelivered ≤ tank is an invariant, not a heuristic.
|
|
@@ -425,23 +471,34 @@ export class CapacityLedger {
|
|
|
425
471
|
// floor rather than being thrown away — discarding left an account whose
|
|
426
472
|
// every reading was contaminated with NOTHING to show. After a plan
|
|
427
473
|
// downgrade the floor over-states until old cycles age out — conservative.
|
|
428
|
-
|
|
474
|
+
// The floor's own base uses the complete windows only — a partial cycle's
|
|
475
|
+
// tokens may end mid-window, understating a single delivery.
|
|
476
|
+
const maxDelivered = closed.filter(c => c.complete)
|
|
477
|
+
.reduce((m, c) => Math.max(m, c.tokens), 0);
|
|
429
478
|
const usable = closed.filter(c =>
|
|
430
479
|
Number.isFinite(c.finalUtilization) && c.finalUtilization >= TANK_MIN_UTIL);
|
|
431
480
|
if (!usable.length) return null;
|
|
432
481
|
let sum = 0, exact = 0, bounded = 0;
|
|
433
482
|
for (const c of usable) {
|
|
434
483
|
const observedFromStart = c.startedAt != null && c.windowStartedAt != null
|
|
435
|
-
&& c.startedAt <= c.windowStartedAt + 60_000;
|
|
484
|
+
&& c.startedAt <= c.windowStartedAt + 60_000 && c.complete;
|
|
436
485
|
sum += Math.max(c.tokens / c.finalUtilization, maxDelivered);
|
|
437
486
|
if (observedFromStart) exact++; else bounded++;
|
|
438
487
|
}
|
|
439
488
|
const last = usable[usable.length - 1];
|
|
489
|
+
const prevCycle = usable[usable.length - 2];
|
|
440
490
|
return {
|
|
441
491
|
avg: Math.round(sum / usable.length),
|
|
442
492
|
exact, bounded,
|
|
443
493
|
n: usable.length,
|
|
444
|
-
last: Math.round(last.tokens / last.finalUtilization),
|
|
494
|
+
last: Math.round(Math.max(last.tokens / last.finalUtilization, maxDelivered)),
|
|
495
|
+
// PREV in TANK units (tokens ÷ that cycle's own reading) — the page's
|
|
496
|
+
// Prev column used to come from windowStats (delivered tokens), mixing
|
|
497
|
+
// units across one row (2026-10-13 owner report). Same physical floor as
|
|
498
|
+
// the average: a reading implying less than a past delivery is impossible.
|
|
499
|
+
prev: prevCycle != null
|
|
500
|
+
? Math.round(Math.max(prevCycle.tokens / prevCycle.finalUtilization, maxDelivered))
|
|
501
|
+
: null,
|
|
445
502
|
lowerBound: bounded > 0 && exact === 0,
|
|
446
503
|
};
|
|
447
504
|
}
|
package/src/tui.js
CHANGED
|
@@ -1252,7 +1252,13 @@ export class TUI {
|
|
|
1252
1252
|
? `${Math.round(existing * 100)}%${existingMode === 'dynamic' ? ' dynamic' : ' fixed'}`
|
|
1253
1253
|
: 'off';
|
|
1254
1254
|
this.mode = 'input';
|
|
1255
|
-
|
|
1255
|
+
// Plain-English prompt (owner 2026-10-13: "I'm not sure how does this work.
|
|
1256
|
+
// I want to keep the dynamic floor, but I also want to raise the basic cap").
|
|
1257
|
+
// Type just a number = the dynamic cap's STARTING level (it holds the account
|
|
1258
|
+
// to NN% early in each window, then rises toward ~95% as the window nears
|
|
1259
|
+
// its reset, so unused capacity isn't stranded). fNN = fixed wall (no rise).
|
|
1260
|
+
// 0 = no cap.
|
|
1261
|
+
this.inputPrompt = `Usage cap for "${current}" — type a % like 75: the account stays free until it hits that, then unlocks gradually as the window refills (dynamic). f75 = never unlock early (fixed). 0 = remove. Now ${nowLabel}`;
|
|
1256
1262
|
this.inputBuf = '';
|
|
1257
1263
|
this.inputSensitive = false;
|
|
1258
1264
|
this.inputCb = value => this._doSetCap(targetIdx, String(value || '').trim());
|
|
@@ -2508,7 +2514,7 @@ export class TUI {
|
|
|
2508
2514
|
if (win === 'wk' && a.type === 'provider' && a.quota?.weeklyAbsent) {
|
|
2509
2515
|
const sesTank = this.am.capacityTank?.(i, 'ses');
|
|
2510
2516
|
const approx = sesTank && sesTank.n > 0
|
|
2511
|
-
? formatTokens(Math.round(sesTank.avg * (7 * 24) / 5)) : '--';
|
|
2517
|
+
? `≈ ${formatTokens(Math.round(sesTank.avg * (7 * 24) / 5))}` : '--';
|
|
2512
2518
|
const cellsByName = { Current: cyan(approx), Prev: '--', Avg: '--', N: sesTank?.n ? String(sesTank.n) : '--' };
|
|
2513
2519
|
out.push(' ' + name + ' ' + prov + ' '
|
|
2514
2520
|
+ COLS.map(c => cellsByName[c].padStart(CW)).join('')
|
|
@@ -2532,12 +2538,14 @@ export class TUI {
|
|
|
2532
2538
|
cur = formatTokens(Math.round(nowOpen.tokensSoFar / util));
|
|
2533
2539
|
}
|
|
2534
2540
|
const curPct = util != null && cur !== '--' ? dim(`@${Math.round(util * 100)}%`) : '';
|
|
2535
|
-
|
|
2541
|
+
// Every history column is a TANK number (tokens ÷ closing %). Prev/N used to
|
|
2542
|
+
// come from windowStats — delivered tokens and a different cycle set — so one
|
|
2543
|
+
// row mixed units (2026-10-13 owner report; see tankStats' reading-set note).
|
|
2536
2544
|
const cellsByName = {
|
|
2537
2545
|
Current: cur.padStart(CW - (curPct ? curPct.length + 1 : 0)),
|
|
2538
|
-
Prev: (
|
|
2546
|
+
Prev: (tank?.source === 'cycles' && tank.prev != null ? formatTokens(tank.prev) : '--'),
|
|
2539
2547
|
Avg: (tank?.source === 'cycles' ? formatTokens(tank.avg) : '--'),
|
|
2540
|
-
N: (
|
|
2548
|
+
N: (tank?.source === 'cycles' ? String(tank.n) : '--'),
|
|
2541
2549
|
};
|
|
2542
2550
|
const row = ' ' + name + ' ' + prov + ' '
|
|
2543
2551
|
+ COLS.map(c => cellsByName[c].padStart(CW)).join('');
|