修复生成草稿隔离与回合计时恢复及布局排队

按占位身份隔离生成面板并保存草稿,阻止改变失败请求输入后伪装重试。
保留用户真实发送时间,按既有用户条目身份恢复空运行态回合的终态边界。
修复跨栏目整理队列覆盖及多选拖动预览起点漂移。
补齐六项 review 发现的回归、原生绑定、交叉审查及浏览器验收记录。
This commit is contained in:
2026-09-18 13:25:18 +08:00
parent 2ffccb844c
commit cd8f480719
25 changed files with 2412 additions and 266 deletions
@@ -31,3 +31,15 @@
## 收口
已完成本轮实现、独立 review 返修与自动化/模拟浏览器验证,证据见对应里程碑。用户已授权更新 Issue/PR 并推送当前功能分支;不得据此合并 PR、发布或恢复定时任务。真实客户端端到端验收尚待完成,因此保留计划,卡片全面重设计和画布内任务浮层不计入本轮已交付内容。
## PR 补审返修(2026-09-18)
用户确认修复补审发现:保留同身份乐观消息的真实发送时间;live 为空时仍向明确的本轮用户条目保存终态边界。先补失败回归,再最小修改原 reducer/回合投影与必要的 App 接线,不新增持久化 schema 或平行回合状态源。取消后迟到终态只补可验证测试,不能仅凭时间大小改变现役事件顺序合同。独立复核后运行定向与集成验证。本次 fix 不自动授权新的远程写入。
补审返修中已复现 bootstrap 只有生命周期事件、用户消息经 history slice 回读且 live 恒为空的缺口。前端无法证明归属,因此批准原生在 turn.started/turn.completed 上透传现有用户条目 userItemId;沿用原事件与已有消息身份,不另造 turnId。前端按精确 itemId 补时间边界,移除按历史尾项或时间戳相等猜测用户归属的兜底;完成先于历史到达时,在历史回读后同样按该身份补齐。原生与 TypeScript 绑定同批更新并验证重放。
### 返修结果
已完成同身份发送时间保留、原生 userItemId 关联、live 为空或终态先于历史时的精确回填;旧回合终态及取消回包不能关闭另一条已知身份的新请求。计时 40 项定向、appSurface 462 项(17 跳过)通过,原生身份序列化/重放/取消用例 3 项及原阶段时间序列化 1 项通过;绑定由 ts-rs 导出,Rust all-targets locked offline check 通过。
Edge 真实浏览器使用生产 reducer/组件和模拟原生事件,确认发送后的 8 秒启动等待计入总耗时、100ms 递增及终态冻结;仅历史恢复、live 为空的回合显示正确的 2.0 秒。真实 Provider 与原生客户端端到端尚未验证,不据本地通过宣称远程 CI 或发布通过。
@@ -1,5 +1,13 @@
# 【实施计划】画布验收问题统一修复
## PR 补审返修(2026-09-18)
用户确认修复:生成面板按 draftId 隔离且切换保留各草稿;失败重试保留失效参考身份并在提交前明确拒绝,不改变原付费请求;不同栏目整理意图分别排队;多选拖动预览和写回统一使用按下时起点。每项先加失败回归,再最小修复、独立复核与集成验证。共用 index.tsx 时限定不重叠区域,禁止整文件重写。卡片重设计、任务浮层和远程写入不在这次 fix 范围。
返修已完成:生成占位实例与草稿隔离、失效参考及原请求输入修改阻断、队尾同范围整理合并、场景预览与局部写回分别冻结同一按下时基准。生成/布局/计时合计 17 文件 213 项定向通过;appSurface 462 项通过、17 项跳过。音频失败后切换导致草稿丢失的集成回归也已修复并重跑通过,没有删断言或加任意等待。
独立交叉 review 无新增阻断;浏览器使用真实工作台和模拟原生接口确认 BGM/音效以及同类图片的不同占位输入隔离、切回恢复原输入。未发起真实付费生成、未运行真实 IPC 端到端;不同栏目排队整理的乐观中间态仍可能短暂回退,最终落盘范围与顺序正确,该既有表现未纳入本次返修。
| 字段 | 值 |
| --- | --- |
| Milestone | docs/project-memory/plans/【里程碑】画布验收问题统一修复-2026-09-17.md |
@@ -27,6 +27,8 @@
## 验证与剩余风险
补审返修已保留同身份真实发送时间,并为生命周期事件补 userItemId,使 live 为空时也能精确关联历史回合;独立 review 与新增恢复、迟到终态和取消回包回归通过。最终证据见对应实施计划,真实客户端验收项仍不勾选。
- appSurface 与 reducer/回合投影三文件合计 493 项通过、17 项跳过;最终初始占位与计时边界补丁另跑 5 项通过。
- 隔离依赖配置下 AGC TypeScript、skill/config、ESLint、编码与文档索引检查通过;Rust all-targets locked offline check 通过。
- 原生实现者执行 direct_thread 35 项、direct_ 312 项(1 跳过)、codex_app_server 58 项(1 跳过)及系统工程提示定向用例通过,过滤集合有重叠,不能相加作为独立用例总数。
@@ -1,5 +1,11 @@
# 踩坑与排障记录
## 生成草稿与异步展示边界必须按身份隔离
非模态生成浮层切换占位时按 draftId 分实例,卸载保留未提交/失败草稿,成功提交不再复活草稿;旧项目占位不存在时丢弃其保存回调。失败重试保留原请求输入和引用身份,引用失效不能静默过滤;修改已绑定输入须明确另起请求,不伪装成原请求重试。
聊天真实发送时间按相同用户 itemId 与正式条目合并,不能被启动应答后的观测时间覆盖。Thread Manager 生命周期事件透传已有 userItemId,使仅历史回读、live 为空的回合仍可精确补终态时间;不得按历史尾项或时间近似猜归属。布局整理仅可合并队尾同范围意图,不能越过中间手动写入;拖动预览和保存均冻结按下时的相应坐标基准。
## Phaser 与 CSS 双重居中导致游戏画面偏移
Phaser `Scale.FIT` 与 `autoCenter: CENTER_BOTH` 会给 canvas 计算定位外边距。若 canvas 的直接父容器同时使用 `display: grid; place-items: center` 或另一套 CSS 居中,浏览器再次定位带 margin 的元素,竖屏游戏会相对预览区域偏右。应只保留一个居中责任方:Phaser 居中时直接父容器使用尺寸明确的普通块布局;CSS 居中时设置 `autoCenter: NO_CENTER`。不禁止外围页面的 Grid/Flex 布局,不通过修改 AGC iframe 的固定偏移掩盖项目 CSS 问题。
@@ -4,6 +4,12 @@
开发 Agent 的系统工程提示与 `agc-web-game-development` Skill 明确约束同一 canvas 的居中只能由一方负责:Phaser `FIT + CENTER_BOTH` 配合尺寸明确的普通块级父容器,不叠加同一父容器的 Grid/Flex 居中、自动外边距或居中 transform;如由 CSS 居中则设置 Phaser `NO_CENTER`,外围页面的 Grid/Flex 不受此限制。布局修改后构建实际 dist,并在桌面、移动和 resize 下核对 canvas 对游戏父容器中心偏差不超过 1 CSS px、无溢出与意外滚动条。出现偏移先检查游戏项目的 CSS/scale,不修改 AGC 预览固定偏移掩盖问题;这些要求通过 Agent 指引执行,不新增运行时门禁或平行校验系统。
## 画布验收返修边界
- 生成浮层的实例、输入、失败状态与请求身份必须按占位草稿身份隔离;切换到另一张占位时不能沿用上一张的工具类型、输入或 operation。切换未提交草稿仍须保留各自输入,回到原占位可继续编辑。
- 失败任务重试必须保留原请求的完整参考资产 ID 集合。参考资产失效时明确提示并阻止旧请求提交,不得静默过滤后用改变的参考集恢复原 operation,也不得自动创建新的付费请求。
- 显式整理的待写意图不能因切换栏目而覆盖其他栏目的排队范围。每个受影响范围与撤销步骤保持一致;拖动预览和最终写回使用同一份按下时冻结的起点快照,即使拖动期间布局收到异步更新也不跳位。
## 多选素材批量标签
- 画布与资源面板共用选中集合。选择至少两项同项目已登记素材后,从已有“编辑标签”入口或资源面板的“批量标签”动作打开同一标签编辑器的批量模式;入口遵循既有“常用操作 + 更多”收纳,不新增平行资源管理页。
@@ -27,6 +27,8 @@
- 沿用 Thread Manager 的生命周期与条目身份,不引入第二套回合状态源、计时账本、远程 API 或数据库字段。前端仅保存原事件的展示时间边界;旧历史缺少完整边界时不声称知道精确总耗时或工具耗时,不为补齐计时启动模型请求。
- 必须覆盖:两组工具共用整轮起点、无新事件仍增长、工具完成后 LLM 继续、并行工具分别计时、完成/失败/终止冻结、同身份重放不改终态时间、切项目与卸载停止计时、缺失与倒序时间、0.0 / 59.9 / 60.0 秒边界。真实 Provider 验证与模拟事件的客户端验证分开报告。
- Direct 对话的初始消息占位仅在正式用户消息尚未进入当前显示链路时显示;正式条目或乐观用户条目出现后撤下占位,不在消息列表外额外保留一份。只控制占位是否显示,不按文本合并或删除用户真实重复发送的消息;分页已有更早历史时不把初始占位补到当前页。
- 同一用户消息从本地发送转为正式条目时必须保留原发送时间,不能因去重丢掉该时间而改用启动应答后的观测时间。回合明确结束时,即使当前 live 集合为空,也应将终态边界关联到已知的本轮用户条目;不得仅按“历史最后一项”猜测或向无关旧回合补时间。
- 生命周期事件可携带已有用户条目的 `userItemId`,用于把时间边界精确关联到同一条历史消息(不产生新的回合 ID 或持久化字段)。恢复时该关联随 Thread Manager 原事件重放;带旧用户身份的终态不能收口另一条新请求。缺少身份的旧事件不据时间猜测归属。
## 背景与现状(已核实)