Commit 5967b684 by luoqi

fix: scenario SQL 加 ⑤c — 同牙位 surgical 拔除 = 任何信号排除

陈化冰 case (5 reasons → 2 reasons):
  改前误召:K05@17;18 / K04@46 / K00@46 — 3 颗都已拔(2025-12-14/12-20)
  根因:SQL ⑤a 只看"同 expectedCats actual 排除",surgical 不在任何 K0x 的 expectedCats
       但临床上拔除是任何牙病的终结,拔了就不需要后续治疗

修(treatment-initiation-recall.scenario.ts):
  加新 NOT EXISTS ⑤c 子句:
    任何 actual surgical 同牙位 overlap → 排除该信号
  关键设计:
    - 不限时间方向(拔了就拔了,后期诊断只是记录现状如"牙列缺失")
      → 解决 K00@46 在 2026-03 才诊但 46 已 2025-12 拔的情况
    - 仅对**有具体牙位的信号**生效(信号 tooth_position 必须非空)
      → 全口诊断(K05 全口)不走这分支,避免任何拔牙误排全口

验证(陈化冰):
  recompute-plans: tenant=77057 plansSuperseded=1 (陈化冰 v1→v2)
  v2 reasons (2 条):
    K02@24;25;47 (caries_no_filling)  ✓ 该召(未充填)
    K03@14;15 (hard_tissue_damage)    ✓ 该召(未充填)
  v1 排除的 3 条 (✓ 正确):
    K05@17;18 (17;18 已拔) ✓
    K04@46 (46 已拔) ✓
    K00@46 (46 已拔) ✓

副作用:全量重导 5K 患者后,召回池可能下降 5-10%(扣掉"已拔不该召"的噪音)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
parent 961328bd
...@@ -253,6 +253,8 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin { ...@@ -253,6 +253,8 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin {
// ║ └────────────────────────────────────────────────────────────────────┘ ║ // ║ └────────────────────────────────────────────────────────────────────┘ ║
// ║ ║ // ║ ║
// ║ ┌─ ⑤a 排除闸:NOT EXISTS 同类 actual 治疗(牙位级 W4 末升级)─┐ ║ // ║ ┌─ ⑤a 排除闸:NOT EXISTS 同类 actual 治疗(牙位级 W4 末升级)─┐ ║
// ║ ┌─ ⑤c 排除:同牙位拔除(W4 末加,临床:拔了就终结)────────────┐ ║
// ║ ┌─ ⑤b 排除:患者已有未来预约 ────────────────────────────────┐ ║
// ║ │ tx.type = 'treatment_record' AND tx.kind = 'actual' │ ║ // ║ │ tx.type = 'treatment_record' AND tx.kind = 'actual' │ ║
// ║ │ tx.status IN ('active','fulfilled') (完成的 actual 是 fulfilled)│ ║ // ║ │ tx.status IN ('active','fulfilled') (完成的 actual 是 fulfilled)│ ║
// ║ │ tx.content->>'category' = ANY(excludeCats) │ ║ // ║ │ tx.content->>'category' = ANY(excludeCats) │ ║
...@@ -330,6 +332,26 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin { ...@@ -330,6 +332,26 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin {
) )
) )
) )
AND NOT EXISTS ( -- ⑤c 排除:同牙位拔除 actual(W4 末)
-- 临床原则:拔除是任何牙病的终结处理 — 拔了就不需要任何后续治疗(根管/充填/牙周等)
-- 例:陈化冰 K05 17;18 同日拔了 17;18 → 不该召牙周;K04 46 拔了 → 不该召根管
-- 不限时间方向(拔了就拔了,后期 host 写"牙列缺失" 类诊断只是记录现状,不该召)
-- 仅对**有具体牙位的信号**生效(全口诊断 K05 不走这里,避免任何拔牙误排全口)
SELECT 1 FROM patient_facts surg
WHERE surg.patient_id = p.id
AND surg.type = 'treatment_record'
AND surg.kind = 'actual'
AND surg.status IN ('active', 'fulfilled')
AND surg.content->>'category' = 'surgical'
AND COALESCE(NULLIF(trim(sig.content->>'tooth_position'), ''), '') != '' -- 信号必须有牙位
AND array_remove(
string_to_array(regexp_replace(sig.content->>'tooth_position', '[^0-9;]+', ';', 'g'), ';'),
''
) && array_remove(
string_to_array(regexp_replace(surg.content->>'tooth_position', '[^0-9;]+', ';', 'g'), ';'),
''
)
)
AND NOT EXISTS ( -- ⑤b 排除:患者已有未来预约(W3 末放宽) AND NOT EXISTS ( -- ⑤b 排除:患者已有未来预约(W3 末放宽)
-- 召回目的 = 让客服建预约。患者已经有未来预约 → 客服不需要再 push,医生到诊现场处理即可 -- 召回目的 = 让客服建预约。患者已经有未来预约 → 客服不需要再 push,医生到诊现场处理即可
-- 不按 complaint_category 匹配(陆伟根典型:K07 诊断 + 修复预约 → 不召也对,反正会来诊) -- 不按 complaint_category 匹配(陆伟根典型:K07 诊断 + 修复预约 → 不召也对,反正会来诊)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment