Files
brain/tools/secretary-sessions.test.mjs
T
Дмитрий 90f1360065 feat(secretary): устойчивость к обрывам — источник=транскрипт, склейка продолжений, догон сессий
Секретарь перестал терять промпт владельца при обрыве (сбой API / ручной стоп /
жёсткий крах). Источник правды — транскрипт на диске: сырьё (Слой 1) пересобирается
из всего транскрипта на каждом завершении, а не дописывается по последнему обмену.

- classifyEntry/assembleExchanges: распознавание машинных меток (isApiErrorMessage,
  [Request interrupted by user] обе формы, isCompactSummary, isMeta) — метка не считается
  настоящим промптом; промпт после обрыва помечается продолжением (cont=1), хвост — tail=1.
- realBoundariesFromRaw: продолжение не открывает новый спан (одна работа не дробится).
- честные пометки спана: «(связь прерывалась — продолжено)» / «(прервана, не завершена)».
- stop-хук: пересборка сырья из транскрипта + догон недоразобранного хвоста прошлых
  (умерших) сессий дела при «включи секретаря <дело>» (_sessions.json, secretary-sessions).
- parseLastExchange → тонкая обёртка над assembleExchanges (без дубля логики).

Свод секретаря зелёный: 172 теста / 12 файлов.
Спека: docs/superpowers/specs/2026-06-23-secretary-interruption-resilience-spec.md
План: docs/superpowers/plans/2026-06-23-secretary-interruption-resilience.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 04:19:16 +03:00

21 lines
1.1 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { upsertSessionPointer, prevSessionsForCatchUp } from './secretary-sessions.mjs';
describe('secretary-sessions — учёт сессий дела', () => {
it('upsertSessionPointer добавляет новую сессию с курсором', () => {
const out = upsertSessionPointer([], { session: 's1', cursor: 2 });
expect(out).toEqual([{ session: 's1', cursor: 2 }]);
});
it('upsertSessionPointer обновляет курсор существующей', () => {
const out = upsertSessionPointer([{ session: 's1', cursor: 1 }], { session: 's1', cursor: 5 });
expect(out).toEqual([{ session: 's1', cursor: 5 }]);
});
it('prevSessionsForCatchUp — все сессии дела кроме текущей', () => {
const list = [{ session: 's1', cursor: 3 }, { session: 's2', cursor: 0 }];
expect(prevSessionsForCatchUp(list, 's2')).toEqual([{ session: 's1', cursor: 3 }]);
});
it('prevSessionsForCatchUp — пустой список → пусто', () => {
expect(prevSessionsForCatchUp([], 's2')).toEqual([]);
});
});