146 lines
5.0 KiB
Markdown
146 lines
5.0 KiB
Markdown
# 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 快照 | 无差异 | 实现正确 |
|