Ctrl K
ComunidadGuías…

test/auth-quota-cooldown-monotonic.test.js

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

Archivo original ↗Preguntar a KiBot
// V-18 (audit CORE-004) — one quota cooldown dimension, two writers.
//
//   * applyQuotaSnapshot() reacts to a proactive weekly-credit snapshot.
//   * markQuotaExhausted()  reacts to a LIVE 402 for an actual request.
//
// The audit probe: a live 402 armed a three-hour deadline; a later snapshot that
// reported 80% weekly cleared it, and a snapshot reporting 0% overwrote it with
// the 30-minute default. Both are wrong:
//
//  1. MONOTONIC — a cooldown is a deadline, not a value. A later write may
//     extend it (more evidence of dryness) but must never pull it closer, or an
//     account re-enters rotation before the upstream said it would be usable.
//  2. SAME-SOURCE PROOF — a weekly snapshot only knows the INCLUDED-quota
//     dimension. A live 402 can be about the on-demand/ACU dimension while the
//     weekly number reads healthy, so "weekly 80%" is not evidence that the
//     dimension the 402 came from recovered. Only a snapshot that wrote the
//     deadline may clear it; a live-402 deadline self-heals on expiry.

import { afterEach, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import {
  addAccountByKey, removeAccount, applyQuotaSnapshot, markQuotaExhausted,
  __isRateLimitedForModel, __serializeAccounts, __deserializeAccount,
} from '../src/auth.js';

const created = [];
const ENV_KEYS = [
  'WINDSURFAPI_QUOTA_COOLDOWN', 'WINDSURFAPI_QUOTA_COOLDOWN_MS',
  'WINDSURFAPI_QUOTA_DRY_THRESHOLD', 'WINDSURFAPI_SPEND_ON_DEMAND',
];
const savedEnv = {};

function add(label) {
  const account = addAccountByKey(
    `v18-key-${Date.now()}-${created.length}-${Math.random().toString(36).slice(2)}`,
    label,
  );
  created.push(account.id);
  return account;
}

function persistEnv(key) { savedEnv[key] = process.env[key]; }

afterEach(() => {
  for (const k of ENV_KEYS) {
    if (!(k in savedEnv)) continue;
    if (savedEnv[k] === undefined) delete process.env[k];
    else process.env[k] = savedEnv[k];
    delete savedEnv[k];
  }
  while (created.length) removeAccount(created.pop());
});

describe('V-18 — quota cooldown is monotonic and source-aware', () => {
  it('weekly quota snapshot cannot shorten a live 402 cooldown', () => {
    persistEnv('WINDSURFAPI_QUOTA_COOLDOWN_MS');
    process.env.WINDSURFAPI_QUOTA_COOLDOWN_MS = '1800000'; // 30m snapshot default
    const acct = add('v18-shorten');
    const now = 30_000_000;
    const liveMs = 3 * 60 * 60 * 1000;                     // upstream said 3h
    markQuotaExhausted(acct.apiKey, liveMs, now);
    const liveDeadline = acct.quotaResetAt;
    assert.equal(liveDeadline, now + liveMs);

    applyQuotaSnapshot(acct, 0, now + 1000);               // still dry
    assert.equal(acct.quotaResetAt, liveDeadline,
      'a 30m snapshot must not pull a 3h live-402 deadline closer');
    assert.equal(__isRateLimitedForModel(acct, null, liveDeadline - 1), true,
      'the account stays out of rotation until the upstream window ends');
  });

  it('a recovered weekly snapshot does not clear a live-402 cooldown', () => {
    const acct = add('v18-cross-source');
    const now = 31_000_000;
    markQuotaExhausted(acct.apiKey, 60 * 60 * 1000, now);
    const liveDeadline = acct.quotaResetAt;

    // Weekly data reads healthy — but it says nothing about the dimension the
    // live 402 came from (it can be an on-demand/ACU exhaustion).
    applyQuotaSnapshot(acct, 80, now + 1000);
    assert.equal(acct.quotaResetAt, liveDeadline,
      'unrelated weekly data cannot clear a live-402 cooldown');
    assert.equal(__isRateLimitedForModel(acct, null, now + 2000), true,
      'the account stays cooled');
  });

  it('a snapshot-written cooldown still clears on a recovered snapshot (control)', () => {
    const acct = add('v18-same-source');
    const now = 32_000_000;
    applyQuotaSnapshot(acct, 0, now);
    assert.ok(acct.quotaResetAt > now, 'dry snapshot cools');
    applyQuotaSnapshot(acct, 42, now + 60_000);
    assert.equal(acct.quotaResetAt, 0, 'same-source recovery clears it immediately');
    assert.equal(acct.quotaResetSource, null, 'and the provenance is dropped with it');
  });

  it('a snapshot never shortens a longer snapshot cooldown either', () => {
    persistEnv('WINDSURFAPI_QUOTA_COOLDOWN_MS');
    process.env.WINDSURFAPI_QUOTA_COOLDOWN_MS = '7200000'; // 2h
    const acct = add('v18-snapshot-monotonic');
    const now = 33_000_000;
    applyQuotaSnapshot(acct, 0, now);
    const first = acct.quotaResetAt;
    assert.equal(first, now + 7200000);
    process.env.WINDSURFAPI_QUOTA_COOLDOWN_MS = '1800000'; // operator lowers it
    applyQuotaSnapshot(acct, 0, now + 1000);
    assert.equal(acct.quotaResetAt, first,
      'a tunable change does not retroactively shorten an armed cooldown');
  });

  it('an expired live-402 cooldown is cleaned up by the next snapshot (self-healing)', () => {
    const acct = add('v18-expire');
    const now = 34_000_000;
    markQuotaExhausted(acct.apiKey, 60 * 60 * 1000, now);
    const liveDeadline = acct.quotaResetAt;
    applyQuotaSnapshot(acct, 80, liveDeadline + 1);
    assert.equal(acct.quotaResetAt, 0, 'an expired deadline is stale state, not a cooldown');
    assert.equal(acct.quotaResetSource, null);
  });

  it('a spendable balance does not clear a live-402 deadline either (deliberate)', () => {
    const acct = add('v18-funded-live');
    const now = 36_000_000;
    markQuotaExhausted(acct.apiKey, 30 * 60 * 1000, now);
    const liveDeadline = acct.quotaResetAt;
    acct.credits = { balance: 50 };      // policy says a funded account may serve
    applyQuotaSnapshot(acct, 0, now + 1000);
    assert.equal(acct.quotaResetAt, liveDeadline,
      'the 402 window bounds the re-probe rate; only expiry clears it');
  });

  it('the live-402 provenance survives a restart', () => {
    const acct = add('v18-persist');
    const now = Date.now();
    markQuotaExhausted(acct.apiKey, 60 * 60 * 1000, now);
    const record = __serializeAccounts().find(a => a.apiKey === acct.apiKey);
    assert.equal(record.quotaResetSource, 'live402',
      'the source is persisted with the deadline');

    const restored = __deserializeAccount(record);
    assert.equal(restored.quotaResetAt, record.quotaResetAt);
    assert.equal(restored.quotaResetSource, 'live402');
    applyQuotaSnapshot(restored, 90, now + 1000);
    assert.equal(restored.quotaResetAt, record.quotaResetAt,
      'a restart must not make the live-402 deadline clearable by weekly data');
  });

  it('a legacy deadline with no recorded source is treated as not-snapshot-clearable', () => {
    const now = 35_000_000;
    // Written by a version that did not persist provenance (or hand-edited).
    const legacy = __deserializeAccount({ apiKey: 'v18-legacy', quotaResetAt: now + 60_000 });
    assert.equal(legacy.quotaResetSource, null, 'unknown provenance is null, not guessed');
    applyQuotaSnapshot(legacy, 80, now + 1000);
    assert.equal(legacy.quotaResetAt, now + 60_000,
      'the snapshot cannot prove anything about a deadline it did not write');
    applyQuotaSnapshot(legacy, 80, now + 120_000);
    assert.equal(legacy.quotaResetAt, 0, 'expiry still self-heals it');
  });
});