# PCC 演習系統 ↔ 設備終端（defib-sim / vitals-monitor）整合接口

> 狀態：**設計草案，未實作**。此文件是 `irislin-tps/pcc-training-deck`（PCC 母系統）與
> `irislin-tps/shane-wonderland`（設備終端所在）之間的接口合約，供雙方各自開發時對齊。
> ⚠️ PCC 資料夾 `/Users/.../PCC訓練系統` 僅供參考、**不在本 repo、勿改動**。

---

## 0. 角色與層級

```
L1 演習主控 EXCON  (PCC excon.html：分段/分站/劇本時鐘+控速/況單/AAR)
        │  派發傷情、推進劇本時鐘、收遙測
        ▼
L2 現場教官        (PCC 分站控制 + shane 的 defib-remote 遙控器：可手動覆寫)
        │
        ▼
傷情狀態機(單一真相) (PCC casualty.html：ClinicalState + trajectories + snapAt())
        │  ↓ ClinicalState 快照              ↑ intervention 事件
        ▼                                     │
L3 設備終端        (shane：vitals-monitor / defib-sim / 12-lead …)
   ‧ 讀狀態→畫波形數值   ‧ 互動(電擊/量NIBP/起搏)→寫回 intervention
```

- **PCC 大宗傷患的終端是 vitals-monitor**（趨勢監測+記錄）；defib-sim 只在需要急救時切入，是其中一個環節。
- 傷情狀態機是**單一真相**：設備只是它的「皮層/視圖」。互動設備可寫回，但最終仲裁權在狀態機/教官。

---

## 1. ClinicalState（下行主資料）

PCC `casualty.html` 的 `snapAt(劇本時間)` 會內插出某時刻的臨床狀態。設備終端訂閱它來顯示。

```jsonc
// ClinicalState：某劇本時刻的權威臨床狀態（單一真相）
{
  "casualtyId": "cas-07",
  "scenarioTimeSec": 1830,          // 劇本秒（吃劇本時鐘×速）
  "vitals": {
    "HR": 138, "SBP": 78, "DBP": 50, "RR": 30,
    "SpO2": 90, "EtCO2": 32, "Temp": 36.0, "GCS": 13
  },
  "labs":   { "Hb": 9, "Lactate": 5.0, "K": 4.2 },     // 選填；走 PCC sampling 排程
  "exam":   { "airway":"通暢", "breathing":"快淺", "circulation":"橈動脈弱", "skin":"花斑", "wound":"腹部活動性出血" },
  "symptoms": ["躁動","意識下降"],
  "derived": { "MAP": 59, "SI": 1.77 },

  // ── 設備終端專用擴充（PCC schema 需新增；見 §3 缺口）──
  "rhythm": "竇性心搏過速",          // 選填：ECG 終端畫波形用；缺則由 §3 對照表推導
  "rhythmOverlays": ["STEMI 下壁"],  // 選填：疊加共病(對映 ecg-engine overlay)
  "perfusion": "low",               // none|low|normal；驅動 ABP/Pleth 是否有搏動
  "sensorsAllowed": ["ecg","spo2","abp","co2","nibp"]  // 選填：此傷患可用哪些感測器
}
```

### 1.1 欄位 → defib-sim 顯示對映（直接可用）
| ClinicalState | defib-sim 內部 | 備註 |
|---|---|---|
| `vitals.HR`（+`rhythm`）| 心律 + `eng.instHR()` | HR 由 rhythm 的速率呈現 |
| `vitals.SBP/DBP` | `sysBP/diaBP` → ABP 波 + NIBP | |
| `vitals.SpO2` | `spo2` → Pleth | |
| `vitals.EtCO2` | `etco2` → capnogram | |
| `vitals.RR` | `respRate` | |
| `vitals.Temp/GCS` | （數值顯示，無波形）| 監視器顯示 |
| `perfusion:"none"` | `eng.noPulse=true` / 死亡心律 | ABP/Pleth 歸零、PEA 呈現 |
| `labs/exam/symptoms` | （教官面板 / 監視器側欄）| |

→ 除 `rhythm` 外，**SpO₂/EtCO₂/BP/RR 全部直接對映** defib-sim 現有狀態與我已加的「漸進回升 / 感測器連接」邏輯。

---

## 2. Intervention（上行：設備→狀態機）

設備互動 = 一個「處置」事件，餵回 PCC 狀態機，可觸發 trajectory 分支（PCC §3 transition）。

```jsonc
{
  "t": "intervention",
  "casualtyId": "cas-07",
  "scenarioTimeSec": 1842,
  "actor": "device:defib-sim@room-3",
  "kind": "shock",                  // shock|cardiovert|pace|nibp|drug|airway|fluid|tourniquet|...
  "params": { "energyJ": 200, "sync": false },
  "deviceState": { /* 選填：rcSync() 全狀態快照，供 AAR 重現 */ },
  "ts": 1717749999                  // 真實時間戳（AAR）
}
```

