Files
brain/tools/m3d-router-invariants.test.mjs
T

34 lines
2.2 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { loadRegistry, clearCache } from './registry-load.mjs';
import { buildNodeGraph } from './node-graph.mjs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { runRouter, buildRouterPrompt, detectHighRisk } from './router-engine.mjs';
const here = dirname(fileURLToPath(import.meta.url));
const registryPath = join(here, '..', 'docs', 'registry', 'nodes.yaml');
describe('Машина 3-D — движок на реальном графе узлов', () => {
it('выбор реального узла проходит, выдуманный отклоняется (на реальном графе)', async () => {
clearCache();
const graph = buildNodeGraph(loadRegistry({ registryPath, useCache: false }));
const real = await runRouter({ prompt: 'нужна архитектурная диаграмма', graph,
llmCall: async () => ({ candidates: ['mermaid'], chosen: 'mermaid', why_chosen: 'диаграмма', twins_considered: 'нет', confidence: 0.9 }) });
expect(real.ok).toBe(true);
const fake = await runRouter({ prompt: 'x', graph,
llmCall: async () => ({ candidates: ['totally-invented'], chosen: 'totally-invented', why_chosen: 'y', twins_considered: 'z', confidence: 0.9 }) });
expect(fake.ok).toBe(false);
});
it('промпт несёт каталог реальных узлов', () => {
clearCache();
const graph = buildNodeGraph(loadRegistry({ registryPath, useCache: false }));
// W1 (C2, CD-R6-G): catalog ≠ graph — каталог передаётся ЯВНО (граф-фолбэк удалён;
// buildNodeGraph несёт .nodes → валидная catalog-форма). Инвариант сохранён.
const { system } = buildRouterPrompt({ prompt: 'x', graph, catalog: graph });
expect(system).toMatch(/mermaid|adr-kit|writing-plans/);
});
it('детерминированный риск на прод-выкате не зависит от мнения модели', () => {
expect(detectHighRisk({ op: 'Bash', command: 'php artisan migrate', prodDeploy: true }).high).toBe(true);
});
});