From 0ab110d2558b23cccee558041b5437f3bc21c944 Mon Sep 17 00:00:00 2001 From: chengma Date: Thu, 16 Jul 2026 14:52:35 +0800 Subject: [PATCH] docs(tasks): close two remaining gaps in T-637 spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - restore-default validates built-in template before atomic write; invalid bundled template errors out without touching user template - {差异化要求} must occupy its own line, enforced by validation, so empty rendering can delete the whole line without inline residue Co-Authored-By: Claude Fable 5 --- docs/tasks/T-637.md | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/docs/tasks/T-637.md b/docs/tasks/T-637.md index 96b7d8c..9a1dcf7 100644 --- a/docs/tasks/T-637.md +++ b/docs/tasks/T-637.md @@ -53,10 +53,15 @@ created: 2026-07-16 - 弹窗使用可调整的左右分栏,初始比例 `1:1`,设置合理最小尺寸;左侧是可编辑模板,右侧是只读最终提示词预览。 - 第一行从左到右提供: - 「保存」:校验通过后原子写入用户模板,并显示轻量中文成功提示; - - 「恢复默认」:二次确认后仅把内置模板回填到编辑区并刷新预览,**不直接写盘**;确认弹窗需明示会丢弃编辑区当前未保存修改。落盘仍走「保存」,未保存关闭时由统一的三选项流程兜底,保证全程只有「保存」一条原子写盘路径; + - 「恢复默认」:二次确认后读取安装包内置模板,写盘前先执行与「保存」完全相同的占位符和结构校验——校验失败(打包缺陷、资源损坏)时显示中文错误、不写盘、不改动用户模板和编辑区;校验通过后调用与「保存」完全相同的原子写入服务立即覆盖用户套图模板,成功后同步更新编辑区、预览区和已保存基线,不要求再次点击「保存」。确认弹窗需明示会丢弃编辑区当前未保存修改;恢复或写盘失败时保留原用户模板和当前编辑内容; - 右侧「预览分类」下拉框:默认选中「白底图」,可切换当前固定分类和当前项目已有自定义分类。 +- 在「预览分类」右侧增加紧凑的「预览第 X 张」步进器: + - 范围为 `1..max(1, 当前预览分类配置数量)`,默认值为 1; + - 分类数量为 0 或 1 时固定为 1 并禁用,禁止出现 `第 1/0 张`; + - 分类数量大于 1 时允许切换序号,用于核对 `{分类序号}`和 `{差异化要求}`的真实变化; + - 切换分类时重置为第 1 张,不修改项目内真实生成数量。 - 左侧编辑区顶部提供「插入变量」菜单或按钮菜单。用户选择变量后,在当前光标位置插入,不要求手工记忆占位符。 -- 右侧预览区不可编辑、不可获得保存语义;内容使用当前商品任务的真实平台、地区、语言、比例、商品 ID、分类、参考图序号和卖点。预览的序号类占位符使用固定值:`{主参考图序号}`=1、`{分类序号}`=1、`{分类总数}`=该分类当前配置数量,不随预览分类切换之外的因素变化。当前值为空时使用明确的中文示例值,内部 `draft_` 标识不得出现在预览中。 +- 右侧预览区不可编辑、不可获得保存语义;内容使用当前商品任务的真实平台、地区、语言、比例、商品 ID、分类、参考图序号和卖点。预览默认使用 `{主参考图序号}`=1、`{分类序号}`=步进器当前值、`{分类总数}`=`max(1, 当前预览分类配置数量)`;当前值为空时使用明确的中文示例值,内部 `draft_` 标识不得出现在预览中。 - 编辑内容变化后使用约 `200ms` 单次防抖刷新,连续输入不得触发大量重复渲染或造成界面卡顿。 - 关闭存在未保存修改的弹窗时,提供「保存」「不保存」「取消」三种中文选择;保存校验失败时保持弹窗打开。 @@ -80,7 +85,10 @@ created: 2026-07-16 {商品卖点与要求} ``` -- `{分类要求}`、`{套图分类}`、`{图片比例}`、`{参考图规则}`、`{商品卖点与要求}`为必需占位符;缺失时预览区显示中文校验结果,「保存」禁用。`{套图分类}`列为必需是因为固定分类的说明文案不保证包含分类名,删掉后最终提示词可能丢失分类信息。 +- `{分类要求}`、`{套图分类}`、`{图片比例}`、`{分类序号}`、`{分类总数}`、`{差异化要求}`、`{参考图规则}`、`{商品卖点与要求}`为必需占位符;缺失时预览区显示中文校验结果,「保存」禁用。 +- `{套图分类}`列为必需是因为固定分类的说明文案不保证包含分类名,删掉后最终提示词可能丢失分类信息。 +- `{分类序号}`、`{分类总数}`和 `{差异化要求}`列为必需,用于保证同一分类配置多张时最终提示词具有明确序号和差异化约束;分类总数为 1 时 `{差异化要求}`可以渲染为空,但模板中仍必须保留该占位符,防止以后把数量调大时退化为完全相同的提示词。 +- `{差异化要求}`必须独占一行(所在行去除首尾空白后只剩该占位符),否则校验失败、「保存」禁用。这保证渲染为空时可整行定点删除,不会产生「要求:。」之类的内联残句。 - 未知占位符、未闭合花括号和渲染后仍残留的占位符都视为错误,不得静默原样发送给模型。 - 重复使用合法占位符允许保存;第一版模板**不支持字面花括号**,任何非合法占位符形式的花括号一律校验报错,不定义转义规则,也不做字符串猜测。 - 占位符替换必须使用结构化上下文字典和统一 renderer,不允许在 GUI 中连续手写 `.replace()` 拼接另一套规则。 @@ -105,7 +113,8 @@ created: 2026-07-16 - 将当前仅存在于 GUI 的固定分类说明迁移或集中到业务层,渲染为 `{分类要求}`;GUI 通过同一来源显示说明,不能复制另一份字典。 - 自定义分类的 `{分类要求}`必须明确包含自定义分类名称,例如「生成商品套图中的『使用方法图』,按照该分类名称表达用途」,不能使用不含分类名的泛化文案。 - `{差异化要求}`至少包含分类内序号和“与本分类其他图片采用不同构图、角度或场景”的约束。若第一版没有可靠的商品语义,不自动编造具体卖点、参数或使用场景。 -- 退化规则:分类总数为 1 时 `{差异化要求}`渲染为空,最终提示词不得出现“与本分类其他图片不同”这类无意义残句;renderer 需折叠占位符独占一行且替换为空后产生的空白行。 +- 退化规则:分类总数为 1 时 `{差异化要求}`渲染为空,最终提示词不得出现“与本分类其他图片不同”这类无意义残句。 +- 空行清理必须是定点操作:仅当 `{差异化要求}`渲染为空时删除该占位符所在行及其行尾(校验已保证其独占一行),不得全局压缩连续空行、修改用户主动保留的段落间距或顺带清理其他空白。 - `{参考图规则}`必须与当前实际请求一致。每个 `image_studio_job` 只有一个 `source_asset_id` 时,应明确表述当前图片是本任务唯一主参考图,不得声称未提交的其他图片也参与参考。 ### 5. 强制保护规则 @@ -124,7 +133,13 @@ created: 2026-07-16 - 安装包内置模板只读;首次运行仅在用户模板不存在或为空时复制默认值,已有用户模板不得被版本升级静默覆盖。 - 扩展现有 `app/prompts.py` 的模板读写能力或增加职责单一的套图提示词模块,复用路径防越界、UTF-8 和文件名安全纪律。 - 保存采用同目录临时文件后原子替换,写入失败时保留原用户模板并给出中文错误。 +- 「保存」和「恢复默认」必须调用同一个原子写入服务;统一写盘服务不等于只允许「保存」按钮触发,禁止为恢复默认另写非原子的覆盖路径。 - 「恢复默认」只覆盖商品套图基础模板,不影响②AI生成标题/封面模板、AI工场模板、商品卖点、图片或生成历史。 +- 用户模板每次加载后都必须执行与保存前相同的占位符和结构校验,覆盖用户手工编辑文件、文件损坏及未来模板契约升级等情况。 +- 用户模板无效时不得静默改用内置默认模板,也不得把残留占位符提交给 cmhub: + - 打开设置弹窗时保留并展示当前无效内容及中文校验错误,允许用户修复或恢复默认; + - 点击「生成套图」时在创建 job、启动 worker 或调用 cmhub 前中止,并提示 `套图提示词模板无效,请在提示词设置中修复或恢复默认。`; + - 中止不得修改用户文件、项目卖点、图片、历史 job 或当前分类设置。 - PyInstaller 构建脚本/spec 必须显式包含内置套图默认模板;开发环境和打包程序使用同一资源读取入口。 ### 7. 预览与真实生成共用渲染 @@ -146,29 +161,33 @@ created: 2026-07-16 - [ ] 点击「提示词设置」打开左右等宽弹窗,左侧可编辑、右侧只读,默认预览白底图最终提示词。 - [ ] 预览分类下拉可以切换固定分类和当前自定义分类;切换只刷新预览,不修改项目配置。 - [ ] 从「插入变量」菜单选择每个合法变量,都会插入到当前光标位置并在约 200ms 后刷新预览。 -- [ ] 当前商品数据完整时,预览正确替换平台、地区、语言、比例、商品 ID 和商品卖点;序号类占位符按约定固定为主参考图序号 1、分类序号 1/该分类配置总数。 +- [ ] 当前商品数据完整时,预览正确替换平台、地区、语言、比例、商品 ID 和商品卖点;主参考图序号默认为 1,分类序号使用步进器值,分类总数使用 `max(1, 当前分类配置数量)`。 +- [ ] 当前预览分类数量为 0 或 1 时显示第 1/1 张且步进器禁用,不出现第 1/0 张;数量大于 1 时可切换预览第 1 至第 N 张。 - [ ] 临时草稿预览使用 `未绑定商品` 或等价中文值,不显示内部 `draft_` 标识。 -- [ ] 删除必需占位符、输入未知变量、花括号未闭合或渲染残留变量时不能保存,并显示中文校验错误。 +- [ ] 删除任一必需占位符(含分类序号、分类总数和差异化要求)、输入未知变量、花括号未闭合、`{差异化要求}`未独占一行或渲染残留变量时不能保存,并显示中文校验错误。 - [ ] 固定分类说明实际进入提示词;自定义分类提示词明确包含自定义分类名称。 - [ ] 同一分类多张任务的最终提示词包含各自序号/总数和差异化要求,不再完全相同。 -- [ ] 分类总数为 1 时,该分类最终提示词不含差异化残句,也不留悬空空行。 +- [ ] 分类总数为 1 时,该分类最终提示词不含差异化残句;仅删除空的差异化占位符所在行,用户主动保留的其他段落空行不变。 - [ ] 参考图规则与实际单个 `source_asset_id` 一致,不声称未提交图片参与参考。 - [ ] 强制商品一致性、禁止虚构参数/价格/尺码等规则始终出现在最终预览和真实请求中,用户不能从编辑器删除。 - [ ] 保存后关闭并重启程序仍加载用户模板;已有用户模板不会被启动初始化或软件升级覆盖。 -- [ ] 「恢复默认」经确认后回填编辑区并刷新预览,不直接写盘;经「保存」后才落盘,且只影响商品套图模板。 +- [ ] 「恢复默认」经确认后通过统一原子写入服务立即落盘,并刷新编辑区和预览;关闭弹窗不再提示该次恢复为未保存修改,且只影响商品套图模板。 +- [ ] 「恢复默认」写盘前校验内置模板;内置模板无效时显示中文错误、不写盘、不改动用户模板和编辑区。 - [ ] 弹窗存在未保存修改时关闭会出现保存/不保存/取消三选项,任何失败都不损坏原模板。 - [ ] 同一 context 下右侧预览文本与新建 job 保存的最终 prompt 完全一致。 - [ ] 生成开始后再修改模板不影响本轮已经冻结的 job;历史重试继续使用历史 prompt 快照。 - [ ] 打包程序首次运行能初始化套图默认模板,且用户无需手工创建文件即可打开弹窗和生成。 +- [ ] 用户手工把模板改成缺失必需变量、未知变量或未闭合花括号后,程序不会崩溃或静默回退;点击生成会在创建 job 和调用 cmhub 前中止,并引导用户修复或恢复默认。 - [ ] `1180x760` 及项目最小窗口尺寸下,标题行和弹窗控件不重叠、文字不截断。 - [ ] SQLite schema、cmhub API、计费、并发、CDP 和③「更新蝦皮」不受影响。 ## 测试要求 -- 新增纯逻辑测试覆盖全部合法占位符、必需变量(含 `{套图分类}`)、未知变量、未闭合/字面花括号报错、重复变量、强制规则追加和 Unicode 文本。 -- 覆盖白底图、其他固定分类、自定义分类、正式商品、临时草稿、分类多张、分类总数为 1 的差异化退化与空行折叠,以及单参考图 context。 -- 覆盖用户模板首次初始化、不覆盖已有文件、原子保存失败保持原文件和恢复默认。 -- `tests/test_product_suite_gui.py` 覆盖标题行按钮顺序、AI 帮写运行时取消按钮、弹窗初始分栏、默认白底图、分类切换、变量插入、防抖刷新、只读预览、保存校验和未保存关闭三选项。 +- 新增纯逻辑测试覆盖全部合法占位符、必需变量(含 `{套图分类}`、`{分类序号}`、`{分类总数}`、`{差异化要求}`)、未知变量、未闭合/字面花括号报错、`{差异化要求}`未独占一行报错、重复变量、强制规则追加和 Unicode 文本。 +- 覆盖白底图、其他固定分类、自定义分类、正式商品、临时草稿、分类多张、分类数量为 0/1 的预览退化、分类总数为 1 的差异化退化与定点空行删除,以及单参考图 context。 +- 覆盖用户模板首次初始化、不覆盖已有文件、原子保存失败保持原文件、保存和恢复默认共用写入服务、恢复成功更新已保存基线、内置模板无效时恢复默认报错且不写盘。 +- 覆盖用户文件被外部改成无效模板时的加载校验、弹窗修复入口和生成前中止,断言无 job、worker、cmhub 或文件覆盖副作用。 +- `tests/test_product_suite_gui.py` 覆盖标题行按钮顺序、AI 帮写运行时取消按钮、弹窗初始分栏、默认白底图、分类切换、预览序号步进器、变量插入、防抖刷新、只读预览、保存校验和未保存关闭三选项。 - 覆盖预览 renderer 与 `build_job_specs()` 最终 prompt 相等,以及生成运行中模板变更不污染本轮 job。 - 更新构建测试或脚本断言,确认内置套图模板进入 PyInstaller 数据文件。 @@ -202,4 +221,6 @@ git diff --check ## 执行记录 - 2026-07-16 补:按全栈评审调整规格——`{套图分类}`升为必需占位符;第一版禁止字面花括号(不做转义规则);「恢复默认」改为只回填编辑区、落盘统一走「保存」;预览序号类占位符固定值约定;分类总数为 1 时差异化要求退化为空并折叠空行;补充纯逻辑先行的推进顺序建议。 +- 2026-07-16 补:修正评审后仍存在的契约缺口——分类序号/总数/差异化要求升为必需变量;预览总数最小为 1,并增加分类内序号步进器;「恢复默认」改为复用统一原子写入服务立即落盘;补充无效用户模板的加载校验和生成前阻断;空行处理限定为只删除空的差异化占位符所在行。 +- 2026-07-16 补:封堵两处剩余小洞——「恢复默认」写盘前先校验内置模板,校验失败报错不写盘(防打包缺陷/资源损坏写入坏模板);`{差异化要求}`必须独占一行,校验层强制,杜绝渲染为空时的内联残句。 - 待实现。