AGC 画布:生成期间可退出与任务侧栏(高优)、画布手动整理、透明底判据、素材类型独立入口 #358
Reference in New Issue
Block a user
Delete Branch "fix/agc-canvas-acceptance-batch"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
来自验收人 2026-09-14 15:50 之后的反馈,以及随后的真机复测反馈。范围共 6 项(问题 5「16:08 截图指代」按决定不做)。
一、范围
二、逐项改动
1. 生成:可退出 + 进度可见 + 本地排队(高优)
ThemedModal全屏遮罩 + FocusTrap 冻结整窗);前端只有单值生成槽;单次invoke最长 await 35 分钟。start_local_project_asset_generation(提交即返回任务记录)与list_local_project_asset_generations(读回项目内账本.agent/runtime/asset-generation-tasks/tasks.json),生成在后台任务里跑并复用既有生成通道(不复制幂等 / 计费 / 登记逻辑);前端单值槽改为任务列表 + 单条在途的本地排队;新增常驻画布的可折叠任务侧栏(分栏「排队 / 生成中」与「已完成」+ 条数、每项状态徽标 + 后端阶段文案 + 已耗时 + 定位、折叠把手带在途计数、提交受理后自动展开)。提交后面板锁死、看不到进度→提交即关面板、侧栏随时看进度;第二条提交被拒→第二条进本地队列、前一条终态后自动补发。src-tauri/src/asset_generation_tasks.rs(新)、resourceCanvasAssetGenerationQueue.ts/…TaskModel.ts/…TasksPanelView.tsx(新)、ResourceCanvasAssetGenerationPanelView.tsx、index.tsx。2. 生成面板:点「生成」即同步关闭,面板内不出现阶段文案
phaseDetail的渲染与整套submitting;点击处理器里同步执行onSubmit + onClose(不等 IPC);只有「点击瞬间就失败」(校验 / 权限 / start IPC 立即报错)才自动重开面板并带回草稿与原因;受理之后才失败只在侧栏收口为失败 + 原因。3. 画布:新素材不再自动重排,改显式「整理画布」+ 生成后自动聚焦
type侧rederiveAutomaticPositions无条件true、dependency侧长期等于resourceGraphReady;每次资源签名变化(含新增一张素材)都会丢掉全部非手动坐标整体重算,且没有「新素材」聚焦。preserve;整张重排只由资源工具条里独立的「整理画布」按钮(排在「生成素材」之后、「管理未完成编辑」之前,不在「资源排列方式」分组内、也不做行尾按钮)与「关系图首次就绪」那一次发起;新增按manifest.assets新增 id 复用既有聚焦裁决链自动带出新卡(首次打开 / 切项目不跳转)。4. 透明底判据:按图像真实 alpha 决定是否铺棋盘格
image_inspect.rs增加头部级hasAlpha(PNG colorType 4/6 与tRNS、WebP VP8X/VP8L;不做像素解码;截断头部 fail-closed)→ 预览 payload 透传 → 卡片data-preview-has-alpha→ CSS 只对真有 alpha 的卡铺棋盘格,无 alpha 退回既有纯色底。5. 素材类型独立入口
ResourceTypePanel(标题与ariaLabel均为「设置素材类型」,选中即落盘,选项为纵向单选列表:role=radiogroup/radio+aria-checked、方向键移焦点、Enter 落盘);「编辑素材标签」只留标签且保存时category回传落盘原值(「没碰过分类就回传原值」不变量改为结构性保证);入口两处:选中卡工具条「素材类型」+ 信息浮层「分类 → 设置」。6. 「定位到素材」终局化
Rust 侧并发放开(第 1 项的后端前提)
{outputPath, requireSlices}(工具栏恒null→ 同项目共用一个槽)改为精确动作指纹;同一精确动作仍复用原operationId、不二次 POST;旧槽账本由同一精确动作懒迁移(形状可读、不 panic、不 fail-closed)。三、验证
npm run agc:typecheck(含check-config.mjs的 invoke 白名单门禁)通过asset_generation_task12 /image_inspect18 /standalone7 /recovery_scan4 / 权限门禁用例 2 —— 全绿node scripts/check-encoding.mjs、node scripts/check-doc-index.mjs、git diff --check干净decision-log(4 条新条目 + 2 条更正)、pitfalls(1 条新条目)、AGC 资源工作台 V3 端到端验收用例 S12/api/external/v1/ SpacetimeDB schema 变更四、Review 建议重点
canvas_generation.rs/external_generation_state.rs):幂等语义是否完整保住tRNS、WebP、截断头部)index.tsx是本批冲突最集中的文件(4 个工作流都改过),合并后的按钮顺序与浮层遮挡判据请重点看- canvas_generation.rs:standalone 图片生成的 durable 输出槽身份改为由精确动作身份派生(run_id = slot-<actionFingerprint>),同一项目里不同 prompt/素材名/参数的生成各自独立成槽,可以同时在途 - canvas_generation.rs:动作指纹材料逐字节保持升级前取值,新增 legacy_standalone_platform_art_generation_run_id 复现升级前 {outputPath, requireSlices} 槽公式,只用于定位升级前遗留账本 - canvas_generation.rs:在取得 durable guard 之后、任何远端 POST 之前调用旧槽账本一次性迁移 - external_generation_state.rs:新增 adopt_legacy_standalone_platform_art_generation_runtime_state_at,在项目写锁内把仍属于本次精确动作的旧 slot- 账本迁移到新身份路径并保留原 idempotencyKey 与 operationId;属于其他动作的旧账本原样保留,不迁移、不删除、不阻塞 - external_generation_state.rs:新增三个 #[cfg(test)] 只读访问器,供跨模块用例断言账本身份 - canvas_generation.rs:新增两条不同动作并发都成功且远端各 POST 一次、不同动作的 durable 槽互不阻塞、旧槽账本仅被同一精确动作迁移三组用例;同动作并发冲突用例改用同一精确动作以钉住幂等语义- resourceCanvasManualLayout.test.tsx:installLayoutTauri 登记 list_local_project_asset_generations(工作台打开 / 切项目时由 WS1 的生成任务面板读取), 回空账本,形状按 src-tauri/src/asset_generation_tasks.rs 的 list_local_project_asset_generations 返回值核对为数组(Vec<AssetGenerationTaskRecord>), 与前端 invoke<LocalProjectAssetGenerationTaskRecord[]> 一致,不是 { tasks: [] } - 保留 unexpectedCommands 断言不放宽,也不删除:这条门禁继续拦截意外 IPC- index.tsx 新增 `resourceAssetGenerationFocusRequest` 序号并加进聚焦 effect 的依赖:手动点定位不改画布 任何状态,原依赖一个都不变 → effect 不重跑、intent 永远没人消费,这正是「点了没反应 + 提示条永久 停在中转文案」的根因 - index.tsx `focusResourceAssetGenerationTask` 重写:先按当前投影与清单判一次目标——不在投影里就当场给 结论(素材已不在项目里 / 已登记但尚未同步),不挂 intent 也不留中转提示;在别的栏目先切栏目再定位; 挂 intent 后推进聚焦请求序号,并起一个 3 秒有界兜底:仍停在中转文案就收口成可执行提示,intent 被判 invalid 被静默清掉时也给一条「定位请求已失效」的结论,绝不留下悬而未决的状态 - index.tsx 聚焦 effect 的 `focusedCommitIdsRef` 提前返回分支补 `setResourceWorkbenchNotice('')`: 已聚焦过时把中转提示一并收掉,不再永久留在提示条上(自动落卡那条链同源问题) - index.tsx `resourceAssetGenerationContextRef` 扩到带 `manifest` / `resources` / `activePageCategory` 并在每次渲染刷新:定位回调据此取权威目标与栏目,不再依赖可能过期的闭包值 - 新增 4 条 AppSurface 用例(同栏目直点定位并选中卡片、素材在另一个栏目先切栏目再定位、被搜索挡住时给出 既有「清除搜索并定位」、素材不在项目里时给明确结论且清掉中转提示)- index.tsx:把「整理画布」从 aria-label=\"资源排列方式\" 的 role=group 里搬出来, 紧跟排序 tab 之后、作为 game-workbench-view-actions 动作区里的独立按钮, 外观直接复用该容器既有动作按钮样式(有边圆角 + secondary 填充),不新增 CSS - index.tsx:语义与行为一字未改——aria-label=\"整理画布\"、disabled={!resourceLayoutReady}、 aria-busy={resourceLayoutSaving}、onClick 仍调 activeResourceLayout.rederiveNow(), 成功/失败反馈仍复用既有 resourceLayoutNotice / resourceLayoutSaving,changed 门保留 - resourceCanvasManualLayout.test.tsx:新增结构断言——「资源排列方式」分组里只有 「按依赖 / 按类型」两枚按钮、「整理画布」不在该容器内也不在 .game-resource-sort-tabs 里, 同时仍是动作区内可用按钮(布局就绪后不再 disabled)- index.tsx:把「整理画布」从 game-workbench-view-actions 行尾(排序 tab 之后) 移到「生成素材」之后、「管理未完成编辑」之前,与其它资源动作同类相邻, 标签仍为 aria-label=\"整理画布\",零 CSS 改动 - index.tsx:语义与行为一字未改——disabled={!resourceLayoutReady}、 aria-busy={resourceLayoutSaving}、onClick 仍调 activeResourceLayout.rederiveNow(), 反馈仍走既有 resourceLayoutNotice / resourceLayoutSaving,changed 门保留 - resourceCanvasManualLayout.test.tsx:位置断言改为钉新位置——该行最后一个按钮不是它、 它在「生成素材」之后(previousElementSibling)、在排序组左侧; 继续保留「资源排列方式」组内只有「按依赖 / 按类型」与本按钮不在该组 / 不在 .game-resource-sort-tabs 内的断言