完善Game Agent资源画板与图片精修链路

将资源依赖视图改为统一自由画板,并增加真实比例卡片和隐藏导航边界。

复用素材画布实现图片快速编辑、候选生成、导入、失败任务归档和正式图提交。

补齐原生事务恢复、服务身份确认、全屏失败遮罩及任务列表交互。

同步资源投影、布局、预览、前后端测试和技术文档。
This commit is contained in:
2026-08-21 15:03:59 +08:00
parent aaac44a622
commit a86b7db951
29 changed files with 8060 additions and 5105 deletions
@@ -14271,3 +14271,31 @@
- 验证:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml canvas_generation_tests:: -- --test-threads=1`。
- 2026-08-19 追加:同一默认认证切换也覆盖资源编辑和 autonomous main-loop fixture。`resource_editor` 的 External Editor 视频提交/轮询/服务身份恢复测试同样使用 task-local 凭据;平台账号语义测试使用隔离测试会话。main-loop 的视觉任务配置测试不再通过旧 `editorApi` 文件伪造登录态。所有 loopback listener 在 accept 时设有 5 秒 deadline,并把 accepted stream 恢复为 blocking,避免 Windows `WouldBlock(10035)` 或请求未发出时无限等待。
- 定向验证:`project::asset_canvas::generation::tests::` 14/14、`project::resource_editor::tests::` 36/36、`agent::runtime_driver::main_loop_tests::` 48/48、`agent::runtime_protocol::autonomous_completion_contract_tests::` 107/107 通过。此前一次 Windows 全量 Native Rust 为 1811 passed、108 failed、15 ignored;失败集合仍包含 Provider/mock 调度与既有专业链断言。HEAD 基线独立复现 `tests::project::generate_platform_art_asset_downloads_and_registers_external_image` 的同一登录态缺失,故不能把全量结果伪报为本次 fixture 修复引入;本次新增认证/accept deadline 相关用例均已隔离通过,最后两个 autonomous completion fixture 的认证迁移已单独通过,完整套件未在该两行测试改动后重新执行。
## 2026-08-20 AGC 图片精修候选与最终图事务
- 只有可栅格编辑的图片资源拥有持续精修草稿;同一 `sourceAssetId` 只恢复一个活动 refine 草稿。生成成功只把 PNG 写入草稿私有 `draft-media` 并追加候选图层,不自动修改 manifest,也不自动关闭画布。
- 每次生成在提交远端任务前冻结并持久化 `sourceLayerId` 与有边界的 `placeholder`。任务侧栏和画布占位共同消费 generation record;成功候选复用冻结落点,失败只终结当前任务,重启恢复不得重新提交或重复扣费。
- “设为最终图”是唯一正式资源切换入口:refine 保持原 asset ID,把正式文件切换到 `assets/canvas/<name>--<commitId>.png`,并用候选图层 ID 与媒体 SHA-256 交叉验证 staging、ledger 和 transaction journal。manifest 继续是当前最终图权威。
- 最终图事务完成或恢复后,草稿必须回到 `editing`,清空 `pendingCommit`,保留其它候选与 generation records,并在 `lastCommit.sourceLayerId / mediaSha256` 记录当前最终候选;不能把持续精修草稿永久停在 `committed`。
- 资源详情保持非模态,不能卸载资源工具栏或背景画板。图片卡展示尺寸来自安全预览元数据,受 `220x180`、最小短边 `96` 和 `1:2..2:1` 约束;碰撞、世界范围和依赖连线共同消费同一实际矩形。
# 2026-08-21 Game Agent 精修来源、批量导入与失败任务归档
- refine 主来源不能仅凭已有 Editor Resource ID 直接复用;历史 Game Agent 私有 kind 必须基于本地正式图片重新登记为 External v1 canonical kind,并使用绑定服务身份、owner、Editor Project、源 SHA256 和 canonical kind 的本地私有缓存避免重复上传。不得扩大 External v1 快速编辑白名单或向 edit DTO 补发 `assetKind`。
- Tauri 图片导入采用原生多选与 Rust 批量事务:安全读取、媒体安装、图层绑定和一次 draft revision 推进必须作为一个可恢复单元,前端只 hydrate 权威 draft,不再依赖隐藏 input 加后续 autosave 完成正式绑定。
- 生成失败任务的“删除”固定为归档私有 ledger 并移出 draft 公开投影;只允许明确 `failed`,结果未知和 `reconciliation-required` 必须继续留在恢复队列。任务侧栏折叠是会话 UI 状态,不进入业务持久化。
## 2026-08-21 Game Agent 图片生成恢复与正式图来源身份
- 图片 generation 恢复是任务级后台工作:关键提交事务恢复和草稿 hydrate 完成后,画布立即进入 editing;`recoverImages` 继续恢复原 operation 并更新任务投影,但不得锁住整张画布。
- 精修候选设为最终图保持入口资产 ID。入口 manifest 已有有效 `source.resourceId` 时原样保留;只有未登记来源才使用 `local-asset:<assetId>`。提交与恢复回读使用同一解析规则。
- Game Agent 任务列表视觉复用现役美术画布的右上角独立按钮、白色面板、活动/完成双 Tab 和状态图标;失败归档是 Game Agent 的业务扩展。阻断性画布错误通过 body portal 覆盖整个 Tauri WebView。
## 2026-08-21 Game Agent 资源自由画板使用稳定隐藏边界
- 依赖画板的导航范围由当前项目全部资源的权威世界 extent 决定,并在屏幕坐标外扩 96px 安全留白;搜索过滤、详情卡和临时可见性只影响展示,不缩小导航边界。
- 滚轮、指针平移、缩放、复位和容器 resize 统一经过 viewport constraint。最小缩放为全量资源边界 fit scale;内容小于视口时居中,内容较大时边缘不能越过安全留白。该边界是会话级导航约束,不持久化为第二份布局真相。
@@ -4773,3 +4773,30 @@
- 原因:测试代码仅为动态生成 RSA fixture 引入 `openssl` dev-dependency,从而把原本使用纯 Rust 加密实现的 crate 额外绑定到本机原生 OpenSSL 工具链;Strawberry 附带的库面向 MinGW,不等于可用的 MSVC OpenSSL SDK。
- 处理:测试优先使用明确标记、只供测试的固定 PEM fixture,并继续通过项目自身的密钥解析与签名验证路径覆盖真实行为;不要仅为生成 fixture 引入系统原生库,也不要把 MinGW OpenSSL 路径写入 `OPENSSL_DIR` 冒充 MSVC 依赖。
- 验证:运行目标 crate 的 `cargo tree -i openssl-sys --target all` 确认依赖已退出,再执行包含测试目标的 `cargo test --tests`,不能只用不会编译 dev-dependency 的 `cargo check --lib` 代替。
## 图片编辑请求与资源卡几何不能依赖宽松 DTO 或可淘汰预览(2026-08-20)
- 现象一:Game Agent 快速编辑返回“平台明确拒绝”,远端没有创建任务。原因是 `/api/external/v1/editor/images/edits` 使用 `deny_unknown_fields`,客户端却把创建接口的 `assetKind` 以及本地来源字段一起发送;统一 400 文案又掩盖了真实参数错误。处理时必须按 create/edit 各自权威 DTO 组装请求,Game Agent kind 先映射为编辑器 canonical kind,并把安全业务错误分类,不能回显远端敏感 body。
- 现象二:图片预览已经读取真实宽高,但大量资源触发 LRU 淘汰后,卡片又退回 `180x128`,布局和连线随之跳动。原因是布局尺寸直接从可淘汰的 Blob/Object URL 预览缓存派生。处理时预览二进制仍按预算淘汰,但已验证的轻量 `pixelWidth/pixelHeight` 必须在当前项目、模式和资源 identity 作用域内独立保留;identity 或 scope 变化时再清理。
- 验证:分别覆盖严格 edit body、错误分类、生成占位恢复,以及超过预览缓存条目上限后首张图片仍保持真实比例、布局碰撞和依赖端点不退化。
# 2026-08-21 已有资源 ID 不等于可用于快速编辑的 canonical 来源
- manifest 中的 `source.resourceId` 可能指向历史按 `game-background` 等 Game Agent 私有 kind 登记的远端资源。只检查 ID 前缀并直接传给 `sourceReferenceId` 会在 External v1 入队前得到 `unsupported-source-kind`;本地 kind 映射只有在真正重新登记来源时才生效。
- 隐藏文件 input、逐张写 `draft-media`、前端追加图层再等待 autosave 的组合不是导入事务。失败可能表现为“按钮没反应”、留下孤立媒体或让图片出现在不可见的固定坐标。Tauri 正式链路应由原生多选和后端批量草稿更新闭环。
- 批量导入不能在安装首个媒体后继续执行带 `?` 的 ID、路径、层序或 revision 计算;这些步骤必须先完成。原子草稿写入返回错误后,回读失败属于提交结果未知,必须保留媒体并报对账错误,不能把回读错误压成“未提交”后删除可能已被草稿引用的文件。所有回滚删除失败也必须显式上报。
- 失败 generation 同时存在私有 ledger 和 draft 投影,只在 React state 中 `filter` 会在重启后复活。删除 UI 必须调用只允许明确失败任务的后端归档操作,结果未知任务不能删除。
## 运行中 generation 与 refine 来源身份不能按 create 链路处理(2026-08-21)
- 草稿 hydrate 后同步等待远端 generation recovery,会让生命周期长期停在 recovering,连平移和选图也被 inert。关键事务恢复与任务恢复必须拆开:前者先完成,后者后台推进且失败只进入任务/notice。
- refine 提交若无条件校验 `source.resourceId == local-asset:<assetId>`,会拒绝本来合法的 `editor-resource-*` 已登记来源,并可能把事务卡在 `revision-installed`。创建与未登记本地资产才补 local identity;已登记 refine 必须保留并按解析后的来源身份回读。
- 画布内部 absolute overlay 只能覆盖宿主网格,嵌在左右分栏时不会遮住整个窗口。阻断性失败必须 portal 到 `document.body`,并用 fixed inset 覆盖整个 WebView;测试应验证 portal 的直接宿主和 fullscreen modifier。
## 自由画板只限制缩放比例不能防止资源整体离屏(2026-08-21)
- 只依赖共享画布的全局 `MIN_SCALE/MAX_SCALE`,或只在“复位”时 fit,不会约束滚轮和平移拖拽;用户仍能把整个资源世界移到视口外。每一个 viewport 写入口都必须经过同一个边界函数,容器尺寸和资源 extent 改变后也要重新约束。
- 隐藏边界不能从搜索后的 `visibleResources` 派生,否则输入搜索词会突然收缩边界并跳动 viewport。应使用全项目布局 positions、真实卡片尺寸和分区世界 extent,搜索只控制渲染与连线可见性。