Merge branch 'master' into codex/agc-delivery-efficiency
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 8m2s
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled

This commit is contained in:
2026-09-21 02:29:20 +08:00
48 changed files with 5095 additions and 373 deletions
@@ -1,6 +1,6 @@
# AI 游戏创作项目开发工作台 PRD
更新时间:`2026-09-20`同步功能画布图片类生成后台化的当前事实,以及 2026-09-20 音频生成并入同一条后台任务账本:入口 IPC 为 `start_local_project_asset_generation` + 项目内任务账本 + 本地排队 + 非模态「生成任务」面板,见 §3.10 / §7.92026-09-13 新增的功能画布底部工具栏入口矩阵 §3.10 / §7.9,以及右侧 Supervisor 对话气泡、可访问对比度与过程卡布局收口,资源卡预览、分区布局、非破坏性资源编辑、资源替换与 Godot 双根合同保持不变)
更新时间:`2026-09-21`2026-09-20 音频生成并入图片类那份后台任务账本、派生/修改类任务并入同一「生成任务」侧栏,2026-09-21 卡片浮层改为「提交即关」,见 §3.10 / §7.9;2026-09-14 图片类生成后台化:入口 IPC 为 `start_local_project_asset_generation` + 项目内任务账本 + 本地排队 + 非模态「生成任务」面板;2026-09-13 新增的功能画布底部工具栏入口矩阵 §3.10 / §7.9,以及右侧 Supervisor 对话气泡、可访问对比度与过程卡布局收口,资源卡预览、分区布局、非破坏性资源编辑、资源替换与 Godot 双根合同保持不变)
## 1. 产品定位
@@ -153,13 +153,13 @@
实现状态(2026-09-132026-09-14 图片类生成后台化:提交即返回 + 项目内任务账本 + 本地排队 + 非模态「生成任务」面板;2026-09-20 音频生成并入同一条后台任务账本):功能画布 = 资源栏目页(`resourceBookState.view === 'child'`)。栏目页左下角的底部工具栏按 manifest 资产的**功能分类** `category` 分流,矩阵由用户 2026-09-13 拍板,工具项顺序即下表顺序(最右一项为「上传」)。
| 栏目 | 工具栏里的生成入口 |
| --- | --- |
| UI 与交互 `ui-interaction` | 生成图片 | 生成规范(二级:图标规范 / 自定义规范)| 生成图标素材 | 生成 UI 设计图 | 上传 |
| 角色与对象 `character` | 生成图片 | 生成规范(二级:角色规范 / 自定义规范)| 生成角色形象 | 上传 |
| 场景与环境 `scene` | 生成图片 | 生成规范(二级:自定义规范)| 上传 |
| 音频 `audio` | 生成背景音乐 | 生成音效 | 上传 |
| 文档 `document`、待归类 `unclassified`、项目版本 `version`、「所有资源」展开态、资源总览 | **不渲染工具栏** |
| 栏目 | 工具栏里的生成入口 |
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| UI 与交互 `ui-interaction` | 生成图片 | 生成规范(二级:图标规范 / 自定义规范)| 生成图标素材 | 生成 UI 设计图 | 上传 |
| 角色与对象 `character` | 生成图片 | 生成规范(二级:角色规范 / 自定义规范)| 生成角色形象 | 上传 |
| 场景与环境 `scene` | 生成图片 | 生成规范(二级:自定义规范)| 上传 |
| 音频 `audio` | 生成背景音乐 | 生成音效 | 上传 |
| 文档 `document`、待归类 `unclassified`、项目版本 `version`、「所有资源」展开态、资源总览 | **不渲染工具栏** |
- 位置与层级:画布左下角(`left: 14px; bottom: 14px; z-index: 40`)。右下角是既有的缩放 / 撤销 Dock(`right: 14px; bottom: 14px`),左下角是画布上唯一两者都不占的稳定空位。工具栏是管理区 `.game-resource-book-manager` 的**直接子节点**、与画本场景并列,不进带 `scale()` 的场景层;二级菜单与「入口不可用原因」都贴着工具栏上沿弹出,不做内嵌内容。
- 外壳用共享 chrome`packages/image-canvas-react``CanvasToolbar / CanvasToolbarGroup / CanvasChromeButton`),样式落在 AGC 的 `resourceCanvasChrome.css`;共享包只承接通用表现,不含业务规则。
@@ -171,6 +171,8 @@
- 前置规范图:`start_local_project_asset_generation``ui-prototype``art-spritesheet` 要求项目里已有登记并绑定当前账号的 `assets/art-spec.png``kind: icon-spec`、图片媒体类型、来源为画布)。**后台化没有改这条前置判据**:Rust 侧仍是同一口径,前端 `projectHasIconSpecReference` 仍与它逐字对齐,缺前置时对应入口**保持可点击**并给出可执行的原因与指路(仓库口径:视觉不可用但可点击说明原因,不用原生 `disabled`),原因文案包含 `assets/art-spec.png` 与「生成规范 → 图标规范」。
- 权威规范图由工具栏自身可满足:「图标规范」入口在项目尚无权威规范图时按 `assets/art-spec.png` 落盘;已有权威规范图时**不再传 `outputPath`**Rust 侧 `replace_existing` 固定为 `false`,指向已存在文件会被硬拒绝「outputPath 已存在,禁止静默覆盖」),改为生成一张新的普通图标规范资产。这条前端策略不扩接口。
- 音频入口收敛:音频画布的「生成背景音乐 / 生成音效」由工具栏承载,既有「生成素材」浮层入口**只保留生成视频**(视频能力不删,只是不出现在工具栏里)。
- 派生/修改类任务并入同一侧栏(2026-09-20):快速编辑、生成动画、视频 / 音效 / 背景音乐与抠图这类走**资源编辑链路**的任务也进「生成任务」侧栏。数据源 = 原生资源编辑账本 `list_pending_local_project_resource_edits` + **本会话的本地提交记录**,按 `operationId` 合并去重:本地那份负责「按下提交当帧可见」,原生那份负责「重开项目、别处提交也看得见,阶段文案以后端为首」。这类任务不写图片类生成账本(`.agent/runtime/asset-generation-tasks/tasks.json`),也不改原生资源编辑账本 schema。
- 卡片浮层同一条「提交即关」(2026-09-21):快速编辑 / 生成动画这类挂在资源卡上的浮层只负责**把任务交出去**,点提交当帧即关面板(不等 IPC),进度、阶段与结果都在「生成任务」侧栏里跟;面板内不出现「修改中 / 生成中」这类等待态。只有**点击瞬间就失败**(名称预检、源素材不在画布上、没有客户端)留在面板里可见;**受理之后才失败**只把侧栏那条收口为失败 + 提示条,不重开面板,草稿回落成「未完成编辑」等用户重开。因此原有的「生成中的卡片浮层不参与清焦点」判据一并退役(浮层不会带着进行中的任务留在画布上)。身份跟着资源走:按「入口 + 资源路径」记住最后一次派生请求,重开面板再提交时提示词没变就沿用同一 `operationId` / 幂等键,命中同一 operation 账本;派生成成功即清掉。同一张素材仍有在途提交时,再提交会被拦下并给出原因。
- 本轮明确不做:生成视频(保留在既有浮层入口)、宣发素材、生成游戏场景、画布级「选择工具 / 抓手工具」(AGC 现无画布级工具模式)。这五类都**不得**出现在工具栏里。
- 本地 IPC 边界(前端只做本地收窄,不改接口):提示词上限 `32000` 字符、素材名上限 `120` 字符、比例白名单 `1:1 / 2:3 / 3:2 / 9:16 / 16:9`、尺寸白名单 `0.5K / 1K / 2K`
@@ -364,7 +366,7 @@ type UpdateProjectResourceCanvasLayoutResult =
1. **查找素材**:关键词,就是画布搜索本身,与筛选条件共用同一份状态,只有一个入口读写它,不得各存一份;判据沿用搜索既有的名称、路径、媒体类型、任务名四字段与大小写不敏感口径。
2. **所在区域**:取值为「全部区域」加上现行分区栏目(`PROJECT_RESOURCE_CANVAS_SECTIONS` 的 6 类资产分类与末尾独立的「项目版本」栏),显示名沿用 `@` 面板资源筛选那份唯一中文口径,不另建译名表。
3. **自定义标签**:从 manifest `assets[].tags` 派生的标签库,多选且为 AND 语义(已选标签必须全部命中,空选择不过滤),复用共享判据 `assetTagsMatchSelection`
不提供「状态」字段:manifest 资产与资源投影都没有状态事实源,候选的任务状态与附件导入状态在资源投影里已被上游过滤,任何取值都恒为同一结果,因此不渲染该字段,也不保留占位下拉。
不提供「状态」字段:manifest 资产与资源投影都没有状态事实源,候选的任务状态与附件导入状态在资源投影里已被上游过滤,任何取值都恒为同一结果,因此不渲染该字段,也不保留占位下拉。
- 「所在区域」**既是筛选维度也是画布当前栏目**,两者必须是同一份状态:区域取值由画布栏目状态派生,切换区域走与栏目切换完全相同的那一条路径,因此用户用滚轮、总览卡片或下一页切换栏目时区域显示随之变化,不需要双向同步逻辑,也不会出现两处状态互相漂移。
- 区域取值与其它维度叠加时,筛选只作用于当前区域内的资源;「全部区域」作用于全部资源。两种语义共用同一份过滤实现,不为「只筛当前区域」另写一套裁集合逻辑。
- 筛选浮层是画布唯一的搜索与筛选入口:Dock 上的放大镜按钮与 `Ctrl/Cmd+F` 叫出的是同一个浮层,不存在第二个浮层,因此也不存在「两个浮层互斥」这一说。
@@ -54,7 +54,6 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 决策(无写副作用):只在生成本轮 prompt 时展开该上下文;历史 item 回读走 `direct_codex_user_item_to_response_item` 的纯投影,不得触发 UI 代码导出或任何项目写入。
- 验证:`agent::direct_codex_user_item` 定向 16 条通过,覆盖成功注入、生成失败保留引用摘要、非 UI 文档不触发与历史回读不产生 `ui/generated-*.js`
## 2026-09-19 AGC Direct 删除每回合四项媒体资源请求上限
- 背景:2026-08-24 引入的单回合四项上限以「整个 agent run(一条用户消息到回合结束)」为窗口,计数只增不减、请求完成不释放额度;autonomous 游戏构建要求 agent 不停下跑完整局,额度耗尽后的报错实际是终态,与技能的三次重试纪律冲突,现场表现为长时间无效重试。2026-09-18 先将不计费的抠图豁免,但付费 create/derive 仍受同一窗口问题影响。
@@ -68,6 +67,24 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 决策:`agc_remove_background` 不再经过 `resource_request_ids` 计数,直接按回合身份与请求指纹确定性派生 operation/idempotency id(与 map 复用结果一致),同指纹重试与 pending 对账语义不变。付费的 create/derive(含 `agc_edit_image` 委托)维持四项上限与原有报错文案,且抠图请求不再挤占其额度。
- 验证方式:`cargo check`ai-game-creator-shell src-tauri)与 `git diff --check` 通过;未新增测试。
## 2026-09-18 AGC 未提交快速编辑草稿按资源路径归属,正式恢复账本不动
- 背景:画布验收项 AGC-006/023 要求「点外部 / Esc 收起面板、或换素材卡」不再无条件丢弃用户刚写的提示词与 `@` 引用,于是宿主内存里多了一份未提交草稿表(`resourceCanvasQuickEditModel.ts``ResourceQuickEditDraftStore`),与原生 `list_pending_local_project_resource_edits` / `resume_local_project_resource_edit` 那条正式可恢复账本**并存**。
- 决策:草稿键是投影的稳定身份 `ProjectResource.path`,不是投影 id。资源投影本来就按 path 去重(`resourceProjectionModel``uniqueByPath`),而 id 会变——任务产物经 `normalize_local_project_raster_resource` 登记成正式素材后,同一张卡从 `task:<任务>:<路径>` 变成 `asset:<id>`。用 id 当键时,任何**不是打开中这一笔快速编辑自身触发**的重投影(换素材卡收起面板、Agent 或外部编辑器把同一路径登记成资产)都会让草稿落到再也点不到的键上:恢复入口按 id 过滤后静默丢弃、重开面板按新 id 查不到。按路径归属后不需要任何「跟着投影搬家」的换键逻辑,那条逻辑本身就是搬丢的来源。
- 决策:本地草稿是**会话内存态**——不落盘、不进账本、不参与对账;共享入口「管理未完成编辑」同时列出来源不同的两种条目,草稿条目显式标注「本会话未提交,关闭客户端不保留」,账本读取失败时仍报出本会话草稿条数,避免用户把两者当成同一种持久事实。
- 决策:`ResourcePromptPolishSlot` 与共享聊天输入区(`ResourceReferenceInput`)共用 `usePromptPolish`;「与原文相同」以**规范化之后要写回宿主的文本**为准(回包被长度上限截回原文同样算没变化),此时不落原文快照、不回填宿主,只给提示,避免出现点了等于没点的「恢复原文」假入口。
- 边界:发送前提醒面板里「AI 润色并发送」遇到原样回包仍按用户意图直接提交,本轮按产品取舍保留(记录在 `docs/project-memory/todos/【待办】画布验收后续修复-2026-09-18.md`)。
- 落地:`apps/ai-game-creator-shell/src/features/resource-canvas/resourceCanvasQuickEditModel.ts`(工厂空表 / 按路径写入读取丢弃 / `listResourceQuickEditDraftEntries`)、`apps/ai-game-creator-shell/src/view/project-development/index.tsx`(草稿接线与恢复入口)、`apps/ai-game-creator-shell/src/features/resource-canvas/ResourcePromptPolishSlot.tsx``apps/ai-game-creator-shell/src/features/project-workspace/{usePromptPolish.ts,ResourceReferenceInput.tsx}`;回归见 `tests/resourceCanvasQuickEditModel.test.ts``tests/resourceCanvasQuickEditDraft.test.tsx`(含「面板收起后旁路重投影」用例,改回 id 作键即红灯)、`tests/usePromptPolish.test.tsx``tests/resourcePromptPolishSlot.test.tsx``tests/chatPromptPolish.test.tsx`
## 2026-09-18 派生资源名称在前端镜像 Rust 门禁,宁可按原话拦下也不截断
- 背景:快速编辑(`-编辑版`)与角色动画(`-角色动画`)的派生资源名由前端按源资源 label 拼出,直接进 `derive_local_project_resource``input.assetName`Rust `normalize_resource_edit_name``resource_editor.rs:802-808`)要求 `trim` 后非空、码点数 1..=120 且不含控制字符,任一不满足即整条请求失败。源 label 取任务标题(Agent 回执)或长生成文件名时,用户必须提交一次才看到「派生资源名称必须在 1..=120 字符内且不能包含控制字符」。这是画布验收遗留项 AGC-025 的成因之一。
- 决策:前端只做镜像,不另造中文语义——上限 120、`Cc` 控制字符判定(C0 / DEL / C1`Cf` 继续放行)、`trim` 后判空、按 Unicode 码点计长(Rust `chars().count()`,不是 JS UTF-16 `.length`)四条与 Rust 逐条对齐,提示文案与 Rust 返回串逐字相同;两份判定由跨语言测试直接读 Rust 源码对表。
- 决策:名称不合法时**阻止并提示**,不截断。截到 120 会让同前缀的两个长源名塌成同一个名字,把一次可见失败换成一次静默重名;默认名函数因此保持返回不合法原名,由检查结果里的 `error` 让调用方先停下。
- 落地:`apps/ai-game-creator-shell/src/view/project-development/resourceEditModel.ts``RESOURCE_EDIT_NAME_MAX_LENGTH` / `RESOURCE_EDIT_NAME_INVALID_NOTICE` / `resolveResourceEditNameCheck` / `resolveDerivedResourceNameCheck(resource, 'edit' | 'character-animation')`,纯函数与跨语言对表见 `tests/resourceEditModel.test.ts`;两种后缀共用同一张后缀表,避免「-编辑版」与「-角色动画」再次分叉。
- 接线:`index.tsx``submitResourceQuickEdit``submitResourceCharacterAnimation` 都在**调 `resolveResourceDeriveSource` 之前**做检查(正规化写盘发生在那一步之后),不合法时只把 `status: 'failed'` 与 Rust 原话写进各自的浮层面板并 return,不发派生请求;`assetName` 用检查结果里的 `name`。回归见 `tests/projectResourceLiveIntegration.test.tsx` 的两条「源名超 120 码点」用例与既有的合法名校验 `source-art-编辑版` / `hero-角色动画`
- 边界:资源画布的图片类生成走另一条门禁(`commands.rs``LOCAL_PROJECT_ASSET_MAX_ASSET_NAME_CHARS`,文案「素材名称超出安全边界」),不在本条口径内;提示词上限仍是 `resourceEditPromptMaxLength` 那一份,本决策不动它。
## 2026-09-18 Provider 瞬态重试次数严格按设置执行(游戏开发 Agent 与策划 Agent 不再被档位收进区间)
- 背景:AGC 客户端此前把 `agentLlm.<agent>.maxRetries` 按运行档位重新收进固定区间——`autonomous-game-build` 档位(自主构建的游戏开发 Agent 及其继承档位的专业子 Agent)被抬到 12~16`standard` 档位(含立项策划入口的策划 Agent 与普通 Agent 对话)被压到最多 3;瞬态分类里的上游 400 还在同一预算上再收窄到 2 次。现场把 `maxRetries` 设成 5 时,游戏开发与策划两条链路都不按设置执行。
@@ -81,6 +98,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 背景:AGC 已通过本地项目 ID 建立并持久化本地项目到主站远端画布项目的绑定,但 `agc_remove_background` 提交请求仍把本地 `manifest.project_id` 放入 `projectId``assetFolderId` 已使用远端素材目录 ID。主站因此按项目不存在或不属于当前账号返回 404,主站抠图和 BgFilter 本身均正常。
- 决策:抠图请求及工具回执统一使用 `prepare_external_canvas_generation_context` 返回的远端 `context.project_id`;本地 manifest 项目 ID 只用于绑定键和本地状态,不得作为主站业务请求的 `projectId`
- 验证:客户端定向 Rust 测试、格式、编码和 diff 检查通过;未修改主站路由或 BgFilter。
## 2026-09-17 图集切分模式改为显式声明
## 2026-09-17 DirectProject 首屏历史锚点只认订阅回执的 lastCompletedItemId
@@ -102,6 +120,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 标准美术包:客户端显式声明 `sliceMode=connected-components` + `sliceCount=4`,本地按用途位置写四张 canonical 切片前再次校验数量正好为四,数量不符时失败关闭,禁止截断或补位。
- 测试环境:在提权 shell 的 Windows 主机上,`%TEMP%` 下新建目录的默认所有者是 `BUILTIN\Administrators` 而不是当前 TokenUser,AGC 的所有者校验会拒绝测试自己创建的项目根;测试构建对该情形(仅限 `%TEMP%` 内、且失败原因为所有者不匹配)先按“本调用创建的对象”初始化所有者后重试,临时目录之外的越权所有者继续失败关闭。
- 权威合同:[画板图标素材生成入口设计](../../【编辑器】画板图标素材生成入口设计-2026-06-15.md)。
## 2026-09-17 `agc_tools` 媒体资源提示词上限收敛为单一口径,并按 kind 暴露给模型
- 背景:有人反馈「客户端没法由 agent 调用图片快速编辑功能以及背景音乐生成功能」。核查后工具本身都在(`agc_edit_image` / `agc_create_or_derive_resource`),图片快速编辑在 2026-09-14 的真实项目日志里也有成功记录;但存在三类真实缺陷:① `agc_create_or_derive_resource``prompt` 在 schema 里只声明 4000,真实上限却是按 kind 分的(背景音乐 140、音效 1900、视频/角色动画 4000、图片 32000),MCP 层还额外写死了一条 140 判断,模型从 schema 与 skill 都看不出 140/1900,写一句正常长度的背景音乐描述就当场被拒;② 客户端 UI 用同一口径但会截断并提示,agent 侧却只有硬拒,形成「UI 能做、agent 调不动」的观感;③ `sourceLocalAssetId` 不是已登记资源时只报「不属于当前项目已登记资源」,模型会原地重试而不会先登记。
@@ -220,6 +239,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 决策:图片类生成接线改为 `start_local_project_asset_generation` + `list_local_project_asset_generations` 后,同步命令 `generate_local_project_asset` **已无生产调用方**,只剩 `src-tauri/src/tests/project.rs` 的三条集成用例与 `commands.rs` 的自身单测在调它;因此登记进 `scripts/check-config.mjs` 的 native-only 白名单(该门禁有「App invoke 与白名单互斥」断言,谁重新给它接调用方就必须同时删掉这条白名单项)。
- 待办:它是**注册中的可调用 IPC**,一旦被将来代码调用就是一条绕过任务账本、单次阻塞最长 35 分钟的并行生成路径。下一批次应删除它,或改为转调 `start_local_project_asset_generation`(连带迁移那三条集成用例)。
- 关联文档:[栏目画布底部工具栏入口矩阵](../../technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md)。
## 2026-09-14 AGC 壳 Rust 套件按「一片一 job」拆分,客户端 Rust 关键路径压到 7 分钟以内
- 背景:`AI game creator shell Rust tests` 是客户端 CI 的关键路径(run 2097 实测 15 分 27 秒)。拆开来看:前置 5 分 30 秒(checkout 10s + `npm ci` 2m45s + Cargo fetch 2m35s)、编译 1m39s、**AGC 壳 bin target 的 2466 条单测串行 507s**、`agent-run` smoke 51s。这 2466 条全在 `apps/ai-game-creator-shell/src-tauri` 的 bin target 里,一条 `cargo test … -- --test-threads=1` 跑完。
@@ -232,6 +252,7 @@ Godot 编辑器操控复用既有 AGC 插件宿主、EditorAdapter、Runner 和
- 影响范围:`.gitea/workflows/project-ci.yml`(十一个 job)、`scripts/check-native-shells.mjs`(分组由五个到十个:新增 `agc-rust-crates``agc-rust-shard-1..4``agc-rust-smoke`,移除 `agc-rust` 与随后的 `agc-rust-shell`)、根 `package.json``scripts/project-ci-workflow.test.ts`(新增纯 cargo job 免 `npm ci`、分片运行器覆盖校验、crate 级 job 预热顺序断言)、开发运维文档与共享记忆。本仓库不把 Project CI 的 context 配成 `master` 分支保护的合并必需检查(2026-09-14 复核),合并前由人工确认结果,因此 job 拆分/改名不需要同步分支保护设置。
- 验证方式:`npx vitest run scripts/project-ci-workflow.test.ts`;分片运行器本地以 `agent-runtime-core`7 条 → 2/2/2/1)与 `platform-llm`146 条 → 49/49/48)验证分片、`--exact` 与片 TMPDIR 隔离,负例 `--shard-index=5` 立即失败;`node scripts/check-native-shells.mjs --groups=contract` 回归。预期每个分片 job 收敛到 5 分钟以内(前置约 1 分 30 秒 + 编译约 1 分 39 秒 + 约 617 条用例)。
- 关联文档:[开发运维](../../【开发运维】本地开发验证与生产运维-2026-05-15.md)、[踩坑记录](pitfalls.md)。
## 2026-09-14 AGC 资源画布改为「手动整理」:新素材不再自动重排,整张重排只由「整理画布」发起
- 背景:生成一张新素材会让整张资源画布重排。两个 layout hook 都把 `rederiveAutomaticPositions` 打开(type 侧无条件 `true`dependency 侧长期等于 `resourceGraphReady`),而该开关的语义是「每次资源协调签名变化就丢掉全部 `manuallyPlaced=false` 坐标、按当前资源与拓扑整体重算」;新增一张素材必然改签名,于是既有自动卡全部跟着挪位,用户刚记住的位置就没了。画布上也没有任何显式整理入口(`复位资源视图` 只复位视口)。
@@ -8919,7 +8940,6 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 影响范围:新增 `apps/ai-game-creator-shell/src-tauri/src/asset_generation_tasks.rs`+ `main.rs` 注册)、`src/features/resource-canvas/{resourceCanvasAssetGenerationTaskModel.ts,resourceCanvasAssetGenerationQueue.ts,ResourceCanvasAssetGenerationTasksPanelView.tsx}`;改动 `ResourceCanvasAssetGenerationPanelView.tsx` / `ResourceCanvasGenerationPanelView.tsx` / `src/view/project-development/index.tsx`;测试改动 `tests/{resourceCanvasAssetGenerationBackgroundClose.test.tsx,resourceCanvasAssetGenerationQueue.test.ts,resourceCanvasAssetGenerationTasksPanel.test.tsx}`(新增)与 `tests/appSurface/project-development.suite.ts`(把「每个入口一次 `generate_local_project_asset`」改成 `start_local_project_asset_generation` + `list_...` 轮询桩,载荷断言逐字不变)。**未动**external v1 / OpenAPI、`packages/`、SpacetimeDB、音频入口的 pending-edit 账本语义、生成参数与 IPC 载荷字段名。
- 关联文档:`docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md`(§4 / §4a / §8)、`docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md`S11a / §7.3)。
## 2026-09-15 非 Suno 的 VectorEngine 能力切换到 Tiantoken
- 决策:新增本地私密环境变量 `TIANTOKEN_BASE_URL` / `TIANTOKEN_API_KEY`(图片 timeout 可独立配置),承载原 VectorEngine 的文本和图片;`VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 仅保留给 Suno 背景音乐与 Suno 音效。编辑器 SFX V2 继续走 ElevenLabs。
@@ -8944,6 +8964,7 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 决策:平台会话拆成身份(`userId + api origin + identity generation`)与凭据(当前 access token)。identity generation 只在登录、切号、登出或新的 GUI authority epoch 推进;同账号续期只更新凭据并推进只用于拒绝迟到写入的 revision。冻结会话校验、MCP 会话身份与 Runner attach 统一按身份判定,换号 / 退出仍然失败关闭。刷新失败只在服务端明确 401/403 且一次收敛重试后仍失败时清会话;`/api/auth/refresh` 的轮换失败不再下发清空 refresh cookie 的响应。
- 关联规范:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 的“2026-09-16 平台会话身份与凭据分离”;开发期计划见 `docs/project-memory/plans/【里程碑】平台会话身份与凭据分离-2026-09-16.md` 与对应实施计划。
- 验证:AGC `platform_session::tests``runner::tests``assets::tests` 定向通过;AGC `appSurface` 前端套件 468 项通过;网站 `src/services/apiClient.test.ts` 33 项通过;`cargo test -p api-server refresh_session` 通过。项目夹具类 Rust 用例受本机临时目录属主为 `BUILTIN\Administrators` 的环境限制,未计入本次证据。
## 2026-09-15 Direct 回合跨页面继续运行与活动项目面板
- 决策:采用后台继续运行语义。Direct 回合由进程内项目身份锁持有,页面离开不取消;重进项目通过活动回合只读快照与 Thread Manager bootstrap/consume 恢复忙碌态和进度。左上角面板复用同一快照列出正在运行的 Direct 项目并支持进入。
@@ -9045,3 +9066,23 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 不变口径:平台侧 `/api/editor/audios/*/generations` 路由、请求体、计费与 `/api/external/v1`、OpenAPI、共享 DTO、SpacetimeDB schema 一律未动;音频仍复用既有资源编辑派生实现,不复制生成逻辑。
- 关联规范:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`(§3.10 / §7.9)、`docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md``docs/project-memory/plans/【里程碑】AGC音频生成进入后台任务账本-2026-09-20.md`
- 验证:9 个定向 vitest 文件 73 项、`appSurface.test.ts` 552 项(17 跳过)、`cargo test asset_generation_task` 14 项、`npm run agc:typecheck``npm run check:encoding``npm run check:doc-index``git diff --check` 全部通过;未跑真实付费生成。
## 2026-09-20 派生/修改类任务并入「生成任务」侧栏(AGC-039 / AGC-040
- 背景:客户端验收现场,快速编辑提交后画布右上角「生成任务」全程是「还没有生成任务」,同一条草稿又还挂在「管理未完成编辑」里,用户据此判断「点了没生成」;随后同一次修改被重复提交,同一张源图派生了两份一模一样的「-编辑版」。
- 决策(取数):派生/修改类任务(快速编辑、生成动画、视频 / 音效 / 背景音乐、抠图)进图片类生成任务**同一个**「生成任务」侧栏,数据源 = 原生资源编辑账本 `list_pending_local_project_resource_edits`(重开项目、别处提交、阶段文案以后端为首)+ 本会话**本地提交记录**(按下提交当帧即可见),两边按 `operationId` 合并去重。**不改**原生资源编辑账本 schema,也**不**把派生任务写进图片类生成账本 `.agent/runtime/asset-generation-tasks/tasks.json`——两套账本各管各的事实,只在视图层合并。
- 决策(草稿口径):提交进行中的那一笔不再列进「管理未完成编辑」;失败回落自动把它还回未完成列表,提示词与 `@` 引用不丢。
- 决策(重复提交):同一张素材存在在途提交时,重新打开面板再提交会被拦下(可见原因),不重铸 operation 身份。**未做**「同提示词成功后再提交」的去重——那是用户显式重复的付费动作,本批只消除误触来源。
- 理由:用户对「生成」的心智是「交出去就得能看见它在跑」,而不是必须区分两条账本;而防重复必须在**身份重铸之前**拦,等到原生账本判重时已经派生过一次。
- 验证:新增模型用例 9 条、快速编辑两组宿主用例(提交当帧进侧栏并收口 / 在途重复提交被拦),两处新判据做过变异验证;定向 7 个文件 97 条全绿。
- 口径更正(2026-09-21):当时记的「`appSurface` 16 条既有失败」是**从 `apps/ai-game-creator-shell` 目录跑**造成的 cwd 假红(`resolve(process.cwd(), 'apps/…')` 路径翻倍 → ENOENT),不是用例本身红。规范跑法是仓库根 `npm test`;现已用 `tests/repoPath.ts`(按 `import.meta.url` 反推仓库根)修掉 19 个文件的同类写法,从仓库根跑 `appSurface` 为 0 失败。远程 CI 与真实客户端验收仍未跑。
## 2026-09-21 卡片浮层改为「提交即关」:快速编辑 / 生成动画只负责交任务
- 背景:客户端验收反馈——「生成动画」这类卡片浮层在失焦时不会收起,而且这块的关闭判据一直是东一处西一处拼的(点画布空白、换选中卡、Esc、点画布以外各有一条);动画面板在生成中还会被「生成中不关」判据锁在画布上。产品口径澄清:生成都归「生成任务」侧栏,**卡片浮层只用于提交任务,提交完生命周期就结束**。
- 决策(提交即关):快速编辑 / 生成动画点提交当帧即关面板,不等 IPC、不留等待态;阶段与结果只由「生成任务」侧栏承载(本地提交记录 + 原生待办按 `operationId` 合并,见 2026-09-20 那条)。只有**点击瞬间就失败**留在面板里;**受理之后才失败**把侧栏收口为失败 + 提示条并回落草稿,不重开面板。
- 决策(身份跟着资源走):按「入口 + 资源路径」记最后一次派生请求(`resourceEditRequestKey`)。重开面板再提交时提示词没变就沿用同一 `operationId` / 幂等键,重试仍命中同一 operation 账本;派生成成功即清掉,下一次编辑是新的一笔。原「按上次打开的 sourceLayerId 复用」在提交即关之后不再成立(面板重开时层 id 可能已被重投影换掉)。
- 清理:`canDismissResourceCanvasQuickEdit`(生成中的浮层不参与清焦点)与宿主里两个只为它服务的面板状态 ref 一并删除;`clearResourceCanvasFocus` 恢复成「清选中 + 关两块浮层」的直线逻辑。
- 影响面:`apps/ai-game-creator-shell/src/view/project-development/index.tsx``.../features/resource-canvas/resourceCanvasFocusModel.ts``tests/{projectResourceLiveIntegration,resourceCanvasQuickEditDraft,resourceCanvasFloatingDismiss}.test.tsx`、PRD §3.10。
- 验证:定向 `projectResourceLiveIntegration`(32 条,三条断言面板留在失败态的用例按新口径改写为「重开面板再重试,身份不变」)、`resourceCanvasQuickEditDraft`10 条)、`resourceCanvasFloatingDismiss`18 条)全绿;`npm --prefix apps/ai-game-creator-shell run typecheck` 通过。
- 合并前复核(2026-09-21):合并 master 后按**仓库根**跑全量 `npx vitest run`,**373 个测试文件全过、4512 通过 / 34 跳过 / 0 失败**PR #419 显示 `No Conflicts`。真实客户端观感与远程 CI 未复验(后者按用户要求不追,runner/镜像问题见 Issue #431)。
@@ -0,0 +1,68 @@
# 画布验收后续修复
状态:待排查与方案确认。承接 Issue #411;首批修复已由 PR #412 合入,基准为 master `9a21690fe`。本提交仅登记后续范围,不代表以下问题已经修复。
## 优先排查
- 动画生成持续失败:读取具体操作错误及原请求状态后再定位,不盲目重复付费生成。
- AI 润色无变化;恢复原文退出编辑面板、再次打开丢稿。
- 文档全文预览入口不可用或不可发现,需在当前版本复验。
- 标签面板无法查看更多标签;资源面板多选后卡死。
- 未完成编辑缺少继续入口;快速编辑的素材名称校验报错。
## 进展
### 2026-09-20 第一批(已提交到本分支,待客户端验收)
已完成并在本机跑通:AI 润色原样回包提示与「恢复原文」不再丢稿(AGC-004/005)、快速编辑未提交草稿的保留与继续入口(AGC-006/023)、派生资源名称的前端镜像校验与提交前拦截(AGC-025)。
- 本机执行过:`npx vitest run` 定向 9 个文件(138 用例全绿)、`npm --prefix apps/ai-game-creator-shell run typecheck``npm run check:encoding``git diff --check`、改动文件的 prettier / eslint,以及 `appSurface` 等 20 个渲染工作台的用例文件。仅本地;远程 CI 与真实客户端验收都还没跑。
- 本轮独立 review 的 4 条 P2 已处理:草稿身份改为资源路径(原先按投影 id,旁路重投影后草稿会静默消失)、润色判据改为「规范化后要写回的文本」、共享聊天输入区显示润色提示、本会话草稿与账本条目在入口上区分来源;P3 处理了名称预检的抛错兜底、恢复入口按钮对齐、提示随编辑失效、空表改工厂、跨语言用例按 `import.meta.url` 解析路径。
- 明确保留未改:发送前提醒面板里「AI 润色并发送」遇到原样回包仍直接提交(按用户意图发出去,不做二次拦截)。
- 仍未做:动画生成失败的真实复现与定位、文档全文入口、标签面板查看更多标签、多选卡死,以及卡片全类型重设计、画布内任务浮层、替换交互与聊天引用这批后续需求。
### 2026-09-20 第二批(AGC-039 / AGC-040,待客户端验收)
现场(项目 `gameagent-6e53c9e8`):快速编辑提交后画布右上角「生成任务」全程是「还没有生成任务」,而「管理未完成编辑」里仍挂着同一条草稿——用户据此判断"点了没生成";同一次修改在 22:05:16 与 22:05:34 各派生一次,manifest 多出两份重复的「-编辑版」。
- 交付三条口径(本批一起改):① 派生/修改类任务进「生成任务」侧栏——本地提交记录负责"按下按钮当帧可见",原生 `list_pending_local_project_resource_edits` 负责"重开项目 / 别处提交也看得见、阶段以后端为准",两边按 `operationId` 合并去重;② 提交期间那一笔不再算「未完成编辑」(失败后自动回落,草稿不丢);③ 同一张素材还有在途提交时,重开面板再提交会被拦下并给出原因,避免重复派生。
- 已知未做:成功之后**再次提交**仍会再派生一次(按用户显式重复计费),前端没有做"同提示词去重";原生账本 schema、Rust 门禁与请求载荷都没有改动。
- 本机执行过:新增模型用例 9 条与快速编辑两套新用例(提交当帧进侧栏 / 收口为已完成、在途重复提交被拦),两处新判据都做过变异验证(改回旧实现即红灯);定向 7 个文件 97 条全绿;`tests/appSurface.test.ts` 与本批基线逐条一致(16 失败均为本分支既有,未新增);`npm --prefix apps/ai-game-creator-shell run typecheck` 通过。远程 CI 与真实客户端验收仍未跑。
### 2026-09-21 第三批(卡片浮层生命周期与画布样式,待客户端验收)
验收现场又报三条:①「生成动画」面板样式与美术画布不一致(缩略图、预设、提交按钮落回默认流);② 该浮层失焦不收起;③ 生图弹窗里**点提示词输入框任意位置**都会弹出「选择素材」。
- 产品口径澄清后按「**卡片浮层只用于提交任务,提交完生命周期就结束**」改:快速编辑 / 生成动画点提交当帧即关面板(不等 IPC、不留等待态),进度与结果全在「生成任务」侧栏;受理后的失败不再重开面板(侧栏收口为失败 + 提示条、草稿回落到「未完成编辑」),只有点击瞬间就失败留在面板里。原「生成中不关」判据与此一并退役。
- 派生请求身份改为按「入口 + 资源路径」记忆:重开面板再提交、提示词没变就沿用同一 `operationId` / 幂等键,重试仍命中同一 operation 账本。
- 动画面板样式改为**按网页端整档照抄**:补上第二条同名规则(`.image-canvas-editor__generation-close` 的浮层内绝对定位——只搬第一条时关闭键会掉进网格流、跑到面板正中)、提示词聚焦 / `aria-invalid` 两档、composer 内参数簇底色,以及 `@media (max-width: 760px)` 整档;同时删掉面板里重复回显提示词的「动画描述」行。
- 新增样式缺口守卫 `tests/resourceCanvasCharacterAnimationPanelStyle.test.tsx`:按 `src/main.tsx` 的真实 import 关系解析 AGC 加载的样式表,逐条比对「网页端命中该面板的规则(选择器 + 声明)AGC 是否都有一条」。第一版守卫只比选择器,漏掉了同名覆盖,已按现口径收紧。
- 生图弹窗那个是 `<label>` 转发点击:`<label>` 会把点击交给内部第一个可标注控件,而这一格里第一个正是引用输入区的「插入素材引用」按钮。输入区改为 `<div>` 包裹(可访问名仍由控件自身 `aria-label` 提供),并补一条「点输入区不该自己弹出选择框、只有 @ 按钮才开」的用例——先用旧代码复现出红灯再修。
- 本机执行过:定向 `projectResourceLiveIntegration` 32 条、`resourceCanvasQuickEditDraft` 10 条、`resourceCanvasFloatingDismiss` 18 条、样式守卫 3 条、`resourceCanvasAssetGenerationReferences` 10 条(含新增复现用例)等全绿;网页端 `ImageCanvasEditorGenerationIntegration` 44 条 + 面板 6 条全绿;`typecheck``check:encoding``git diff --check`、prettier、eslint 通过;`tests/appSurface.test.ts` 与基线逐条一致(16 失败均为本分支既有)。远程 CI 与真实客户端观感仍需复看。
### 2026-09-21 复核收口(review 修复 + 生图浮层美化)
- 在途拦截补齐**生成动画**:提交记录里「这笔属于哪张资源」从 `draftKey` 拆成 `resourcePath`,快速编辑与生成动画共用同一条 `…BlocksResource` 判据。此前动画这条键对不上拦不住——重开面板再提交会复用同一 `operationId` 卡在原生 per-operation 锁上,或(改了提示词)直接多出一笔付费生成。
- 样式缺口守卫**扩到三块面板**(动画面板 / 快速编辑面板 / 生图面板),判据改为按「选择器分支 + 声明」逐条比对:只比类名会漏同名覆盖,只比整串选择器会逼宿主连不相干的兄弟支一起搬。实测把快速编辑面板的两条缺口一并照抄补上(其中两条按宿主差异显式登记:窄屏底栏与 `overflow: auto`)。
- 网页端 `@media (max-width: 760px)` 只搬**动画面板**那一支:AGC 的快速编辑浮层是「居中贴资源卡」的绝对定位,跟随网页端改成整宽底栏会压住栏目工具栏与左侧「生成任务」侧栏。
- **生图浮层紧凑化**(验收现场那条滚动条):字段行改两列、比例与尺寸并排、提示词 6 行降到 3 行、润色 / 参考计数 / 两个动作收进同一行——面板高度回落到几何上界以内,滚动条物理上不再出现(`overflow` 只作极端窗口兜底)。相关卡片外形收敛到 `.game-project-workbench` 上的 `--game-canvas-card-*` 基类 token(取值照抄网页端画布面板),占位卡与生成浮层/弹窗共用一套圆角 / 描边 / 底色 / 投影。
- **口径更正**:此前记的「`appSurface` 16 条既有失败」是**从 `apps/ai-game-creator-shell` 目录跑**造成的 cwd 假红(`resolve(process.cwd(), 'apps/…')` 路径翻倍 → ENOENT),不是用例本身红。规范跑法是仓库根 `npm test`;本次新增 `apps/ai-game-creator-shell/tests/repoPath.ts`(按 `import.meta.url` 反推仓库根)并把 19 个用例文件改成用它,另修掉 `HOST_STYLE_SHEETS.filter(existsSync)` 把仓库相对路径交给 cwd 解析的同类假红。改完从仓库根跑 `appSurface`**538 通过 / 17 跳过 / 0 失败**。
- 本机执行过(均在合并 master 之后):`typecheck``check:encoding``git diff --check`、prettier、eslint 通过;AGC 定向 `projectResourceLiveIntegration` 32 + `resourceCanvasQuickEditDraft` 10 + `resourceCanvasFloatingDismiss` 18 + 样式守卫 5 + `resourceCanvasAssetGenerationReferences` 11 + 派生任务模型 9 等全绿;网页端 50 条全绿;`appSurface` 从仓库根 0 失败。真实客户端观感与远程 CI 仍需复看(CI 目前按用户要求不追)。
### 合并前复核(2026-09-21PR #419
- 合并 master`cd98e0603`)后按**仓库根**跑全量 `npx vitest run`:**373 个测试文件全过,4512 通过 / 34 跳过 / 0 失败**;PR 显示 `No Conflicts`,分支与远端一致、工作区干净。
- 范围核对:48 个改动文件全部落在 AGC 前端、3 个共享画布组件与 3 份文档;`server-rs` / `spacetime` / `docs/openapi` / `src-tauri` **零改动**(后端与契约无红线涉及),无 `.env`、密钥、构建产物或日志进入改动。
- 合并后仍**未复验**的只有两类,且都不阻塞合并:① 真实客户端观感(本批动了动画面板样式、生图浮层紧凑排布与卡片基类 token——声明级与结构级都有守卫,真机要客户端验收确认);② 远程 CI(runner/镜像问题仍在处理,见 Issue #431;按用户要求本批不追)。
## 后续需求
- 资源卡顶部独立名称区与全类型统一样式,确认 assetName/用户素材名的正式来源。
- 生成任务列表移到画布右上角,进行中/已完成分组、失败可见、限高滚动及自动开合。
- 素材替换关系与画布点选替换;聊天拖拽批量引用、复制对话保留有效引用。
## 边界与验收
先核对测试包/提交,避免旧包反馈与已合入修复混淆。每个问题先复现、明确原因与最小修复,再补回归和独立 review;复杂需求按现有规范驱动流程推进。首批本地通过不等于远程 CI 或真实 Provider 验收通过,遗留 Rust shard 2 失败仍需跟踪实际 SHA。不得为验证擅自提交付费生成、部署或修改他人项目。
完成条件:逐项记录修复提交、实际执行的检查和客户端验收;长期规则回归主规范,全部关闭后删除本待办。