Ctrl K
ComunidadGuías…

test/dashboard-model-reconcile.test.js

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

Archivo original ↗Preguntar a KiBot
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { buildModelReconciliation, mapToggleableVersion } from '../src/dashboard/model-reconcile.js';
import {
  clearLiveCatalogSelectors,
  getSnapshotSelectors,
  setLiveCatalogSelectors,
} from '../src/devin-connect-models.js';

const TOGGLEABLE = [
  'devin-gpt-6-1-sol',
  'devin-gpt-6-sol',
  'devin-gpt-6-astra',
  'devin-fable-5-1',
  'devin-opus-5-5',
  'devin-swe-2-high',
  'devin-swe-2-max',
  'devin-swe-2-lightning-high',
  'devin-swe-2-lightning-max',
  'devin-2-5',
  'devin-auto',
  'devin-fast-opus',
  'devin_lite',
  'devin-ultra',
  'devin-swe-2-low',
  'devin-swe-2-priority-low',
  'devin-swe-2-priority-high',
  'devin-swe-2-priority-max',
  'devin-swe-2-lightning-low',
];

const MAPPED_SELECTORS = [
  'gpt-6-1-sol-medium',
  'gpt-6-sol-medium',
  'gpt-6-astra-medium',
  'claude-fable-5-1-medium',
  'claude-opus-5-5-medium',
  'swe-2-high',
  'swe-2-max',
  'swe-2-high-lightning',
  'swe-2-max-lightning',
];

function localRows(selectors) {
  return selectors.map((selector) => ({ id: selector, _windsurf_id: selector }));
}

function base(over = {}) {
  return {
    local: localRows(MAPPED_SELECTORS.slice(0, 8)), // omit swe-2-max-lightning
    live: [],
    snapshot: getSnapshotSelectors(),
    toggleable: TOGGLEABLE,
    fedModels: { tiers: {}, helpers: [], models: {}, allowlist: null },
    orgConfigs: {
      enterpriseTeamConfig: { teamId: 'team-test-value', allowMcpServers: true, maxUnclaimedSites: 5 },
      enterpriseControlConfig: { extensionModelLabels: ['Base Model', 'Claude 3.7 Sonnet'], teamId: 'team-test-value' },
    },
    upstreamCatalog: { groups: [], sections: [] },
    sources: {
      catalog: { ok: true, stale: false, fetchedAt: 1 },
      fed: { ok: true, stale: false, fetchedAt: 1 },
      toggleable: { ok: true, stale: false, fetchedAt: 1 },
      orgConfig: { ok: true, stale: false, fetchedAt: 1 },
    },
    now: 42,
    ...over,
  };
}

describe('mapToggleableVersion', () => {
  it('follows the deterministic mapping ladder', () => {
    assert.deepEqual(mapToggleableVersion('devin-gpt-6-1-sol'), { selector: 'gpt-6-1-sol-medium', mapped: true });
    assert.deepEqual(mapToggleableVersion('devin-fable-5-1'), { selector: 'claude-fable-5-1-medium', mapped: true });
    assert.deepEqual(mapToggleableVersion('devin-swe-2-lightning-high'), { selector: 'swe-2-high-lightning', mapped: true });
    assert.deepEqual(mapToggleableVersion('devin-2-5'), { selector: null, mapped: false });
    assert.deepEqual(mapToggleableVersion(''), { selector: null, mapped: false });
  });

  // The ladder is catalog-driven, not a hardcoded table: the same upstream
  // version maps or stays unmapped depending on what the live catalog exposes.
  // This is the difference between "we know this is swe-2-low" and "we guessed".
  it('maps the effort-reordered families only when the live catalog has them', () => {
    try {
      setLiveCatalogSelectors([
        'swe-2-low',
        'swe-2-low-priority',
        'swe-2-high-priority',
        'swe-2-low-lightning',
        'auto',
      ]);
      assert.deepEqual(mapToggleableVersion('devin-swe-2-low'), { selector: 'swe-2-low', mapped: true });
      assert.deepEqual(mapToggleableVersion('devin-swe-2-priority-low'),
        { selector: 'swe-2-low-priority', mapped: true },
        'upstream writes the effort tier last: <family>-<effort>-priority');
      assert.deepEqual(mapToggleableVersion('devin-swe-2-priority-high'),
        { selector: 'swe-2-high-priority', mapped: true });
      assert.deepEqual(mapToggleableVersion('devin-swe-2-lightning-low'),
        { selector: 'swe-2-low-lightning', mapped: true });
      assert.deepEqual(mapToggleableVersion('devin-auto'), { selector: 'auto', mapped: true },
        'a catalog that exposes `auto` is the only evidence that `auto` is callable');
      // Still unmapped: no token-preserving selector exists for these, so the row
      // must say so rather than point at a different model.
      assert.deepEqual(mapToggleableVersion('devin-2-5'), { selector: null, mapped: false });
      assert.deepEqual(mapToggleableVersion('devin-fast-opus'), { selector: null, mapped: false });
      assert.deepEqual(mapToggleableVersion('devin_lite'), { selector: null, mapped: false });
    } finally {
      clearLiveCatalogSelectors();
    }
  });

  it('keeps unmapped versions visible in the reconciliation rows', () => {
    try {
      setLiveCatalogSelectors(['swe-2-low']);
      const out = buildModelReconciliation(base({ live: ['swe-2-low'] }));
      const low = out.toggleable.rows.find((r) => r.version === 'devin-swe-2-low');
      assert.deepEqual(low, { version: 'devin-swe-2-low', selector: 'swe-2-low', mapped: true });
      const auto = out.toggleable.rows.find((r) => r.version === 'devin-auto');
      assert.deepEqual(auto, { version: 'devin-auto', selector: null, mapped: false },
        'an unmapped version still gets a row — hiding it is what makes a gap invisible');
      assert.equal(out.toggleable.unmappedCount, out.toggleable.total - out.toggleable.mappedCount);
    } finally {
      clearLiveCatalogSelectors();
    }
  });
});

