Files
cmshoppe/docs/tasks/T-552.md
T

52 lines
5.2 KiB
Markdown
Raw 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.
---
id: T-552
title: 任务失败原因带上失败步骤(①②③ 阶段/状态列可见)
phase: 7
deps: [T-207, T-523]
status: DONE
created: 2026-07-08
---
## 问题 / 背景
①导入采集(及②③)列表里任务失败时,阶段/状态列只显示「失败」,操作员**看不出卡在哪一步**(打开商品页 / 页面就绪 / 读标题 / 读封面 / 下载封面 / 写库 / 回写Excel)。
- 失败**步骤信息其实已被采集**:T-207 把 `step=preflight/open_product/wait_ready/read_title/read_cover/download_cover/db_write/excel_write_back` 记进了 `run_log_events`。
- 但 `db.mark_failed(task_id, phase, error)` 里 `phase` 只是粗粒度(collect/generate/apply),`error` 只是原始消息;`tasks.last_error` 不含步骤。
- ① 阶段列的 tooltip 已经在显示 `last_error`,但只有消息、没有步骤 → 要知道哪步得去翻「采集运行日志」逐条对,摩擦大。
这是"数据有、但没暴露在失败发生处"的可见性问题,不是要重新采集数据。
## 方案(P0:prepend 步骤到 last_error,最小改动)
让失败的 `last_error` 带上**中文步骤**,例如「读封面失败:图片超过大小上限」「打开商品页失败:CDP 端口无响应」。
- **worker**(`app/gui/workers.py` 的 `CollectWorker`,及②③对应 worker):失败时 worker 已知当前 step(T-207 在逐任务追踪),把该 step 传给失败写库。
- **db**(`app/db.py` `mark_failed`):把中文步骤 **prepend 到 `last_error`**(不改 schema),存成 `「<步骤中文>失败:<原因>」`;step 已是中文/已知失败步骤时避免重复前缀。
- **step→中文映射**(放一处共用,如 worker 或 db helper):`preflight→预检 / open_product→打开商品页 / wait_ready→页面就绪 / read_title→读标题 / read_cover→读封面 / download_cover→下载封面 / db_write→写库 / excel_write_back→回写Excel`;未知 step 用原值兜底。
- **展示**:①②③ 的阶段/状态列 tooltip 已显示 `last_error`(含步骤后即自动可见);阶段列文案可选显示「失败·<步骤>」(能从 last_error 派生就派生,不额外加列)。
- 三个模块共用同一套 step→中文 + prepend 逻辑,一次覆盖①②③"失败看不出哪步"。
> 备注:更结构化的做法是新增 `tasks.last_error_step` 字段(便于阶段列内联显示/上色),但需 schema 迁移;本任务按 P0 走 prepend,`last_error_step` 作为后续可选增强,双击看完整步骤链(run_log_events 按 task_id 过滤)也作为后续 P1。
## 验收要点
- 采集/生成/更新任一步失败后,`tasks.last_error` 以「<中文步骤>失败:<原因>」开头。
- ①②③ 失败行悬停 tooltip 能看到"是哪一步失败 + 原因",无需翻运行日志。
- step→中文映射覆盖上述所有步骤,未知 step 不崩、用原值。
- 已带步骤前缀的 error 不重复加前缀。
- 单测:`tests/test_db.py` 断言 `mark_failed` 带 step 时 `last_error` 前缀正确、无 step 时保持原样;`tests/test_gui.py` 断言失败行 tooltip 含步骤文案(至少①覆盖,②③视改动补充)。
## 边界(不改什么)
只改 `mark_failed` 的 step 前缀 + worker 传 step + 模型 tooltip/阶段文案 + 单测;不改采集/生成/更新执行流程、`run_log_events` 结构(T-207 保留)、CDP/Shopee 交互、Excel、DB schema(P0 不加字段)。
## 执行记录
- 2026-07-08:完成 T-552。
- 代码:`app/db.py` 新增 `FAILURE_STEP_LABELS`、`failure_step_label()`、`format_failure_error()`;`mark_failed()` 与 `set_applied()` 增加可选 `step` 参数,带 step 时把 `last_error` 统一保存为「<中文步骤>失败:<原因>」,无 step 时保持旧行为,已带步骤前缀时不重复添加。
- 代码:①`CollectWorker` 采集失败时把当前 step 传给 `mark_failed`,并立即向 GUI 发出带步骤前缀的 `last_error`;②`app/ai.py` 的生成失败写库传入当前 title/cover step;③`ApplyWorker` 更新失败和异常失败传入当前 step 给 `set_applied`,默认归因为 `apply_task`,真实编辑器步骤仍由 `on_step` 覆盖。
- 展示:①②③ 表格模型原本 tooltip 已读取 `last_error`,因此失败行悬停可直接看到失败步骤与原因;未新增列、不改 DB schema、不改 run_log_events。
- 测试:`tests/test_db.py` 覆盖 `mark_failed` 带 step 前缀、未知 step 兜底、重复前缀不叠加、无 step 保持原样,以及 `set_applied` 更新失败 step 前缀;`tests/test_gui.py` 覆盖①②③失败行 tooltip 显示步骤与原因,并更新③ worker 失败原因断言。
- 验证:`py -3.10 -m unittest discover -s tests -p "test_db.py"` 通过(9 tests);`py -3.10 -m unittest discover -s tests -p "test_gui.py"` 通过(104 tests);`py -3.10 -m unittest discover -s tests -p "test_ai.py"` 通过(40 tests);`python -m ruff check app tests main.py` 通过;`python -m ruff check scripts\gen_task_board.py tests\test_task_board.py` 通过;`py -3.10 -m compileall app main.py` 通过;`py -3.10 -m py_compile scripts/gen_task_board.py` 通过;`git diff --check` 通过;`py -3.10 -m unittest discover -s tests` 通过(257 tests)。