Files
brain/tools/router-pin-store.test.mjs
T
Дмитрий f22f8bd2ef feat(router): пининг совета роутера по goalHash (переписка шагов не зовёт LLM заново)
Новый router-pin-store: пин совета роутера по (task_id, goalHash) пер-сессионно.
on-plan-write пин-aware: пин-попадание по неизменной цели → совет переиспользуется,
classifyImpl НЕ зовётся; промах/смена цели → classify + сохранение пина. Проводка в
активный наставник-хук инъекцией реального стора с sessionId (инъекция-выкл по умолчанию,
старое поведение/тесты целы). Хвост спеки роутера §4 (пининг по goalHash), эпик роутер-реестр
этап 3, item 2. Граница не тронута (recommended_chain, цепочки, observer-stop-hook, owner-seal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:18:15 +03:00

45 lines
2.2 KiB
JavaScript

// tools/router-pin-store.test.mjs
import { describe, it, expect } from 'vitest';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { goalHashOf, loadRouterPin, saveRouterPin } from './router-pin-store.mjs';
const mkBase = () => mkdtempSync(join(tmpdir(), 'router-pin-'));
describe('goalHashOf (D1)', () => {
it('детерминирован для одинакового текста', () => {
expect(goalHashOf('цель X')).toBe(goalHashOf('цель X'));
});
it('разный текст → разный хеш', () => {
expect(goalHashOf('цель X')).not.toBe(goalHashOf('цель Y'));
});
});
describe('saveRouterPin / loadRouterPin (D1)', () => {
it('save→load с той же целью возвращает совет', () => {
const baseDir = mkBase();
saveRouterPin({ taskId: 't1', planGoal: 'цель A', classification: { recommended_chain: ['x'] }, sessionId: 's', baseDir });
expect(loadRouterPin({ taskId: 't1', planGoal: 'цель A', sessionId: 's', baseDir })).toEqual({ recommended_chain: ['x'] });
rmSync(baseDir, { recursive: true, force: true });
});
it('смена цели (другой goalHash) → load даёт null', () => {
const baseDir = mkBase();
saveRouterPin({ taskId: 't1', planGoal: 'цель A', classification: { a: 1 }, sessionId: 's', baseDir });
expect(loadRouterPin({ taskId: 't1', planGoal: 'цель B', sessionId: 's', baseDir })).toBeNull();
rmSync(baseDir, { recursive: true, force: true });
});
it('перезапись per taskId', () => {
const baseDir = mkBase();
saveRouterPin({ taskId: 't1', planGoal: 'A', classification: { v: 1 }, sessionId: 's', baseDir });
saveRouterPin({ taskId: 't1', planGoal: 'A', classification: { v: 2 }, sessionId: 's', baseDir });
expect(loadRouterPin({ taskId: 't1', planGoal: 'A', sessionId: 's', baseDir })).toEqual({ v: 2 });
rmSync(baseDir, { recursive: true, force: true });
});
it('нет пина / нет файла → null (fail-safe)', () => {
const baseDir = mkBase();
expect(loadRouterPin({ taskId: 'nope', planGoal: 'A', sessionId: 's', baseDir })).toBeNull();
rmSync(baseDir, { recursive: true, force: true });
});
});