Когда мы строим отчёт о здоровье на определённую дату (например, на сегодня — «как пациент выглядит сейчас», или на дату старого теста — «как он выглядел тогда»), нужно решить какие данные пациента подать на вход.
У выбора две независимые оси:
- По времени — берём только то, что произошло до этой даты. Это очевидно: нельзя строить отчёт за прошлое с данными из будущего.
- По охвату — берём всю историю пациента или только биомаркеры этого конкретного теста.
В этой странице обсуждаем вторую ось. Эта же тема разбиралась в interpretation-scope-patient-vs-test — родительская decision-page (V2 test-scoped → V2.5 patient-scoped).
Откуда вопрос
Возникает при интерпретации со страницы старого теста. Пользователь нажимает «Run analysis» на тест t2 — и ожидает «расскажи мне про эту конкретную бумажку». Должна ли система отвечать узко (только то, что в этом тесте) или широко (с учётом всего, что есть у пациента)?
Что есть у пациента в FHIR (baseline)
Чтобы не отвлекаться на «что значит Glucose vs HbA1c», иллюстрации абстрактные: биомаркеры 1…10, диагнозы и лекарства a…f. Срок актуальности биомаркера в примерах = 12 месяцев (через это время значение считается устаревшим). Биомаркер 10 — что-то, что есть на каждую дату теста (например, возраст или вес — не всегда «измеряется», но всегда можно зафиксировать), даёт длинный тренд.
Полная история — каждый ряд это отдельный биомаркер, время слева направо. Длинные бары внизу — диагнозы и лекарства от даты их появления (« означает, что началось раньше шкалы). Оси на картинке показывают две независимые оси выбора охвата.
В вариантах ниже цвета означают:
- 🟢 Яркий зелёный — свежее значение, идёт в генератор как текущее состояние
- 🟩 Бледный зелёный — старое значение того же биомаркера, идёт в генератор как тренд (когда последнее значение свежее)
- 🟡 Жёлтый — последнее значение устарело, surfaced пользователю как «нужно пересдать»
- ⬜ Серый — есть в истории, но генератор не использует (или нужный охват не включает, или последнее значение биомаркера само устарело и тренд тоже неполезен)
Метки рядов слева (числа и буквы) подсвечены тем же цветом, что и состояние ряда. Красные линии очерчивают «коробку» данных, которые идут в генератор: вертикальная отсекает будущее, горизонтальная отсекает устаревшие.
Вариант 1 — Отчёт здоровья на сегодня
Дата анализа = сегодня. Берём всё, что произошло за всю историю пациента до сих пор. Генератор получает по каждому биомаркеру последнее значение — если оно свежее (актуально), идёт в отчёт; если старое — помечается для пользователя как устаревшее (при необходимости можно пересдать).
Что в результате:
- 🟢 5, 6, 7, 8, 9, 10 — последнее значение из t3 или t4 (≤ 12 мес назад) → яркий зелёный, идёт в отчёт как текущее состояние
- 🟩 Старые наблюдения тех же биомаркеров (например, тренд 10 через все 4 теста, 9@t1, 9@t3 и т.д.) — бледный зелёный, идут в отчёт как тренд (исторические значения для сравнения)
- 🟡 1, 2, 3, 4 — последнее значение из t1 или t2 (17-24 мес назад) → помечается как устаревшее
f— transient condition, существовал в 2025-03…2025-09, к сегодня уже завершился → серый, бар обрывается на end date
Вариант 2 — Ретроспективный отчёт здоровья
Тот же health report, что и в Варианте 1, но с датой анализа в прошлом — на любой старый тест пациента или даже произвольную дату. Логика идентичная: последнее значение по биомаркеру + активный на эту дату клинический контекст. Просто всё, что произошло после, исчезает.
На примере выше — анализ сдвинут на дату t3. Видна полезная иллюстрация смешанной картины: одни биомаркеры свежие, другие уже устарели, третьи имеют тренд из более ранних тестов. Бары диагнозов и лекарств обрезаются вертикальной линией — продолжение после даты анализа нерелевантно для ретроспективы.
Это то, как работает сейчас при «Run analysis» на странице старого теста.
Вариант 3 — Только данные документа
Берём ровно то, что напечатано на бумажке t3 — значения биомаркеров из этого теста. Никакой истории, никаких диагнозов, никаких лекарств (ну, если только они не были включены в сам документ теста — но в реальной практике лабораторные тесты обычно ограничиваются числами без клинического контекста).
Что в результате:
- 🟢 Только биомаркеры из t3 (включая 10 с этой даты)
- Биомаркеры не из t3 — выше верхней красной линии, не рисуем
- Все диагнозы и лекарства — ниже нижней красной линии (поднятой), тоже не рисуем
- Старые наблюдения биомаркеров из t3 — отрезаны, тренд недоступен
Клинически заметно менее полезен — генератор не знает ни про диагнозы, ни про лекарства, ни про предыдущие значения. Фиксирует крайний случай в спектре.
Вариант 4 — Биомаркеры теста + клинический контекст (промежуточный)
Это поведение сейчас работает в B2C на проде — см. interpretation-scope-patient-vs-test.
Берём биомаркеры из t3 + активные на t3 диагнозы и лекарства. Не используем тренды биомаркеров из других тестов и не используем биомаркеры, которых в t3 не было.
Что в результате:
- 🟢 Биомаркеры из t3 + активные на t3 диагнозы и лекарства (
a, b, c, d, f) - Биомаркеры не из t3 — выше красной линии, не рисуем
- Старые наблюдения t3-биомаркеров — отрезаны как «не latest», тренд недоступен
e(после t3), не рисуем
Генератор знает контекст, но не видит ни истории биомаркеров из других тестов, ни «вторичных» биомаркеров пациента. Промежуточная позиция между Вариантом 2 (вся история) и Вариантом 3 (ничего кроме бумажки).
Сравнение
| Вариант | Что генератор видит |
|---|---|
| 1. Отчёт на сегодня | Все актуальные биомаркеры + активные диагнозы/лекарства |
| 2. Ретроспективный отчёт | То же, но сдвинутое в прошлое (исчезает всё что после даты) |
| 3. Только документ | Ровно содержимое бумажки теста, без истории и контекста |
| 4. Биомаркеры теста + контекст | Биомаркеры теста + активные диагнозы/лекарства |
Позиции
Узкая интерпретация (вертикальный срез) — Вариант 3
Генератор берёт только биомаркеры из выбранного теста. Ни истории, ни диагнозов, ни лекарств — ничего сверх содержимого бумажки.
За:
- Семантически чище — «вот что про эту конкретную бумажку», похоже на то, что видит доктор (он же не знает контекста предыдущих тестов)
- Проще для отображения — на странице теста и так показываются только биомаркеры этого теста; здесь UI и pipeline согласованы
Против:
- Теряем клинически важный контекст — устаревший Hgb из старого теста может намекнуть «надо пересдать CBC», но узкий cut его не увидит, и совет не появится
- Без диагнозов и лекарств интерпретация значений «в вакууме» — заметно менее полезна клинически
Широкая интерпретация (только горизонтальный срез) — Варианты 1 и 2 (текущая)
Генератор берёт ВСЁ доступное у пациента до даты анализа. Биомаркеры из других тестов, диагнозы, лекарства. Страница теста = отфильтрованный view (показывает только биомаркеры этого теста, но проза сгенерирована с полным контекстом).
Вариант 2 — это та же широкая интерпретация, просто с датой анализа сдвинутой в прошлое. Логика идентична Варианту 1, отличается только asOfDate.
За:
- Реалистичная клиническая интерпретация — учитываем весь профиль пациента, не только бумажку
- Тренды доступны (когда передадим их в Reasoner — Артур carry-over)
- Один pipeline для страницы теста и health report — упрощение
- Устаревшие биомаркеры приоритизируются (помечается «нужно пересдать»)
Против:
- На странице теста может выглядеть «лишним» что генератор знает про биомаркеры, которых нет на бумажке — это главное, что путает пользователя
- Train of thought генератора может ссылаться на биомаркеры, не отображённые на странице теста — нужно решить как показывать это пользователю, возможно по аналогии с тем как отображается health report
Компромисс — Вариант 4
Вертикальный срез только для биомаркеров, но не для диагнозов/лекарств: генератор берёт биомаркеры только из теста + все активные диагнозы и лекарства. Это поведение сейчас работает в B2C на проде.
За:
- Сохраняет «охват = бумажка теста» для биомаркеров
- Диагнозы/лекарства всё равно нужны как глобальный контекст — без них клинической интерпретации не сделать
Против:
- Непоследовательно — почему диагнозы считаются global, а биомаркеры нет?
- Если пациент сдавал биомаркер год назад — он часть медицинской истории, не «другой тест»
Текущая реализация
Широкая интерпретация (Варианты 1 и 2). Подтверждено в health-report.function.ts:2b (dedupLatestPerBiomarker): берётся obs.date <= asOfDate без фильтрации по testId или DiagnosticReport.id. Все Observations из FHIR пациента, попадающие во временное окно, идут в pipeline.
Страница теста (/desk/<id>/test/<testId>/results) — фильтр на уровне UI: показывает только биомаркеры из этого теста, но проза тянется из patient-wide ClinicalImpression. То есть «вижу только биомаркеры теста, но описание знает про весь контекст пациента».
Что нужно для разрешения
Не закрыто. Конкретные пункты:
- Ожидание пользователя: что человек ожидает увидеть когда нажимает «Run analysis» на старом тесте? Это «расскажи про эту бумажку» или «как я выглядел тогда»?
- Сценарии использования: кто и зачем смотрит ретроспективные тесты? Сам пациент для самоконтроля? Врач для клинической истории? Каждый сценарий может хотеть разный охват.
- Скорость и стоимость: широкий охват тяжелее, больше токенов. Если ретроспективная генерация редкая операция — терпимо. Если частая — может стоит ограничить.
- Согласованность UI: если pipeline берёт более широкий охват чем UI показывает, пользователь может удивляться откуда генератор знает про биомаркер, которого «нет на странице». Решается через прозрачность (показать «учтены следующие биомаркеры» отдельным сегментом) или сужением охвата.
Связано
- interpretation-scope-patient-vs-test — родительская decision-page (V2 test-scoped → V2.5 patient-scoped). Этот page — sub-question внутри её — active
- multi-test-user-journey — concrete scenario (Анна, 3 теста) где dilemma всплывает — draft
- health-report-pipeline — pipeline shape где этот scope применяется — active
- biomarker-actuality-service — actuality classifier выдаёт verdict relative to asOfDate (использует horizontal cut) — draft
- test-page-content — что показываем на test detail page — draft
- my-health — HealthReport surface — active
Открытые вопросы
- Что с диагнозами, которые уже не активны? Если у пациента было transient condition (например,
fв примерах) — он завершился до даты анализа, должен ли учитываться? Кажется, мы ещё не учитываем разницу между активным и неактивным состоянием. - Что с family history? Семейный анамнез по природе не имеет даты — всегда «active». Включаем?
- Широкая интерпретация предполагает что pipeline видит биомаркеры из других тестов. Что если пациент удалил один из старых тестов — соответствующие observations пропадают из охвата, и предыдущий health report станет неконсистентным. Возникает вопрос о перегенерации отчёта. Связано с document-deletion-strategy (draft).