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

69 lines
5.0 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-689
title: 商品套图已完成历史任务不阻断原图删除
phase: 7
deps: [T-631, T-658b]
status: TODO
created: 2026-07-22
---
## 问题 / 背景
商品套图第一轮全部生成成功后,用户需要移除一张商品原图、调整参考素材并开始第二轮生成。当前 `remove_original_assets_if_unused()` 只要发现任意 `image_studio_jobs.source_asset_id` 指向该原图,就一律阻断删除,不区分任务是否已经结束。因此第一轮已成功且不可重试的历史 job 仍会错误提示“选中的图片正在被生成任务或终选引用,不能移除”。
此外,T-658b 已把参考图保存为 `reference_asset_ids` JSON 快照,但现有引用计数只统计 `source_asset_id`、`output_asset_id` 和终选表,未检查参考图快照。若直接放宽所有 job 引用,会造成仍在执行或可恢复的任务读取到已删除参考图,违反任务快照和 fail-fast 规则。
## 方案
### 1. 按可执行性而非历史存在性判定阻断
- 为“从商品原图列表删除”提供专用的引用判定 helper;不直接放宽通用 `asset_reference_counts()` 或非原图的删除语义。
- 对每个待删原图同时检查:
- 当前 `image_studio_selections` 终选直接引用;
- job 的 `source_asset_id`;
- job 的 `reference_asset_ids` 有序 JSON 快照。
- 以下情形必须阻断整批删除:
- job 状态为 `pending`、`submitted`、`running`;
- job 为 `failed`、`expired`、`cancelled` 且 `recovery_action` 为 `resume` 或 `regenerate`,仍可继续查询或重试;
- 原图被当前终选直接引用;
- 参考图快照格式无效,无法可靠判定引用关系。
- `succeeded` 且 `recovery_action=none` 的 job 仅属于不可重试的历史记录,不得阻断删除。其他终态且 `recovery_action=none` 同样按已放弃历史处理。
- 批量删除保持全有或全无:任一图片有阻断原因时,全部不删,并向 GUI 返回中文、可行动的原因,例如“所选原图仍被可继续处理的生成任务引用,请先完成、停止或放弃该任务”。
### 2. 删除后的历史兼容
- 允许删除已完成历史 job 的原图资产行。既有 SQLite 外键会将 job 的 `source_asset_id` 和生成图的 `parent_asset_id` 置为 `NULL`;历史 job 的提示词、状态、扣点、生成结果和生成轮次仍保留,历史生成列表和已生成图片不得丢失。
- 对已完成 job 的 `reference_asset_ids` 保持原快照文本,不尝试重写、猜测替代图片或改变历史 prompt;该 job 不可重试,因此不再依赖当前原图资产。
- 原图本地文件继续保留,不删除蝦皮线上图片;用户重新拉取蝦皮原图时,线上仍存在的图片可重新进入原图列表。
### 3. GUI 反馈与第二轮生成
- 第一轮所有任务已成功结束后,删除未被终选直接引用的原图应正常通过,删除成功后重排 `source_order`,用户可立即以新顺序开始第二轮生成。
- 若第一轮存在运行中、远端已提交未完成、失败可重试或可恢复任务,维持删除阻断;提示应说明是“可继续处理的生成任务”而非笼统的“正在生成”。
- 已完成的生成结果、历史生成弹窗、终选和导出继续按原轮次读取;下一轮 job 只使用删除后的当前原图列表,并保持 T-658b 的输入快照冻结规则。
### 4. 服务与兼容边界
- 继续复用 `remove_original_assets_if_unused()` 作为 GUI 的唯一原图删除入口,在内部改用专用阻断判定;单张、勾选批量、键盘、右键和悬停删除必须一致。
- 保持项目归属、资产类型、下载中、拉取中、生成中和事务重排校验;不允许通过 GUI 直接删除数据库行。
- 不新增 SQLite schema,不删除 job、生成结果、终选记录或本地文件,不修改 cmhub 提交、轮询、下载、计费、Shopee CDP 和①至⑤模块。
## 验收要点
- 第一轮全部 `succeeded/recovery_action=none` 后,删除作为主图或参考图使用过、但未被终选直接引用的商品原图成功;剩余 `source_order` 连续,第二轮使用新顺序。
- `pending/submitted/running` job 的源图和参考图删除均被阻断。
- `failed/expired/cancelled` 且可 `resume/regenerate` 的源图和参考图删除均被阻断。
- 已完成历史 job 不再误拦截;历史轮次、生成结果、提示词、扣点和已选生成图片仍可查看,历史 job 的源图显示缺失时不影响查看生成结果。
- 任意被终选直接引用的原图仍被阻断;混合选择“可删 + 不可删”时不发生部分删除。
- 无效 `reference_asset_ids` 快照走保守阻断并显示中文错误,不得静默放行。
- 自动验证:
- `py -3.10 -m unittest tests.test_image_studio tests.test_product_suite tests.test_product_suite_gui`
- `py -3.10 -m unittest discover -s tests`
- `py -3.10 -m ruff check app tests main.py`
- `py -3.10 -m compileall app main.py`
- `git diff --check`
## 执行记录
- 待实施。