Ctrl K
ComunidadGuías…

test/devin-connect-warning-cache-bound.test.js

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

Archivo original ↗Preguntar a KiBot
// D-SCALE-001 (scale lane, reproduced P2) — the DEVIN_CONNECT degrade-warning record
// was process-lifetime AND caller-controlled.
//
// resolveConnectSelector() records every UNKNOWN model name so the "paid request
// downgraded to free tier" warning fires once per distinct name instead of on every
// request. That record had no cap, no TTL and no delete, and src/handlers/chat.js:3245
// resolves the model BEFORE the strict-model 400 at :3253 — so a completed, rejected
// request still left the caller's raw string resident until restart. 1,025 distinct
// junk names retained 1,025 strings; nothing in the suite bounded it.
//
// The repair keeps the dedupe, keys the cache by SHA-256 digest (fixed 64 chars, so
// retained bytes are bounded as well as cardinality) and evicts the oldest insertion
// once 1,024 entries are exceeded. A duplicate hit does NOT refresh its position, so
// the oldest name may warn again after eviction.
//
// Everything below drives the REAL resolver and the REAL handler; the only seam is
// __testing.degradeWarned, the same object the two pre-existing suites reset. Bounded
// fixtures only: short synthetic names, no sockets, no accounts, no upstream calls.
// A live socket attempt fails loudly here — the deny preload that the audit gates
// export into this child turns any non-loopback connect into NETWORK_STUB_MISS.

