fsm.abandonable(prefix, when=None) — пометить состояния-вопросы, которые движок может бросить по тайм-ауту.
meds.record_dose(..., ref=None), meds.record_side_effects(..., ref=None) — ref из кнопки; без него — сегодняшняя доза.
Намеренно изменённые тесты:test_dialog_meds.py, test_dialog_veteran_days.py — данные кнопок лекарств теперь med:taken:<dose_id> и т.д.; в д.13 после п.9 ожидается crisis (C-SSRS уже пройден), а не повторный scale.cssrs_screen.
Как проверить
make lint test (684 passed); uv run pytest tests/test_dialog_engine_gaps.py tests/test_dialog_veteran_days.py.
Чек-лист
rebase на origin/dev
make lint + make test зелёные
лог в issue (### 2026-10-03)
нет ПДн в логах, нет реальных данных, нет секретов
## Что меняется
Закрывает пробелы движка диалога, найденные в прогоне 13 дней Андрея: C-SSRS не повторяется в течение 24 ч после завершённого скрининга (кризис и алерт остаются), реестр вступлений шкал `register_scale_intro`, префиксные триггеры с данными в кнопке (`button:med:taken:*` → `trigger_payload(event)`, кнопки лекарств несут `dose_id`), тайм-аут брошенного шага `abandon_after_hours` (6 ч).
Closes #56
## Зона
A
**API для флоу:**
- `scale_session.register_scale_intro(scale_id, text | fn(ctx, scale_id, scheduled, return_state) -> str | None, *, replace=False)`; `start_scale(intro=None)` берёт из реестра (явный `intro` важнее).
- `@trigger("button:<prefix>:*")` + `fsm.trigger_payload(event) -> str | None`; точный ключ важнее префикса, длинный префикс важнее короткого.
- `fsm.abandonable(prefix, when=None)` — пометить состояния-вопросы, которые движок может бросить по тайм-ауту.
- `meds.record_dose(..., ref=None)`, `meds.record_side_effects(..., ref=None)` — `ref` из кнопки; без него — сегодняшняя доза.
**Намеренно изменённые тесты:** `test_dialog_meds.py`, `test_dialog_veteran_days.py` — данные кнопок лекарств теперь `med:taken:<dose_id>` и т.д.; в д.13 после п.9 ожидается `crisis` (C-SSRS уже пройден), а не повторный `scale.cssrs_screen`.
## Как проверить
`make lint test` (684 passed); `uv run pytest tests/test_dialog_engine_gaps.py tests/test_dialog_veteran_days.py`.
## Чек-лист
- [x] rebase на origin/dev
- [x] make lint + make test зелёные
- [x] лог в issue (### 2026-10-03)
- [x] нет ПДн в логах, нет реальных данных, нет секретов
- [x] общие файлы и замороженные контракты не тронуты
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- No same-day C-SSRS repeat: a risk screen completed within cssrs_cooldown_hours is not queued again
after PHQ-9 item 9 >= 1 (scale crisis path, rule schedule_scale, scale_due); crisis script and alerts stay.
- Scale intro registry: register_scale_intro(scale_id, text_or_fn); start_scale(intro=None) uses it.
veteran_daily migrated from per-scale on_enter hooks.
- Prefix triggers "button:<prefix>:*" with trigger_payload(event); medication buttons carry the dose
(med:taken:<dose_id>, ...), med_pending dropped; payload-less legacy buttons answer as stale.
- Abandoned-step timeout: settings.abandon_after_hours (default 6 h) returns abandonable states
(daily.*, meds.*, scale.* not in onboarding) to idle before the next event; never in crisis or with intake on.
Refs #56
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Что меняется
Закрывает пробелы движка диалога, найденные в прогоне 13 дней Андрея: C-SSRS не повторяется в течение 24 ч после завершённого скрининга (кризис и алерт остаются), реестр вступлений шкал
register_scale_intro, префиксные триггеры с данными в кнопке (button:med:taken:*→trigger_payload(event), кнопки лекарств несутdose_id), тайм-аут брошенного шагаabandon_after_hours(6 ч).Closes #56
Зона
A
API для флоу:
scale_session.register_scale_intro(scale_id, text | fn(ctx, scale_id, scheduled, return_state) -> str | None, *, replace=False);start_scale(intro=None)берёт из реестра (явныйintroважнее).@trigger("button:<prefix>:*")+fsm.trigger_payload(event) -> str | None; точный ключ важнее префикса, длинный префикс важнее короткого.fsm.abandonable(prefix, when=None)— пометить состояния-вопросы, которые движок может бросить по тайм-ауту.meds.record_dose(..., ref=None),meds.record_side_effects(..., ref=None)—refиз кнопки; без него — сегодняшняя доза.Намеренно изменённые тесты:
test_dialog_meds.py,test_dialog_veteran_days.py— данные кнопок лекарств теперьmed:taken:<dose_id>и т.д.; в д.13 после п.9 ожидаетсяcrisis(C-SSRS уже пройден), а не повторныйscale.cssrs_screen.Как проверить
make lint test(684 passed);uv run pytest tests/test_dialog_engine_gaps.py tests/test_dialog_veteran_days.py.Чек-лист
🤖 Generated with Claude Code