describe('buildModelReconciliation', () => {
  it('reports the real 233-row snapshot and an unsynced live catalog', () => {
    const out = buildModelReconciliation(base());
    assert.equal(out.snapshotCount, 233);
    assert.equal(out.liveCount, 0);
    assert.equal(out.synced, false);
    assert.deepEqual(out.added, []);
    assert.deepEqual(out.missing, [], 'an unsynced account must not report 233 missing rows');
    assert.equal(out.upstreamCatalog.empty, true);
    assert.equal(out.upstreamCatalog.groupCount, 0);
    assert.equal(out.fedModels.present, false);
    assert.equal(out.fedModels.allowedLiveCount, null);
    assert.equal(out.fedModels.blockedLiveCount, null);
    assert.equal(out.fetchedAt, 42);
  });

  it('maps toggleable versions 9/19 and compares them with the local selectors', () => {
    const out = buildModelReconciliation(base());
    assert.equal(out.toggleable.total, 19);
    assert.equal(out.toggleable.mappedCount, 9);
    assert.equal(out.toggleable.unmappedCount, 10);
    assert.equal(out.toggleable.rows.length, 19);
    const sol = out.toggleable.rows.find((r) => r.version === 'devin-gpt-6-1-sol');
    assert.deepEqual(sol, { version: 'devin-gpt-6-1-sol', selector: 'gpt-6-1-sol-medium', mapped: true });
    const auto = out.toggleable.rows.find((r) => r.version === 'devin-2-5');
    assert.deepEqual(auto, { version: 'devin-2-5', selector: null, mapped: false });
    assert.equal(out.toggleable.localPresentCount, 8);
    assert.equal(out.toggleable.localMissingCount, 1);
    assert.equal(
      out.toggleable.localPresentCount + out.toggleable.localMissingCount,
      out.toggleable.mappedCount,
    );
  });

  it('counts unique local ids, not duplicate rows', () => {
    const out = buildModelReconciliation(base({
      local: [...localRows(['swe-2-high', 'swe-2-high']), { id: 'swe-2-high', _windsurf_id: 'swe-2-high' }],
    }));
    assert.equal(out.localCount, 1);
  });

  it('applies the fed-models overlay only when present', () => {
    const out = buildModelReconciliation(base({
      live: ['gpt-6-1-sol-medium', 'other-live-selector'],
      fedModels: {
        tiers: {},
        helpers: [],
        models: { 'gpt-6-1-sol-medium': {} },
        allowlist: ['gpt-6-1-sol-medium'],
      },
    }));
    assert.equal(out.synced, true);
    assert.equal(out.liveCount, 2);
    assert.equal(out.fedModels.present, true);
    assert.equal(out.fedModels.modelCount, 1);
    assert.equal(out.fedModels.allowlistPresent, true);
    assert.equal(out.fedModels.allowlistCount, 1);
    assert.equal(out.fedModels.allowedLiveCount, 1);
    assert.equal(out.fedModels.blockedLiveCount, 1);
    assert.deepEqual(out.added, ['other-live-selector']);
  });

  it('reports the snapshot difference when synced', () => {
    const out = buildModelReconciliation(base({
      live: ['gpt-6-1-sol-medium'],
      snapshot: ['gpt-6-1-sol-medium', 'snapshot-only-selector'],
    }));
    assert.equal(out.synced, true);
    assert.deepEqual(out.missing, ['snapshot-only-selector']);
    assert.equal(out.snapshotCount, 2);
  });

  it('redacts teamId and caps extension model labels', () => {
    const labels = Array.from({ length: 25 }, (_, i) => `label-${i}`);
    labels[0] = 'L'.repeat(200);
    const out = buildModelReconciliation(base({
      orgConfigs: {
        enterpriseTeamConfig: { teamId: 'team-test-value' },
        enterpriseControlConfig: { extensionModelLabels: labels, teamId: 'team-test-value' },
      },
    }));
    assert.equal(out.orgConfig.teamIdPresent, true);
    assert.equal(JSON.stringify(out).includes('team-test-value'), false);
    assert.equal(out.orgConfig.extensionModelLabels.length, 20);
    assert.equal(out.orgConfig.extensionModelLabels[0].length, 80);
  });

  it('degrades per source without failing the card', () => {
    const out = buildModelReconciliation(base({
      sources: {
        catalog: { ok: false, error: 'forbidden', status: 403 },
        fed: { ok: true, stale: false, fetchedAt: 1 },
        toggleable: { ok: false, error: 'timeout' },
        orgConfig: { ok: true, stale: false, fetchedAt: 1 },
      },
    }));
    assert.equal(out.partial, true);
    assert.deepEqual(out.degraded.map((d) => [d.source, d.kind]), [['catalog', 'forbidden'], ['toggleable', 'timeout']]);
    assert.equal(out.snapshotCount, 233);
  });

  it('caps toggleable rows at 50 while counting all of them', () => {
    const many = Array.from({ length: 60 }, (_, i) => `devin-version-${i}`);
    const out = buildModelReconciliation(base({ toggleable: many }));
    assert.equal(out.toggleable.total, 60);
    assert.equal(out.toggleable.rows.length, 50);
  });
});