import { afterEach, beforeEach, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { resolveConnectSelector, __testing, FREE_TIER_SELECTOR } from '../src/devin-connect-models.js';
import { handleChatCompletions } from '../src/handlers/chat.js';
import { buildConnectReachability } from '../src/handlers/models.js';

// The cap Main approved: at most 1,024 retained entries, oldest insertion evicted.
const MAX_ENTRIES = 1024;
const DEGRADE_MARK = 'paid request downgraded to free tier';

const SAVED_ENV = {
  DEVIN_CONNECT: process.env.DEVIN_CONNECT,
  WINDSURFAPI_STRICT_MODEL: process.env.WINDSURFAPI_STRICT_MODEL,
};

let warnings = [];
let originalWarn = null;

/** Warning lines this test process captured; the filter isolates the degrade signal. */
const degradeWarns = () => warnings.filter((line) => line.includes(DEGRADE_MARK));
const degradeWarnsFor = (name) => degradeWarns().filter((line) => line.includes(name)).length;

beforeEach(() => {
  warnings = [];
  originalWarn = console.warn;
  console.warn = (...args) => { warnings.push(args.join(' ')); };
  __testing.degradeWarned.clear();
});

afterEach(() => {
  console.warn = originalWarn;
  __testing.degradeWarned.clear();
  for (const [key, value] of Object.entries(SAVED_ENV)) {
    if (value === undefined) delete process.env[key];
    else process.env[key] = value;
  }
});

describe('DEVIN_CONNECT degrade-warning cache is bounded (D-SCALE-001)', () => {
  it('warning-cache-bounds-distinct-rejections', () => {
    const count = MAX_ENTRIES + 1;
    for (let i = 0; i < count; i++) {
      const r = resolveConnectSelector(`zzscale-junk-${i}`);
      assert.equal(r.selector, FREE_TIER_SELECTOR, 'an unknown name still degrades to the free selector');
      assert.equal(r.mapped, false, 'an unknown name still reports mapped:false');
    }

    assert.equal(
      degradeWarns().length, count,
      'every distinct unknown name still gets its one warning — the bound must not swallow names',
    );
    assert.ok(
      __testing.degradeWarned.size <= MAX_ENTRIES,
      `${count} distinct rejected names left ${__testing.degradeWarned.size} entries resident; the cache must stay at or below ${MAX_ENTRIES}`,
    );
    assert.equal(
      __testing.degradeWarned.size, MAX_ENTRIES,
      'after overflowing by one the cache sits exactly at its cap',
    );
  });

  it('warning-cache-forgets-oldest-keeps-recent', () => {
    const oldest = 'zzscale-oldest-ghost';
    const recent = 'zzscale-recent-ghost';

    resolveConnectSelector(oldest);
    resolveConnectSelector(oldest);
    assert.equal(degradeWarnsFor(oldest), 1, 'a repeat of the same unknown name is deduped');

    // Fill the cache: 1,024 distinct names is enough to push the oldest insertion out.
    for (let i = 0; i < MAX_ENTRIES; i++) resolveConnectSelector(`zzscale-fill-${i}`);
    resolveConnectSelector(recent);

    resolveConnectSelector(oldest);
    assert.equal(
      degradeWarnsFor(oldest), 2,
      'the evicted oldest name must be able to warn again instead of being suppressed forever',
    );

    resolveConnectSelector(recent);
    assert.equal(degradeWarnsFor(recent), 1, 'a recent name stays deduped after the eviction');
  });

  it('warning-cache-retains-no-raw-long-model', () => {
    const longName = `zzscale-long-${'ghostname'.repeat(40)}`;
    assert.ok(longName.length > 300, 'fixture precondition: a modestly long synthetic name');

    resolveConnectSelector(longName);

    const entries = [...__testing.degradeWarned];
    assert.equal(entries.length, 1, 'the unknown name is still recorded, so the dedupe works');
    for (const key of entries) {
      assert.notEqual(key, longName, 'the raw caller-supplied name must never be retained');
      assert.equal(
        String(key).includes('zzscale-long-'), false,
        'no retained key may embed the raw model name',
      );
      assert.equal(
        String(key).length, 64,
        `retained keys must be fixed-width digests, not caller-length strings (got ${String(key).length} chars)`,
      );
      assert.match(String(key), /^[0-9a-f]{64}$/, 'a retained key is a lowercase hex SHA-256 digest');
    }
  });

  it('warning-cache-controls-preserve-resolution', () => {
    assert.equal(
      typeof __testing.degradeWarned.clear, 'function',
      'the pre-existing suites reset this seam with __testing.degradeWarned.clear()',
    );
    const before = __testing.degradeWarned.size;
    const known = 'claude-opus-4-8-medium';

    assert.deepEqual(
      resolveConnectSelector(known),
      { selector: known, mapped: true },
      'a real catalog selector still resolves to itself',
    );
    assert.deepEqual(
      resolveConnectSelector('claude-opus-4.8'),
      { selector: known, mapped: true },
      'a curated dotted alias still resolves to its catalog target',
    );
    assert.deepEqual(
      resolveConnectSelector(''),
      { selector: FREE_TIER_SELECTOR, mapped: false },
      'empty input still returns the free-tier default',
    );
    assert.deepEqual(
      resolveConnectSelector('zzscale-warnoff-ghost', { warnOnFallback: false }),
      { selector: FREE_TIER_SELECTOR, mapped: false },
      'warnOnFallback:false still degrades silently',
    );

    assert.equal(
      __testing.degradeWarned.size, before,
      'a mapped, empty or silent call must not consume cache entries',
    );
    assert.equal(degradeWarns().length, 0, 'none of the control calls emits the degrade warning');
  });

  it('warning-cache-handler-strict400-unchanged', async () => {
    process.env.DEVIN_CONNECT = '1';
    process.env.WINDSURFAPI_STRICT_MODEL = '1';
    const model = 'zzscale-handler-ghost';

    const first = await handleChatCompletions({
      model,
      messages: [{ role: 'user', content: 'ping' }],
    });
    assert.equal(first.status, 400, 'an unmapped model is still rejected by the strict gate');
    assert.equal(first.body.error.code, 'model_not_found');
    assert.equal(first.body.error.param, 'model');
    assert.match(first.body.error.message, /not a valid model/i);
    assert.equal(degradeWarnsFor(model), 1, 'the first rejected request warns once');
    const sizeAfterFirst = __testing.degradeWarned.size;

    const second = await handleChatCompletions({
      model,
      messages: [{ role: 'user', content: 'ping' }],
    });
    assert.deepEqual(second, first, 'the strict rejection body must not move');
    assert.equal(degradeWarnsFor(model), 1, 'a repeat rejected request is deduped');
    assert.equal(
      __testing.degradeWarned.size, sizeAfterFirst,
      'a repeat rejected request adds no cache entry',
    );
  });
});

describe('read-only discovery must not consume the degrade warning', () => {
  it('a later real request still warns once after discovery', () => {
    const name = 'zzscale-discovery-ghost';
    const reach = buildConnectReachability({ ...process.env, DEVIN_CONNECT: '1' });
    reach(name);
    assert.equal(
      degradeWarnsFor(name), 0,
      'catalog discovery is not a paid request and must not spend the one-time warning',
    );
    resolveConnectSelector(name);
    assert.equal(
      degradeWarnsFor(name), 1,
      'the first real request after discovery must still warn exactly once',
    );
  });
});