# Treatment Chain Disruption Recall — 治疗链内中断召回

> **scenario key**(候选):`treatment_chain_disruption_recall`
> **版本**:v1 候选(占位,**enum 暂未加** — 待业务拍板归属后再决定独立 / 合并)
> **状态**:⏳ 待业务拍板

---

## 1. 业务定位

> **PAC 关注治疗链内**节点 A 已完成、紧接的节点 B **应做但超期未做**的患者。

跟疗效保障的关键区别:

| 维度 | `treatment_aftercare_recall`(已落地) | `treatment_chain_disruption_recall`(本) |
|---|---|---|
| 治疗链状态 | 链**已完成**(主治疗都做完)| 链**进行中**(主治疗某节点完成,下一节点没做)|
| 触发节点对 | 主治疗节点 A → 周期性保养 B | 主治疗节点 A → 链内下一节点 B |
| 例子 | 种植冠装完 → 年度复查 | 根管完成 → 冠修复 |
| 时间窗 | 长效(330-540 天 / 150-360 天)| 中效(30 天 - 18 个月)|
| 业务定位 | 防失败 / 防复发(长期粘性)| 防治疗失败(治疗链断裂)|

### 边界

| ✅ 可能归本场景 | ❌ 明确不是本场景 |
|---|---|
| 根管完成 + 未戴冠 | < 30 天的"正常推进期"(host 治疗中提醒)|
| 正畸主治完成 + 未启动保持期 | 治疗已完结(归 aftercare 场景)|
| 拔牙完成 + 未续接种植 | 治疗未启动(归 initiation 场景)|

---

## 2. "中断"如何定义

中断 = "进行中"超过合理时间窗,该推进没推进。

```
治疗链时间轴(以根管→冠为例):

  根管 completed ──────────────────────────────► 时间
                ↑           ↑                   ↑
              合理窗内      合理窗外           失访
           (< 30 天)    (30 天 - 18 月)     (> 18 月)
          进行中(host)    中断(PAC)        失访
```

每个候选子场景的时间窗(待业务方根据临床经验拍板):

| 候选子场景 | "进行中"(host 管)| "中断"(PAC 召回)| "失访"|
|---|---|---|---|
| 根管 → 冠 | < 30 天 | 30 天 - 18 个月 | > 18 个月 |
| 正畸主治 → 保持期 | < 6 个月 | 6 - 24 个月 | > 24 个月 |
| 拔牙 → 种植/桥/义齿 | < 90 天 | 90 天 - 18 个月 | > 18 个月 |

---

## 3. 触发条件 + SQL 形态

### 数据要求

- `encounter_record.content.treatments[]`:含主治疗节点 A,`status='completed'`
- `treatments[i].expected_next_step` 表明下一节点 B 的语义(如 `crown_restoration`)
- 后续 encounter 内 `treatments[]` 不含对应 B 节点

### SQL 形态(以根管→冠为例)

```sql
SELECT DISTINCT p.external_id
FROM patients p
JOIN patient_profiles pp ON pp.patient_id = p.id
JOIN patient_facts pf_endo ON pf_endo.patient_id = p.id
WHERE pf_endo.status = 'active'
  AND pf_endo.type = 'encounter_record'
  AND pf_endo.kind = 'actual'
  AND pf_endo.occurred_at BETWEEN <18m 前> AND <30 天前>
  AND EXISTS (
    SELECT 1 FROM jsonb_array_elements(pf_endo.content->'treatments') t
    WHERE t->>'treatment_category' = 'endodontic'
      AND t->>'status' = 'completed'
      AND t->>'expected_next_step' = 'crown_restoration'
  )
  AND p.active = true
  AND pp.do_not_contact = false AND pp.deceased = false
  AND p.phone IS NOT NULL AND p.phone <> ''
  -- 无后续冠修复 encounter
  AND NOT EXISTS (
    SELECT 1 FROM patient_facts pf_crown
    WHERE pf_crown.patient_id = p.id
      AND pf_crown.status = 'active'
      AND pf_crown.type = 'encounter_record'
      AND pf_crown.occurred_at > pf_endo.occurred_at
      AND EXISTS (
        SELECT 1 FROM jsonb_array_elements(pf_crown.content->'treatments') t2
        WHERE t2->>'treatment_subtype' = 'crown'
      )
  )
  -- 无未来 crown 预约
  AND NOT EXISTS (
    SELECT 1 FROM patient_facts pf_apt
    WHERE pf_apt.patient_id = p.id
      AND pf_apt.status = 'active'
      AND pf_apt.type = 'appointment_record'
      AND pf_apt.kind = 'planned'
      AND pf_apt.content->>'appointment_type' = 'crown_restoration'
  )
```

---

## 4. priorityScore 默认基线

| 候选子场景 | 默认基线 | 理由 |
|---|---|---|
| 根管未戴冠 | 80 | 立刻可转化 ¥3,000+ + 防恶化(根管不戴冠易牙折,只能拔)|
| 正畸未启动保持期 | 75 | 高客单防流失(4-5 万投入)|
| 拔牙未续接种植 | 70 | 中长期转化 |

---

## 5. 跟 aftercare 的合并可能性

| 维度 | 本场景 | aftercare | 能合? |
|---|---|---|---|
| SQL 算法 | 检测"A 完成 + 后续无 B" | 检测"A 完成 + 后续无周期 B" | ✅ 模式相同 |
| A / B 配置 | 治疗 → 治疗 | 治疗 → 复查 | ⚠️ B 不同 |
| 时间窗 | 中效(月)| 长效(年)| ⚠️ 不同 |
| 业务定位 | 防治疗链断裂 | 防失败 / 长期粘性 | ⚠️ 不同 |
| 客服话术 | "您的根管该戴冠了" | "您该年度复查了" | ⚠️ 不同 |

**结论**:**算法模式可共用,业务定位独立** — 拆 / 合都行。详见 `scenarios/README.md`。

---

## 6. 业务方拍板清单

| # | 项 | 待答 |
|---|---|---|
| 1 | 链内中断算 PAC 还是 host 治疗中提醒?| ? |
| 2 | 如果算 PAC,独立 scenario 还是归入 aftercare?| ? |
| 3 | 各子场景时间窗(下限 / 上限)| ? |
| 4 | "拔牙→种植"算链内中断(同一链)还是漏开新链(initiation)?医学定义 | ? |

如果业务方决定**不做**:
- enum 不加 `treatment_chain_disruption_recall`
- mock 数据 #1 #2 砍掉(或仅作"反面教材"留着)
- 文档归档为"已评估但未采纳"

如果决定**做且独立**:
- enum 加 `treatment_chain_disruption_recall`
- mock 数据 #1 #2 算正例,verify-scenarios 跑独立 SQL

如果决定**做但合并到 aftercare**:
- aftercare 文档段 3 加 #1 #2 进"已落地"
- "链已完成"定义放宽:任何主治疗节点完成都算"链阶段完成"

---

## 7. 文档关联

- 主战场 → `scenarios/treatment_aftercare_recall.md`
- 新链召回 → `scenarios/treatment_initiation_recall.md`
- 漏诊 → `scenarios/missed_diagnosis_recall.md`
- 4 scenario 对比 → `scenarios/README.md`