- PCC 狀態機收到後依 trajectory transition 判定結果（例：VF+`shock`→機率 ROSC）。
- defib-sim 既有的 **「電擊結果 自動/手動」開關**正好對應：
  - **自動**＝終端本地先算結果（離線可玩）；
  - **手動/連線**＝把結果讓 PCC 狀態機/教官裁定，終端只送 intervention、等下一個 ClinicalState 回來。

---

## 3. Schema 缺口：rhythm（唯一要補的）

PCC ClinicalState 目前有**數字無心律名**。vitals-monitor 用數字就夠；但 **defib / 12-lead 要畫 ECG 需要心律**。

- **主**：PCC trajectory 的每個關鍵 state 加選填 `rhythm`（對映 `lib/ecg-engine.js` 的 `RHYTHM_GROUPS` 名稱）+ 選填 `rhythmOverlays`。
- **墊底 fallback**：終端用「數字+exam→心律」對照表，例：
  - `circulation:"脈不可觸"` 或 `perfusion:"none"` → 無脈/瀕死節律
  - `HR<50 + GCS↓` → 嚴重心搏過緩；`HR>150` → 竇性心搏過速 / 對應快速性心律
  - 預設 → 竇性，速率取 `vitals.HR`

> rhythm 名稱必須是 `ecg-engine` 既有目錄字串，避免終端對不上。

---

## 4. 傳輸層

- PCC `excon/casualty` 現為 **localStorage 單機**。多裝置同步用 shane-wonderland 既有的 **`relay/server.js`（WS）**。
- 房號模型擴充：`演習(exercise) → 分站/傷患頻道(room) → 裝置(device)`。主控訂閱所有頻道收遙測；終端訂閱自己被指派的傷患頻道。
- 訊息型別（沿用現有 `{t:...}` 慣例）：
  - `deploy`：L1→終端，派傷情模型 + 起始劇本時間（見 §5）。
  - `clock`：L1→終端，劇本時鐘 tick / 速率變更（`{scenarioTimeSec, rate}`）。
  - `state`：傷情→終端，ClinicalState 快照（§1）。
  - `intervention`：終端→傷情/L1（§2）。
  - `telemetry`：終端→L1，回報目前顯示狀態 + 由誰控制（教官手改 vs 腳本）。

---

## 5. 演習前預載（教官團編好的自動腳本）

- 教官團在 PCC `casualty.html` 編好每位傷患 → 匯出 `casualty-model.json`（**已可用**）。
- `deploy` 把整包模型送進終端 → 終端可**離線**自行 `snapAt` 跑（斷線也不崩）；
- 連上 L1 後改吃 L1 的 `clock`/`state`，並接受教官即時覆寫、回送 `telemetry`。

```jsonc
{ "t":"deploy", "exercise":"EX-0607", "room":"room-3",
  "casualtyModel": { /* casualty-model.json 全文 */ },
  "startScenarioTimeSec": 0, "autorun": true }
```

---

## 6. 衝突解法（L1 腳本 vs L2 教官手改）

待拍板（先記著）：
1. **教官優先、鎖住自動**：教官一手改 → 暫停該傷患自動推進，直到教官「交還腳本」。
2. **教官改完回歸腳本**：手改是瞬時擾動，之後回到 trajectory。

建議 (1) 為預設（對映 defib-sim 既有「手動結果」語意），並在 `telemetry` 標 `controlledBy:"scene"|"auto"` 讓主控看得到。

---

## 7. 分階段落地（不急、照需求接）

1. **單機 PoC**：vitals-monitor 直接 import `casualty-model.json`，用內建時鐘跑 `snapAt`→畫數值/趨勢（不連線）。
2. **rhythm 欄位**：PCC trajectory state 加 `rhythm`；defib-sim 能由 ClinicalState 還原波形。
3. **relay 訂閱**：終端訂閱 `state`/`clock`；送 `intervention`/`telemetry`。
4. **L1 派發**：excon.html 透過 relay `deploy` 多傷患到多終端 + 收遙測儀表板。
5. **AAR**：intervention/telemetry 事件流回 PCC 事件日誌，對齊既有 AAR 回放。

---

### 對映速查
| 概念 | PCC 母系統 | shane 終端 |
|---|---|---|
| 單一真相 | `casualty.html` ClinicalState/trajectories | 讀 `state` 渲染 |
| 劇本時鐘+速 | `excon.html` `sclk`/`sspd`/`speed` | 收 `clock` |
| 設備讀寫 | §5b 設備終端 | `rcSync()`/`applyCmd()` |
| 處置事件 | trajectory transition | `intervention` 上送 |
| 傳輸 | （現 localStorage）| `relay/server.js` WS |
| 急救環節 | 1 個設備 type | `defib-sim` |
| 監測/記錄主力 | flowsheet/趨勢 | `vitals-monitor` |
