Feat: 完善 Game Agent 资源画板与图片精修链路 #176
Reference in New Issue
Block a user
Delete Branch "codex/game-agent-resource-workbench"
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?
摘要
本 PR 将 Game Agent 资源管理页升级为真实自由画板,并打通图片资源的快速编辑、候选生成、导入、失败归档与正式图提交流程。
同时补齐图片精修的事务恢复、候选身份校验、生成中任务恢复、鉴权重试,以及“设为最终图”后游戏运行资源的稳定刷新链路。
主要变更
1. 资源管理页自由画板
Ctrl / Meta + wheel以指针为锚点缩放pixelWidth / pixelHeight2. 图片资源快速编辑与精修画布
reconciliation-required任务不允许删除3. 候选图与正式图事务
生成成功只加入草稿私有候选层,不直接修改 manifest。
“设为最终图”是唯一正式资源切换入口。
refine 保持原 asset ID 和来源身份,不追加新的业务资产身份。
正式文件使用不可变路径:
当前 head 仍有 5 个由 PR 176 直接引入的阻塞项:生成请求失败后会遗留永久 running 的公开记录;候选完成态和失败归档态都在对应草稿事实落盘前写成终态,崩溃恢复会跳过未完成事务;新增 Host Port 方法被声明为可选,违反冻结的结构化 unsupported 契约;快速编辑卡未按 viewport 边界钳制。请按行内建议修复,并补齐失败注入/重启恢复、宿主能力合同和四边 viewport 回归。master 既有旧债未混入本次请求更改,将单独在 master 修复。
@@ -2261,0 +3254,4 @@set_private_phase(root,&mut ledger,GenerationLedgerPhase::CandidateReady,[P1]
CandidateReady不能早于候选事实落盘。这里先把私有 ledger 写成恢复逻辑会直接视为终态的CandidateReady,下一行persist_generation_candidate_at仍可能因草稿写入、revision 或 I/O 失败退出;重启后恢复入口会跳过重放/直接读取尚不存在的候选,形成无法自动收敛的终态账本。请先以幂等方式持久化候选草稿/图层并回读成功,再推进终态,或增加可重放的中间 phase;补在两次写之间故障注入并重启恢复的测试。@@ -2459,0 +3537,4 @@}ledger.phase = GenerationLedgerPhase::Archived;ledger.archived_at = Some(asset_canvas_now());write_generation_ledger(root, &mut ledger)?;[P1] 归档终态写在草稿删除之前会留下永久半归档。此处 ledger 已写成
Archived后,草稿移除 generation 的写入仍可能失败;恢复扫描会跳过 Archived,而再次归档又受调用方持有的旧 revision/公开记录状态影响,导致任务在草稿中残留且无法可靠收敛。请使用可恢复的中间 phase/事务 journal,确保草稿删除成功并回读后才发布 Archived,且重放保持幂等;补 ledger 写成功、draft 写失败后的重启恢复测试。@@ -1727,0 +2337,4 @@createdAt: Date.now(),updatedAt: Date.now(),};const initialGenerationRecord: ImageCanvasGenerationRecord = {[P1] 不要在宿主接受生成前持久化无法收敛的 running 记录。这里把
generation-running先塞进 draft 并由后续persistDraft()落盘;如果generateImage在创建私有 ledger 前失败或抛错,下面只更新内存 task/lifecycle,没有移除或持久化失败后的 generation。刷新后公开记录会永久显示运行中,恢复又找不到对应私有账本。请让占位与宿主创建生成形成可恢复事务:失败时以当前 revision CAS 删除/终结该记录并持久化,或由后端原子创建权威记录后再 hydrate;补“草稿保存成功、生成调用失败/抛错、刷新恢复后无幽灵 running 任务”的回归。@@ -1899,0 +2685,4 @@: null;const quickEditPanelStyle: CSSProperties | null = quickEditSourceLayer? {left:[P2] 快速编辑卡位置需要按 viewport 四边钳制或自动翻转。当前直接用图层底部中心作为
left/top,卡片自身宽高没有参与计算;图片靠近右侧/底部(移动端也包括左侧)时,卡片会被 viewport 的 overflow 裁掉,输入框和操作按钮不可达。请在测得/约束卡片尺寸后选择上/下方并 clamp 到可视区域,滚动/缩放/resize 时同步更新;补四边及窄 viewport 的交互回归。@@ -193,6 +200,11 @@ export interface ImageCanvasProjectPort {}export interface ImageCanvasAssetPort {importLocalImages?(input: {[P1] 保持冻结 Host Port 的“方法始终存在”合同。把
importLocalImages(以及下方archiveFailedGeneration)声明成可选后,共享 UI 开始靠方法是否缺失分支能力,和合同规定的“能力不可用时返回结构化unsupported-capability”冲突,也会让不同 adapter 静默漂移。请把两个方法都改为必选,由不支持的宿主返回unsupportedImageCanvasCapability(...),并增加对所有 Host adapter 的方法存在性与 unsupported 结果测试。当前 head
ea1eae1a3仍有 2 个 P1 阻塞:失败结果没有进入后端权威 generation 生命周期,常见前置失败仍会在重启后恢复成generation-running,且无私有 ledger 的失败卡无法归档;候选成功回包又会用后端快照全量 hydrate,覆盖生成期间尚未 autosave 的画布修改。请按两条行内建议修复,并补真实 Tauri/backend 失败恢复测试与 deferred generation 并发编辑回归。上一轮候选落盘顺序、archive-pending、Host Port 必选合同和快速编辑卡四边钳制已基本修复;当前 4 项 CI 全绿,但未覆盖这两个边界。@@ -1762,0 +2561,4 @@}if (result.status !== 'ok') {const code = result.status === 'failed' ? result.code : result.status;await persistGenerationFailure([P1] 不要依靠前端
updateDraft发布 generation 失败终态。这里虽然调用persistGenerationFailure,但 Rustupdate_asset_canvas_draft_at对已有 generation 只合并placeholder,明确忽略传入的phase/errorCode;例如configuration-missing只让私有 ledger 停在ContextPreparing + errorCode后返回,权威草稿仍保留 optimisticgeneration-running,重启后幽灵任务会复活。若 invoke/listener 在 ledger 创建前失败,则会留下没有私有 ledger 的公开failed卡,后续归档必然报“账本不存在”。此外这里忽略失败持久化的返回值,后面又无条件切回canvas.editing/dirty:false,会覆盖 CAS/IO 保存失败。请让 Rust 所有退出路径明确落为Failed、ReconciliationRequired或结构化not-started;not-started原子移除占位,前端只消费权威结果并在保存失败时保持阻断态。补真实 Tauri/backend 回归:缺配置后刷新、pre-ledger invoke 失败后归档,以及失败态 updateDraft conflict/IO failure。@@ -1769,0 +2593,4 @@result.value.images.forEach((image) =>URL.revokeObjectURL(image.previewUrl),);await hydrateDraft(result.value.draft, epoch);[P1] 应在应用候选快照前保护生成期间的本地 dirty 画布。PR 明确让生成期间继续拖图、平移和选择,而 autosave 有 180ms debounce/在途 saveQueue;候选恰在这段窗口完成时,
result.value.draft不包含刚发生的本地修改。这里直接hydrateDraft会全量替换 layers、viewport、selection,清空 history,并把 documentVersion 重置为 0,随后保存的是旧快照,用户修改被静默丢失。请把权威候选层和 generation 状态重基/合并到当前本地 dirty canvas 后以新 revision 保存,或建立能覆盖在途保存的屏障并重放本地修改。补 deferred generation 回归:完成前拖动图层、平移 viewport、改变选择,完成后逐项验证仍保留。该 PR 暴露的“同一本地项目切换账号后丢失画布项目、无法继续编辑历史本地资源”问题,已拆到 #182 从 master 统一修复。
请先等待 #182 合并并 rebase 最新 master;rebase 后删除或接入 #182 的 account-scoped External Editor binding,不能保留本 PR 当前的局部 canonical cache 或第二套账号身份系统。manifest 中的远端 ID 只能作为来源信息,当前账号没有 binding 时必须从本地正式资源重新上传、confirm、登记,任何 B 账号请求都不能携带 A 的 project/resource/object ID。
#176 已提交的 REQUEST_CHANGES 及其他阻塞项仍然有效,当前不可合并。