docs: bootstrap repo — CLAUDE.md, spec, ADR, TenVex-style workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 14:36:33 +03:00
co-authored by Claude Opus 5.5
commit cf2cc8b5f4
15 changed files with 1671 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
# Архитектурные решения (ADR)
> Живой журнал: **что** решили и **почему**. Новые записи — сверху. Одна запись = одно решение.
> При конфликте с [`docs/info/SPEC.md`](info/SPEC.md) действует ADR.
## 2026-10-03 — ADR-009: Процесс — регламент TenVex в облегчённом режиме хакатона
**Контекст:** 3 дня, сдача в пн 05.10 в 13:00 МСК. Два разработчика и Claude Code-агенты работают параллельно. Опыт TenVex/vobot: без issue и изоляции агенты конфликтуют.
**Решение:** берём ядро регламента vobot: задача = issue, одна зона на issue, worktree + ветка от `origin/dev`, PR в `dev`, Conventional Commits, лог в теле issue, ADR сюда. Облегчения: PR в `dev` можно мержить самому после зелёного `make lint test`, без обязательного ревью; contract-first/orval нет; `main` = сдаваемая версия, промоушн `dev → main` делает человек.
**Последствия:** регламент — [`docs/dev/WORKFLOW.md`](dev/WORKFLOW.md).
## 2026-10-03 — ADR-008: Конфиги в `config/`, данные в `data/`
**Контекст:** требования к оформлению: «конфигурационные файлы — в отдельной папке». В SPEC пороги лежали в `data/scales`.
**Решение:** `config/` — шкалы (пункты, диапазоны, градации), расписания модулей, правила алертов, лексикон риска, тексты для пациента (YAML, вычитывает психиатр). `data/` — синтетика, выдержки ГРЛС, eval-разметка.
**Причина:** соответствие чек-листу жюри; психиатр правит только `config/`, не трогая код.
## 2026-10-03 — ADR-007: «Действия агента» — это выход движка правил, а не tool-calling LLM
**Контекст:** в демо-сценарии действия записаны как вызовы инструментов (`raise_alert`, `notify_doctor`, `crisis_protocol`, `book_visit`). Это выглядит так, будто их решает LLM, а это противоречит правилу «алерты детерминированы».
**Решение:** правила (`config/rules.yaml`) по структурированным данным возвращают список действий; оркестратор их исполняет. LLM только формулирует реплику вокруг уже принятого действия.
**Причина:** юридическая атрибуция ответственности: пороги задаёт врач, ИИ решений не принимает. Это ключевой аргумент для жюри и для специалистов.
## 2026-10-03 — ADR-006: Цвета в UI ↔ уровни алертов
**Решение:** 🔴 = `acute` (кризис, п.9 ≥ 1, C-SSRS с намерением/планом, доступ к оружию при риске); 🟡 = `high` + `moderate` (врачу ≤ 24 ч / флаг к визиту); 🟢 = нет открытых алертов; `info` (молчание, нет ответа) — серый флаг. В БД хранится уровень, цвет вычисляется.
## 2026-10-03 — ADR-005: Демо-часы (виртуальное время)
**Контекст:** демо — 13 дней терапии за 3 минуты. Шедулер на реальном времени это показать не даст.
**Решение:** всё время в системе берётся из `app.core.clock` (реальное или виртуальное, `DEMO_CLOCK=true`). В демо-консоли есть кнопка «следующий день». Шедулер срабатывает по сдвигу часов. Правила считают окна (3 дня подряд, 7 дней) от виртуального «сейчас».
**Последствия:** нигде не вызывать `datetime.now()` напрямую. Проверяется в ревью.
## 2026-10-03 — ADR-004: Канал-независимый диалоговый движок + веб-демо-консоль + офлайн-режим
**Контекст:** решение должно запускаться на технике организатора без нестандартного ПО. Telegram и GigaChat на площадке могут быть недоступны.
**Решение:** диалог — чистая функция `engine.handle(token, event) -> list[Reply]` поверх FSM. Адаптеры: Telegram (aiogram) и веб-чат в демо-консоли (Streamlit). LLM за протоколом с двумя провайдерами: `gigachat` и `mock` (детерминированные ответы для демо-реплик). `LLM_PROVIDER=mock` по умолчанию в `docker compose up`.
**Причина:** главный критерий жюри — работоспособность. Демо не должно зависеть от сети.
## 2026-10-03 — ADR-003: Один Postgres, две базы; без Redis и Alembic в MVP
**Контекст:** в SPEC два контейнера Postgres и Redis.
**Решение:** один сервис `postgres` с двумя базами (`identity`, `clinical`; `audit_log` лежит в `clinical`) и двумя ролями: роль клинического модуля не имеет прав на `identity`. Связь — HMAC-токен. Схема создаётся через `create_all` при старте. FSM-состояние хранится в таблице `dialog_state`.
**Причина:** изоляция сохраняется (разные БД и разные роли), а операционной сложности меньше. Alembic для трёхдневного прототипа — лишнее трение. В проде — отдельные кластеры и миграции.
## 2026-10-03 — ADR-002: Ежедневный чек-ин = настроение + приём + модульный вопрос; шкалы — по расписанию
**Контекст:** в SPEC ежедневно собираются 2–3 пункта PHQ-9 в 14-дневном окне. В демо-персоне и в модулях — ежедневно настроение 0–10, приём, сон, алкоголь, а шкалы целиком по расписанию (PHQ-9 еженедельно/раз в 2 недели) и внепланово по триггеру.
**Решение:** берём модель из модулей. Ежедневно: настроение 0–10, приём препарата, один модульный вопрос (сон/кошмары у ветерана, алкоголь при флаге AUDIT-C) и свободный текст (`extract` → побочки, намерение бросить, алкоголь). Полные шкалы — по расписанию модуля и внепланово (например, настроение ≤ 3 три дня → внеплановый PHQ-9). П.9 PHQ-9 — только кнопками.
**Последствия:** новая таблица `daily_checkins` (mood, med_taken, sleep_bucket, alcohol_bucket, flags).
## 2026-10-03 — ADR-001: Общее ядро + три модуля, включаемые скринингом
**Контекст:** три источника требований (SPEC, демо-персона, концепция/CJM) по-разному ставят фокус: ветераны, депрессия, семьи.
**Решение:** общее ядро (PHQ-9 → C-SSRS, ежедневный чек-ин, молчание как сигнал) и модули `veteran`, `depression`, `family` ([`CLINICAL_MODULES.md`](info/CLINICAL_MODULES.md)). Модули включает стартовый скрининг и/или врач при подключении пациента. Шкалы, расписания и триггеры модулей описаны декларативно в `config/modules.yaml`.
**Приоритет на хакатон:** ядро, `veteran` и `depression` — P0; `family` — P1 (вход «Я близкий», чек-лист, кнопка «сообщить врачу»).
**Кейс:** закрываем сценарии «мониторинг после обращения» и «управление приёмом лекарств». Скрининг/триаж — входная точка, а не отдельный третий сценарий.