Files
2026-03-15 10:15:02 +08:00

105 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Implementation Plan: P4 前置依赖修复
## Overview
6 个定点修复,修正 P4 核心业务层与 Spec 的实现偏差。T1/T2 已在之前修复中完成仅需属性测试验证T3/T4/T5/T6 需要代码变更。所有修改限于现有服务层内部逻辑,无新表、无新接口。
测试框架Hypothesis项目已有依赖测试文件位于 `tests/` 目录。
## Tasks
- [x] 1. 验证 T1任务列表和 T2召回检测器已有实现 + 属性测试
- [x] 1.1 编写 T1 属性测试任务列表状态过滤、排序、abandon_reason 一致性
- 创建 `tests/test_p52_task_list_properties.py`
- 提取 `get_task_list` 的过滤和排序逻辑为纯函数(或 mock DB 层),用 Hypothesis 生成随机任务集合
- **Property 1: 任务列表状态过滤** — 仅返回 active/abandoned不含 completed/inactive
- **Property 2: 任务列表排序正确性** — abandoned 排在 active 之后active 内部按 is_pinned DESC, priority_score DESC NULLS LAST, created_at ASC
- **Property 3: abandon_reason 与 status 一致性不变量** — active → null, abandoned → 非空字符串
- **Validates: Requirements 1.1, 1.2, 1.3, 1.4**
- [x] 1.2 编写 T2 属性测试:召回检测器仅完成 recall 类型任务
-`tests/test_p52_recall_detector_properties.py` 中编写
- 用 Hypothesis 生成包含四种 task_type 的任务集合和服务记录
- **Property 4: 召回检测器仅完成 recall 类型任务** — high_priority_recall/priority_recall 被完成follow_up_visit/relationship_building 状态不变
- **Validates: Requirements 2.1, 2.2, 2.3**
- [x] 2. Checkpoint — 验证 T1/T2 属性测试通过
- Ensure all tests pass, ask the user if questions arise.
- [x] 3. 实现 T3备注回溯重分类器冲突处理
- [x] 3.1 修改 `apps/backend/app/services/note_reclassifier.py``run()` 方法
- 在创建 follow_up_visit 任务前,查询同 (site_id, assistant_id, member_id) 是否已有 follow_up_visit 任务
- 已有 `completed` → 跳过创建(回访完成语义已满足)
- 已有 `active` → 旧任务标记 `inactive`,记录 `superseded` 历史,创建新任务
- 不存在(或仅有 inactive/abandoned→ 正常创建
- 确保重复触发相同 payload 不产生唯一约束冲突
- _Requirements: 3.1, 3.2, 3.3, 3.4_
- [x] 3.2 编写 T3 属性测试:冲突处理三分支
-`tests/test_p52_note_reclassifier_properties.py` 中编写
- **Property 5: 已完成回访任务阻止新建** — 存在 completed 的 follow_up_visit 时跳过创建
- **Property 6: active 回访任务被顶替** — 旧任务 → inactive + superseded 历史,新任务创建
- **Property 7: 无冲突时正常创建** — 不存在 follow_up_visit或仅 inactive/abandoned时正常创建
- **Validates: Requirements 3.1, 3.2, 3.3, 3.4**
- [x] 4. 实现 T4回访完成条件改为「有备注即完成」
- [x] 4.1 修改 `apps/backend/app/services/note_service.py``create_note()` 方法
-`note_type == "follow_up"``task_id is not None` 时:
- 保留 `ai_analyze_note()` 占位调用,返回值仅用于更新 `ai_score` 字段
- 不论 `ai_score` 如何,有备注即标记关联的 active follow_up_visit 任务为 `completed`
- 记录 `completed_by_note` 历史
- _Requirements: 4.1, 4.2, 4.3_
- [x] 4.2 修改 `apps/backend/app/services/note_reclassifier.py``run()` 方法T4 部分)
- 去掉 AI 评分判定逻辑(`ai_score >= 6` 条件)
- 保留 `ai_analyze_note()` 占位调用
- 找到备注(`note_id is not None`)→ 创建 `status='completed'` 的回访任务(回溯完成)
- 未找到备注(`note_id is None`)→ 创建 `status='active'` 的回访任务(等待备注)
- 注意:此步骤需与 3.1 的冲突处理逻辑协同,冲突检查在任务创建前执行
- _Requirements: 4.4, 4.5_
- [x] 4.3 编写 T4 属性测试:有备注即完成
-`tests/test_p52_note_service_properties.py` 中编写
- **Property 8: 有备注即完成回访任务,不依赖 AI 评分** — 对任意 ai_scoreNone/0-5/6-10提交备注后 active follow_up_visit 任务都标记 completed
- **Property 9: 回溯有备注时创建 completed 回访任务** — note_reclassifier 找到备注 → status='completed'
- **Property 10: 回溯无备注时创建 active 回访任务** — note_reclassifier 未找到备注 → status='active'
- **Validates: Requirements 4.2, 4.3, 4.4, 4.5**
- [x] 5. Checkpoint — 验证 T3/T4 实现和测试通过
- Ensure all tests pass, ask the user if questions arise.
- [x] 6. 实现 T5trigger_scheduler last_run_at 事务安全
- [x] 6.1 修改 `apps/backend/app/services/trigger_scheduler.py`
- `fire_event()`handler 接受可选 `conn` 参数,在 handler 最终 commit 前附带更新 `last_run_at`handler 失败时整个事务回滚last_run_at 不更新)
- `check_scheduled_jobs()`:同理,将 `last_run_at``next_run_at` 更新纳入 handler 事务范围
- 需同步修改 `recall_detector.run()``note_reclassifier.run()` 的签名,接受可选 `conn` 参数
- _Requirements: 5.1, 5.2, 5.3_
- [x] 6.2 编写 T5 属性测试:事务一致性
-`tests/test_p52_trigger_scheduler_properties.py` 中编写
- **Property 11: 触发器 last_run_at 事务一致性** — handler 成功 → last_run_at 更新handler 异常 → last_run_at 不变(整个事务回滚)
- **Validates: Requirements 5.1, 5.2**
- [x] 7. 实现 T6cron 默认值改为 07:00 + 迁移脚本
- [x] 7.1 修改 `apps/backend/app/services/trigger_scheduler.py``_calculate_next_run()`
-`trigger_config.get("cron_expression", "0 4 * * *")` 改为 `"0 7 * * *"`
- _Requirements: 6.2, 6.3_
- [x] 7.2 创建迁移脚本 `db/zqyy_app/migrations/2026-03-15__p52_update_cron_0700.sql`
- 幂等 UPDATE`UPDATE biz.trigger_jobs SET trigger_config = jsonb_set(trigger_config, '{cron_expression}', '"0 7 * * *"') WHERE job_name = 'task_generator'`
- 包含回滚注释
- _Requirements: 6.1_
- [x] 8. Final checkpoint — 全部测试通过
- Ensure all tests pass, ask the user if questions arise.
- 运行 `pytest tests/test_p52_*.py -v` 验证所有 P5.2 属性测试通过
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- T1/T2 已在之前修复中实现,任务 1 仅编写属性测试验证覆盖
- T3 和 T4 对 `note_reclassifier.py` 有交叉修改,任务 3.1 和 4.2 需协同实施
- T5 涉及 handler 签名变更,需同步修改 recall_detector 和 note_reclassifier
- T6 种子数据已是 `0 7 * * *`,迁移脚本为幂等更新确保生产环境一致
- 属性测试使用 Hypothesis每个属性最少 100 次迭代