Процесс: как структурированный AI-output BloodGPT (интерпретация анализов, рекомендации, follow-up) ложится на стандартный FHIR R4.
Текущее состояние — подвижное. Раньше страница утверждала «ложится почти полностью, один custom extension». На практике это держится только для deployed-минимума (Observation/DiagnosticReport/Composition/CarePlan + requiresDoctorPreparation). Как только спускаемся в rich-output последнего многостадийного анализа биомаркеров (там тоже пока нет определённости с формой output’а), появляются открытые вопросы и contested-маппинги (foundContext → investigation vs problem vs supportingInfo; missingContext → note vs extension; CI как зонт vs размазать по стандартным ресурсам). Конкретно этот «куда складывать staged-analysis rich-output» — отдельная contested decision-страница staged-output-fhir-storage (первичный источник, эта страница — синтез вокруг). Набор «нужных» custom extensions переоценивался уже несколько раз — финального списка нет. См. zero-extensions-fhir для принципа, секции Trade-off и Открытые вопросы ниже — для актуальных развилок.
Визуальная картина: 5 слоёв
AI-output BloodGPT раскладывается на 5 концептуальных слоёв. Сначала “где сидит ответственность” — потом детали маппинга в секциях ниже.
| Слой | Семантика | FHIR-ресурсы | Status |
|---|---|---|---|
| 0. Source documents (ingest) | оригиналы файлов до парсинга — PDF лаб-отчёты, HL7-сообщения, выписки | fhir-document-reference | research (сейчас оригиналы в GCS без FHIR-обёртки) |
| 1. Patient ground data | факты о пациенте, без AI — выходят из ingest-парсинга | fhir-observation (lab values), Condition, MedicationRequest/Statement, AllergyIntolerance | deployed |
| 2. AI assessment per biomarker | синтез поверх ground data — clinical view per-параметр | fhir-clinical-impression | exploratory |
| 3. Recommendations / actions | предлагаемые действия | fhir-service-request (additionalWorkup), fhir-careplan (follow-up) | SR exploratory, CarePlan deployed |
| 4. Document aggregation | контейнеры для рендера и rollup AI-output’а | fhir-composition (clinical document), DiagnosticReport (test-level) | deployed |
| 5. Audit / provenance | кто/когда/каким AI создал | fhir-provenance | deployed |
L0 (DocumentReference) — отдельный обсуждаемый трек: трекать ли incoming documents как первоклассные FHIR-ресурсы, или оставлять их вне FHIR (как сейчас — оригиналы в GCS, в FHIR живут только распарсенные Observation/Condition). Direction — внедрить, без timeline. Подробности и аргументы на entity-странице.
L4 (Composition) — наш AI-output документ (клиническое narrative + sections). НЕ путать с L0 — это разные сущности: L0 = incoming raw, L4 = generated output.
flowchart TB subgraph L1["L1 — Patient ground data (pure, no AI)"] OBS[Observation<br/>biomarker value + LOINC] COND[Condition] MED[MedicationRequest] end subgraph L2["L2 — AI assessment per biomarker"] CI[ClinicalImpression<br/>summary, investigation,<br/>finding, note, extensions] end subgraph L3["L3 — Recommendations"] SR[ServiceRequest<br/>proposed tests<br/>intent: proposal] CP[CarePlan<br/>follow-up schedule] end subgraph L4["L4 — Document aggregation"] COMP[Composition<br/>section per overview] DR[DiagnosticReport<br/>conclusion + conclusionCode] end subgraph L5["L5 — Audit / provenance"] PROV[Provenance<br/>agent.who Organization/bloodgpt<br/>extension bloodgpt-llm] end CI -->|focus| OBS CI -.->|investigation/supportingInfo<br/>CONTESTED| OBS CI -.->|problem<br/>CONTESTED| COND CI -.->|supportingInfo| MED SR -->|reasonReference| CI DR -->|result| OBS COMP -->|section.entry| CI COMP -->|section.entry| CP PROV -->|target| CI PROV -->|target| SR
Легенда стрелок: сплошная — settled FHIR reference; пунктир + CONTESTED — открытые вопросы (см. foundcontext-fhir-mapping).
Output многостадийного анализа → FHIR (condensed)
Срез mapping’а по полям, которые генерирует многостадийный анализ биомаркеров (форма output’а сама ещё подвижная, см. ту страницу). Status в правой колонке относится к FHIR-маппингу, не к стабильности самого поля.
| Поле | Слой | FHIR slot | Status |
|---|---|---|---|
clinicalInterpretation | 2 | CI.summary | settled |
reasoning | 2 | CI.note[authorString="diagnostician"] | settled |
whatAdditionalDataWouldClarify | 2 | CI.note[authorString="personalizer"] | settled |
foundContext[] | 2 | CI.investigation / problem / supportingInfo | contested (foundcontext-fhir-mapping) |
missingContext[] | 2 | CI.note[] или extension | open |
referenceContext[] | 2 | CI.supportingInfo[] | settled |
additionalWorkup[] | 3 | отдельный ServiceRequest (intent: proposal) | settled |
triage | 2 | CI.extension/bloodgpt-triage (parameter-triage-codes) | settled |
citations[] | 2 | CI.extension/bloodgpt-citation* (repeating) | settled |
Per-resource подробности — fhir-clinical-impression. Boundary с Observation и RiskAssessment (что НЕ относится к CI) — там же. Custom extensions namespace http://bloodgpt.com/fhir/StructureDefinition/..., перечень — секция Какие custom extensions реально нужны ниже.
Маппинг — DB-таблицы → FHIR (легаси-карта)
Эта таблица — другой срез того же mapping’а: с точки зрения наших Postgres-таблиц (это привычная нам ментальная модель — “что лежит в БД, и куда оно поедет в FHIR”). Парная с condensed-таблицей выше — там срез “по полям pipeline-output’а” (что генерирует pipeline, в какой FHIR-slot ложится). Обе нужны: верхняя таблица помогает понимать новый shape AI-output, эта — траекторию миграции каждой существующей DB-сущности.
| Наши таблицы / поля | FHIR-ресурс |
|---|---|
TestOverview (narrativeSummary + sections) | fhir-composition (с nested section[]) |
PanelOverview | sub-sections в той же Composition |
FollowUpRecommendations (расписание + срочные тесты) | fhir-careplan (activity[].detail + LOINC + priority) |
ParameterAnalysis (isHealthy, parameterDetails, reasoning) | fhir-observation (interpretation + note[]) |
ParameterTrends (исторические значения) | Observation с _sort=date запросом по LOINC |
ParameterTrendAnalysis (AI-текст про тренд) | Composition Section “Trends” → sub-section per parameter (065369a0) |
AI-комментарии (любой note[]) | fhir-annotation как data type |
| Авторство всего AI-контента | fhir-organization — Organization/bloodgpt (с Feb 17 2026, fhir-device initial superseded) |
requiresDoctorPreparation | extension на Composition (единственный custom) |
Конкретные поля, JSON-примеры, github-ссылки на builder’ы — в самих entity-страницах. Эта таблица — навигационная.
Ключевые решения
- zero-extensions-fhir — стандартные FHIR-поля везде где они есть. Custom extension только когда стандартного аналога нет. Конкретный decision-framework “когда extension оправдан” — gap в текущем decision-page (см. [О4]).
- ai-enrichment-separate-step — AI-добавки (
note[]+interpretation) пишутся отдельным PUT-step послеfhir-resource-creation, не inline на create. - authorship-organization-not-device —
Organization/bloodgptкак author (Device был initial выбор, заменён после Healthcare API limitation).
Направление: FHIR-only storage (confirmed Ильдаром 2026-04-26: «точно стоит переехать, тут нет вопросов, мы всё храним в FHIR»). Rich-output многостадийного анализа сейчас в Postgres parameterAnalysis columns + UI читает оттуда. Cutover на FHIR-only — pending. Proposed FHIR target — fhir-clinical-impression (per-parameter CI), explored в session d9de9416 (BG-1323). Builder + parser в worktree, не deployed.
См. также где-этот-pipeline-живёт-в-коде — open вопрос «куда сохранять facts/reasoning в FHIR» из generation-pipeline относится сюда: ClinicalImpression — основной кандидат для output этого pipeline.
Принципы FHIR-моделирования AI-контента
При выборе где хранить новые AI-генерируемые данные в FHIR — придерживаемся правил:
- Native FHIR-поля > custom extensions. Если есть стандартное поле под смысл (
finding[]для diagnostic conclusions,note[]для prose,investigation[].itemдля evidence) — используем его. Custom extension оправдан только когда стандартного аналога нет. - Не сливать структурированные данные в свободный текст. Если есть массив items (found-context / missing-context / additional-workup) — кладём в native list-поле, не в
summaryкак «mush». - Сохранять структуру какой она была сгенерирована — не упрощать ради удобства одной consumer-странички.
- Append-only история. Старые AI-ассессменты не переписываются при поступлении новых данных — это исторические записи «что мы думали тогда», нужны для медицинского audit.
Конкретный пример калибровки (session d9de9416): builder для CI изначально клал structural evidence в плоские extensions (bloodgpt-found-context, bloodgpt-missing-context); после ревью переписан на native поля. Это иллюстрирует правило «native > extensions».
Какие custom extensions нужны — рабочий список
Список пересматривался несколько раз и пока не закрыт. Текущий минимум для rich-output многостадийного анализа биомаркеров, где стандартного FHIR-аналога заведомо нет:
bloodgpt-triage— наша product-specific taxonomy (urgent_doctor / routine_doctor / monitor / ok_in_context, см. parameter-triage-codes).bloodgpt-citation— AI traceability (title / url / quote / source).bloodgpt-llm— model / prompt version / latency / tokens (на Provenance, single per Provenance).
Что может ещё добавиться — зависит от того, как разрешатся contested-маппинги (foundContext, missingContext, см. condensed-таблицу выше и foundcontext-fhir-mapping). Что может уйти — если выберем вариант B из trade-off ниже («размазать по стандартным ресурсам»), часть из этих трёх может оказаться лишней.
Остальные поля анализа гипотетически укладываются в native FHIR-поля или существующие ресурсы (детали — mapping-v25-ci-где-plan-файл-расходится-со-spec), но это не settled до cutover.
Trade-off: ClinicalImpression-зонт vs комбинация стандартных ресурсов
Полное обсуждение с осями и аргументами — на отдельной decision-странице staged-output-fhir-storage (contested). Ниже — короткая версия двух полюсов, чтобы не открывать ту страницу для оглавления.
Два архитектурных варианта для rich-output многостадийного анализа, оба обсуждаются:
Вариант A — ClinicalImpression как зонт per-параметр
Один CI на параметр. CI собирает в себя clinicalInterpretation, reasoning, evidence references, triage и пр. Подробно — fhir-clinical-impression. Форма самого pipeline-output’а, который сюда укладывается, ещё подвижна — см. biomarker-analysis-pipeline.
Плюсы:
- AI-output сгруппирован per-параметр в одном объекте — один
GET ClinicalImpression?subject=Xотдаёт всё AI на пациенте. - Provenance / audit chain прозрачно ссылается на отдельные CI.
- Concept «AI assessment» как FHIR-сущность — удобно для downstream consumers.
Минусы:
- ClinicalImpression в R4 — Trial Use, менее стабильный.
assessor: только Practitioner— блокер для AI-author, нужен workaround черезProvenance.agent.who: Device.- Несколько custom extensions нужно именно на CI, плюс vocabulary около него.
Вариант B — комбинация стандартных ресурсов без ClinicalImpression
Размазать output многостадийного анализа по существующим FHIR-ресурсам:
| Поле | Куда |
|---|---|
clinicalInterpretation (prose) | Observation.note[] на самом параметре (где предыдущая версия уже живёт) |
| likely-diagnoses (если выделим) | Condition с verificationStatus=provisional, attached к patient |
foundContext[] evidence | Не отдельный ресурс — Observations доступны через subject=Patient |
additionalWorkup[] | ServiceRequest (intent: proposal) |
referenceContext[] | Observation.referenceRange[] — стандартное место |
| Test overview | Composition (как сейчас) с section[].entry → Observation/Condition/ServiceRequest |
triage | extension на Composition или на Condition |
| AI metadata | Provenance на каждом resource |
Плюсы:
- Всё native FHIR. Никаких новых ресурсов. Меньше custom extensions.
- Используем Trial-Use ресурсы по минимуму.
- Каждый resource по прямому назначению (Condition для диагнозов, ServiceRequest для tests).
Минусы:
- AI-consumer должен делать
_include-запрос чтобы собрать всё AI на пациенте — нет одного-go-to ресурса «дайте мне AI assessment». - Concept «AI assessment per параметр» теряется как объект — размазан по нескольким resources.
Финально не выбрано. Plan-файл и текущий builder идут по варианту A; вариант B — альтернатива для рассмотрения, особенно если CI окажется неудобным в production (Trial Use, vendor compat).
Workflow при новом тесте — что регенерируется
Inngest-pipeline должен быть идемпотентным и append-only — это вытекает из принципа append-only истории.
- Recognition создаёт новые
Observationдля новых параметров. - Diagnostic + Retriever + Generator запускается только для новых аномальных параметров. Старые Observations не трогаются — pipeline skip уже-processed.
- Создаются новые CI / Conditions / ServiceRequest для новых параметров. Старые остаются как есть — медицинский audit-friendly, никогда не переписываем.
- Test overview
Composition— новый per тест, ссылается на новые Observations (+ опционально исторические для контекста). Старые Composition не апдейтятся. CarePlan(follow-up) — новый, зависит от текущего состояния пациента (все active Conditions + только что найденное). Старые CarePlan остаются.- Trends — рассчитываются on-read через все Observations с одинаковым
codeиsubject=Patient. Не предгенерируются, не хранятся как ресурс. - При snapshot-модели (health-report-vision): patient-level snapshot создаётся новый,
ClinicalImpression.previouschain (или его аналог) соединяет с предыдущим — timeline доступен как linked list.
Ключевые свойства которые pipeline должен соблюдать:
- Идемпотентность — для уже-processed Observation pipeline не создаёт дубликатов AI-output.
- Append-only — старые ассессменты не пересматриваются, новые добавляются.
- Patient-state-driven follow-up — CarePlan смотрит на текущее состояние, не на «что было в этом тесте».
- On-read trends — timeline не предгенерируется.
Связанные exploratory (часть BG-1323, FHIR-cutover для многостадийного анализа):
- fhir-clinical-impression — primary container для rich-output анализа (proposed)
- fhir-service-request — для
additionalWorkupper-item (proposed, may change FollowUp generation) - parameter-triage-codes — triage enum custom CodeSystem (open вопрос про FHIR-стандартный alternative)
- fhir-provenance — multi-agent chain pattern для multi-stage pipelines
Открытые decisions:
- TBD
decisions/ai-versioning-in-fhir— model version + prompt version сейчас в Postgres (aiModel/promptVersionполя). При FHIR-only cutover — multi-agent Provenance chain (fhir-provenance) сDevice/bloodgpt-pipeline-vNчерезProvenance.agent.whoхранит эту информацию. Не резкая необходимость до compliance audit. - TBD
decisions/interpretation-source-priority— multi-source interpretation. Production deployed (3-tier): seed CodeableConcept → LLM code → deterministic (BG-1207 + BG-1258, session731a3f60, см. fhir-observation). Экспериментально (4-tier): веткаbg-1297-lab-interp(commit05846324, не merged) добавляет top-runglabInterpretationCodeчерез POST API + HL7 OBX-8. Frontend display при divergence — open.
BloodTest.overallStatus — legacy unused field (calibration по Ильдаром, 2026-04-26)
Поле BloodTest.overallStatus — устаревшее, неиспользуемое, на текущую систему не влияет. Per-parameter interpretation (через fhir-observation standard ValueSet) и parameter_range_type — actual sources. overallStatus остаётся в schema как legacy, безопасно игнорируется.
(Замечание: в первичном digest 731a3f60 [Н2] было неправильное предположение про “overview-LLM который выставляет overallStatus” — это была misinterpretation Ильдара’s instruction “не гадай, посмотри кто”, не архитектурное утверждение.)
Pipeline — где это всё происходит во времени
Порядок Inngest-функций (по domain-группам из worker.ts, упрощённо, без error-paths):
- Input —
input-pdf-recognition/input-hl7-parsing/input-json-parsing→ распознанные параметры - Normalization —
normalization-loinc→normalization-parameters→normalization-ranges - FHIR creation —
fhir-resource-creation→ Patient + DiagnosticReport + Observations с базовыми полями (valueQuantity,code,referenceRange) - Interpretation —
analysisPipeline(interpretation-analysis.function.ts) → LLM читает Observations из FHIR, генерирует AI-content (interpretation, parameterDetails, panel overviews, narrative, follow-ups) - Enrichment —
enrichFhirObservations+ family (overviewGeneration/panelOverviewGeneration/followUpGeneration/trendsGeneration/productRecommendationGeneration) +saveFhirAiResources→ PUT’ы на Observations сnote[]+interpretation; создание Composition (включая Section “Trends” сtrendAnalysisper parameter, добавлено в 065369a0) + CarePlan; записьfhirAssessmentId+fhirFollowUpIdколонок вBloodTest(065369a0) - Doctor Validation (HITL) —
doctor-review-gate(опциональный gate) - Output —
output-pdf-generation
Между шагами FHIR store работает как shared state (replaces legacy BloodTest.rawRecognitionResult JSON). Detailed orchestration → inngest.
Что попадает в FHIR store
Структурный snapshot после полного прогона одного теста (placeholder’ы вместо конкретных биомаркеров). Справа — на каком pipeline-шаге элемент появляется или дополняется:
Patient/{patientId} ← fhir-resource-creation
└─ DiagnosticReport/{reportId} ← fhir-resource-creation
│ (status: final, performer: лаб, resultsInterpreter: bloodgpt-com)
│
└─ result[]
├─ Observation/{panel} ← fhir-resource-creation
│ │ (panel = группирующий Observation: code + hasMember[], без value)
│ │
│ └─ hasMember[] → Observation/{biomarker} ← fhir-resource-creation
│ │
│ ├─ valueQuantity + referenceRange ← fhir-resource-creation
│ ├─ interpretation (H/L/N) ← enrichFhirObservations (PUT)
│ └─ note[] (parameterDetails, AI-комментарий) ← enrichFhirObservations (PUT)
│
└─ ... другие panel'ы
Composition/{compId} ← saveFhirAiResources
│ (type: Assessment, author: Organization/bloodgpt)
│ (subject: Patient — не DR; event = trigger reference, опционально)
│ (extension: requiresDoctorPreparation — единственный custom)
│
├─ section "Interpretation" (text.div + entry → DiagnosticReport)
├─ section "Patterns" (sub-sections per identified pattern)
├─ section "Health Considerations"
├─ section "Pay Attention" (recommendations с category)
└─ section "Trends" ← saveFhirAiResources (065369a0)
└─ sub-sections per biomarker (text.div = trendAnalysis от AI)
CarePlan/{planId} ← saveFhirAiResources
│ (intent: proposal, author: Organization/bloodgpt)
├─ supportingInfo → DiagnosticReport
└─ activity[] → ServiceRequest (LOINC + scheduledPeriod + priority)
Organization/bloodgpt ← создаётся один раз при provisioning
Что это показывает:
- Граф растёт layer’ами, а не переписывается.
fhir-resource-creationстроит skeleton (Patient + Report + Observations с raw values). Enrichment достраивает существующие Observations (PUT с дополнительными полями, не replace) и добавляет новые ресурсы (Composition / CarePlan). - Атомарность Observation = биомаркер. Panel — группирующий wrapper, у него только
code+hasMember[], без value. Это стандартный FHIR-паттерн, не наша придумка. - Composition и CarePlan связаны с DiagnosticReport, не дублируют его. Через
entry/supportingInforeferences — DiagnosticReport остаётся single source of truth для лабораторных значений. - Authorship чёткое. Лаб-данные — без author. AI-генерации —
Organization/bloodgpt. Фильтр по author даёт ответ “только det” / “только AI” (см. [О5]).
Следствия для BloodGPT
(Черновик — не согласовано с Ильдаром.)
- Минимизация custom extensions = страховка для B2B integration. У нас не ноль (
requiresDoctorPreparationесть), но один extension — приемлемо. Партнёр-лаб / EMR читает FHIR-ресурсы стандартным парсером,interpretation(H/L/N) иnote[].textотрисовываются в любом FHIR-клиенте. Patient/$everythingиспользуется вapps/b2b-api/src/utils/fhir-response-builder.ts, но с defensive fallback: Composition и CarePlan фетчатся отдельно — Google Healthcare API не гарантирует их возврат в$everythingbundle. То есть готов “почти” out-of-the-box, с одним workaround. Не custom export endpoint.requiresDoctorPreparation— мониторим как single point of vendor lock-in. Один extension хорошо изолирован. Если custom extensions начнут расти — это сигнал что концепт не fits R4. R5 как fallback неочевиден — vendor support под вопросом (см. [О3]); возможные пути — IPS extensions, SNOMED concepts, или переоценить как поле моделится через стандартный механизм.- AI enrichment как отдельный step — generalizable pattern. Если завтра появится HITL doctor-review (врач добавляет свой
note), архитектура готова —doctor-review-gate.function.tsуже существует как gate, расширение под note-write встанет в ту же модель post-create update. - Тест-центричная модель — текущая, не финальная. В session 065369a0 обсуждался paradigm-shift на snapshot-центричную модель (
Composition.subject = Patient, триггеры — тест / новый диагноз / лекарство / прошедшее время). Текущая страница описывает тест-центричную реализацию; exploratory direction зафиксирован в health-report-vision.
Открытые вопросы
[О1] B2B API read path — миграция с Prisma include на FHIR queries
GET-endpoints в b2b-api пока ходят в Prisma include. Должны читать из FHIR (GET Composition?subject=Patient/{id} + parsing nested sections). Требует pagination strategy, caching consideration (latency), и frontend mapping (UI ждёт ту же shape что Prisma давал).
Ильдар: «они по сути все должны использовать fhir как источник истины»
[О2] ParameterTrends — как frontend получает trend chart
Маппинг “ParameterTrends → Observation с derivedFrom” зафиксирован, но как именно frontend агрегирует значения за период (одиночный _revinclude запрос? batch-fetch? отдельный custom endpoint?) не разобрано.
[О3] FHIR R4 vs R5 — vendor support
Stored как R4. R5 опубликован (2023) и стабилен, имеет обновлённый Annotation, новые value types. Главный блокер — vendor support: Google Healthcare API на 2026-04 R5 не в GA (нужен periodic re-check). HAPI R5 поддерживает. Поэтому R5 для нас не tactical fallback — sticking with R4 на 12+ мес., через год переоценить vendor landscape.
[О4] Decision-framework “когда extension оправдан”
decisions/zero-extensions-fhir фиксирует принцип (“standard где можно, extension когда нет”), но не процесс как это решать в конкретный момент. Tactical практика подсказывает шорткат: Composition Section с custom code предпочитается extension’у с typed value — secвенно проверено в 065369a0 на Trends section. Хороший process-snippet: (1) поискать стандартное FHIR-место, (2) если нет — попробовать Composition.section с custom section-type коде, (3) extension как последний резорт.
[О5] Разделение детерминированного и AI-генерированного контента — ongoing
Technical путь найден (но не финал) через fhir-meta-tagging (session 7ff79368, Mar 30):
meta.tag.code = "document-import"— лабораторные данные из загруженных документовmeta.tag.code = "health-chat"— patient-reported через chat с AI-агентомmeta.tag.code = "survey"— patient-reported через опросникauthorReference = Organization/bloodgptдополнительно: лаб-данные без author, AI с author
Это filter-механизм на читающей стороне, не полное решение разделения. Открыто на более широком уровне:
- Pipeline-уровень: должны ли det и AI идти разными pipeline-шагами? Сейчас в
analysis-workerони переплетены (FHIR-resource-creation создаёт лаб-Observations и затем enrich-fhir-observations добавляет AI note[]/interpretation на те же ресурсы). - Storage-уровень: разделять ли хранилища? Сейчас всё в одном FHIR store, разделение только через теги.
- API surfaces: должен ли B2B API отдавать только-det и только-AI как разные эндпоинты? Сейчас один path возвращает всё.
- Source-of-truth ownership: для перезаписей (re-process одного теста) — что считается truth-set? Det-данные иммутабельны (от лаборатории), AI-данные могут пересоздаваться. Это влияет на dedup и versioning.
- Governance: какие use-cases требуют det-only view? Какие — only-AI? Это продуктовое решение, не technical.
Это была одна из важных итераций архитектурного поиска (065369a0, 7ff79368). Tag-based filter — необходимый, но не достаточный шаг.
[О6] AI-content audit / маркировка для compliance — partial
Базовый audit готов через fhir-meta-tagging + fhir-provenance (session 7ff79368) для V0.5 write tools:
- Кто (
Provenance.agent.who = Organization/bloodgpt) - Когда (
Provenance.recordedtimestamp) - Из чего (
Provenance.entity.what→ DocumentReference, для document-import) - Source class (
meta.tag.code = "health-chat" | "survey" | "document-import")
Что не покрыто (поэтому partial, не closed):
- AI model version + prompt version — хранятся в
BloodTestPostgres (aiModel,promptVersion), не в FHIR. Если regulatory потребует full provenance в FHIR — нужно решить как (TBDdecisions/ai-versioning-in-fhir). - Audit для
analysis-workerpipeline (test-flow):save-fhir-resourcesсоздаёт Composition + CarePlan без Provenance. План описан (~30-40 строк кода), реализация отложена в session 7ff79368. - Audit trail для re-process — если пациент перезагружает тот же тест и AI генерирует другую интерпретацию, как это связать с предыдущей версией. Не зафиксировано.
- Audit на read-side: кто читал PHI, когда, через какой endpoint. Это уже Cloud Audit Logs / WAF-уровень, не FHIR-data; см. multi-tenant-fhir-storage [О3] HIPAA compliance.
[С1] Drift между FHIR builders и frontend
fhir-composition-builder.ts создаёт structure { Section "Interpretation" → Sub-sections → text.div }. Frontend парсит её обратно в narrativeSummary + identifiedPatterns[]. Если builder поменяется без updates frontend → silent breakage. Не решено: shared TypeScript types? Schema validation? Contract test?
Связано
- staged-output-fhir-storage — куда складывать staged-analysis rich-output в FHIR — contested
- biomarker-analysis-pipeline — pipeline, производящий тот rich-output (форма pipeline-output’а ещё подвижна)
- foundcontext-fhir-mapping — sub-вопрос про конкретный slot для
foundContext[]— contested - formalize-fhir-profiles — формализовать ли наш mapping через StructureDefinitions / codegen / IG — draft
- extension-url-conventions — URL pattern для наших extensions / SDs — draft
- fhir-profiling — общая механика FHIR-профилирования
- fhir-conformance-resources — семейство meta-ресурсов (SD / VS / CS / CapStmt / IG)
- fsh — DSL для авторства SDs (если решим формализовать)
- fhir-implementation-guide — packaging для downstream партнёров
- fhir-code-generation — autogenerated types / Zod на основе наших профилей
- fhir-tooling — выбор инструмента (codegen / validator / client)
- fhir-composition · fhir-careplan · fhir-observation · fhir-annotation · fhir-device · fhir-organization · fhir-provenance
- zero-extensions-fhir — наша политика про extensions — active
- ai-enrichment-separate-step · authorship-organization-not-device · fhir-meta-tagging · llm-numeric-codes-policy · clinical-record-reconciliation
- multi-tenant-fhir-storage — FHIR store как shared state между Inngest steps
- patient-summary — IPS-стандарт overlap
- llm-safety-in-medicine — Device ≠ SaMD framing
- google-healthcare-api — конкретный backend и его gotchas
Источники
Сноски
-
HL7 FHIR R4, accessed 2026-05-17, https://hl7.org/fhir/R4/. ↩
-
v3-ObservationInterpretation ValueSet, accessed 2026-05-17, https://terminology.hl7.org/CodeSystem-v3-ObservationInterpretation.html. ↩
-
Реализация (
enrichment/family), accessed 2026-05-17, https://github.com/Realai-plus/bloodgpt-for-business/tree/main/apps/analysis-worker/src/inngest/functions/enrichment. ↩