Ctrl K
ComunidadGuías…

test/devin-connect-trouble-selection.test.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// C2×C5: the persisted rolling health window feeds account SELECTION.
//
// An account that's wobbling right now (recent dead-token / error burst) should
// be softly de-prioritized for a short window even while it's still 'active'
// with RPM headroom — instead of being hammered until it hard-fails. Failures
// decay out of a 5-min window so a recovered account climbs back on its own.
// Crucially this must be a NO-OP for healthy accounts (score 0) so existing
// inflight→quota→LRU ordering is untouched.

import { afterEach, beforeEach, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
  addAccountByKey, removeAccount, getApiKey,
  reportError, reportDeadToken, markRateLimited,
  __recentTroubleScore, releaseAccount,
} from '../src/auth.js';

const createdIds = [];
afterEach(() => { while (createdIds.length) removeAccount(createdIds.pop()); });

function seed(label) {
  const key = `devin-session-token$trouble-${label}-${Math.random().toString(36).slice(2)}`;
  const acct = addAccountByKey(key, label);
  acct.email = label;
  acct.tier = 'free';
  acct._health = [];
  createdIds.push(acct.id);
  return acct;
}

describe('recentTroubleScore', () => {
  it('is 0 for a clean account (no effect on healthy selection)', () => {
    const a = seed('clean');
    assert.equal(__recentTroubleScore(a), 0);
  });

  it('weighs dead/error (3) heavier than throttle/capacity (1)', () => {
    const a = seed('weights');
    reportDeadToken(a.apiKey);              // +3
    reportError(a.apiKey);                  // +3
    markRateLimited(a.apiKey, 1000);        // +1 (throttle)
    markRateLimited(a.apiKey, 1000, 'm', 'c'); // +1 (capacity)
    assert.equal(__recentTroubleScore(a), 8);
  });

  it('ignores trouble older than the 5-min window (decay)', () => {
    const a = seed('decay');
    const now = Date.now();
    a._health = [
      { t: now - 6 * 60 * 1000, k: 'd' }, // stale: outside 5-min window
      { t: now - 6 * 60 * 1000, k: 'e' },
      { t: now - 30 * 1000, k: 't' },     // fresh: +1
    ];
    assert.equal(__recentTroubleScore(a, now), 1);
  });
});

describe('selection de-prioritizes a recently-wobbling account', () => {
  it('prefers the healthy account when a peer just burst dead-tokens', () => {
    const healthy = seed('healthy');
    const wobbly = seed('wobbly');
    // Wobbly just threw two hard failures (score 6 → bucket 2); healthy is clean.
    reportDeadToken(wobbly.apiKey);
    reportError(wobbly.apiKey);

    // Acquire once; with equal inflight/quota/LRU the trouble tiebreaker should
    // route to the healthy account.
    const picked = getApiKey([], null, '');
    assert.ok(picked, 'selected an account');
    assert.equal(picked.id, healthy.id, 'healthy account preferred over the wobbling one');
    releaseAccount(picked.apiKey);
  });

  it('does NOT demote on a single minor throttle (sub-bucket noise)', () => {
    const a = seed('minor-a');
    const b = seed('minor-b');
    // One throttle on `a` → score 1 → bucket 0, same as b's bucket 0. The
    // tiebreaker must not fire; selection falls through to quota/LRU as before.
    markRateLimited(a.apiKey, 1000);
    assert.equal(Math.floor(__recentTroubleScore(a) / 3), 0);
    assert.equal(Math.floor(__recentTroubleScore(b) / 3), 0);
    const picked = getApiKey([], null, '');
    assert.ok(picked, 'still selects an account despite a minor throttle');
    releaseAccount(picked.apiKey);
  });
});