# P5.2:P4 前置依赖修复 — p4-prerequisite-fixes > 优先级:P5.2(P6 前置,必须在 P6 开发前完成) > 预估工作量:小(6 个定点修复,无新表/新接口) > 依赖:P4 已完成 > 来源:P4 Spec vs 实现差异分析(`docs/reports/P4-spec-vs-implementation-gap-analysis.md`) --- ## 背景 P4 核心业务层已实现并通过属性测试,但对比最新 Spec 发现 6 处实现偏差。 这些偏差会影响 P6(前端任务模块)的正常开发,必须前置修复。 参考文档: - 差异分析:`docs/reports/P4-spec-vs-implementation-gap-analysis.md` - 生命周期全景:`docs/reports/P4-task-lifecycle-panorama.md` --- ## 需求(Requirements) ### 验收标准 - AC1:任务列表 API 返回 active + abandoned 两种状态,abandoned 排在最后且包含 abandon_reason - AC2:召回完成检测器仅完成 high_priority_recall / priority_recall 两种任务类型 - AC3:备注回溯重分类器创建回访任务时,已有 active 回访 → 顶替(旧→无效),已完成 → 跳过 - AC4:回访任务完成条件为「助教为该客户提交备注」,不依赖 AI 评分 - AC5:trigger_scheduler 的 last_run_at 更新具备事务安全性 - AC6:任务生成器 cron 时间为 07:00 --- ## 任务清单 ### T1:任务列表返回已放弃任务(GAP-3) 文件:`apps/backend/app/services/task_manager.py` → `get_task_list()` 修改内容: 1. SQL WHERE 条件:`status = 'active'` → `status IN ('active', 'abandoned')` 2. SQL ORDER BY 增加:`CASE WHEN status = 'abandoned' THEN 1 ELSE 0 END` 排在 `is_pinned DESC` 之前 3. SELECT 增加 `abandon_reason` 字段 4. 返回结构增加 `abandon_reason` 字段 验证: - 有 abandoned 任务时,列表末尾出现灰化任务且包含 abandon_reason - 有 active + pinned 任务时,排序为:置顶 → 一般 → 已放弃 --- ### T2:召回完成检测器过滤任务类型(GAP-6) 文件:`apps/backend/app/services/recall_detector.py` → `_process_service_record()` 修改内容: 1. SQL 增加 `AND task_type IN ('high_priority_recall', 'priority_recall')` 验证: - follow_up_visit 和 relationship_building 类型的 active 任务不会被召回检测器完成 - high_priority_recall 和 priority_recall 正常完成 --- ### T3:备注回溯重分类器冲突处理(GAP-7) 文件:`apps/backend/app/services/note_reclassifier.py` → `run()` 修改内容: 1. 创建回访任务前,先查询是否已有同 (site_id, assistant_id, member_id) 的 follow_up_visit 任务 2. 已有 completed 的回访任务 → 跳过创建(回访完成 +1 的语义已满足) 3. 已有 active 的回访任务 → 旧任务标记 inactive,创建新任务 4. 不存在 → 正常创建 验证: - 重复触发不会产生唯一约束冲突 - 已完成的回访任务不会被覆盖 --- ### T4:回访完成条件改为「有备注即完成」(新-1) 文件: - `apps/backend/app/services/note_service.py` → `create_note()` - `apps/backend/app/services/note_reclassifier.py` → `run()` 修改内容: 1. `note_service.create_note()` 增加逻辑:创建备注后,通过 user_assistant_binding 查 assistant_id, 再查该 (site_id, assistant_id, member_id) 是否有 active 的 follow_up_visit 任务,有则标记 completed 2. `note_reclassifier.py`:去掉 AI 评分判定逻辑,有备注 → 回访任务直接标记 completed; 无备注 → 创建 active 回访任务(等待备注) 验证: - 助教提交备注后,对应客户的 active 回访任务自动完成 - 不依赖 AI 评分返回值 --- ### T5:trigger_scheduler last_run_at 事务安全(GAP-9) 文件:`apps/backend/app/services/trigger_scheduler.py` 修改内容: 1. `fire_event()` 和 `check_scheduled_jobs()` 中,将 last_run_at 更新纳入 handler 的事务范围, 或改为执行前更新(at-most-once 语义,配合 handler 幂等性) 验证: - handler 成功但 commit 失败的场景不会导致重复处理(或重复处理是幂等的) --- ### T6:任务生成器 cron 改为 07:00(新-2) 文件: - `db/zqyy_app/migrations/2026-03-15__p52_update_cron_0700.sql`(新建迁移脚本) - `apps/backend/app/services/trigger_scheduler.py` → `_calculate_next_run()` 默认值 修改内容: 1. 新建迁移脚本:`UPDATE biz.trigger_jobs SET trigger_config = '{"cron_expression": "0 7 * * *"}' WHERE job_name = 'task_generator'` 2. `_calculate_next_run()` 中 cron 默认值从 `"0 4 * * *"` 改为 `"0 7 * * *"` 验证: - trigger_jobs 表中 task_generator 的 cron_expression 为 `0 7 * * *` - 下次运行时间计算正确 --- ## 执行顺序 ``` 批次 1(无依赖,可并行):T1、T2、T6 批次 2(依赖 T2 确认):T3、T4 批次 3(依赖 T3/T4 验证):T5 ``` --- ## 不在本 SPEC 范围 | 项目 | 归属 | 说明 | |------|------|------| | GAP-5 备注分页 | P6-T6 | 已写入 P6 Spec | | GAP-8 问问 AI | P5 | P5 AI 集成层已覆盖 | | GAP-2 cancel_abandon 重置 is_pinned | 已修复 | 2026-03-14 | | GAP-4 completed_task_type 快照 | 无差异 | 实现正确 |