947796adef
Заменяет зоопарк из ~26 useRef-флагов в chat-thread.tsx на один чистый
редьюсер с перечислимыми переходами (event × state → next state — впервые
юнит-тестируемо напрямую).
Коммит 1 из 5. Содержит СПЕКУ (пишется первой, входит в PR) и каркас:
- run-fsm.spec.md: таблица «событие × состояние», карта всех ref'ов
→ {состояние | контекст | данные}, протокол run-факта, список инвариантов;
- run-fsm.ts: чистый reduce(machine, event) → machine с epoch-инвариантом (I1),
состояниями idle|sending|streaming|attaching|reconnecting|polling|stalled|
stopping|superseding|error, ownership как ПОЛЕ контекста (I2), run-фактом
как first-class (I3), выходом из stopping по данным (I4), dispose-протоколом
(I5) и слоем command-эффектов (attach/postStream/postRun/stop/supersede);
- run-fsm.test.ts: 31 тест переходов, включая поведение коммитов 2–5 как
переходы автомата (reconnect по run-факту; повторные циклы reconnect;
polling→stalled; supersede CAS-исходы; фильтрация позднего колбэка по epoch).
8 зафиксированных решений реализованы; epoch-инвариант неотключаем.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>