d44254a0e1
- оглавление: реальная тема (поле «тема» в моторе) + дата со временем вместо заглушки (дело) - флажок по сессии 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>
67 lines
3.5 KiB
JavaScript
67 lines
3.5 KiB
JavaScript
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);
|
||
});
|
||
});
|