Биомаркер, который был назначен или ожидался в панели лабораторного анализа, но фактически не выполнен (не сдан, отказ, технический сбой, нет образца). Это не «отсутствует в данных», а «известно, что должен был быть, но измерения нет».
Зачем выделять как сущность
- Не путать с null. Биомаркер которого нет в результатах ≠ биомаркер который не был выполнен. Первое — нет информации, второе — есть информация о невыполнении.
- Тренд сохраняется. Если у пациента есть исторический ряд по этому биомаркеру, оценка тренда продолжает работать поверх предыдущих точек. Один пропущенный анализ — это не сброс серии.
- Сигнал для напоминаний/follow-up. Не-выполненный биомаркер — кандидат на «пересдай» / повтор по patient-portal follow-up.
FHIR encoding
В FHIR Observation для not-performed используется поле dataAbsentReason (CodeableConcept). Стандартные коды из http://terminology.hl7.org/CodeSystem/data-absent-reason:
not-performed— измерение не выполненоunknown— статус неизвестенnot-applicable— не применимо к данному пациенту/контекстуerror— попытка измерения, ошибкаnot-asked— биомаркер не был запрошен
Для не-выполненных в нашей доменной модели — обычно not-performed (известно из источника, что назначен и не сделан) или unknown (если источник не уточняет причину).
Resource shape:
Observation {
status: "registered" | "cancelled", // не "final"
code: { coding: [{ system: "loinc", code: "..." }] },
// value[x] ОТСУТСТВУЕТ
dataAbsentReason: { coding: [{
system: "http://terminology.hl7.org/CodeSystem/data-absent-reason",
code: "not-performed"
}]}
}
См. parameter-range-type-prompt — LLM-промпт уже знает про dataAbsentReason как один из 8+1 вариантов value[x] в Observation.
UI rendering (legacy patient portal)
На старом фронте patient portal not-performed биомаркеры рендерились в серых панелях:
- Без числового значения и без unit
- С сохранённым историческим трендом (если была серия предыдущих значений)
- Визуально отделены от выполненных биомаркеров (приглушённый цвет, опциональный hint «не выполнено»)

Скриншот старого UI — оставлен как иллюстрация паттерна (новый design system может рендерить иначе). Виден бейдж «Unknown», reason-текст в body, и Trend Analysis с trend-индикатором.
Источник скриншота — Slack thread с @mk (приватная ссылка; локальный файл — attachments/not-performed-biomarker-legacy-portal.png).
Pipeline preservation
Текущий открытый риск: новый /upload pipeline может терять Observation без value[x] при ingestion (если фильтрация фокусируется на «есть значение → создать Observation»).
Что должно сохраняться:
- Сам Observation создаётся даже без value, со status
registered/cancelled. dataAbsentReasonприсутствует, чтобы фронт мог дискриминировать «not-performed» от других дыр в данных.- Тренды на UI собираются из совокупности Observation с одинаковым LOINC
code— pipeline не должен ронять «пустые» Observation, иначе тренды разорвутся.
Tracker: BG-1449 — Preserve not-performed parameters in /upload pipeline (status: Todo, project B2C Dashboard Migration).
Открытые вопросы
- Какой именно
dataAbsentReasonкод выбирать в каких случаях —not-performedвсегда, или различатьunknown/not-asked? - Поведение в новом design system дашборда — серые панели сохраняются или меняется представление?
- Cross-resource: если назначение фиксируется как
ServiceRequest, должен ли быть pairServiceRequest.status="completed-with-error"+ObservationсdataAbsentReason, или это избыточно?
Связано
- biomarker — основная сущность
- fhir-observation — основная resource, куда мы пишем not-performed
- parameter-range-type-prompt — LLM-промпт, в котором dataAbsentReason — один из вариантов value[x]
- follow-up-reminders-ui-pattern — not-performed биомаркеры — кандидаты на reminders
- biomarker-actuality-thresholds — TTL-логика для actuality; not-performed не должен «сбрасывать» серию