摘要
Day 21 已經把 demo contract JSON 對齊 companion guide / trading partner agreement 的語境。Day 22 補上 contract schema validation、contract compatibility classification、unit normalization evidence、live FHIR/metadataCapabilityStatement evidence。
Day 21 的重點是:
這份 demo contract JSON 是否比較像真實合作方交換契約?
Day 22 的重點改成:
這份 contract 能不能被比較嚴格地載入?
契約升版會不會讓目前這份 Bundle 變成 blocking?
檢驗數值單位是否能產生可比較的 exchange evidence?
合作方 FHIR server metadata 是否和 selected contract 對得起來?
也就是說,Day 21 是把契約格式講清楚。
Day 22 是把契約品質、升版風險、單位正規化與 live metadata preflight 放進同一份 Quality Test Report。
目前定位更明確:
FHIR/TW Core validator = Profile validation
TW Lab Contract Gate = Profile validation + partner contract policy + upgrade evidence + metadata preflight
但 Day 22 仍然不是 production exchange platform。
它沒有讀取 Patient / Observation / DiagnosticReport endpoint,也沒有處理 OAuth、SMART、mTLS、PHI、audit retention 或 persistent history。
今天新增或修改的範圍有:
src/main/java/com/twlab/qualitygate/validation/ExchangeContractService.java
src/main/java/com/twlab/qualitygate/validation/ContractComparisonResult.java
src/main/java/com/twlab/qualitygate/validation/CompatibilityClassification.java
src/main/java/com/twlab/qualitygate/validation/ContractDifference.java
src/main/java/com/twlab/qualitygate/validation/BundleParseService.java
src/main/java/com/twlab/qualitygate/validation/ValidationResult.java
src/main/java/com/twlab/qualitygate/validation/UnitNormalizationService.java
src/main/java/com/twlab/qualitygate/validation/UnitNormalizationEvidence.java
src/main/java/com/twlab/qualitygate/validation/FhirMetadataValidationService.java
src/main/java/com/twlab/qualitygate/validation/FhirMetadataValidationResult.java
src/main/java/com/twlab/qualitygate/validation/FhirMetadataHttpClient.java
src/main/java/com/twlab/qualitygate/validation/DefaultFhirMetadataHttpClient.java
src/main/java/com/twlab/qualitygate/web/ParseController.java
src/main/resources/templates/index.html
src/test/java/com/twlab/qualitygate/validation/ExchangeContractServiceTests.java
src/test/java/com/twlab/qualitygate/validation/ContractComparisonServiceTests.java
src/test/java/com/twlab/qualitygate/validation/UnitNormalizationServiceTests.java
src/test/java/com/twlab/qualitygate/validation/FhirMetadataValidationServiceTests.java
src/test/java/com/twlab/qualitygate/web/ParseControllerTests.java
README.md
docs/journal/20260823.md
Day 22 做四件事:
加強 uploaded contract schema validation。
替 contract comparison 加 compatibility classification 與差異摘要。
替 glucose mg/dL / mmol/L 加非阻擋 unit normalization evidence。
新增 optional FHIR base URL,只呼叫 /metadata 並解析 CapabilityStatement。
Day 21 的 uploaded contract validation 已經檢查 required metadata、policy assertion、terminology policy 和 unknown rule code。
Day 22 再補上更接近 schema 的檢查。
現在 uploaded contract 會檢查:
| 欄位 / 區塊 | Day 22 檢查 |
|---|---|
status |
只能是 draft、active、retired |
effectiveDate |
必須是 ISO date |
retireDate |
若提供,必須是 ISO date,且不可早於 effectiveDate |
| retired contract | 必須提供 retireDate |
policyAssertions.obligation |
只能是 SHALL、SHOULD、MAY |
policyAssertions.severity |
只能是 fatal、error、warning、information |
| enabled assertion id | 必須對應已知 Java rule |
terminologyPolicy.*ValueSetCanonical |
必須是 versioned ValueSet canonical |
allowedLoincCodes |
不可空,代表 local expansion snapshot |
allowedUcumCodes |
不可空,代表 local expansion snapshot |
這仍然不是正式 JSON Schema。
它也不是 FHIR IG package validation。
比較精準的說法是:
application-level contract schema validation
也就是本專案對 companion-contract JSON 的最小可信載入條件。
Day 20 / Day 21 的 comparison 可以看出同一份 Bundle 在 v1.0 / v1.1 的結果不同。
但 report 還有一個問題:
這次 contract upgrade 對目前資料是不是 breaking?
Day 22 新增 CompatibilityClassification:
| Classification | 意思 |
|---|---|
NON_BREAKING |
沒有新增 blocking assertion,也沒有縮小 allowed code/unit set |
POTENTIALLY_BREAKING |
新增 SHALL/error/fatal assertion,或 allowed code/unit set 變窄 |
BREAKING_FOR_INPUT |
目前這份 Bundle 在新版 contract 下新增 blocking rule failure |
INCOMPATIBLE_CONTRACT |
contract/result 不足以比較 |
目前 demo 裡最重要的例子是:
v1.0 沒啟用 LAB-UNIT-002
v1.1 啟用 LAB-UNIT-002 as SHALL/error
如果 Bundle 的 UCUM system/code 正確:
classification = POTENTIALLY_BREAKING
因為新版 contract 增加了 blocking assertion,但這份資料沒有被擋。
如果 Bundle 的 UCUM system/code 錯誤:
classification = BREAKING_FOR_INPUT
因為新版 contract 對這份 input 新增了 blocking rule failure。
Day 22 只做其中安全、可驗證、可展示的一小段:
glucose LOINC 2345-7
mg/dL <-> mmol/L
新增 UnitNormalizationService 會對 Bundle 裡的 Observation 產生:
UNIT-NORM-GLUCOSE-001
PASS 或 NOT_EVALUATED
例如:
95 mg/dL -> 5.27 mmol/L
5.3 mmol/L -> 95.50 mg/dL
(glucose conversion 使用 18.0182 作為 MVP 固定係數。)
這個 evidence 不會 block exchange。
它也不做:
所以它的定位是:
exchange comparison evidence
不是醫療判斷
Day 22 新增 optional FHIR base URL 欄位。
若使用者提供 base URL,後端只呼叫:
GET {FHIR_BASE_URL}/metadata
然後用 HAPI FHIR R4 parser 解析成:
CapabilityStatement
目前檢查:
CapabilityStatement。fhirVersion 是否和 selected contract 的 fhirVersion 一致。implementationGuide 或 supportedProfile evidence。HTTP client 的安全邊界:
/metadata URL。/Patient、/Observation、/DiagnosticReport。這不是 production conformance testing。
它只能回答:
這個 FHIR base URL 的 metadata 是否看起來和 selected contract 不衝突?
它不能回答:
這個合作方 API 是否真的能交換 Patient / Observation / DiagnosticReport?
Day 22 首頁新增:
Optional FHIR base URL for live metadata check
Unit normalization evidence
Live FHIR metadata evidence
Compatibility classification
Quality Test Report 的 layer summary 也新增兩層:
| Layer | Blocking? | 說明 |
|---|---|---|
| Unit normalization evidence | No | 只做 glucose mg/dL / mmol/L exchange evidence |
| Live FHIR metadata evidence | No | 只呼叫 /metadata,不碰 PHI resource |
這兩層都不會改變原本 Quality Gate blocking policy。
Quality Gate 仍由 JSON parse、FHIR R4 parse、Bundle gate、FHIR validation、TW Core validation、SHALL/error contract rule failures 決定。
本機 Maven 測試:
./mvnw test
結果:
Tests run: 80, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Day 22 新增或調整的測試確認:
status 會被拒絕。POTENTIALLY_BREAKING。BREAKING_FOR_INPUT。95 mg/dL 會產生 5.27 mmol/L normalization evidence。5.3 mmol/L 會產生 95.50 mg/dL normalization evidence。NOT_EVALUATED。NOT_EVALUATED。啟動:
./mvnw spring-boot:run
http://localhost:8080/ -> 200
並確認首頁包含:
Optional FHIR base URL for live metadata check
ExchangeContractService 補強 uploaded contract application-level schema validation。CompatibilityClassification。ContractDifference。ContractComparisonResult 新增 classification 與 differences。UnitNormalizationService。UnitNormalizationEvidence。BundleParseService 成功解析 Bundle 後會產生 unit normalization evidence。ValidationResult 新增 unit normalization 與 FHIR metadata evidence。FhirMetadataValidationService。FhirMetadataHttpClient 與 default Java HTTP client。ParseController 新增 optional fhirBaseUrl input。./mvnw test 通過,測試數 80。Day 22 尚未處理:
$expand / $validate-code。目前的 MVP 進度:
validation-flow
├─ JSON parse 完成
├─ FHIR R4 parse 完成
├─ FHIR R4 validation 完成
├─ TW Core validation / safe NOT_EVALUATED 完成
├─ Partner exchange contract loading
│ ├─ demo-lab-v1.0.json 完成
│ ├─ demo-lab-v1.1.json 完成
│ ├─ policyAssertions 完成
│ ├─ obligation / severity 完成
│ ├─ lifecycle metadata 完成
│ ├─ terminologyPolicy metadata 完成
│ ├─ allowedLoincCodes local snapshot 完成
│ ├─ allowedUcumCodes local snapshot 完成
│ ├─ optional uploaded contract 完成
│ └─ application-level schema validation 完成
├─ Exchange contract rules
│ ├─ LAB-REF-001 完成並由 contract 啟用
│ ├─ LAB-REF-002 完成並由 contract 啟用
│ ├─ LAB-REF-003 完成並由 contract 啟用
│ ├─ LAB-CODE-001 完成,允許值由 contract 提供
│ ├─ LAB-UNIT-001 完成並由 contract 啟用
│ └─ LAB-UNIT-002 完成,允許值由 contract 提供
├─ Quality Gate
│ ├─ SHALL error/fatal blocking 完成
│ └─ SHOULD/MAY warning behavior 完成
├─ Contract comparison
│ ├─ comparison service test 完成
│ ├─ homepage comparison display 完成
│ ├─ compare checkbox 完成
│ ├─ uploaded 2+ version comparison 完成
│ ├─ upgrade blocker evidence display 完成
│ ├─ compatibility classification 完成
│ └─ contract difference summary 完成
├─ Unit normalization evidence
│ ├─ glucose mg/dL -> mmol/L 完成
│ ├─ glucose mmol/L -> mg/dL 完成
│ └─ unsupported code/unit NOT_EVALUATED 完成
├─ Live FHIR API metadata
│ ├─ optional FHIR base URL 完成
│ ├─ GET /metadata only 完成
│ ├─ CapabilityStatement parse 完成
│ ├─ fhirVersion alignment 完成
│ ├─ JSON format evidence 完成
│ └─ IG / profile declaration evidence 完成
├─ Scenario test pack
│ ├─ v1.0 / v1.1 representative cases 完成 4 例
│ └─ SHOULD warning behavior 完成 1 例
├─ Homepage Quality Test Report 完成
└─ Reproducible delivery
├─ Dockerfile 完成最小版
├─ Docker Compose 完成最小版並驗證啟動
└─ GitHub Actions CI 完成最小版
下一步預計處理:
production security and live exchange track
Repository:twcore-data-quality-gate