В FHIR-store BloodGPT сосуществуют ресурсы разной природы: user-uploaded (PDF расшифровка, выписки от других клиник), AI-generated (наш Composition / CarePlan / ClinicalImpression), patient-reported (через chat / survey). Через resourceType их не различить — например, Composition может быть и нашей summary, и выпиской чужой клиники. Нужны явные discriminators для:

  1. Атрибутировать каждый resource источнику — когда написан, кем, на основе чего
  2. Фильтровать для consumer-side — «только AI», «только patient-reported», «только из chat», «полный audit конкретного write-event»

Рассматривали (source attribution alternatives)

  • Разделение по resourceType (early option) — использовать отдельные FHIR resource types для AI и user-uploaded одного и того же концепта (например, Composition user-uploaded vs пользовательский Basic-ресурс для AI). Отвергнуто как нелогичное: один и тот же концепт (clinical document) в разных типах ломает FHIR-семантику и search; consumer-side тоже ломает (нужно знать оба типа для query «вся documentation patient»).
  • evidence.detail на Condition (initially proposed) — поле есть только на Condition, не работает для Medication / Allergy / Procedure / FamilyMemberHistory.
  • contained DocumentReference — DocumentReference как embedded ресурс в каждом target. Дублирование: один import-документ → DocumentReference копируется в каждый созданный resource.
  • Custom extension на каждом resource. Технически работает (GCP Healthcare API поддерживает extensions в search через _include), но плодит non-standard FHIR — нарушает zero-extensions-fhir policy («минимизировать extensions, использовать стандартные слоты, где возможно»).
  • meta.tag + meta.security + Provenance resource — стандартные FHIR mechanisms, search-able через стандартные параметры. Выбрано.

Решение — четыре слоя

Оговорка: четыре слоя могут быть избыточно. Origin (Слой 1) + Provenance (Слой 4) — минимальный надёжный набор; source (Слой 2) и AIAST security (Слой 3) — оптимизации частых consumer-queries и industry-стандартная маркировка соответственно. Если в практике окажется что одного оригина хватает — слои 2-3 можно отложить. Зафиксировано как open question (см. ниже).

Слой 1: meta.tag origin — store-wide классификация

CodeSystem http://bloodgpt.com/fhir/CodeSystem/origin с тремя кодами. Применяется ко всем ресурсам:

OriginКогдаLifecycle
user-uploadedRecognition pipeline пишет Observation / DiagnosticReport / Condition / MedicationStatement / Composition (incoming clinical doc)Immutable после POST — без PUT’ов после создания
external-data(future) API-import от лаб-партнёров, Apple Health, других hospital’овImmutable
ai-generatedsave-fhir-ai-resources, V2.5 writeV25RichOutputToFhir, V0.5 Mastra write toolsMutable — PUT-обновления норма (пере-интерпретация на каждом analysis run)

Lifecycle rules детальнее — см. fhir-resource-origin-and-lifecycle.

Слой 2: meta.tag source — fine-grained source-of-truth для ai-generated

CodeSystem http://bloodgpt.com/fhir/CodeSystem/source. Применяется только к ресурсам с origin: ai-generated:

"meta": { "tag": [{
  "system": "http://bloodgpt.com/fhir/CodeSystem/source",
  "code": "health-chat" | "survey" | "document-import"
}]}

Зачем отдельно от origin: даёт filter без extra _revinclude запроса. Например, ?_tag=source|health-chat&subject=Patient/X → все ресурсы пациента из chat-агента. Дублирующая информация с Provenance, но оптимизирует частые consumer-side queries.

Open question: в meta.tag не зашита версия pipeline (промпт hash, model id, code revision), создавшая resource. Сейчас эту информацию несёт Provenance (через agent и signature/extension’ы), но не tag — поэтому нет дешёвого consumer-query вида «всё, что писал pipeline v2.5.3». TBD: добавить ли отдельный meta.tag pipeline-version|<semver>, или оставить Provenance как единственный источник истины для версионирования.

Слой 3: meta.security AIAST — HL7 standard для AI-asserted resources1

"meta": { "security": [{
  "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue",
  "code": "AIAST"
}]}

AIAST — стандартный HL7 v3 ObservationValue code (не self-invented)1. Хранится в meta.security[] (integrity tag, не workflow tag), запрос через _security search param на любом resource type:

GET /ClinicalImpression?_security=AIAST       → все AI-impressions
GET /Observation?_security=AIAST              → AI-asserted observations
GET /?_security=AIAST                         → всё AI по серверу
GET /Observation?subject=Patient/123&_security:not=AIAST  → trusted lab data, NO AI

Generalizable transferable pattern — public FHIR API без знания BloodGPT-specifics. Любой FHIR-клиент понимает.

Слой 4: Provenance resource — full audit chain

Один Provenance per write-event ссылается на все resources из этого события через target[]:

  • agent.who = Organization/bloodgpt (AI-author) — см. authorship-organization-not-device
  • recorded timestamp
  • entity.role: source + entity.what ссылка на DocumentReference (если source — документ); пусто для chat/survey
  • target[] — все created resources в этом write event

Не для runtime filter — дорогой ?_revinclude=Provenance:target, не масштабируется. Для audit / compliance / legal queries (HIPAA reporting и т.п.).

