[bot][A] Пробелы движка: повтор C-SSRS, вступления шкал, данные в кнопках, тайм-аут шага #56

Closed
opened 2026-10-03 18:49:20 +03:00 by Eleboba · 0 comments
Owner

Описание

При сквозном прогоне 13 дней Андрея (#37, PR #55) нашлись пробелы движка диалога (#10). Демо они не ломают, но на защите их может увидеть жюри, а одно затрагивает безопасность.

Желаемый результат

  1. C-SSRS не дублируется в тот же день. Сейчас после п.9 PHQ-9 ≥ 1 C-SSRS снова ставится в очередь, даже если его только что прошли по сигналу «возможный риск». Пауза 24 ч должна действовать и для пути через п.9, если C-SSRS завершён меньше 24 ч назад. Кризисный скрипт и алерт при этом остаются.
  2. Вступление у отложенных шкал. _start_pending передаёт intro только для C-SSRS. Нужно брать вступление из реестра (хук или словарь intro по scale_id), чтобы флоу не обходили это через @on_enter("scale.<id>").
  3. Данные в кнопках. Сделать сопоставление триггеров по префиксу (button:med:taken:<dose_id>), чтобы dose_id передавался в кнопке, а не через data.med_pending.
  4. Тайм-аут незавершённого шага. Если чек-ин или шкала брошены, через N часов (настройка в config/texts/dialog.yaml) движок возвращается в idle, и шкалы из очереди могут стартовать. Ответы, данные до тайм-аута, остаются сохранёнными.

Как проверить

make lint test; новые тесты в tests/test_dialog_engine_gaps.py. Тест 13 дней Андрея по-прежнему проходит, на 13-й день C-SSRS задаётся один раз.

Ограничения

Флаг intake (#53) выключен по умолчанию; при включённом флаге поведение не меняется. Замороженные контракты не трогать.


Лог выполнения

2026-10-03

2026-10-03

Что сделано

  • C-SSRS не повторяется: если скрининг риска (cssrs_screen) завершён меньше cssrs_cooldown_hours (24 ч) назад, после п.9 PHQ-9 ≥ 1 он не ставится в очередь — ни из сессии шкалы, ни из действия правила phq9_item9 (schedule_scale), ни по scale_due. Проверка по scale_results (только завершённые), центрально в Engine._start_pending + в scale_session._finish. Кризисный скрипт, план безопасности и алерт без изменений.
  • Реестр вступлений шкал: scale_session.register_scale_intro(scale_id, text | fn(ctx, scale_id, scheduled, return_state)); start_scale(intro=None) берёт вступление из реестра (явный intro важнее). veteran_daily перешёл на реестр, enter-хуки scale.<id> удалены.
  • Префиксные триггеры: @trigger("button:med:taken:*"), хвост данных кнопки — fsm.trigger_payload(event); точный ключ важнее префикса, длинный префикс важнее короткого. Кнопки лекарств несут дозу: med:taken|skip|side_effects:<dose_id>, med:skip_reason:<r>:<id>, med:se:<code>:<id>, med:dose:yes|no:<id> (без строки doses — дата напоминания). data.med_pending больше не используется (очищается); старые кнопки без payload и кнопки чужой/вчерашней дозы → «устарело», ничего не пишется. Ответы без кнопки (шаг чек-ина, свободный текст) → сегодняшняя доза из БД.
  • Тайм-аут брошенного шага: settings.abandon_after_hours (по умолчанию 6 ч, 0 = выкл.) в config/texts/dialog.yaml. Состояния помечаются fsm.abandonable(prefix, when=None): daily, meds, scale (кроме шкал онбординга). Время шага — data.step_at (по app.core.clock; системные события, которые шаг игнорирует, его не продлевают). Следующее событие сначала возвращает в idle (ответы в item_responses/daily_checkins остаются, незавершённая шкала без scale_results), затем обрабатывается; очередь шкал стартует. Не действует в кризисе и при включённом intake.

Результат

  • tests/test_dialog_engine_gaps.py — 23 теста; тест 13 дней Андрея: на 13-й день C-SSRS ровно один раз, состояние crisis.
  • make lint test: 684 passed, 1 skipped.

Заметки/решения

  • Изменены существующие тесты (намеренно): test_dialog_meds.py и test_dialog_veteran_days.py — кнопки лекарств теперь с dose_id; д.13 — ожидается crisis вместо scale.cssrs_screen.
  • Брошенная плановая шкала не ставится в очередь заново — повтор отправит шедулер (scale_due).
  • Код intake (#53) не трогал; при включённом флаге поведение прежнее.
## Описание При сквозном прогоне 13 дней Андрея (#37, PR #55) нашлись пробелы движка диалога (#10). Демо они не ломают, но на защите их может увидеть жюри, а одно затрагивает безопасность. ## Желаемый результат 1. **C-SSRS не дублируется в тот же день.** Сейчас после п.9 PHQ-9 ≥ 1 C-SSRS снова ставится в очередь, даже если его только что прошли по сигналу «возможный риск». Пауза 24 ч должна действовать и для пути через п.9, если C-SSRS завершён меньше 24 ч назад. Кризисный скрипт и алерт при этом остаются. 2. **Вступление у отложенных шкал.** `_start_pending` передаёт intro только для C-SSRS. Нужно брать вступление из реестра (хук или словарь intro по scale_id), чтобы флоу не обходили это через `@on_enter("scale.<id>")`. 3. **Данные в кнопках.** Сделать сопоставление триггеров по префиксу (`button:med:taken:<dose_id>`), чтобы `dose_id` передавался в кнопке, а не через `data.med_pending`. 4. **Тайм-аут незавершённого шага.** Если чек-ин или шкала брошены, через N часов (настройка в `config/texts/dialog.yaml`) движок возвращается в `idle`, и шкалы из очереди могут стартовать. Ответы, данные до тайм-аута, остаются сохранёнными. ## Как проверить `make lint test`; новые тесты в `tests/test_dialog_engine_gaps.py`. Тест 13 дней Андрея по-прежнему проходит, на 13-й день C-SSRS задаётся один раз. ## Ограничения Флаг intake (#53) выключен по умолчанию; при включённом флаге поведение не меняется. Замороженные контракты не трогать. --- ## Лог выполнения ### 2026-10-03 ### 2026-10-03 **Что сделано** - C-SSRS не повторяется: если скрининг риска (`cssrs_screen`) завершён меньше `cssrs_cooldown_hours` (24 ч) назад, после п.9 PHQ-9 ≥ 1 он не ставится в очередь — ни из сессии шкалы, ни из действия правила `phq9_item9` (`schedule_scale`), ни по `scale_due`. Проверка по `scale_results` (только завершённые), центрально в `Engine._start_pending` + в `scale_session._finish`. Кризисный скрипт, план безопасности и алерт без изменений. - Реестр вступлений шкал: `scale_session.register_scale_intro(scale_id, text | fn(ctx, scale_id, scheduled, return_state))`; `start_scale(intro=None)` берёт вступление из реестра (явный `intro` важнее). `veteran_daily` перешёл на реестр, enter-хуки `scale.<id>` удалены. - Префиксные триггеры: `@trigger("button:med:taken:*")`, хвост данных кнопки — `fsm.trigger_payload(event)`; точный ключ важнее префикса, длинный префикс важнее короткого. Кнопки лекарств несут дозу: `med:taken|skip|side_effects:<dose_id>`, `med:skip_reason:<r>:<id>`, `med:se:<code>:<id>`, `med:dose:yes|no:<id>` (без строки `doses` — дата напоминания). `data.med_pending` больше не используется (очищается); старые кнопки без payload и кнопки чужой/вчерашней дозы → «устарело», ничего не пишется. Ответы без кнопки (шаг чек-ина, свободный текст) → сегодняшняя доза из БД. - Тайм-аут брошенного шага: `settings.abandon_after_hours` (по умолчанию 6 ч, 0 = выкл.) в `config/texts/dialog.yaml`. Состояния помечаются `fsm.abandonable(prefix, when=None)`: `daily`, `meds`, `scale` (кроме шкал онбординга). Время шага — `data.step_at` (по `app.core.clock`; системные события, которые шаг игнорирует, его не продлевают). Следующее событие сначала возвращает в `idle` (ответы в `item_responses`/`daily_checkins` остаются, незавершённая шкала без `scale_results`), затем обрабатывается; очередь шкал стартует. Не действует в кризисе и при включённом intake. **Результат** - `tests/test_dialog_engine_gaps.py` — 23 теста; тест 13 дней Андрея: на 13-й день C-SSRS ровно один раз, состояние `crisis`. - `make lint test`: 684 passed, 1 skipped. **Заметки/решения** - Изменены существующие тесты (намеренно): `test_dialog_meds.py` и `test_dialog_veteran_days.py` — кнопки лекарств теперь с dose_id; д.13 — ожидается `crisis` вместо `scale.cssrs_screen`. - Брошенная плановая шкала не ставится в очередь заново — повтор отправит шедулер (`scale_due`). - Код intake (#53) не трогал; при включённом флаге поведение прежнее.
Eleboba added this to the Этап 1 · Ветераны СВО milestone 2026-10-03 18:49:20 +03:00
Eleboba added the safetysize/1lane/Astage/veteransfixbotP1 labels 2026-10-03 18:49:20 +03:00
Eleboba self-assigned this 2026-10-03 18:49:20 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: MedITron/PTSRaiAgent#56