Files
brain/tools/secretary-protocol.test.mjs
T
Дмитрий d44254a0e1 feat(secretary): качество выжимки — тема+время, флажок по сессии, дедуп, промпт без шума, стабильная тема, навигация протокол->Слой 1
- оглавление: реальная тема (поле «тема» в моторе) + дата со временем вместо заглушки (дело)
- флажок по сессии secretary-mode-<session>.json — параллельные сессии не смешиваются
- дедуп при записи (applyExtraction) — не плодим одинаковые пункты
- промпт-дисциплина: игнор служебного шума, «воля» только у [ЮЗЕР], решения не вопросы
- стабильная тема (первая непустая, не уезжает на тему хода)
- провенанс несёт сессию (@<session>) -> навигация в raw/<session>.log; steps/ убраны как дубли
- мёртвый код снят: secretary-slice + computePeriod + buildStepLinks

37 тестов green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:30:02 +03:00

67 lines
3.5 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 { applyExtraction, renderProtocol, EMPTY_PROTOCOL } from './secretary-protocol.mjs';
describe('secretary-protocol', () => {
it('добавляет решение с провенансом', () => {
const p = applyExtraction(EMPTY_PROTOCOL(), {
decisions: [{ text: 'единица = дело', why: 'тянется через сессии', turns: [7] }],
});
const md = renderProtocol(p);
expect(md).toContain('единица = дело');
expect(md).toContain('[→7]');
});
it('сверка зачёркивает, не удаляет', () => {
let p = applyExtraction(EMPTY_PROTOCOL(), { decisions: [{ text: 'A', turns: [1] }] });
p = applyExtraction(p, { supersede: [{ oldText: 'A', newText: 'B', turns: [2] }] });
const md = renderProtocol(p);
expect(md).toContain('~~A~~');
expect(md).toContain('B');
});
});
describe('secretary-protocol — тема дела', () => {
it('сохраняет тему из выжимки', () => {
const p = applyExtraction(EMPTY_PROTOCOL(), { subject: 'о чём дело', decisions: [] });
expect(p.subject).toBe('о чём дело');
});
it('пустая тема не затирает прежнюю', () => {
let p = applyExtraction(EMPTY_PROTOCOL(), { subject: 'первая', decisions: [] });
p = applyExtraction(p, { subject: '', decisions: [] });
expect(p.subject).toBe('первая');
});
it('тема стабильна: вторая (непустая) не перезатирает первую', () => {
let p = applyExtraction(EMPTY_PROTOCOL(), { subject: 'создание секретаря', decisions: [] });
p = applyExtraction(p, { subject: 'узкая тема последнего хода', decisions: [] });
expect(p.subject).toBe('создание секретаря');
});
});
describe('secretary-protocol — навигация в Слой 1 (провенанс с сессией)', () => {
it('applyExtraction сохраняет session в записи решения', () => {
const p = applyExtraction(EMPTY_PROTOCOL(), { decisions: [{ text: 'D', turns: [7], session: 'abc12345-zzz' }] });
expect(p.decisions[0].session).toBe('abc12345-zzz');
});
it('renderProtocol показывает сессию рядом с [→N] для перехода в raw', () => {
const p = applyExtraction(EMPTY_PROTOCOL(), { decisions: [{ text: 'D', turns: [7], session: '69992620-aaaa' }] });
const md = renderProtocol(p);
expect(md).toContain('[→7]');
expect(md).toContain('69992620');
});
});
describe('secretary-protocol — дедуп (без хлама)', () => {
it('не дублирует решение с тем же текстом (регистр/пробелы)', () => {
let p = applyExtraction(EMPTY_PROTOCOL(), { decisions: [{ text: 'берём Postgres', turns: [1] }] });
p = applyExtraction(p, { decisions: [{ text: ' берём postgres ', turns: [2] }] });
expect(p.decisions.filter((d) => !d.struck).length).toBe(1);
});
it('не дублирует пункты воли / открытых / сделано', () => {
const ext = { will: [{ text: 'не коммить без спроса' }], open: [{ text: 'какой бэкенд?' }], doneNext: [{ text: 'написать тест', done: false }] };
let p = applyExtraction(EMPTY_PROTOCOL(), ext);
p = applyExtraction(p, ext);
expect(p.will.length).toBe(1);
expect(p.open.length).toBe(1);
expect(p.doneNext.length).toBe(1);
});
});