Standard search param _revinclude=Provenance:target работает на GCP Healthcare API (verified).

См. fhir-provenance entity-page для деталей resource shape.

Соотношение слоёв

СлойЧто отвечаетSearch
meta.tag originПрирода ресурса (user vs AI vs external)?_tag=origin|ai-generated
meta.tag sourceКонкретный agent/path для AI-generated?_tag=source|health-chat
meta.security AIASTIntegrity classification (AI-asserted)?_security=AIAST
ProvenanceFull audit chain (когда / кем / из чего / каким путём)?_revinclude=Provenance:target (только для audit)

Все четыре могут coexist на одном ресурсе. Origin и source — разные codesystems, оба в meta.tag[]. Security и tag — два разных search params в FHIR.

Implementation status by writer

Writerorigin tagsource tagsecurity: AIASTProvenance
Recognition pipeline (save-fhir-preliminary)TBD — должен писать user-uploadedN/AN/ATBD
V2.5 AI builders (writeV25RichOutputToFhir)TBD — должен писать ai-generatedTBD — document-import?TBDСоздаёт Provenance per run (done)
V0.5 Mastra write tools (recordSymptom/etc)TBD — ai-generatedTBD — health-chat или surveyTBDДолжен — один Provenance per write-event
TextToFHIR document import (V2 port в TS)TBD — ai-generatedTBD — document-importTBDTBD

Сейчас ни один writer не выставляет meta.tag — gap зафиксирован в fhir-resource-origin-and-lifecycle раздел про gap. Migration policy: drop dev / bulk-tag stage / помечать с момента deploy.

Следствия

  • Закрывает (separate det/AI) в fhir-modeling-ai-content — filter по meta.tag.code = "document-import" даёт лабораторные данные; meta.tag.code = "health-chat" или "survey" — patient-reported.
  • Закрывает (AI-content audit marking) там же — Provenance + meta.tag = full audit (когда, кем, из какого документа). Versioning model/prompt — отдельная задача.
  • Stale-detection прямолинеен — newer raw resource через ?_tag=origin\|user-uploaded&_lastUpdated=gt<...>. См. health-report-versioning-model.
  • Discharge summary case работает — пациент приносит выписку → Composition + origin: user-uploaded; наша summary → Composition + origin: ai-generated; lookup ?_tag=ai-generated различит. Не нужны костыли с identifier-сопоставлением.

Open questions

  • Tagging not yet applied at writers — все writer’ы должны быть обновлены чтобы выставлять tags. Скоп ~1-2 дня + migration policy. Важно зашить в существующую миграцию (BG-1337 stage-2, координация с Vlad), иначе старые ресурсы остаются без origin/source и query’и фильтрации не работают на исторические данные.
  • Provenance в save-fhir-resources (analysis pipeline) — приоритет. Сейчас вся запись в FHIR происходит без Provenance: Composition + CarePlan + Observation* создаются и audit chain не закрывается. Это значит «4 слоя» сейчас фактически 1.5 (только tag/security; Provenance отсутствует там, где особенно нужен). План на ~30-40 строк, реализация отложена — но это не TBD-исследование, а уже понятная to-do единица работы.
  • CodeSystem URL bloodgpt.com/fhir/CodeSystem/origin и .../source — final URLs? (Параллельный вопрос про identifier namespace в health-report-versioning-model.)
  • 4-слойная избыточность — нужны ли все 4 слоя, или достаточно origin + Provenance? Source-tag и AIAST-security дублируют информацию из Provenance ради cheaper queries и industry-стандартной маркировки. Если consumer-side queries окажутся редкими — слои 2-3 кандидаты на упрощение.
  • Pipeline version в tag — см. выше open question рядом с Слоем 2 (хранить ли семвер pipeline’а в meta.tag pipeline-version, или достаточно Provenance).
  • 2-tier vs 3-tier для AI — origin tag единственный или дополнительный tier: derived\|aggregate? Рекомендация: 2-tier пока нет use-case для 3-tier. См. fhir-resource-origin-and-lifecycle раздел про tier debate.

Отдельный (не tagging-вопрос):

  • Composition «misleading completed» статус — recognition завершается со status=completed, но без AI-интерпретации. Промежуточный статус (awaiting_interpretation)? Это не tagging-проблема, а отдельный вопрос про lifecycle Composition в pipeline — см. fhir-composition / fhir-resource-origin-and-lifecycle для extraction в отдельную decision-страницу при разрешении.

Связано

Источники

Источники: 2 3 1 4 5 6.

Сноски

  1. HL7 v3 ObservationValue codesystem (AIAST code), accessed 2026-05-17, https://terminology.hl7.org/CodeSystem-v3-ObservationValue.html. 2 3

  2. FHIR R4 Resource.meta.tag, accessed 2026-05-17, https://www.hl7.org/fhir/R4/resource.html#tag.

  3. FHIR R4 Resource.meta.security, accessed 2026-05-17, https://www.hl7.org/fhir/R4/resource.html#Meta.

  4. FHIR R4 Provenance, accessed 2026-05-17, https://hl7.org/fhir/R4/provenance.html.

  5. FHIR R4 DocumentReference, accessed 2026-05-17, https://hl7.org/fhir/R4/documentreference.html.

  6. Сессия ildar/7ff79368, 2026-03-27 — (original decision.