[backend][B] Сад: детерминированный расчёт роста из активностей, config/garden.yaml, GET /me/{token}/garden #118

Closed
opened 2026-10-31 11:10:15 +03:00 by Eleboba · 0 comments
Owner

Описание

Часть эпика «Демо к гранту ВШЭ и пилоту „Династия“». Слайд 13: «Любая полезная активность растит сад. Геймификация — общая оболочка над всеми модулями». Источники роста: приём лекарств, дневник/чек-ин, регулярные опросы, материалы от врача. Принципы без давления:

  1. сад не вянет: прогресс монотонно не убывает, пропуски ничего не отнимают;
  2. рост не зависит от ответов: учитывается сам факт активности, а не баллы шкал и не настроение;
  3. нет соревнования: только свой сад, без рейтингов и сравнений.

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

  • config/garden.yaml (ADR-008): очки за активность, дневной лимит по каждому типу (чтобы пять сообщений подряд не давали пятикратный рост), пороги стадий (росток → куст → цветение → …), количество растений.
  • app/services/garden.py: детерминированный расчёт из существующих таблиц без новой таблицы и без миграции (ADR-003):
    • doses со статусом taken (отметка «Принял(а)», в том числе с опозданием);
    • daily_checkins (чек-ин или запись дневника);
    • scale_results (завершённый назначенный опрос);
    • «материалы»: если отдельного события нет, в v1 не учитываем и пишем об этом в лог issue.
  • «Сегодня» берётся из app.core.clock (демо-часы, ADR-005), чтобы на демо можно было промотать неделю и увидеть рост.
  • GET /api/v1/me/{token}/garden возвращает {points, stage, stage_title, next_stage_at, progress_to_next (0..1), plants: [{kind, stage}], today: [{activity, done, title}]}.
  • Сид демо: у Андрея к моменту демо сад на 2–3 стадии, который вырос из уже существующих в сиде доз и чек-инов.

Подзадачи

  • config/garden.yaml и загрузчик
  • app/services/garden.py
  • ручка в app/api/patient_web.py, схема ответа
  • проверка сида (scripts/, data/), что сад Андрея выглядит живым
  • тесты tests/test_services_garden.py: монотонность, лимиты, независимость от баллов, граница суток по демо-часам

Анализ

Ограничения и риски

  • Расчёт детерминированный, без LLM (guardrail 3).
  • Не награждать кризис: сообщения и опросы, приведшие к кризисному сценарию, считаются как обычная активность, но web не показывает празднование в кризисной ветке (это задача web).
  • Сад видит только пациент. Врачу и в дашборд не передаётся, в сводку не попадает.

Архитектурный выбор

Расчёт «на лету» из существующих событий, а не отдельная таблица очков: нет миграций, нет рассинхрона, история переигрывается при смене правил в yaml. Цена — несколько COUNT по пациенту на запрос, для демо и пилота несущественно.

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

make seed → GET /me/<token>/garden у Андрея → стадия > 1. Отметить дозу → points выросли. Промотать демо-часы на 7 дней без активности → points не уменьшились. make lint test.

2026-10-31

  • Что сделано: config/garden.yaml, app/services/garden.py (расчёт на лету из doses/daily_checkins/questionnaire_records/scale_results), ручка /me/{token}/garden, тесты.
  • Результат: 1071 тест зелёный. Андрей (день 12): 66 очков, 6 шагов, стадии растений [4,2,0,0,0,0]. «Материалы от врача» в v1 не считаются: событие просмотра не пишется (решение в #120).
## Описание Часть эпика «Демо к гранту ВШЭ и пилоту „Династия“». Слайд 13: «Любая полезная активность растит сад. Геймификация — общая оболочка над всеми модулями». Источники роста: приём лекарств, дневник/чек-ин, регулярные опросы, материалы от врача. Принципы **без давления**: 1. сад **не вянет**: прогресс монотонно не убывает, пропуски ничего не отнимают; 2. рост **не зависит от ответов**: учитывается сам факт активности, а не баллы шкал и не настроение; 3. **нет соревнования**: только свой сад, без рейтингов и сравнений. ## Желаемый результат - `config/garden.yaml` (ADR-008): очки за активность, **дневной лимит** по каждому типу (чтобы пять сообщений подряд не давали пятикратный рост), пороги стадий (росток → куст → цветение → …), количество растений. - `app/services/garden.py`: детерминированный расчёт из **существующих** таблиц без новой таблицы и без миграции (ADR-003): - `doses` со статусом taken (отметка «Принял(а)», в том числе с опозданием); - `daily_checkins` (чек-ин или запись дневника); - `scale_results` (завершённый назначенный опрос); - «материалы»: если отдельного события нет, в v1 не учитываем и пишем об этом в лог issue. - «Сегодня» берётся из `app.core.clock` (демо-часы, ADR-005), чтобы на демо можно было промотать неделю и увидеть рост. - `GET /api/v1/me/{token}/garden` возвращает `{points, stage, stage_title, next_stage_at, progress_to_next (0..1), plants: [{kind, stage}], today: [{activity, done, title}]}`. - Сид демо: у Андрея к моменту демо сад на 2–3 стадии, который вырос из уже существующих в сиде доз и чек-инов. ## Подзадачи - [ ] `config/garden.yaml` и загрузчик - [ ] `app/services/garden.py` - [ ] ручка в `app/api/patient_web.py`, схема ответа - [ ] проверка сида (`scripts/`, `data/`), что сад Андрея выглядит живым - [ ] тесты `tests/test_services_garden.py`: монотонность, лимиты, независимость от баллов, граница суток по демо-часам ## Анализ ### Ограничения и риски - Расчёт детерминированный, без LLM (guardrail 3). - Не награждать кризис: сообщения и опросы, приведшие к кризисному сценарию, считаются как обычная активность, но web не показывает празднование в кризисной ветке (это задача web). - Сад видит только пациент. Врачу и в дашборд не передаётся, в сводку не попадает. ### Архитектурный выбор Расчёт «на лету» из существующих событий, а не отдельная таблица очков: нет миграций, нет рассинхрона, история переигрывается при смене правил в yaml. Цена — несколько COUNT по пациенту на запрос, для демо и пилота несущественно. ## Как проверить `make seed` → `GET /me/<token>/garden` у Андрея → стадия > 1. Отметить дозу → `points` выросли. Промотать демо-часы на 7 дней без активности → `points` не уменьшились. `make lint test`. ### 2026-10-31 - **Что сделано:** `config/garden.yaml`, `app/services/garden.py` (расчёт на лету из doses/daily_checkins/questionnaire_records/scale_results), ручка `/me/{token}/garden`, тесты. - **Результат:** 1071 тест зелёный. Андрей (день 12): 66 очков, 6 шагов, стадии растений [4,2,0,0,0,0]. «Материалы от врача» в v1 не считаются: событие просмотра не пишется (решение в #120).
Eleboba added this to the Грант ВШЭ · пилот «Династия» milestone 2026-10-31 11:10:15 +03:00
Eleboba added the lane/Bfeaturesize/1P0stage/veteransbackend labels 2026-10-31 11:10:15 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: MedITron/PTSRaiAgent#118