04ef3972a8400ad24fe7facfe7246acf7c9d061f
T05 卡片要求"先 timeline,再候选,再编辑/测试/审核"。本批是第一步。 新增 contracts:DecisionEvent(区分 occurred_at 与 recorded_at)、CaseTimeline。 新增 services/history_cases.py:确定性提炼,无模型调用。 两条硬规则的实现: - **不编造发生时间**(BR-02):occurred_at 只取材料里记载的日期;缺失/占位值 ("-"、"缺失"、"未知")或无法解析时保持 None 并给缺证提示。recorded_at 必填, 但它**不表示发生时间**——有测试断言二者不相等 - **不编造经过**(14 §4):只有最终报告或非结构化材料时产出 **0 个事件** 并标 `partial` + "过程材料不完整",绝不生成虚构的问询顺序 其它:列名靠别名表识别,**未识别的列忽略而非猜测**;未声明事件类型时保守记为 question 而不丢弃该行;事件携带行级 evidence_id 以便回溯原文定位;同项目重复提炼 是同一对象 revision 递增(03 §4);缺日期事件排序时置于末尾,不被打乱成"近期"。 实现中修掉一处自己的问题:build() 初版调了两次 store.put(首次建库 revision 会变 2), 且校验发生在落库之后——非法时间线本可能入库。现改为先校验再单次 put。 测试:新增 test_history_cases.py 18 项(不编造 6 + 提炼 6 + 隔离与版本 6), 含"缺日期为 None 且不等于导入时间""只有最终报告不得生成时间线"等反例。 全量 290 项 OK(272 → 290);verify.py 10/10 PASS。 Co-Authored-By: Claude Code <noreply@anthropic.com>
mini_openclaw
Languages
Python
78.8%
TypeScript
18.4%
JavaScript
1.7%
CSS
0.5%
Shell
0.3%
Other
0.3%