test/connect-selector-scope.test.js
Rama master · réplica de lectura del repositorio original.
// Reviewer #1 — a MODEL-level rejection must not be read as an account auth
// failure.
//
// Measured upstream body: "This model is no longer available for your account",
// carried on gRPC `permission_denied` / HTTP 401. Before this suite existed,
// classifyUpstreamError matched it with the UNAUTHORIZED arm, and the rest of the
// chain inherited the wrong scope:
//
// classify → UNAUTHORIZED
// → finalizeConnectAccount → reportError → three requests for ONE retired
// selector flipped a healthy account to status='error' (persisted), which
// blacked out every OTHER model that account could still serve;
// → the UNAUTHORIZED arm also fired a background re-login for a token that
// was never dead, and the handler's dead-token path ran requestReauthCheck;
// → isAccountFailoverError('UNAUTHORIZED') is false, and the MODEL_BLOCKED
// fallback is excluded too, so the request never moved to a peer that COULD
// serve the selector;
// → isLastUsableAccount only compared tier buckets, so a same-tier peer that
// could not serve the selector still counted as a fallback and disqualified
// the sole account that could.
//
// The fix gives the condition its own scope — the (account, canonical selector)
// PAIR — and this file pins each link of the chain:
// 1. classification (and its near-misses: a real bad token stays UNAUTHORIZED)
// 2. blame (three rejections touch no auth state, no re-login, no reauth)
// 3. routing (the account stays selectable for every other selector)
// 4. failover (the request lands on a peer eligible for that selector)
// 5. the last-account exemption is selector-aware
// 6. a genuine bad token still trips the existing protection
import { describe, it, beforeEach, afterEach } from 'node:test';
import assert from 'node:assert/strict';
import {
addAccountByKey, removeAccount, getApiKey, releaseAccount, getAccountInternal,
setAccountTier, isSelectorIneligible, isConnectSelectorAllowedForAccount,
resolveAccountState, reportError, __isLastUsableAccount,
__setReloginDeps, __resetReloginState, markAccountReauthenticated,
} from '../src/auth.js';
import { classifyUpstreamError, isRetryable } from '../src/devin-connect.js';
import { getConnectMetrics } from '../src/devin-connect-metrics.js';
import {
handleChatCompletions, finalizeConnectAccount, connectErrorToHttp,
isAccountFailoverError, __setConnectDeps, __resetConnectDeps,
} from '../src/handlers/chat.js';
// Canonical connect selectors, used as the SELECTOR dimension directly (the
// classifier and finalizeConnectAccount both take the resolved selector).
const X = 'gpt-5-5-low'; // paid selector — needs a paid bucket
const Y = 'swe-1-6-slow'; // free-reachable selector — any bucket
const X_MODEL = 'gpt-5.5'; // client-facing name that resolves to X
const BODY = 'This model is no longer available for your account';
const created = [];
const prevEnv = {};
function seed(label, tier = 'pro') {
const acct = addAccountByKey(`devin-session-token$sel-${label}-${Math.random().toString(36).slice(2)}`, label);
created.push(acct.id);
if (tier) setAccountTier(acct.id, tier);
return getAccountInternal(acct.id);
}
function rejectSelector() {
const c = classifyUpstreamError(BODY, 'permission_denied', 401);
return Object.assign(new Error(c.message), { code: c.code, status: 401 });
}
function unauthorized() {
return Object.assign(new Error('invalid token'), { code: 'UNAUTHORIZED' });
}
function failSelector(acct, selector = X, times = 3) {
for (let i = 0; i < times; i++) {
finalizeConnectAccount(
{ id: acct.id, apiKey: acct.apiKey },
{ model: X_MODEL, selector, startTime: Date.now() - 3, err: rejectSelector() },
);
}
return getAccountInternal(acct.id);
}
function fakeRes() {
const listeners = new Map();
return {
body: '', writableEnded: false,
write(chunk) { this.body += String(chunk); return true; },
end(chunk) { if (chunk) this.write(chunk); this.writableEnded = true; for (const cb of listeners.get('close') || []) cb(); },
on(event, cb) { if (!listeners.has(event)) listeners.set(event, []); listeners.get(event).push(cb); return this; },
};
}
function parseFrames(raw) {
return raw.split('\n\n').filter(Boolean).filter(f => !f.startsWith(':')).map(f => {
const d = f.split('\n').find(l => l.startsWith('data: '))?.slice(6) || '';
return d === '[DONE]' ? '[DONE]' : JSON.parse(d);
});
}
beforeEach(() => {
prevEnv.DEVIN_CONNECT = process.env.DEVIN_CONNECT;
process.env.DEVIN_CONNECT = '1';
});
afterEach(() => {
__resetConnectDeps();
__resetReloginState();
__setReloginDeps(null);
if (prevEnv.DEVIN_CONNECT === undefined) delete process.env.DEVIN_CONNECT;
else process.env.DEVIN_CONNECT = prevEnv.DEVIN_CONNECT;
while (created.length) removeAccount(created.pop());
});
// ─────────────────────────────────────────────────────────────────────────────
describe('1. classification — the model-level rejection has its own scope', () => {
it('the measured body is SELECTOR_NOT_ELIGIBLE, not UNAUTHORIZED', () => {
for (const [code, status] of [['permission_denied', 401], ['permission_denied', 403], [null, null]]) {
const c = classifyUpstreamError(BODY, code, status);
assert.equal(c.code, 'SELECTOR_NOT_ELIGIBLE',
`body must not classify as ${c.code} (code=${code} status=${status}) — an auth verdict here is `
+ 'what charged the account error budget and fired a re-login for a live token');
}
});
it('a real auth failure still classifies as UNAUTHORIZED (no over-broad pattern)', () => {
// The new branch must not swallow the auth vocabulary it sits in front of.
for (const [text, code, status] of [
['invalid token', 'unauthenticated', 401],
['Authentication failed', null, 401],
['permission_denied', null, 403],
['unauthenticated', 'unauthenticated', null],
]) {
assert.equal(classifyUpstreamError(text, code, status).code, 'UNAUTHORIZED', `${text} must stay an auth failure`);
}
});
it('the new code is failover-eligible, non-retryable, and not an auth HTTP surface', () => {
const c = classifyUpstreamError(BODY, 'permission_denied', 401);
assert.equal(isAccountFailoverError(c.code), true,
'a peer entitled to the selector can serve this request, so it must fail over');
assert.equal(isRetryable({ code: c.code }), false,
'the same account rejects it identically, so an in-place retry only burns an attempt');
const http = connectErrorToHttp(c.code);
assert.equal(http.status, 403, 'not 401 — the account was never unauthenticated');
assert.notEqual(http.type, 'authentication_error');
});
it('MODEL_BLOCKED stays excluded from failover (tier wall vs per-account wall)', () => {
assert.equal(isAccountFailoverError('MODEL_BLOCKED'), false,
'a tier wall is shared by every account of that tier — hopping would storm the pool');
});
it('an explicit tier wall stays MODEL_BLOCKED (account-only branch does not preempt it)', () => {
// Reviewer F-classifier: the SELECTOR_NOT_ELIGIBLE arm used to accept
// plan/tier/subscription/workspace, so this body classified as a per-account
// selector verdict — which fails over and latches — instead of the tier wall
// it states. The two codes route differently on purpose.
const wall = 'This model is no longer available for your plan. Please /upgrade to access it';
assert.equal(classifyUpstreamError(wall, 'permission_denied', 403).code, 'MODEL_BLOCKED',
'a plan/tier noun plus /upgrade is a tier wall, not evidence about one account');
assert.equal(classifyUpstreamError('Please /upgrade to access this model').code, 'MODEL_BLOCKED',
'the plain /upgrade form keeps its existing verdict');
for (const text of [
'This model is no longer available for your plan',
'This model is no longer available for your workspace',
]) {
assert.notEqual(classifyUpstreamError(text, 'permission_denied', 403).code, 'SELECTOR_NOT_ELIGIBLE',
`${text} is not the measured account-scoped body — it must not latch/hop`);
}
});
});
// ─────────────────────────────────────────────────────────────────────────────
describe('2. blame — three rejections touch no account auth state', () => {
it('leaves the account active with no error budget, cooldown, reauth or re-login', () => {
const a = seed('blame-a');
seed('blame-peer'); // voids the last-account exemption, so an eviction WOULD show
let logins = 0;
__setReloginDeps({ windsurfLogin: async () => { logins++; throw new Error('no credential'); } });
const after = failSelector(a, X, 3);
assert.equal(after.status, 'active', 'the account never lost a credential');
assert.equal(after.errorCount || 0, 0, 'a selector-scoped rejection must not charge the eviction counter');
assert.equal(after.reauth, undefined, 'a selector-scoped rejection is not a reauth verdict');
assert.equal(after.rateLimitedUntil || 0, 0, 'not an account-wide cooldown');
assert.equal(after.quotaResetAt || 0, 0, 'not a quota dry-well');
assert.deepEqual(Object.keys(after._modelRateLimits || {}), [],
'not a capacity throttle either — the dashboard would label the account "capacity"');
assert.equal(resolveAccountState(after), 'active', 'the account still reads healthy to the operator');
assert.equal(logins, 0, 'no re-login for a token that was never dead');
});
it('latches the SELECTOR for that account only, and the latch self-heals', () => {
const a = seed('latch-a');
seed('latch-peer');
const after = failSelector(a, X, 3);
assert.equal(isSelectorIneligible(after, X), true, 'the rejected selector is recorded');
assert.equal(isSelectorIneligible(after, Y), false, 'every other selector is untouched');
// Bounded + self-healing: the entry expires on its own (30-minute window).
assert.equal(isSelectorIneligible(after, X, Date.now() + 31 * 60 * 1000), false,
'the latch must expire — a re-enabled model has to come back without a restart');
assert.equal(after._selectorIneligible[X], undefined, 'expiry also drops the entry (bounded map)');
});
it('does not latch when no peer could serve the selector', () => {
// A pro account, and a same-tier peer whose operator blocklist excludes X:
// the pool cannot serve X at all. Latching A would turn the upstream's honest
// 403 into "pool exhausted" for every later request.
const a = seed('nopeer-a');
const b = seed('nopeer-b');
b.blockedModels = [X];
assert.equal(isConnectSelectorAllowedForAccount(b, X), false, 'precondition: peer cannot serve X');
const after = failSelector(a, X, 3);
assert.equal(after.status, 'active');
assert.equal(isSelectorIneligible(after, X), false,
'no peer can take over, so the account must stay selectable and surface the real error');
});
});
// ─────────────────────────────────────────────────────────────────────────────
// Reviewer F1/F2 — the latch is availability state, so it must belong to the
// credential that produced the verdict AND agree with the scheduler about
// whether a peer can actually take over.
describe('2b. latch safety — credential epoch (F1) and scheduler admission (F2)', () => {
it('late_old_selector_denial_must_not_override_new_credential_success', () => {
const a = seed('epoch-a');
const b = seed('epoch-b'); // admitted peer: pre-fix this made the latch writable
const oldSnapshot = { id: a.id, apiKey: a.apiKey };
// A fresh login installs a new credential on the SAME account (same id).
const newKey = `${oldSnapshot.apiKey}-fresh`;
markAccountReauthenticated(a.id, { apiKey: newKey, via: 'manual' });
assert.equal(getAccountInternal(a.id).apiKey, newKey, 'precondition: the pool moved to a new epoch');
// The new credential serves the selector.
finalizeConnectAccount(
{ id: a.id, apiKey: newKey },
{ model: X_MODEL, selector: X, startTime: Date.now() - 2, err: null },
);
// The OLD attempt's denial then lands (it was in flight across the rotation).
const m0 = getConnectMetrics();
finalizeConnectAccount(
oldSnapshot,
{ model: X_MODEL, selector: X, startTime: Date.now() - 2, err: rejectSelector() },
);
const m1 = getConnectMetrics();
const after = getAccountInternal(a.id);
assert.equal(after.status, 'active', 'a selector-scoped denial never benches the account');
assert.equal(isSelectorIneligible(after, X), false,
"the old epoch's denial must not latch the NEW credential — it may still serve this selector");
assert.equal(m1.selector_ineligible - m0.selector_ineligible, 1,
'the observation is still counted; only the availability write is skipped');
// "selectableWithoutB": with the only peer gone, the account must still be
// handed out for X. Pre-fix the latch made the pool empty (getApiKey → null).
removeAccount(b.id);
const picked = getApiKey([], null, '', X);
assert.equal(picked?.id, a.id, 'the fresh credential remains selectable for X without the peer');
releaseAccount(picked.apiKey);
});
it('selector_latch_requires_a_peer_admitted_by_scheduler_maintenance_filter', () => {
const a = seed('maint-a');
const b = seed('maint-b');
b._maintenance = 1; // a background / language-server maintenance slot is held
const pre = getApiKey([], null, '', X);
assert.equal(pre?.id, a.id, 'precondition: the scheduler already skips the busy peer');
releaseAccount(pre.apiKey);
const after = failSelector(a, X, 1);
assert.equal(isSelectorIneligible(after, X), false,
'the only peer is in maintenance — latching A would empty the pool');
const picked = getApiKey([], null, '', X);
assert.equal(picked?.id, a.id, 'A stays selectable for X (no empty-pool 504)');
releaseAccount(picked.apiKey);
});
it('selector_latch_requires_a_peer_admitted_by_scheduler_inflight_filter', () => {
const ENV = 'DEVIN_CONNECT_MAX_INFLIGHT_PER_ACCOUNT';
const prev = process.env[ENV];
process.env[ENV] = '1';
try {
const a = seed('cap-a');
const b = seed('cap-b');
b._inflight = 1; // the peer is at the per-account hard cap
b._inflightAt = Date.now();
const pre = getApiKey([], null, '', X);
assert.equal(pre?.id, a.id, 'precondition: the scheduler already skips the capped peer');
releaseAccount(pre.apiKey);
const after = failSelector(a, X, 1);
assert.equal(isSelectorIneligible(after, X), false,
'the capped peer cannot take over, so latching A would leave no candidate');
const picked = getApiKey([], null, '', X);
assert.equal(picked?.id, a.id, 'A stays selectable for X; the in-flight cap is not bypassed');
releaseAccount(picked.apiKey);
} finally {
if (prev === undefined) delete process.env[ENV];
else process.env[ENV] = prev;
}
});
});
// ─────────────────────────────────────────────────────────────────────────────
describe('3. routing — the account stays usable for every other selector', () => {
it('skips the latched account for the rejected selector, keeps it for the others', () => {
const a = seed('route-a');
const b = seed('route-b');
failSelector(a, X, 3);
const picks = [];
for (let i = 0; i < 3; i++) {
const p = getApiKey([], null, '', X);
assert.ok(p, 'a peer eligible for X must still be selectable');
picks.push(p.id);
releaseAccount(p.apiKey);
}
assert.deepEqual(picks, [b.id, b.id, b.id], 'X never lands on the latched account');
// Y is a different dimension: the SAME account must remain selectable for it.
const yPicks = new Set();
for (let i = 0; i < 4; i++) {
const p = getApiKey([], null, '', Y);
assert.ok(p, 'Y must stay serviceable');
yPicks.add(p.id);
releaseAccount(p.apiKey);
}
assert.ok(yPicks.has(a.id),
'the account rejected for X must still serve Y — the whole point of the selector scope');
});
it('the pinned re-acquire path honors the latch too', async () => {
const { acquireAccountByKey } = await import('../src/auth.js');
const a = seed('pin-a');
seed('pin-peer');
failSelector(a, X, 1);
assert.equal(acquireAccountByKey(a.apiKey, null, X), null,
'a pinned re-acquire must not hand back an account the upstream just refused this selector');
const ok = acquireAccountByKey(a.apiKey, null, Y);
assert.ok(ok, 'the same account is still acquirable for Y');
releaseAccount(ok.apiKey);
});
});
// ─────────────────────────────────────────────────────────────────────────────
describe('4. failover — the request moves to a peer eligible for the selector', () => {
it('non-stream: serves from the eligible peer and never penalizes the rejecting account', async () => {
const a = seed('fo-a');
const b = seed('fo-b');
let logins = 0;
__setReloginDeps({ windsurfLogin: async () => { logins++; throw new Error('no credential'); } });
const seen = [];
__setConnectDeps({
toChatCompletion: async (params) => {
const who = params.token === a.apiKey ? 'A' : (params.token === b.apiKey ? 'B' : '?');
seen.push(`${who}:${params.model}`);
if (who === 'A' && params.model === X) throw rejectSelector();
return { status: 200, body: { id: 'x', choices: [{ message: { role: 'assistant', content: 'FAILOVER_OK' } }] } };
},
});
const m0 = getConnectMetrics();
const result = await handleChatCompletions(
{ model: X_MODEL, stream: false, messages: [{ role: 'user', content: 'hi' }] },
{ callerKey: '' },
);
const m1 = getConnectMetrics();
// The new scope must be observable, and it must NOT be filed under the
// quota/rate dry-well counter — that counter's contract is "out of credit".
assert.equal(m1.selector_ineligible - m0.selector_ineligible, 1, 'the refusal has its own counter');
assert.equal(m1.selector_failover_hops - m0.selector_failover_hops, 1, 'the hop is a SELECTOR hop');
assert.equal(m1.quota_failover_hops - m0.quota_failover_hops, 0, 'not mislabeled as a quota dry-well');
assert.equal(result.status, 200, `expected the eligible peer to serve it, got ${result.status}`);
assert.equal(result.body.choices[0].message.content, 'FAILOVER_OK');
assert.deepEqual(seen, [`A:${X}`, `B:${X}`], 'one hop, onto the peer that is eligible for X');
const after = getAccountInternal(a.id);
assert.equal(after.status, 'active');
assert.equal(after.errorCount || 0, 0);
assert.equal(after.reauth, undefined, 'the rejecting account was never sent to reauth');
assert.equal(logins, 0, 'and never re-logged in');
// Second request: the latch means A is skipped BEFORE the upstream call.
seen.length = 0;
const second = await handleChatCompletions(
{ model: X_MODEL, stream: false, messages: [{ role: 'user', content: 'again' }] },
{ callerKey: '' },
);
assert.equal(second.status, 200);
assert.deepEqual(seen, [`B:${X}`], 'the latched account is not re-probed for the same selector');
// And the account is still healthy for the other selector.
seen.length = 0;
const other = await handleChatCompletions(
{ model: Y, stream: false, messages: [{ role: 'user', content: 'y' }] },
{ callerKey: '' },
);
assert.equal(other.status, 200, 'Y is unaffected by the X latch');
assert.ok(seen.length >= 1);
});
it('stream: fails over before any byte is emitted', async () => {
const a = seed('fo-s-a');
const b = seed('fo-s-b');
__setReloginDeps({ windsurfLogin: async () => { throw new Error('no credential'); } });
const seen = [];
__setConnectDeps({
streamChatCompletion: async (params, send) => {
const who = params.token === a.apiKey ? 'A' : (params.token === b.apiKey ? 'B' : '?');
seen.push(`${who}:${params.model}`);
if (who === 'A' && params.model === X) throw rejectSelector();
send({ id: 's', object: 'chat.completion.chunk', choices: [{ index: 0, delta: { content: 'OK' }, finish_reason: null }] });
send({ id: 's', object: 'chat.completion.chunk', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] });
},
});
const result = await handleChatCompletions(
{ model: X_MODEL, stream: true, messages: [{ role: 'user', content: 'hi' }] },
{ callerKey: '' },
);
const res = fakeRes();
await result.handler(res);
const frames = parseFrames(res.body);
assert.ok(frames.some(f => f !== '[DONE]' && f.choices?.[0]?.delta?.content === 'OK'),
'the eligible peer streamed the answer');
assert.deepEqual(seen, [`A:${X}`, `B:${X}`], 'one pre-emit hop');
assert.equal(getAccountInternal(a.id).status, 'active');
});
// The reviewer's exact client-visible symptom. A is the ONLY account that can
// serve a paid selector Y; B is free-tier, so it cannot serve Y either. Three
// requests for a selector X that upstream retired for A must leave A active, or
// the pool loses Y entirely.
it('a paid Y keeps working after X rejections when only A can serve Y', async () => {
const Y_PAID = 'claude-opus-4-8-medium';
const Y_MODEL = 'claude-opus-4.8';
const a = seed('paidY-a', 'pro');
const b = seed('paidY-b', 'free');
assert.equal(isConnectSelectorAllowedForAccount(b, Y_PAID), false, 'precondition: B cannot serve Y');
const seen = [];
__setConnectDeps({
toChatCompletion: async (params) => {
const who = params.token === a.apiKey ? 'A' : 'B';
seen.push(`${who}:${params.model}`);
if (params.model === X) throw rejectSelector();
return { status: 200, body: { id: 'x', choices: [{ message: { role: 'assistant', content: 'Y_OK' } }] } };
},
});
for (let i = 0; i < 3; i++) {
const r = await handleChatCompletions(
{ model: X_MODEL, stream: false, messages: [{ role: 'user', content: 'x' }] },
{ callerKey: '' },
);
// 403 is the selector verdict. The pre-fix chain answered 401 here ("all
// accounts exhausted (dead session tokens)") because the body was read as
// an auth failure and the dead-token path owned the request.
assert.equal(r.status, 403, `X rejection ${i + 1} must surface the selector verdict, not auth`);
}
assert.equal(getAccountInternal(a.id).status, 'active', 'A still owns Y');
seen.length = 0;
const y = await handleChatCompletions(
{ model: Y_MODEL, stream: false, messages: [{ role: 'user', content: 'y' }] },
{ callerKey: '' },
);
assert.equal(y.status, 200, 'the paid selector must still be servable by the pool');
assert.equal(y.body.choices[0].message.content, 'Y_OK');
assert.deepEqual(seen, [`A:${Y_PAID}`], 'served by A, the only account entitled to Y');
});
it('surfaces the honest 403 when no peer is eligible (no pool blackout)', async () => {
const a = seed('fo-none-a');
const b = seed('fo-none-b');
b.blockedModels = [X];
const seen = [];
__setConnectDeps({
toChatCompletion: async (params) => {
seen.push(params.token === a.apiKey ? 'A' : 'B');
throw rejectSelector();
},
});
const m0 = getConnectMetrics();
const result = await handleChatCompletions(
{ model: X_MODEL, stream: false, messages: [{ role: 'user', content: 'hi' }] },
{ callerKey: '' },
);
assert.equal(result.status, 403, 'the upstream verdict, not 401 and not 429');
assert.equal(result.body.error.code, 'SELECTOR_NOT_ELIGIBLE');
assert.equal(getConnectMetrics().selector_ineligible - m0.selector_ineligible, 1,
'the refusal is counted even though no latch was written (no eligible peer to take over)');
assert.deepEqual(seen, ['A'], 'the ineligible peer is never sent the request');
const after = getAccountInternal(a.id);
assert.equal(after.status, 'active');
assert.equal(isSelectorIneligible(after, X), false,
'nothing latched — the account stays selectable so the next request can still surface the truth');
});
});
// ─────────────────────────────────────────────────────────────────────────────
describe('5. last-account exemption is selector-aware', () => {
it('a same-tier peer that cannot serve the selector does not disqualify the account', () => {
const a = seed('exempt-a');
const b = seed('exempt-b');
b.blockedModels = [X];
assert.equal(__isLastUsableAccount(getAccountInternal(a.id), Date.now(), X), true,
'the peer cannot serve X, so disabling A would black out X for the whole pool');
assert.equal(__isLastUsableAccount(getAccountInternal(a.id), Date.now(), Y), false,
'for Y the peer IS a real fallback');
assert.equal(__isLastUsableAccount(getAccountInternal(a.id), Date.now()), false,
'no selector keeps the account-wide meaning unchanged');
});
it('three auth errors for a selector the peer cannot serve keep the account in rotation', () => {
const a = seed('exempt-c');
const b = seed('exempt-d');
b.blockedModels = [X];
for (let i = 0; i < 3; i++) reportError(a.apiKey, { selector: X });
const after = getAccountInternal(a.id);
assert.equal(after.status, 'active',
'the account is the only one that can serve X — the exemption must keep it selectable');
assert.ok(after.errorCount >= 3, 'the streak is still recorded (it resumes the moment a peer appears)');
// A selector the peer CAN serve is a different story: the breaker trips.
reportError(a.apiKey, { selector: Y });
assert.equal(getAccountInternal(a.id).status, 'error',
'with a real fallback for Y the normal breaker applies');
});
});
// ─────────────────────────────────────────────────────────────────────────────
describe('6. a genuine bad token still trips the existing protection', () => {
it('three UNAUTHORIZED with an eligible peer disables the account', () => {
const a = seed('auth-a');
seed('auth-b'); // same tier, eligible for X → a real fallback
__setReloginDeps({ windsurfLogin: async () => { throw new Error('no credential'); } });
for (let i = 0; i < 3; i++) {
finalizeConnectAccount(
{ id: a.id, apiKey: a.apiKey },
{ model: X_MODEL, selector: X, startTime: Date.now() - 3, err: unauthorized() },
);
}
const after = getAccountInternal(a.id);
assert.equal(after.status, 'error', 'the fix must not weaken real account-fault handling');
assert.ok(after.errorCount >= 3);
assert.equal(isSelectorIneligible(after, X), false,
'a dead token is NOT a selector-scoped rejection — it must not be recorded as one');
});
it('a dead token on one account still fails the request over to the healthy peer', async () => {
const a = seed('auth-c');
const b = seed('auth-d');
__setReloginDeps({ windsurfLogin: async () => { throw new Error('no credential'); } });
const seen = [];
__setConnectDeps({
toChatCompletion: async (params) => {
seen.push(params.token === a.apiKey ? 'A' : 'B');
if (params.token === a.apiKey) throw unauthorized();
return { status: 200, body: { id: 'x', choices: [{ message: { role: 'assistant', content: 'OK' } }] } };
},
});
const result = await handleChatCompletions(
{ model: X_MODEL, stream: false, messages: [{ role: 'user', content: 'hi' }] },
{ callerKey: '' },
);
assert.equal(result.status, 200);
assert.deepEqual(seen, ['A', 'B'], 'dead-token failover path is intact');
assert.notEqual(getAccountInternal(b.id).status, 'error');
});
});