maxpool 1.5.0 → 1.5.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.5.0",
3
+ "version": "1.5.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",
@@ -251,7 +251,40 @@ export class AccountManager {
251
251
  for (const account of this.accounts) {
252
252
  if (excludedIndexes.has(account.index)) continue;
253
253
  if (!this._matchesRequest(account, profile, requestInfo)) {
254
- if (account.type === 'provider' && this._requiresAnthropicThinkingIntegrity(requestInfo)) {
254
+ // A signed-thinking request behind the TRANSIENT FIFO queue-fairness gate
255
+ // (a queue already exists and this newcomer hasn't registered a ticket yet
256
+ // — the `!requestInfo.queueTicket` clause in _matchesRequest) must HOLD,
257
+ // not error-fast. Such a request has NO fallback: providers are barred
258
+ // (signed thinking), so shedding it with a 429 KILLS the session — the
259
+ // reproduced "all N are at their 5h or weekly limit" false kill
260
+ // (2026-06-27) while healthy accounts sat idle behind the queue. The
261
+ // instant it registers a ticket the gate lifts and it waits its FIFO turn
262
+ // behind the existing waiters (which drain as the healthy accounts finish),
263
+ // so a bounded re-poll hold is the right answer.
264
+ // Scoped to THINKING requests on purpose: a non-thinking request can fall
265
+ // back to a provider or be cheaply retried, so the fairness gate keeps
266
+ // shedding it as backpressure (never grow the queue past its cap under a
267
+ // pure-concurrency burst). admissionPaused (restart/shutdown shed) and
268
+ // upstream-throttle keep their existing behavior (throttle is handled by
269
+ // the early return above). NOTE: queueAndRetry does NOT special-case
270
+ // 'queued_behind_fairness' in its window switch, so a STREAMING thinking
271
+ // hold rides streamHoldMaxMs (kept alive by the heartbeat) — intended: a
272
+ // signed-thinking stream should wait its turn, bounded by the per-ticket
273
+ // deadlineAt + _reapStaleQueueHead + the client's own disconnect, not the
274
+ // 15-min concurrency-cap clamp.
275
+ const thinkingFairnessGated = this._requiresAnthropicThinkingIntegrity(requestInfo)
276
+ && !this.admissionPaused
277
+ && !this._isUpstreamThrottleBlocking()
278
+ && this.queueState.waiting.length > 0
279
+ && !requestInfo.queueTicket
280
+ && !requestInfo.queueAdmitted;
281
+ if (thinkingFairnessGated
282
+ && account.type !== 'provider'
283
+ && this._isRequestCompatible(account, profile, requestInfo)
284
+ && this._isAvailable(account, { allowWeeklyReserve: true, allowWeeklyCritical: true })) {
285
+ soonestBoundedHold = Math.min(soonestBoundedHold, BOUNDED_REPOLL_HOLD_MS);
286
+ if (!boundedHoldCause) boundedHoldCause = 'queued_behind_fairness';
287
+ } else if (account.type === 'provider' && this._requiresAnthropicThinkingIntegrity(requestInfo)) {
255
288
  note('provider_fallback_disabled_signed_thinking');
256
289
  }
257
290
  continue;