fix(recall): 终态抑制加时间锚 — 结案后新发同类信号放行复活,'永久'不再误杀

问题:信号级抑制集只按 (scenario|subKey) 一刀切,外院/无效的永久 snooze(36500d)会把
结案后新发的同类诊断也永久压死 —— 同牙位复发(外院种植失败回院再诊断)和 @whole 病种
(外院牙周,多年后新发)整类终身沉默。且 cluster lead 锚最早诊断,老 fact 永远 active
(外院治疗不进本院数据)→ 新旧必聚同 cluster,单看 lead 时间无法区分新发。

修法:
- scenario:cluster 注入 cluster_latest_occurred_at(成员 max),hit 透传
  latestSignalOccurredAt(lead/daysSince 仍锚最早,紧迫度口径不变)
- engine:抑制集 Set<key> → Map<key, 结案锚点>;锚=结案 execution.createdAt(不可变,
  不用 updatedAt——会被召回反馈等后续写顶后);同 key 多次结案取最新锚
- 过滤:key 命中且 latest > anchor → 放行复活;latest 缺省(旧 scenario)/锚不可解析
  (远未来哨兵)→ 维持旧行为全压,宁可多压不误放

测试:tests/plan-engine-snooze-anchor.spec.ts(锚点构建 5 例 + 逃逸判定端到端);
存量 plan-engine-batch 通过(mock 无 executions/updatedAt 走哨兵路径)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Found errors in your .gitlab-ci.yml:

  • jobs:openapi-drift config contains unknown keys: rules
You can also test your .gitlab-ci.yml in the Lint
Status Job ID Name Coverage