Files
brain/tools/secretary-mechanics.test.mjs
T

58 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from 'vitest';
import { applyTend } from './secretary-gardener.mjs';
import { applyResults } from './secretary-apply.mjs';
// Механика, которую на 2-спановых прогонах не проверяли (НАХОДКИ, решение №8). Тесты бьют по реальным
// функциям конвейера A (applyTend/applyResults), а не по воркеру — это поведение разбора, не оркестрации.
describe('mechanics: reopen / обратный каскад', () => {
it('закрытая ветка снова открывается и снимается зачёркивание (несущее решение изменилось)', () => {
const proto = { hidden: [{ id: 'СВ-1', lens: 'Л4', status: 'закрыт', struck: true, text: 'дыра', born: 3, lastTouch: 5 }] };
applyTend(proto, [{ id: 'СВ-1', action: 'reopen', why: 'несущее решение изменилось' }], 8);
const sv = proto.hidden[0];
expect(sv.status).toBe('открыт');
expect(sv.struck).toBe(false);
expect(sv.lastTouch).toBe(8);
expect(sv.born).toBe(3); // корень сохранён — не потеряли историю
});
});
describe('mechanics: сжатие длинной истории (сворачивание ≠ удаление)', () => {
it('на масштабе: закрытые ветки сворачиваются (struck), но остаются с источником (born)', () => {
// 12 живых веток; закрываем половину с пруфом.
const hidden = Array.from({ length: 12 }, (_, i) => ({
id: `СВ-${i + 1}`, lens: 'Л1', status: 'открыт', struck: false,
text: `нет выдержек кода ${i}`, born: i + 1, lastTouch: i + 1,
}));
const proto = { hidden };
const tend = hidden.filter((_, i) => i % 2 === 0).map((h) => ({ id: h.id, action: 'close', proof: `код:${h.born}` }));
applyTend(proto, tend, 20);
// Ни одна ветка не удалена — сворачивание прячет видность, не корень («потом не восстановим»).
expect(proto.hidden).toHaveLength(12);
const closed = proto.hidden.filter((h) => h.status === 'закрыт');
expect(closed).toHaveLength(6);
for (const h of closed) {
expect(h.struck).toBe(true);
expect(Number.isFinite(h.born)).toBe(true); // источник на месте
}
});
});
describe('mechanics: гравитация (кандидат → ствол)', () => {
// ПРОБЕЛ (follow-up): в A механика НЕ реализована. applyResults накапливает кандидатов (p.candidates,
// дедуп по branch), но НЕТ пути продвижения кандидата в ствол (decisions/will), когда владелец заговорил
// об идее. Это суждение РЕДАКТОРА (сопоставить кандидата с движением ствола), не детерминированное
// правило — строить спекулятивно нельзя (решение владельца; реализация = доработка редактор-промпта).
// Документируем как незакрытый хвост, не выдаём отсутствующее за готовое.
it.todo('кандидат поднимается в ствол, когда владелец заговорил об его идее');
it('сейчас: кандидат лишь накапливается в candidates, в ствол сам не уходит (фиксируем текущее поведение)', () => {
const proto = { hidden: [], candidates: [], nextSvId: 1, decisions: [] };
const d13 = { forks: [{ branch: 'вынести очередь в SQLite', trigger: 'цитата', why: 'масштаб', опора: 'догадка', релевантность: 'medium' }] };
const out = applyResults(proto, 5, null, null, d13, null);
expect(out.candidates).toHaveLength(1);
expect(out.candidates[0].branch).toBe('вынести очередь в SQLite');
expect(out.decisions || []).toHaveLength(0); // в ствол не просочился — подтверждает, что гравитации нет
});
});