plan-engine-batch.spec.ts
43.8 KB
-
fix(plan): 归因继承的判据换轴 —— 看客服碰过没,不看召回理由变没变 · 2d8b146e
上一版判据(「召回理由整组换掉就不继承」)是**找错了轴**,产品当场指出两个反例: ① 召回一会儿出现一会儿不出现,**恰恰可能是被客服处理过**造成的 (患者来了、治了一部分、又诊断出新问题)→ 该结账的反而被当成"理由变了"继承走 ② 同一种诊断**再次出现,也不代表客服没处理过** → 该结账的同样继承了 **理由的变化根本不携带「客服做没做事」的信息**,它只反映患者临床状态在动。 两个方向都会错,所以整条判据作废,换成: 客服没碰过 → 这单还欠着 → 继承(理由怎么变都继承) 客服碰过了 → 批次这一条的账已落定 → 不继承,后面再冒出来的是新工单 批次分的是**人**不是诊断:主管要知道的是「这 100 个人有多少被联系/处理了」。 一个人一次都没被联系过,账就还欠着 —— 临床理由怎么变都不改变这件事。⚠ ️ 「碰过没」不新造判据,**直接复用 T21 / D-11 那一套**(撤销整批判"哪些单不能收"): 以 view 事件为主(实测 view 1,024 条 vs plan_executions 7 条,回写率 11%), 外加行上三个现成强信号(snoozedUntil / releaseReason / contactAttempts)。⛔ 别改成只看 plan_executions —— 会把 89% 已打过电话的单判成"没碰过", 于是归因一直继承下去,**批次的账永远结不掉**。 性能:view 事件**只对带 assignment_id 的单查**,批量路径一次 groupBy 预取。 不收窄的话 runAllForHost 全量会为 44 万患者各查一次(已加回归锁住)。 与 T20′ 咬合不变:不继承时旧行仍带 assignment_id 且已 superseded → 跟踪按患者取最新版 取到的就是它,身上带着当时的处置(releaseReason / 已 view)→ 批次分子分母都不丢。 D-12 那条🔴 🔴 守恒断言(「退回后升版本归因仍在」)改为断言**结果**而非机制: 退回也是一种处置 → 新版本不带归因,但旧行带着 assignment_id + releaseReason 留在批次里, 退回率照样算得出。原断言测的是当时的实现手段,不是它想守的东西。 顺带补上 mock 的 planEventLog.groupBy/findFirst(此前没有,view 判据在单测里无从验证)。 965 tests passing。教条 T20″ 与契约 D-12 已按新轴重写,并把"曾经写错的那版判据 + 为什么错" 留在文档里 —— 这个错很容易再犯一次。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>luoqi committed