Направление по AI-блоку сложилось в чате 2026-05-14 1, не обсуждено с Артуром / Катей / Васей. Триггер — BG-1432 (90-сек спиннер тренд-анализа, который никогда не дозаполняется) + Slack-тред 2026-05-14 2 про то, что показывать вместо «тренд-анализа».

Страница описывает test page целиком — что на ней рендерится (обычный + AI content), откуда берутся данные, и какие выборы пока открыты. Обычный content зафиксирован, AI-блок — открытое направление.

Что показываем

Per биомаркер на test page живут две группы:

Обычный content (от лабы / детерминистический):

  • Header: имя биомаркера, значение, единицы, reference range, lab-status (H/L/N) — от лабы как есть.
  • Sparkline — серия исторических значений того же analyte у пациента.
  • Generic description — «что такое X» (энциклопедическое описание, не персонализированное); сейчас из paramData.description / exploreData.lede.clinical.
  • Actuality-badge — статус из актуальности на текущей ветке (currently_representative / _with_caveat / likely_outdated / lifelong_no_retest). UX-представление этого бейджа — open.

AI content (per-биомаркер интерпретация):

Это и есть слот, который сейчас пустует. Раньше его покрывали два UI-блока (trendAnalysis через FHIR-поллинг — BG-1432; ParamConnectionsCard — компонент жив, но data source exploreData не пишется, surface скрыт). Сейчас вместо них рендерится ничего.

Что вообще доступно как AI-output, и какой из вариантов лежит сюда — см. раздел «AI-блок: позиции» ниже.

AI-блок: контекст

Что текущий patient-scoped трек реально пишет: N per-параметр ClinicalImpression (clinicalInterpretation + whatAdditionalDataWouldClarify) и 1 patient-level Composition «Patient Summary» — это старая структура обзора (patternedIdentified / healthConsiderations / recommendedSteps / panelOverviews / trends). Новая структура обзора (Главное сейчас / Общее состояние / Что меняется / Чего не хватает / Что обсудить с врачом) — в работе, pipeline не доработан 3; этой странице потребуется ре-align’ить mapping когда новая структура shipnет. Терминология стадий пайплайна несогласована — см. health-report-vocabulary. Test-level overview как отдельный artefact не пишется в новом треке — он остался только в legacy test-scoped analysisPipeline («Blood Test Overview» для /api/v1/interpret/:testId, см. patient-summary-composition-naming).

Per-параметр CI генерится только для latest-per-analyte observation (часть actuality-дедупа); остальные observation’ы того же биомаркера идут в Reasoner как контекст, собственной prose для них нет.

Следствие: для свежей бумажки её observations = latest, prose для них есть; для старой — её observations не latest, prose отсутствует.

Две позиции, что с пустым AI-слотом делать:

  • Узкая test page. AI-интерпретация уезжает на отдельную Health Status / Patient Summary поверхность, test page = glossary над raw-данными. Соответствует health-report-vision + my-health.
  • Доступ к интерпретации с самой бумажки. Доктор / пациент открывает только что загруженный документ и ожидает увидеть «что про эту бумажку». Узкая страница этот use case не закрывает 2.

AI-блок: позиции

A — узкая test page, AI-интерпретация только на Patient Summary. Test page = raw + sparkline + glossary + actuality-badge. CTA «See your full picture →» на Patient Summary. Соответствует vision. Не закрывает «про эту бумажку», требует объяснять куда идти.

B — переиспользуем существующее: per-параметр CI на test page + (возможно) subset patient overview. Для биомаркеров теста рендерим уже написанные per-параметр ClinicalImpression — это часть, в которой переиспользование прямое (одна prose per биомаркер, фильтр по биомаркерам теста тривиален). Для test-level overview — открытый вопрос: какие секции нового patient overview filterable to test scope, а какие нет («Главное сейчас» — per-биомаркер, легко; «Что обсудить с врачом» — patient-level специалисты, не test-scoped; промежуточные — TBD). До тех пор пока новая overview pipeline не доработана 3, filtered subset как механизм не settled. Skew для старого теста: его observations не latest → per-параметр CI отсутствует, и patient overview про current state не релевантен бумажке.

C — lazy retroactive generation для старых наблюдений. Расширение B. Для биомаркеров теста, чьи measurements не latest, on-demand генерим per-observation prose с asOfDate = test.date (snapshot-семантика — интерпретируем как понимали бы тогда). Тот же biomarker-analysis-pipeline pipeline shape; добавляется asOfDate-фильтрация в context-builder (buildV2PatientContextFromFhirAt(patientId, asOfDate) — filter на active conditions / medications / prior observations по дате). Output — ClinicalImpression с effective = asOfDate. Test-level overview — тем же flow, по запросу.

D — auto-генерим test-level overview на каждый upload, как в legacy. Возвращаем «Blood Test Overview» test-scoped Composition в текущий patient-scoped трек рядом с patient summary. Закрывает use case «бесплатно», но удваивает write, размывает только что зафиксированную расщепку scope и пересекается контентом с patient summary patternedIdentified.

Leaning

B (свежие бумажки) + C (старые, on-demand). Test-level overview не пишется отдельным test-scoped artefact’ом — рендерится переиспользованием patient overview (детали filter’а — открытый вопрос, зависит от формы новой section structure); retroactive trigger покрывает и per-параметр CI, и (если новая структура позволит) test-level одним flow.

Почему

  • Не появляется новый pipeline-шаг — переиспользуем biomarker-analysis-pipeline с параметром asOfDate.
  • Не возвращается test-scoped artefact, который только что выпилили в patient-summary-composition-naming.
  • Single source of truth: prose живёт в FHIR, две поверхности (Health Status + test page) рендерят её с разными фильтрами.
  • Cost растёт только когда пользователь явно открывает старую бумажку — не pre-generate всю историю.

Следствия

  • В biomarker-analysis-pipeline нужен явный asOfDate-параметр в context-builder; сегодня плумбинг частично есть в validity-классификаторе, нужно расширить на остальные стадии (Diagnostician / Retriever / Reasoner — фильтр inputs).
  • Test page UI получает CTA «интерпретировать» per биомаркер для observation’ов без CI, и аналогично для overview-блока. Loading state 6-7 мин нужен (biomarker-analysis-pipeline latency baseline на staging).
  • health-report-vision «узкая страница теста» framing уточняется: страница тонкая по дефолту записи (никаких auto-write test-scoped artefacts на upload), но AI-контент рендерится через переиспользование уже существующего FHIR-output’а — то есть для свежей бумажки страница не «пустая».
  • Quota — отдельный слой поверх trigger’а, см. open ниже.

Что нужно для разрешения

  • Согласие Артура / Катя / Вася на B+C направление — особенно что filtered patient summary subset действительно закрывает их «про эту бумажку» use case (Артур формулировал «как получил бумажку-исследование и читаешь»).
  • Решение по latency UX — что рендерим пока генерится 6-7 мин (skeleton / disabled state / уведомление когда готово).
  • Решение по quota — есть / нет / какая (per patient per month? per observation?). Связано с вопросом per-user re-run quotas.

Открытые вопросы

  • Mapping новой patient overview section structure на test page. Какие секции (Главное сейчас / Общее состояние / Что меняется / Чего не хватает / Что обсудить с врачом) filterable to test scope и как: per-биомаркер intersect / по дате / etc. До завершения нового overview pipeline’а — gap. См. my-health.
  • Событие для retroactive generation — новое (analysis/observation.interpret) или переиспользуем analysis/patient-summary.requested с asOfDate-флагом.
  • asOfDate = now как опциональный override в UI (читать старое значение в свете текущего знания) — обсуждали как возможное, не зафиксировано; default = snapshot.
  • lifelong_no_retest actuality-статус: для таких observation’ов retroactive prose концептуально совпадает с latest-prose; стоит ли вообще генерить отдельно или переиспользовать latest CI (с пометкой).
  • UX для actuality-badge на per-параметр блоке (4 статуса currently_representative / _with_caveat / likely_outdated / lifelong_no_retest → ужимать до 2 для пользователя или сохранять градацию).

Test page — кнопка triggering retroactive analysis (2026-05-16)

Detection «есть/нет AI-prose для биомаркера» — по наличию bloodgpt-parameter-analysis sub-extension с непустым clinicalInterpretation в patient CI (Map<parameterName, V2RichOutput> от parseClinicalImpressionToMap). Empty-state на ParamPanel: «Анализ не проводился для этого параметра» когда rich-output entry отсутствует/пуст.

Trigger affordance: одна кнопка на test page — repurpose существующего RegenerateButton (сейчас зовёт legacy .NET /api/Results/regenerate/:testId для single-prompt per-param regen — BloodParameterAnalysisService). Новое поведение — POST /api/summary с as_of_date = test.testDate, запускает actuality/v1.requestedactualityPipelineV1 → writes CI sub-extensions per биомаркер. Latency 5-6 min, toast «Analysis started, ~5 min».

Pipeline scope в MVP: запускаем full pipeline (parameter analysis + Composition overview update). Это значит каждый click растит Composition._history на одну версию даже когда юзер хотел только параметр-анализ обновить (overview уже актуальный был).

Future optimization — skip-overview mode: добавить event payload skipOverviewGeneration: true (или новый event analysis/parameter-only.requested). В actuality-pipeline-v1 skip enrichment fan-out + save-fhir-patient-resources Composition write. CI sub-extensions обновятся, Composition _history — нет. Юзкейс: «обнови интерпретацию параметров на дату теста, overview не трогай». Когда: после того как UX определит когда overview-update желательный, а когда нет (open question). До тех пор — full pipeline на каждый click.

Pipeline boundary (для skip-mode):

Steps 1-10 (parameter analysis + CI write)              ← always runs
─────────────────────────────────────────
Step 11+ (enrichment fan-out → save-fhir-patient-resources)  ← optional, gated by skipOverviewGeneration

Связано

Сноски

  1. Сессия Ильдара с Claude 2026-05-14, chain 7b3072b6 — последовательно прошли через A → B → C; D рассмотрена и отклонена; договорились о (1) asOfDate-фильтрации в context-builder, (2) FHIR-хост = ClinicalImpression.

  2. Slack-тред #ai-engineering 2026-05-14, https://realaicorp.slack.com/archives/C094G7UG82J/p1778761902068159 — Max (BG-1432) + Артур + Ильдар про trend analysis placeholder и use case «про эту бумажку». 2

  3. Slack-тред #ai-engineering 2026-05-12 (Артур после колла с Васей / Катей / Натой про дашборд пациента), https://realaicorp.slack.com/archives/C094G7UG82J/p1778584568744499 — новая section structure нового overview (Главное сейчас / Общее состояние / Что меняется / Чего не хватает / Что обсудить с врачом); pipeline ещё не существует, в работе только фильтрация для «Главное сейчас»; UX feedback Наты про многословность и желание chat’иться с BG. 2