From 70e92bf407545e869af458fbc7a6c9e7ef6c3330 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Fri, 11 Sep 2026 20:24:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=A1=E5=87=86=E8=B5=84=E6=BA=90=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E7=9A=84=20PRD=E3=80=81=E6=8A=80=E6=9C=AF=E6=96=B9?= =?UTF-8?q?=E6=A1=88=E4=B8=8E=E9=AA=8C=E6=94=B6=E6=96=87=E6=A1=A3=E4=B8=BA?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E6=9B=BF=E6=8D=A2=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - decision-log 新增一条(背景 DDL + 用户裁决 / 决策 / 恒等绑定硬约束 / 准入与提示 / 存储与留痕 / 代价 / 文档口径 / 影响范围 / 验证方式 / 关联文档):说明本次从「版本级替换」改成「直接替换」,并明确记录「替换历史不可回溯」这条代价(上一轮版本级形态里"父版本绑定"就是那份历史,现在只剩一条审计与 manifest 的 .previous 副本) - PRD §3.2:四条保留为未来合同,就地标注「当前实现为直接替换(2026-09-11),版本级替换暂缓」,并说明今天不实现的正是"创建下一迭代版本 / parentVersionId / 前后身份 / 创建原因",而"可运行版本不可变"与"运行中版本不消费尚未生成的新版本变更"仍然成立 - PRD §5.3:DTO 与"三项兼容性必须同时为 true 才能创建下一版本"标注为未来合同;实现口径块整段改写为直接替换(落盘 = 改该版本绑定、绑定改写语义、硬门禁只有分类与类型、尺寸规格降级为提示、失败即拒绝、revision 前进与审计、入口与可见效果) - PRD §5.4 存储边界(当前状态):新增第二个例外「直接替换时显式放行列出的版本允许改写自己的 resourceBindings」,写明六条不变式与两组互斥;开头的"已有记录不得删除、重排或修改"补两个例外的指向 - PRD §4 版本条目、§6 P1、§7.4 第 4 条、§7.8 验收六条全部按直接替换口径改写(验收新增第 7 条:审计留痕 + 替换历史不可回溯的声明) - 技术方案文末那一节整段重写为「资源替换(直接替换:只改该版本的绑定,不建新版本)」:新增放行口与六条不变式、命令与写入语义、准入与提示、成功后行为、已知代价、变异验证四条 + 门禁数字;:641 与 :669 的注解同步校准 - 【测试用例】验收文档:§7.3 第 1 条改写为"版本级替换当前不实现但保留为未来合同",新增第 12/13 条(尺寸规格只提示、替换历史不可回溯),第 10 条去掉"版本下拉多一条";§8 覆盖与不覆盖范围按新形态更新 - 【技术方案】AGC资源派生与非破坏性编辑合同 :28 的"已有版本数组元素不可修改、删除或重排"补上两个例外的指向 --- ...AI游戏创作】项目开发工作台PRD-2026-07-20.md | 44 +++++++++++-------- .../shared-memory/decision-log.md | 13 ++++++ ...】AGC资源派生与非破坏性编辑合同-2026-09-09.md | 2 +- ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 24 +++++----- ...用例】AGC资源工作台V3端到端验收-2026-09-11.md | 10 +++-- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md index e90bacadc..8fc3b7116 100644 --- a/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md +++ b/docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md @@ -40,6 +40,8 @@ - 新版本必须记录 `parentVersionId`、替换前后资源身份和创建原因。 - 当前运行中的版本不消费尚未生成的新版本变更。 +> **实现状态(2026-09-11):本节与 §5.3 的 `ProjectVersionResourceReplacement` 作为未来合同保留,当前实现为「直接替换」**——改 manifest 里该版本的绑定指向另一个已登记资源,**不创建下一迭代版本**(用户当日 DDL 口径:「替换这块先做成直接替换」)。因此本节三条今天**暂不实现**:没有 `parentVersionId` 子版本、没有可回溯的替换历史(替换前身份只剩一条 `asset.version_binding.replace` 审计与 manifest 的 `.previous` 副本)。上面第二条的"可运行版本不可变"与最后一条"运行中的版本不消费尚未生成的新版本变更"仍然成立。直接替换的完整口径见 §5.3 与 §7.8;需要恢复版本级替换时,本节与 §5.3 的 DTO 就是合同。 + ### 3.3 资源布局 - “按依赖”和“按类型”分别保存画布位置。 @@ -187,7 +189,7 @@ idle -> focused(document|art|audio|version) -> idle - 文档:合法 Agent 文本回执直接使用对话投影内容;项目文件只允许读取当前 manifest 已登记资产或已完成任务产物中的 Markdown、文本、JSON、YAML、TOML,必须经过 `file.read` auto 权限、相对路径、项目边界、普通文件、符号链接 / 硬链接、读取漂移、2 MiB、UTF-8 与扩展名白名单校验。正文使用不执行 HTML、不加载远程图片、不产生可点击外链的安全 Markdown 渲染,并在中央画布内独立滚动;读取失败显示错误空态。聊天侧 `/read` 回执中的文件正文必须作为代码块渲染为 `
`,以便用户审阅源码字面量但不执行其中的 HTML;Markdown 渲染使用 `react-markdown` 的 `skipHtml`,依赖库对代码 span / fenced code 的文本转义;不得在整段 Markdown 上预转义 HTML,否则会把代码中的 `` 双重转义为字面量 `<tag>`。
 - 美术:PNG、JPEG、WEBP、GIF、SVG、AVIF、BMP、MP4、WebM、MOV 只在资源卡本体中按既有受控读取、文件签名与解码门禁展示;中央详情不重复加载或放大图片 / 视频本体。SVG 继续拒绝脚本、事件处理器、外部资源引用和实体声明。
 - 音频:只读取 manifest 已登记音频或已成功导入且登记到 manifest 的附件,按文件签名接受 MP3、WAV、OGG / Opus、M4A、AAC、FLAC;聚焦态展示实际格式、浏览器解码后的时长以及带播放进度和暂停能力的内置播放器。音频任务声明中的未登记路径继续不得读取或播放。
-- 版本:只展示 manifest 中正式、不可变的迭代版本记录;版本卡展示项目修订、创建原因与父版本,聚焦态同时展示直接子版本和资源绑定。点击版本卡后高亮仍存在于当前资源投影中的引用资源;缺失历史资源只保留绑定身份,不生成幽灵资源卡。资源替换(2026-09-11 实施)不在版本聚焦态提供,入口在资源卡选中工具条:选中被**当前版本**绑定的素材后替换成另一已登记素材,落盘为「追加下一迭代版本 + 新绑定」,详见 §3.2 / §5.3。
+- 版本:只展示 manifest 中正式、不可变的迭代版本记录;版本卡展示项目修订、创建原因与父版本,聚焦态同时展示直接子版本和资源绑定。点击版本卡后高亮仍存在于当前资源投影中的引用资源;缺失历史资源只保留绑定身份,不生成幽灵资源卡。资源替换(2026-09-11 实施)不在版本聚焦态提供,入口在资源卡选中工具条:选中被**当前版本**绑定的素材后替换成另一已登记素材,落盘为「改该版本的绑定、不建新版本」,详见 §5.3 与 §7.8。
 - mentor 最新决定:资源聚焦不提供工具栏,也不提供工具侧边栏。
 - 音频:只读取 manifest 已登记音频或已成功导入且登记到 manifest 的附件,按文件签名接受 MP3、WAV、OGG / Opus、M4A、AAC、FLAC;聚焦态展示实际格式、浏览器解码后的时长以及带播放进度和暂停能力的内置播放器。音频任务声明中的未登记路径继续不得读取或播放。
 - 版本:只展示 manifest 中正式、不可变的迭代版本记录;版本卡展示项目修订、创建原因与父版本,聚焦态同时展示直接子版本和资源绑定。点击版本卡后高亮仍存在于当前资源投影中的引用资源;缺失历史资源只保留绑定身份,不生成幽灵资源卡。资源编辑只允许追加继承源绑定并记录提示词的子版本,不允许原地替换或修改源版本;资源替换同样不改既有版本,而是追加一条 `resource-replacement` 子版本(§5.3)。
@@ -388,20 +390,22 @@ type ProjectVersionResourceReplacement = {
 
 三项兼容性必须同时为 true 才能创建下一版本。
 
-替换实现口径(2026-09-11):
+> **实现状态(2026-09-11):上面这两段(`ProjectVersionResourceReplacement` 与"三项必须同时为 true 才能创建下一版本")作为未来合同保留;当前实现是「直接替换」**——改 manifest 里该版本的绑定指向另一个已登记资源,**不创建下一版本**,因此"才能创建下一版本"这一门槛今天不成立。今天的准入与提示见下方。
 
-- **落盘 = 改绑定 + 追加新版本**:新版本 `createdReason='resource-replacement'`、`parentVersionId` 指向被替换的源版本;既有版本记录一个字节不改,走 §5.4 的只追加写入边界。子版本的 `resourceBindings` = 源版本绑定集合**去掉源素材**,并保证**替换素材在集合里**(替换素材是源版本创建之后才登记时,按源素材原来的位置插回);恒等绑定口径下不能把源素材那条槽位改写成替换素材,替换素材若在源版本创建时就已登记、本来就在集合里,改写会撞「资源槽位重复」。
-- **替换前后资源身份用推导记录**(不新增 manifest / 跨端契约字段,依据 §5.4 的版本字段表):父版本里有 `asset:{sourceResourceId}` 绑定是「替换前」,子版本里有 `asset:{replacementResourceId}` 绑定是「替换后」,配对由 `parentVersionId` + `createdReason` 确定;差异 `父 − 子 = {源素材}`,`子 − 父 = {替换素材}`(替换素材在源版本创建时就已登记时 `子 − 父` 为空集,此时版本记录无法单独反推配对)。
-- **三项兼容性判据**(后端权威,前端只呈现,不重算):
-  - `categoryEqual`:两侧资产的功能分类相等,用**读时自愈**口径(见本节 2026-09-11 收口)。Rust 侧与之逐分支一致的实现是 `game_creation_app_asset_category_with_read_time_healing`。
-  - `subtypeEqual`:两侧 `kind` 的 canonical 值相等(别名表见 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS` / `canonical_game_creation_app_asset_kind`)。
-  - `sizeSpecEqual`:**规范化媒体格式相等,且「任一方有事实的维度必须相等」**(`imageSequenceFrames[0]` 的宽高、`imageSequenceDurationMs`;两个维度都无事实时不阻断)。**降级声明**:manifest 资产表没有 `width / height / durationMs` 字段,且现役写入侧(上传、派生、画板回传、生成回流)几乎全部写 `imageSequenceFrames: None`,因此该项**在真实数据上退化为「媒体格式相等」**(`png ↔ webp` 会判为不同而被拒绝)。这是刻意接受的最小实现;要支持跨图片格式替换,必须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更),届时把「缺失即未知」的口径写进契约。
-- **失败即拒绝**:任一项不为 true、源版本不存在、源版本未绑定该素材、替换素材未登记、替换素材与源素材相同、`expectedProjectId` / `expectedProjectRevision` CAS 冲突,都必须拒绝并说明原因;拒绝时 manifest 与项目 revision 都不变,界面不得出现成功态。
-- **入口与可见效果**:入口在资源卡选中工具条,只对「manifest 资产 + 被当前版本绑定」的素材放行;候选弹窗列出全部候选、不兼容项渲染但禁用并给出原因。替换成功后当前版本选择切到新版本,但**不自动重载 / 重启运行中的预览**(§3.2 末条);按 §7.4 的口径,改绑定不做运行时资源重映射,运行画面本身不会因改绑定而变化。
+替换实现口径(2026-09-11,**直接替换**):
+
+- **落盘 = 改该版本的绑定**:不创建新版本、不删除版本、不动资源文件、不建文件副本;被改的是源版本自己的 `resourceBindings`,其余字段与其余版本整条不动,版本数量不变。写入走 §5.4 存储边界里的"版本绑定改写放行"(见该节的第二个例外)。
+- **绑定改写 = 源素材从该版本的绑定集合里消失 + 保证替换素材在集合里**:恒等绑定口径下 `resourceBindings` 是"该版本使用的素材集合"而不是槽位表,所以替换素材是源版本创建之后才登记时按源素材原来的位置插回(顺序稳定),替换素材早已登记时只做摘除 —— 不能把源素材那条槽位改写成替换素材,那会撞「资源槽位重复」。
+- **准入与提示**(后端权威,前端只呈现,不重算):
+  - **硬门禁**只有 `categoryEqual` 与 `subtypeEqual`:不满足则拒绝并说明哪一项不等,界面不得出现成功态。`categoryEqual` 用**读时自愈**口径(见本节 2026-09-11 收口),Rust 侧与 `packages/shared` 逐分支一致的实现是 `game_creation_app_asset_category_with_read_time_healing`;`subtypeEqual` 比较 canonical `kind`。
+  - `sizeSpecEqual` **只作提示、不再拒绝**(提示文案「格式与源素材不同」):它的完整判据今天不存在 —— manifest 资产表没有 `width / height / durationMs`,现役写入侧(上传、派生、画板回传、生成回流)几乎全部写 `imageSequenceFrames: None`,实际只等于"媒体格式相等";用不完整到会误拒 `png ↔ webp` 的判据去挡替换是错的。要把它变成硬判据,必须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更),并把「缺失即未知」的口径写进契约。
+- **失败即拒绝**:硬门禁任一项不等、源版本不存在、源版本未绑定该素材、替换素材未登记、替换素材与源素材相同、`expectedProjectId` / `expectedProjectRevision` CAS 冲突,都必须在写入前拒绝并说明原因;拒绝时 manifest、`versions` 与项目 revision 都不变,投影里不得出现新的版本卡或新的"当前使用"高亮。
+- **落盘与留痕**:改绑定属于 `versions` 变化,写入后推进一次 `projectRevision`;并追加一条 `asset.version_binding.replace` 审计(`versionId / sourceResourceId / replacementResourceId / projectRevision`)。**没有可回溯的替换历史**:替换前的身份只有这条审计与 manifest 的 `.previous` 恢复副本。
+- **入口与可见效果**:入口在资源卡选中工具条,只对「manifest 资产 + 被当前版本绑定」的素材放行;候选弹窗列出全部候选,命中硬门禁的项渲染但禁用并给出原因,只有尺寸规格差异的项仍可选但带提示。成功后**不切换版本**(没有新版本可切),只重读 manifest;可见变化是资源卡"当前使用"高亮移到替换素材、`@` 面板"当前版本素材"更新。按 §7.4 的口径,改绑定不做运行时资源重映射,运行画面本身不会因改绑定而变化;也不自动重载 / 重启运行中的预览(§3.2 末条)。
 
 ### 5.4 游戏迭代版本(P1)
 
-阶段六实现状态(2026-08-13 更新):正式版本业务真相扩展在本地项目 `.agent/manifest.json` 的可选 `versions` 字段中;旧项目字段缺失时等价于空列表,不根据 checkpoint、布局 sidecar、静态检查、失败试玩或单独的 `game-creator-project-revision.v1` 自动伪造版本。版本数组只允许追加,已有记录不得删除、重排或修改;首轮没有版本创建按钮。自主首板只有在当前 revision 的 `preview.validate` 已成功形成持久试玩回执后,才幂等追加首条 `initial` 版本,并绑定当时 manifest 中全部已登记资源;同一完成态恢复不得重复创建。已有正式版本时,后续试玩通过不自动追加版本,仍由明确的资源派生事务创建子版本。
+阶段六实现状态(2026-08-13 更新):正式版本业务真相扩展在本地项目 `.agent/manifest.json` 的可选 `versions` 字段中;旧项目字段缺失时等价于空列表,不根据 checkpoint、布局 sidecar、静态检查、失败试玩或单独的 `game-creator-project-revision.v1` 自动伪造版本。版本数组只允许追加,已有记录不得删除、重排或修改(**两个例外见下方存储边界两条**);首轮没有版本创建按钮。自主首板只有在当前 revision 的 `preview.validate` 已成功形成持久试玩回执后,才幂等追加首条 `initial` 版本,并绑定当时 manifest 中全部已登记资源;同一完成态恢复不得重复创建。已有正式版本时,后续试玩通过不自动追加版本,仍由明确的资源派生事务创建子版本。
 
 ```ts
 type GameIterationVersion = {
@@ -424,6 +428,7 @@ type GameCreationAppManifest = {
 - 同一版本内 `slotId` 唯一;`resourceId` 固定保存 manifest asset ID,不保存资源卡显示名称、External Editor resource ID、路径或布局 ID。历史资源已不在当前 manifest 时仍保留原绑定,但界面不为其合成资源卡。
 - Tauri manifest 存储边界在每次写入前校验完整版本图,并与磁盘中的旧 `versions` 前缀逐项比较;只允许追加新记录,已有记录被修改、删除或重排时写入失败且原文件保持不变。
 - (2026-09-10 补充)上述"只允许追加"有且只有一个例外:**用户在删除素材时显式确认"把相关游戏版本一并删除"**。该路径下,只有引用被删素材的那些版本允许消失,其余既有版本仍必须原样、原顺序保留,新增版本仍只能追加在末尾;放行集合按**写入前的 manifest** 求值,且被放行的版本不得出现在追加段里(防止"删除后重排"绕过校验)。除该路径外,任何版本删除、修改、重排仍然失败关闭。
+- (2026-09-11 补充,当前状态)"只允许追加"现在有**两个**例外,第二个比第一个更窄:**直接替换资源时,显式放行列出的版本允许改写自己的 `resourceBindings`**(`mutate_manifest_allowing_version_binding_rewrites`)。它的不变式是:不增不删(候选与磁盘的版本数量必须相等)、不重排(版本 ID 序列逐项相同)、只有放行清单里的版本允许 `resourceBindings` 不同、其余字段(`versionId / parentVersionId / projectRevision / createdReason / createdAt / editPrompt`)逐字段相等、未放行版本整条相等、放行集合按**写入前的 manifest** 求值、与"放行删除"集合**互斥**(同一版本 ID 不得既被放行删除又被放行改写绑定)。这条通道只服务"改绑定",任何版本的新增、删除、重排仍然失败关闭,删除放行通道也不因此获得改写能力。
 - 版本卡标题由稳定追加序号生成,卡片与聚焦态展示 `versionId / projectRevision / createdReason / parentVersionId`;聚焦态额外展示直接子版本和全部 slot 绑定。点击版本卡只高亮当前投影中唯一匹配 `asset:` 的资源卡,不修改版本或资源。
 
 ### 5.5 测试切片与数值参数(P2)
@@ -486,7 +491,7 @@ type ProjectAgentMudPointAttribution = {
 
 - 已实施依赖/类型两套坐标持久化、首次默认不重叠布局、历史坐标跨重启恢复、自动协调 CAS 冲突处理与资源卡手动拖动。
 - 资源关系线在布局持久化验收通过后单独实施,不与本切片捆绑伪造完成。
-- 已实施正式版本不可变模型、版本卡、父子关系与引用资源高亮;“编辑资源”可追加继承源绑定并记录提示词的子版本;资源替换(2026-09-11)已按 §3.2 / §5.3 实施为「改绑定 + 追加 `resource-replacement` 子版本」,入口在资源卡选中工具条;运行版本切换(C7)已完成;兼容性迁移仍待后续切片。
+- 已实施正式版本不可变模型、版本卡、父子关系与引用资源高亮;“编辑资源”可追加继承源绑定并记录提示词的子版本;资源替换(2026-09-11)已按**直接替换**口径实施为「改该版本的绑定、不建新版本」(§5.3 / §7.8),入口在资源卡选中工具条;运行版本切换(C7)已完成;§3.2 的版本级替换与兼容性迁移仍待后续切片。
 - 素材创作无限画布阶段一按权威专题一次交付图片导入、编辑、生成、导出、草稿恢复、正式本地回写、即时投影和焦点竞态闭环。
 - 高级抠图、图集、角色动画、视频时间线编辑和音频波形级编辑按后续切片实施;当前视频走源引用派生,音频只做语义重制。
 
@@ -543,7 +548,7 @@ type ProjectAgentMudPointAttribution = {
 1. manifest 缺少 `versions` 时旧项目正常打开且不显示伪造版本;存在合法记录时,固定“项目版本”分区按追加顺序显示稳定版本卡。
 2. 根版本、父版本和直接子版本关系在卡片或聚焦态可见;悬空父版本、自引用、重复 ID、非递增修订、倒退时间、重复 slot 和超限数字均失败关闭。
 3. 点击版本卡后,当前 manifest 中仍存在的绑定资产卡被高亮;历史已删除资产只在版本详情保留 ID,不创建幽灵卡,也不把 External Editor resource ID 猜成 manifest asset ID。
-4. 版本聚焦态展示身份、修订、创建原因、父子关系、创建时间和 slot 绑定;“编辑资源”只追加继承源绑定并记录提示词的子版本,不提供原地替换、切换、回滚或运行按钮。资源替换**也不在版本聚焦态提供**:它的入口是资源卡选中工具条(§5.3),并且同样不原地改既有版本,而是追加一条新版本;本条限制的是版本聚焦态这个容器,不限制资源卡入口。
+4. 版本聚焦态展示身份、修订、创建原因、父子关系、创建时间和 slot 绑定;“编辑资源”只追加继承源绑定并记录提示词的子版本,不提供原地替换、切换、回滚或运行按钮。资源替换**也不在版本聚焦态提供**:它的入口是资源卡选中工具条(§5.3 / §7.8),本条限制的是版本聚焦态这个容器,不限制资源卡入口。
 5. 任意现有 manifest 写入只能保留磁盘版本前缀并追加新记录;存储边界以跨进程专用锁串行覆盖旧状态读取、前缀校验、安装和回读,修改、删除、重排或并发旧快照覆盖已有版本时写入失败。
 6. 版本选择和高亮不写 manifest、布局 sidecar 或 project revision;dependency / type 两种布局都可显示绑定高亮,既有依赖关系 SVG 语义不变。
 
@@ -595,14 +600,15 @@ type ProjectAgentMudPointAttribution = {
 8. 右侧正式钱包入口在普通工作台和 UI Editor 子路由都始终可见、键盘可达并能打开余额、充值与使用详情;路由切换不得使入口消失或失去交互。
 9. “资源依赖 / 资源类型”以连通分段按钮呈现,点击与键盘操作均只保留一个选中项;使用 Tab 定位和键盘切换时焦点指示清晰、完整,不被容器边界或 `overflow` 裁切。
 
-### 7.8 P1 资源替换验收
+### 7.8 P1 资源替换验收(直接替换)
 
 1. 入口只对「manifest 资产 + 被当前版本绑定」的素材渲染;未绑定素材(版本创建后才登记、或不属于当前版本绑定集合)一律不出现入口,也不出现"点了没反应"的假按钮。
-2. 候选弹窗列出后端返回的全部候选,不兼容项**渲染但禁用**并显示不等维度(分类 / 类型 / 尺寸规格);不得隐藏不兼容候选,不得合成非候选素材,不得在前端重算兼容性判据。
-3. 写入后的 manifest:既有版本记录逐项不变(含 `projectRevision` / `resourceBindings` / `createdAt`),新版本追加在末尾,`createdReason='resource-replacement'`、`parentVersionId` 指向源版本、`projectRevision` 严格大于父版本且等于推进后的项目 revision。
-4. 子版本绑定 = 源版本绑定去掉源素材并保证替换素材在集合里;不得出现重复 `slotId`。替换素材在源版本创建后才登记时,子父差异恰好"一减一增"且顺序稳定。
-5. 三项兼容性任一为 false、源版本不存在、源版本未绑定该素材、替换素材未登记、替换素材与源素材相同、`expectedProjectId` / `expectedProjectRevision` 冲突,都必须在写入前拒绝;拒绝时 manifest、`versions` 与项目 revision 都不变,投影里不得出现新的版本卡或新的"当前使用"高亮。
-6. 成功后重读 manifest 并把当前版本选择切到新版本;**不**自动重载或重启运行中的预览(§3.2 末条),也不做运行时资源重映射。可见变化只有:版本下拉多一条「资源替换 · 时间」、资源卡"当前使用"高亮移到替换素材、`@` 面板"当前版本素材"更新。
+2. 候选弹窗列出后端返回的全部候选:命中硬门禁(分类 / 类型)的项**渲染但禁用**并显示不等维度,只有尺寸规格差异的项**仍可选**并带「格式与源素材不同」的提示;不得隐藏不可选候选,不得合成非候选素材,不得在前端重算判据。
+3. 写入后的 manifest:**版本数量不变**(不新增、不删除),被替换的那个版本除 `resourceBindings` 外逐字段不变(`versionId` / `parentVersionId` / `projectRevision` / `createdReason` / `createdAt` / `editPrompt`),其余版本整条不变;项目 revision 推进一格。
+4. 绑定改写 = 源素材从该版本的绑定集合里消失 + 保证替换素材在集合里;不得出现重复 `slotId`。替换素材在源版本创建后才登记时,差异恰好"一减一增"且顺序稳定;替换素材早已登记时只少掉源素材那一条。
+5. 硬门禁任一为 false、源版本不存在、源版本未绑定该素材、替换素材未登记、替换素材与源素材相同、`expectedProjectId` / `expectedProjectRevision` 冲突,都必须在写入前拒绝;拒绝时 manifest、`versions` 与项目 revision 都不变,投影里不得出现新的"当前使用"高亮或版本卡变化。
+6. 成功后重读 manifest 并**不切换版本**(没有新版本可切);**不**自动重载或重启运行中的预览(§3.2 末条),也不做运行时资源重映射。可见变化只有:资源卡"当前使用"高亮移到替换素材、`@` 面板"当前版本素材"更新。
+7. 替换成功后追加一条 `asset.version_binding.replace` 审计(`versionId / sourceResourceId / replacementResourceId / projectRevision`);**替换历史不可回溯**——替换前身份只有这条审计与 manifest 的 `.previous` 副本,不得声称能查到"某版本历史上换过什么"。
 
 ## 8. 非目标
 
diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md
index 156567094..5991d81b3 100644
--- a/docs/project-memory/shared-memory/decision-log.md
+++ b/docs/project-memory/shared-memory/decision-log.md
@@ -8377,3 +8377,16 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
 - 影响范围:`server-rs/crates/shared-contracts/src/game_creation_app.rs`、`src-tauri/src/project/version_resource_replacement.rs`(新增)、`commands.rs`、`main.rs`、`tests/version_resource_replacement.rs`(新增)、`src/features/resource-canvas/resourceVersionReplacement{Model,Transport}.ts`(新增)、`view/project-development/index.tsx`、`src/components/image-editor/ImageCanvasProjectAssetPickerDialog.tsx`、`apps/ai-game-creator-shell/src/styles.css`。
 - 验证方式:Rust 定向 8 条 + `shared-contracts` 20 条;变异验证三条(去掉媒体格式维度 → 2 条转红;绕开读时自愈 → 自愈用例转红;改成原地改既有版本 → 4 条转红并被「项目版本记录写入后不可修改、删除或重排」拦下,证明只追加守卫真的在挡)。前端新增 12 条,变异验证两条(放宽入口判据 → 「不给假按钮」转红;失败路径静默关弹窗 → 「保留弹窗显示原因」转红)。AGC 全量 1231 passed / 4 skipped / 0 failed;共享美术画布组件 1385 passed;typecheck / `cargo check --locked --all-targets` / `check:encoding` / `git diff --check` 全绿。跨端契约、SpacetimeDB schema、manifest 结构与布局 sidecar schema 均未改动。
 - 关联文档:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`(§3.2 保持,§5.3 补实现口径与降级声明,§7.8 新增替换验收)、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`(新增同章节)、`docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md`(§7.3 第 1 条已按本次口径改写)、Issue #309。
+
+## 2026-09-11 AGC 资源替换改成「直接替换」:只改该版本的绑定,不建新版本
+
+- 背景:同日上午按 PRD §3.2 / §5.3 落地的「版本级替换(改绑定 + 追加下一迭代版本)」,当天下午被用户改口径:「**替换这块先做成直接替换**」(同日 DDL:替换先做,运行画面点选、切图集像素规整先不做)。直接替换 = 改 manifest 里该版本的绑定指向另一个已登记资源,**不追加新版本**,也就是 #309 原先那条「更换资源 = 改 manifest 绑定」的轻形态。
+- 决策(实现):删除版本级路径(按「四不写」:不建 `replace-{revision}` 版本、不写 `parentVersionId`、不写 `createdReason=resource-replacement`、不留兼容分支)。直接替换走**新增的第二条、更窄的版本放行通道** `mutate_manifest_allowing_version_binding_rewrites`:不增不删(版本数量必须相等)、不重排(版本 ID 序列逐项相同)、只有显式放行列出的版本允许 `resourceBindings` 不同、其余字段(`versionId / parentVersionId / projectRevision / createdReason / createdAt / editPrompt`)逐字段相等、未放行版本整条相等、放行集合取自**写入前** manifest、与删除放行集合**互斥**。既有 `validate_version_records_are_append_only` 与既有删除放行通道的语义一行未改;唯一结构性改动是把写盘公共体抽成带校验器参数的内部函数(`write_manifest_locked` 变成一行委托),装盘 / 回读 / 原子替换仍只有一份实现。
+- 恒等绑定口径的硬约束(实测得出,两个形态共用):每个版本的 `resourceBindings` 是「该版本使用的素材集合」而不是槽位表,所以绑定改写 = **源素材从集合里消失 + 保证替换素材在集合里**;不能把源素材那条槽位改写成替换素材(替换素材若早已登记就会撞「资源槽位重复」)。
+- 准入与提示:硬门禁只有 `categoryEqual` 与 `subtypeEqual`(拒绝并说明哪一项不等);`sizeSpecEqual` **降级为提示**(「格式与源素材不同」)不再拒绝。理由:它的完整判据今天不存在(manifest 资产表没有 `width / height / durationMs`,现役写入侧几乎全写 `imageSequenceFrames: None`,实际只等于"媒体格式相等"),硬拦会误拒 `png ↔ webp` 这类直接替换里最常见的需求。要变成硬判据须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更)。
+- 存储与留痕:改绑定属于 `versions` 变化,因此写入后**推进一次 project revision**(跨面快照门禁要求 revision 前进),并追加一条 `asset.version_binding.replace` 审计(复用既有 `append_agent_db_record`,字段 `versionId / sourceResourceId / replacementResourceId / projectRevision`)。审计写失败会报错但不回滚,与 `asset.register` 同口径。
+- **代价(用户已确认接受,记账备查):直接替换没有可回溯的替换历史。** 上一轮版本级形态里"父版本绑定"就是那份历史;现在替换前的身份只存在于 ① 那条审计记录 ② manifest 的 `.previous` 恢复副本(只保留上一次写入)。需要"某个版本历史上被换过几次、换成过什么"时必须另立切片(PRD §3.2 / §5.3 保留为未来合同正是为此)。
+- 文档口径:PRD §3.2 的两条与 §5.3 的 `ProjectVersionResourceReplacement` / "三项兼容性必须同时为 true 才能创建下一版本"**保留为未来合同**并就地标注「当前实现为直接替换(2026-09-11),版本级替换暂缓」;PRD 的**存储边界**("只允许追加…有且只有一个例外")改写成当前状态——现在是**两个例外**(删除素材时连带删版本 / 显式放行版本的绑定改写),因为它是"现在写入校验行为"的描述,留未来式会误导。
+- 影响范围:`src-tauri/src/project/manifest.rs`、`src-tauri/src/project/manifest/version_binding_rewrite_tests.rs`(新增)、`src-tauri/src/project/version_resource_replacement.rs`、`src-tauri/src/tests/version_resource_replacement.rs`、`src/features/resource-canvas/resourceVersionReplacement{Model,Transport}.ts`、`view/project-development/index.tsx`、`src/components/image-editor/ImageCanvasProjectAssetPickerDialog.tsx`、`apps/ai-game-creator-shell/src/styles.css`。
+- 验证方式:放行通道定向 7 条 + 替换定向 8 条 + `shared-contracts` 20 条;**变异验证四条**(去掉"未放行版本整条相等"→两周转红;放行集合改成整个版本数组→"未放行版本"转红;去掉长度检查→"不增不删"转红;准入删掉 category→硬门禁与候选两条转红,均已实测并还原)。前端 13 条(模型 9 + 真链路 4)。门禁:AGC 全量 1231 passed / 4 skipped / 0 failed、共享美术画布组件 1385 passed、`ai-game-creator-shell:typecheck`(含 check-config)、`cargo check --locked --all-targets`、`check:encoding`、`git diff --check` 全绿。
+- 关联文档:`docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md`(§3.2 / §5.3 / §5.4 存储边界 / §7.8 验收)、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`(同章节)、`docs/technical/【技术方案】AGC资源派生与非破坏性编辑合同-2026-09-09.md`、`docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md`、Issue #309。
diff --git a/docs/technical/【技术方案】AGC资源派生与非破坏性编辑合同-2026-09-09.md b/docs/technical/【技术方案】AGC资源派生与非破坏性编辑合同-2026-09-09.md
index ded83bb73..86359928e 100644
--- a/docs/technical/【技术方案】AGC资源派生与非破坏性编辑合同-2026-09-09.md
+++ b/docs/technical/【技术方案】AGC资源派生与非破坏性编辑合同-2026-09-09.md
@@ -25,7 +25,7 @@
 - 文本、SVG 与 Agent 回执在 Provider 调用前必须先持久化 request-issued;成功响应必须先原子安装到与原 operation、请求指纹和内容摘要绑定的私有 durable handoff,再做 envelope 解析、格式校验和 staging。issued 后缺少可信 handoff 只能对账;handoff 已存在且校验通过时恢复只消费该正文,两种情况都禁止再次调用 Provider。
 - 普通客户端视频使用 `POST /api/editor/videos/generations`。有稳定远端引用时直接作为 `referenceVideoSrcs`,只有本地文件时先走 `/api/assets/direct-upload-tickets`、OSS 表单上传和 `/api/assets/objects/confirm`,再提交同一逻辑生成;结果必须下载到新的本地文件并登记远端稳定身份。
 - 普通客户端音效和背景音乐分别使用 `POST /api/editor/audios/sound-effects/generations` 与 `POST /api/editor/audios/background-music/generations`。当前接口没有源音频引用字段,因此产品语义固定为"基于原资源语义的派生重制",界面不得描述为对源波形的裁剪、变声或局部修改;结果仍必须引用源资源身份并保留原音频。
-- 项目版本编辑固定追加 `parentVersionId` 指向源版本的子版本,继承源版本资源绑定并记录本轮编辑提示;已有版本数组元素不可修改、删除或重排。
+- 项目版本编辑固定追加 `parentVersionId` 指向源版本的子版本,继承源版本资源绑定并记录本轮编辑提示;已有版本数组元素不可修改、删除或重排(两个例外见 PRD §5.4 的存储边界两条:删除素材时连带删版本、资源直接替换时改写该版本的 `resourceBindings`)。
 - 角色动画派生结果的 manifest `kind` 固定写 `character-animation`,`source.generationKind` 同步保留 `character-animation`,媒体仍以预览视频加正式序列帧登记。图片编辑等普通派生继续继承源资源语义 kind;后续如需改写为 canonical kind,只能在读取投影或显式迁移中完成,不重写历史 manifest。
 - 图片编辑、视频、音效和背景音乐请求统一在 `generationInputs.source` 写入专用消费身份 `game-creator-resource-editor`;普通内部路由和高级 External 路由都必须实际读取并传递同一稳定 `Idempotency-Key`。队列完成态只向该消费身份返回经过裁剪的稳定 `objectKey / resource / asset` 引用和必要媒体元数据,不暴露 provider、worker、队列内部字段或临时签名 URL。
 
diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md
index a02c879e1..126644d06 100644
--- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md
+++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md
@@ -638,7 +638,7 @@ game-project/
 - 五栏目页签的未读红点由 `ProjectDevelopmentView` 在会话内比较各栏目稳定资源 ID 派生:首次快照只建立基线,只有非当前栏目后续出现新 ID 才加入未读集合;所有栏目切换路径统一以当前栏目变化清除对应未读,项目 scope 变化时重建基线并清空。该状态以 `projectPath + projectId` 隔离,不进入 manifest、布局 sidecar、localStorage、sessionStorage 或后端契约。
 - type 默认布局固定按 `subtype -> mediaType -> label -> id` 排序。manifest 资产的 subtype 使用 `asset.kind`,任务产物、导入附件和 Agent 文本成果使用稳定的来源 fallback;subtype 必须进入资源协调签名,不能因 MIME 相同而退化成按名称混排。
 - 自动协调保存失败时保留当前会话布局;CAS 冲突载入对方最新布局,需要继续协调时最多追加两次重试,持续跨窗口竞争时停止自旋。用户提示只说明“布局已在其他窗口更新”,不要求重新拖动。损坏、未知 schema、身份冲突、超限与链接文件失败关闭,不能用空布局覆盖原文件。
-- 本布局持久化切片不包含资源关系线、资源替换、聚焦态持久化、分区高度、分区内容倍率、整个画布平移、搜索 / 筛选条件、当前 mode,也不修改 `api-server` 或 SpacetimeDB。资源关系线、当前会话内中央聚焦、分区独立高度与内容倍率已在后续独立前端切片接入,都不改变本段 sidecar 合同;其余 P1 能力继续独立实施。**资源替换已在 2026-09-11 按 PRD §3.2 / §5.3 独立实施**(见本文末「版本级资源替换」一节),同样不改布局 sidecar 合同。
+- 本布局持久化切片不包含资源关系线、资源替换、聚焦态持久化、分区高度、分区内容倍率、整个画布平移、搜索 / 筛选条件、当前 mode,也不修改 `api-server` 或 SpacetimeDB。资源关系线、当前会话内中央聚焦、分区独立高度与内容倍率已在后续独立前端切片接入,都不改变本段 sidecar 合同;其余 P1 能力继续独立实施。**资源替换已在 2026-09-11 按「直接替换」口径独立实施**(见本文末「资源替换」一节),同样不改布局 sidecar 合同。
 - 本资源总览布局 sidecar 不包含资源关系线、资源替换、聚焦态持久化、资源总览缩放 / 平移、搜索 / 筛选条件、当前 mode,也不修改 `api-server` 或 SpacetimeDB。资源关系线与当前会话内中央聚焦已在后续独立前端切片接入;素材创作 viewport 和图层使用独立草稿 schema,不能写入 `game-creator-resource-layout.v1`。
 
 历史实施顺序已完成 TypeScript / Rust DTO、Tauri sidecar/CAS、前端纯模型与持久 Hook。二维手动拖动接线现已暂缓;重新开放前必须先更新 PRD 与验收合同。任何后续步骤不得用 `localStorage`、manifest 字段或只在当前 React 会话有效的状态冒充项目持久化。
@@ -666,7 +666,7 @@ game-project/
 
 2026-08-03 阶段六:正式迭代版本直接扩展本地 `.agent/manifest.json`,不新增 checkpoint / layout sidecar / SpacetimeDB 平行业务真相。共享 Rust / TypeScript 合同新增可选 `versions: GameIterationVersion[]`;旧项目缺失字段时只读为空,不回填。Rust 在 manifest 读写边界校验版本唯一性、父先于子、根/原因一致、父子修订与时间单调、slot 唯一和 JavaScript 安全整数,并在覆盖已有 manifest 前要求磁盘版本数组是新数组的逐项相等前缀,从存储边界保证历史记录不可修改、删除或重排。2026-08-13 起,自主首板在当前 revision 的 `preview.validate` 成功结果和持久试玩回执均落盘后,幂等追加唯一首条 `initial` 版本,并以稳定 `asset:` 槽位绑定当时全部已登记资源;失败试玩、静态 smoke、checkpoint 和普通预览状态不得触发版本创建,恢复重放和已有版本项目也不得重复追加。
 
-工作台资源投影只从 `manifest.versions` 构建版本卡,按数组追加顺序生成稳定“版本 N”标题;不再接收前端独立 `projectVersions` 注入。`resourceBindings.resourceId` 只解释为 manifest asset ID,并映射到现有 `asset:` 卡片。选中版本后在 dependency / type 两种布局中高亮当前仍存在的绑定资产;缺失历史资产只留在版本聚焦详情,不能合成幽灵卡或猜测 External Editor resource ID。版本聚焦复用中央只读容器,展示身份、修订、原因、父版本、直接子版本、创建时间与 slot 绑定。**本阶段**不提供版本创建、替换、切换、回滚、测试切片或运行态消费入口;其中**运行版本切换、资源替换与版本创建**已由 2026-09-10 / 2026-09-11 的后续切片补齐(见下方命令段),版本聚焦态本身仍不提供创建、替换、切换、回滚按钮。
+工作台资源投影只从 `manifest.versions` 构建版本卡,按数组追加顺序生成稳定“版本 N”标题;不再接收前端独立 `projectVersions` 注入。`resourceBindings.resourceId` 只解释为 manifest asset ID,并映射到现有 `asset:` 卡片。选中版本后在 dependency / type 两种布局中高亮当前仍存在的绑定资产;缺失历史资产只留在版本聚焦详情,不能合成幽灵卡或猜测 External Editor resource ID。版本聚焦复用中央只读容器,展示身份、修订、原因、父版本、直接子版本、创建时间与 slot 绑定。**本阶段**不提供版本创建、替换、切换、回滚、测试切片或运行态消费入口;其中**运行版本切换、资源创建与资源替换**已由 2026-09-10 / 2026-09-11 的后续切片补齐(替换按「直接替换」口径,见本文末一节),版本聚焦态本身仍不提供创建、替换、切换、回滚按钮。
 
 历史命令式 drag preview 句柄与局部连接索引可以保留,但项目工作台不再向资源卡传入该入口。拖动热路径、4096 张真实卡片拖动重渲染和 Chromium p95 门槛统一暂缓;当前回归只要求 Pointer Move 不改变卡片坐标、SVG path 或布局 revision。`ResizeObserver` 仍保持单图层单实例,任何实时 DOM 几何都不得通过 Tauri IPC 往返 Rust。
 
@@ -1336,13 +1336,15 @@ DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过
 - 定向验收覆盖:同进程重叠写等待后成功、同一轮并行写多个文件、有界等待不占 runtime worker(`current_thread` + 心跳任务)、活外部进程持锁(错误带 `ownerIsSelf=false` 且锁文件不被回收)、ACL 拒绝不投影成争用,外加两条平台无关判据用例(重试性只由错误码决定、终态改判三条件)——后两条让 Linux CI 也能盯住 Windows 分支。对应 `project_lock_recovery`、`direct_tool_bridge` 与 `project/write_lock` 定向测试;`tests/project_tools.rs` 既有的 `runtime_project_write_lock_waits_for_delete_pending_target` 继续覆盖“带句柄的 delete-pending 必须等到成功”。
 - 仍待收口(后续事项):① 其余仍用零等待取锁的入口(`command.exec / project.verify / memory / conversation / task / checkpoint / 预览 / UI 编辑器 / 资源编辑器 / Tauri 命令`)本批不改,遇到同类争用仍会立刻失败;零等待入口无法区分“拆链窗口 / ACL 拒绝”,因此在前缀不变的前提下补一句“锁文件此刻不存在,可能是删除挂起、删除拆链窗口或权限 / ACL 拒绝”。② 锁策略已按“单一职责”收口到 `project/write_lock.rs`(887 行:取锁、等待分类、持锁方诊断、残留回收),`project/filesystem.rs` 回到项目文件 IO(680 行);仍待收口的是 Direct 锁用例,它们还留在 `direct_tool_bridge.rs`(3135 行,锁用例与桥实现混在一起),后续移到 `tests/project_lock_recovery.rs` 或独立测试文件。③ 行为级 Windows 用例(delete-pending 等)仍只在 Windows 本地执行,CI 没有 Windows runner;关键判据已参数化到 Linux 可覆盖,行为级覆盖仍需本地执行或后续补 runner。
 
-## 2026-09-11 AGC 资源工作台 V3:版本级资源替换(改绑定 + 追加下一迭代版本)
+## 2026-09-11 AGC 资源工作台 V3:资源替换(**直接替换**:只改该版本的绑定,不建新版本)
 
-- **口径**:按 PRD §3.2 / §5.3 实施「替换某个版本引用的资源」——**不原地修改既有版本、不动资源文件、不建文件副本**,落盘为「追加一条 `createdReason='resource-replacement'` 的新版本 + 新绑定」。Issue #309 的 C6(候选素材 / 替换关系 / 替换队列 / Agent 审核 / 批量提交)仍然不做;C6 原设计里被一并取消的“替换后生成新版本”按 PRD 口径恢复。
-- **命令**:`read_local_project_version_resource_replacement_candidates`(只读,`asset.list`)与 `replace_local_project_version_resource`(写,`asset.register`),实现落在 `src-tauri/src/project/version_resource_replacement.rs`。入参都是单个 `input` 对象、`deny_unknown_fields`:读命令 `{projectPath, sourceVersionId, sourceResourceId}`,写命令额外要求 `expectedProjectId + expectedProjectRevision + replacementResourceId`。出参的 `replacement` 形状就是 PRD §5.3 的 `ProjectVersionResourceReplacement`;这两个 DTO 是 Tauri 本地 DTO,**不进跨端契约**。
-- **写入语义**:持项目写锁(与删除 / 重命名 / 标签同一把)→ 锁内复核 `projectId` 与 durable revision(CAS 失败报 `project-identity-conflict` / `project-revision-conflict` 且零写入)→ `mutate_manifest_at`(**从不**调用 `mutate_manifest_at_allowing_version_removals`)追加子版本 → 成功后推进一次项目 revision,且子版本 `projectRevision` 必须等于推进后的值。子版本 `resourceBindings` = 源版本绑定**去掉源素材**,并保证**替换素材在集合里**(替换素材是源版本创建之后才登记时按源素材原位置插回)。恒等绑定口径下不能把源素材那条槽位改写成替换素材:替换素材若在源版本创建时就已登记,它本来就在集合里,改写会撞「资源槽位重复」。
-- **替换前后资源身份**:按 PRD §5.4 的版本字段表口径**用推导记录**,不新增 manifest / 跨端契约字段。父版本里有 `asset:{sourceResourceId}` 是「替换前」,子版本里有 `asset:{replacementResourceId}` 是「替换后」,配对由 `parentVersionId` + `createdReason` 确定;差异 `父 − 子 = {源素材}`、`子 − 父 = {替换素材}`。已知限制:替换素材在源版本创建时就已登记时 `子 − 父` 为空集,版本记录无法单独反推配对;要无歧义持久化配对必须先给 `GameIterationVersion` 增字段(跨端契约变更)。
-- **三项兼容性判据(后端权威,前端只呈现)**:`categoryEqual` 用**读时自愈**口径——Rust 侧新增 `game_creation_app_asset_category_with_read_time_healing`(`server-rs/crates/shared-contracts`),与 `packages/shared` 的 `gameCreationAppAssetCategory` 逐分支一致并配定向用例锁定;`subtypeEqual` 比较 canonical `kind`;`sizeSpecEqual` 比较「规范化媒体格式 + 已知帧宽高 + 已知时长」,任一方有事实的维度必须相等。**降级声明**:manifest 资产表没有 `width / height / durationMs`,现役写入侧几乎全写 `imageSequenceFrames: None`,因此该项在真实数据上退化为「媒体格式相等」(`png ↔ webp` 会被拒);要支持跨格式替换须先给 manifest asset 增尺寸字段(跨端契约变更)。
-- **入口**:资源卡选中工具条的宿主 `extraActions` 新增「替换素材」,判据复用现役 `isResourceUsedByCurrentVersion`(manifest 身份 + 被当前版本绑定),未绑定素材不渲染入口,避免假按钮;不动 `ImageCanvasSelectedLayerToolbarAction` 共享 union、不改 `resourceCanvasToolbarModel` 的 `supportedActions`。候选弹窗复用 `ImageCanvasProjectAssetPickerDialog`(该弹窗在 AGC 侧首次使用),以可选 prop 扩展:`singleSelect` / `assetBlockedReasons` / `renderAssetMedia` / `selectionNoun` / `errorMessage`,**默认值保持网页端美术画布行为逐字不变**。候选行渲染类型占位而不挂 ``:AGC 的预览读取要经带 scope 的原生调度器拿 Blob URL,弹窗内没有同步 `src`。
-- **成功后行为**:重读 manifest 并把当前版本选择切到新版本(复用 `selectActiveVersion`,已改为 `useCallback` 固定身份),**不自动重载 / 重启运行中的预览**(PRD §3.2 末条),不做运行时资源重映射。可见变化只有版本下拉多一条「资源替换 · 时间」、资源卡「当前使用」高亮移动、`@` 面板「当前版本素材」更新。
-- **验证**:Rust 定向 8 条(`tests/version_resource_replacement.rs`)+ `shared-contracts` 20 条;变异验证三条(去掉格式维度 → 2 条转红;绕开读时自愈 → 自愈用例转红;改成原地改既有版本 → 4 条转红并被「项目版本记录写入后不可修改、删除或重排」拦下,证明只追加守卫真的在挡)。前端新增 12 条(`tests/resourceVersionReplacement.test.tsx` 真链路 4 条、`tests/resourceVersionReplacementModel.test.ts` 8 条),变异验证两条(放宽入口判据 → 「不给假按钮」转红;失败路径静默关弹窗 → 「保留弹窗显示原因」转红)。AGC 全量 1231 passed / 4 skipped / 0 failed;共享美术画布组件 1385 passed;`npm run ai-game-creator-shell:typecheck`、`cargo check --locked --all-targets`、`npm run check:encoding`、`git diff --check` 全绿。`/api/external/v1`、SpacetimeDB schema、`packages/shared` 与 `shared-contracts` 的 wire DTO、manifest 结构、布局 sidecar schema 均未改动。
+- **口径**:用户当日 DDL 口径「替换这块先做成直接替换」→ 改 `.agent/manifest.json` 里该版本的绑定指向另一个已登记资源:**不创建新版本、不删除版本、不动资源文件、不建文件副本**。PRD §3.2 的「创建下一迭代版本」与 §5.3 的 `ProjectVersionResourceReplacement` /「三项兼容性必须同时为 true 才能创建下一版本」**保留为未来合同**,今天不实现;Issue #309 的 C6(候选素材 / 替换关系 / 替换队列 / Agent 审核 / 批量提交)仍然不做。
+- **写入通道(新增的第二条、也是更窄的版本放行口)**:`project/manifest.rs` 的 `mutate_manifest_allowing_version_binding_rewrites` + `validate_version_records_allow_binding_rewrites`。不变式:**不增不删**(候选与磁盘版本数量必须相等)、**不重排**(版本 ID 序列逐项相同)、**只有放行清单里的版本**允许 `resourceBindings` 不同、其余字段(`versionId / parentVersionId / projectRevision / createdReason / createdAt / editPrompt`)逐字段相等、**未放行版本整条相等**、放行集合取自**写入前** manifest、与删除放行集合**互斥**。既有 `validate_version_records_are_append_only` 与既有 `mutate_manifest_at_allowing_version_removals` 语义一行未改;唯一结构性改动是把写盘公共体抽成 `write_manifest_locked_with_version_guard`(校验器由调用方注入,`write_manifest_locked` 变成一行委托),装盘 / 回读 / 原子替换仍只有一份实现。
+- **命令**:`read_local_project_version_resource_replacement_candidates`(只读,`asset.list`)与 `replace_local_project_version_resource`(写,`asset.register`),实现在 `src-tauri/src/project/version_resource_replacement.rs`。入参都是单个 `input` 对象、`deny_unknown_fields`:读 `{projectPath, sourceVersionId, sourceResourceId}`,写额外要求 `expectedProjectId + expectedProjectRevision + replacementResourceId`;出参 `{versionId, committedProjectRevision, replacement:{versionId, sourceResourceId, replacementResourceId, compatibility, warning}}`(**没有** `parentVersionId`,因为没有新版本)。这两个 DTO 是 Tauri 本地 DTO,**不进跨端契约**。
+- **写入语义**:持项目写锁(与删除 / 重命名 / 标签同一把)→ 锁外与锁内各复核一次 `projectId`,锁内复核 durable revision(CAS 失败报 `project-identity-conflict` / `project-revision-conflict` 且零写入)→ 走上面的绑定改写通道,放行集合固定为 `[sourceVersionId]` → 成功后推进一次项目 revision(改绑定属于 `versions` 变化,跨面快照门禁要求 revision 前进)→ 追加一条 `asset.version_binding.replace` 审计(复用既有 `append_agent_db_record`)。审计写失败会报错但不回滚,与 `asset.register` 同口径。
+- **绑定改写语义**(恒等绑定口径的硬约束):`resourceBindings` 是"该版本使用的素材集合"而不是槽位表,因此改写 = **源素材从集合里消失 + 保证替换素材在集合里**;替换素材是源版本创建之后才登记时按源素材原来的位置插回(顺序稳定),早已登记时只做摘除 —— 不能把源素材那条槽位改写成替换素材,那会撞「资源槽位重复」。
+- **准入与提示(后端权威,前端只呈现)**:**硬门禁**只有 `categoryEqual`(用 PRD §5.3 的**读时自愈**口径,Rust 侧 `game_creation_app_asset_category_with_read_time_healing` 与 `packages/shared` 的 `gameCreationAppAssetCategory` 逐分支一致并配用例锁定)与 `subtypeEqual`(canonical `kind`);`sizeSpecEqual` **降级为提示**(「格式与源素材不同」)不再拒绝 —— 它的完整判据今天不存在(manifest 没有 `width / height / durationMs`,现役写入侧几乎全写 `imageSequenceFrames: None`,实际只等于"媒体格式相等"),硬拦会误拒 `png ↔ webp` 这类最常见需求;要变成硬判据须先给 manifest asset 增尺寸字段并在写入侧回填(跨端契约变更)。
+- **入口**:资源卡选中工具条的宿主 `extraActions` 新增「替换素材」,判据复用现役 `isResourceUsedByCurrentVersion`(manifest 身份 + 被当前版本绑定),未绑定素材不渲染入口;不动 `ImageCanvasSelectedLayerToolbarAction` 共享 union、不改 `resourceCanvasToolbarModel` 的 `supportedActions`。候选弹窗复用 `ImageCanvasProjectAssetPickerDialog`(该弹窗在 AGC 侧首次使用),以可选 prop 扩展:`singleSelect` / `assetBlockedReasons` / `assetHints` / `renderAssetMedia` / `selectionNoun` / `errorMessage`,**默认值保持网页端美术画布行为逐字不变**。候选行渲染类型占位而不挂 ``(AGC 的预览要经带 scope 的原生调度器拿 Blob URL,弹窗内没有同步 `src`)。
+- **成功后行为**:重读 manifest,**不切换版本**(没有新版本可切),**不自动重载 / 重启运行中的预览**(PRD §3.2 末条),不做运行时资源重映射。可见变化只有资源卡「当前使用」高亮移到替换素材、`@` 面板「当前版本素材」更新。
+- **已知代价(用户已确认接受)**:**替换历史不可回溯**——替换前身份只剩那条审计与 manifest 的 `.previous` 副本;需要"某版本历史上换过什么"时要另立切片(PRD §3.2 / §5.3 保留为未来合同正是为此)。
+- **验证**:绑定改写通道定向 7 条(`project/manifest/version_binding_rewrite_tests.rs`)+ 替换定向 8 条 + `shared-contracts` 20 条。**变异验证**:① 去掉「未放行版本整条相等」→ 两周转红;② 放行集合改成整个版本数组 → 「未放行版本」转红;③ 去掉长度检查 → 「不增不删」转红;④ 准入删掉 category → 硬门禁与候选两条转红;另有 ⑤ 改回"原地改既有版本但绕过放行口"→ 被「项目版本记录写入后不可修改、删除或重排」拦下。前端 13 条(模型 9 + 真链路 4)。AGC 全量 1231 passed / 4 skipped / 0 failed;共享美术画布组件 1385 passed;`npm run ai-game-creator-shell:typecheck`(含 check-config)、`cargo check --locked --all-targets`、`npm run check:encoding`、`git diff --check` 全绿。`/api/external/v1`、SpacetimeDB schema、`packages/shared` 与 `shared-contracts` 的 wire DTO、manifest 结构、布局 sidecar schema 均未改动。
diff --git a/docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md b/docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md
index 6ae2a8c25..f6e486af5 100644
--- a/docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md
+++ b/docs/technical/【测试用例】AGC资源工作台V3端到端验收-2026-09-11.md
@@ -231,7 +231,7 @@ api-server 是否本次重启:□ 是  □ 否
 
 ### 7.3 已知未做 / 已取消(不要报成缺陷)
 
-1. **C6 的候选素材 / 替换关系 / 替换队列 / Agent 审核 / 批量提交整条取消**(#309)。PRD §5.3(L387 附近)的 `ProjectVersionResourceReplacement` 兼容性三项**不属于**该取消范围:2026-09-11 已按「改绑定 + 追加下一迭代版本」实施,入口在资源卡选中工具条,验收见 PRD §7.8。
+1. **C6 的候选素材 / 替换关系 / 替换队列 / Agent 审核 / 批量提交整条取消**(#309)。PRD §5.3 的 `ProjectVersionResourceReplacement` 与 §3.2 的「创建下一迭代版本」**当前不实现**(2026-09-11 用户 DDL 口径「替换这块先做成直接替换」),但**保留为未来合同**:今天的实现是「改该版本的绑定,不建新版本」,验收见 PRD §7.8。
 2. **画布生成入口只覆盖 3 类**(视频 / 音效 / 背景音乐);图片等类型会直接报"当前资源类型不支持无源生成",这是设计而非缺陷。
 3. **工具条 7 个动作按 opt-in 不渲染**:重绘 / 裁剪扩图 / 去背景 / 像素完美 / 切图集 / 提取 UI 素材 / 角色动画;只有 `快速编辑` 与 `下载` 真渲染(宿主另附加 `UI 编辑器` / `编辑标签` / `重命名`,以及**只在素材被当前版本绑定时**出现的 `替换素材`)。
 4. **C7 只做记录层 + UI 层**:切换版本即重载当前预览;版本化资源解析机制未实现。资源替换同样不做运行时资源重映射:改绑定只改「这个版本用哪些素材」的记录,运行画面要按游戏自身引用的资源路径渲染。
@@ -240,8 +240,10 @@ api-server 是否本次重启:□ 是  □ 否
 7. **重命名不改游戏源码中的旧 `assets/` 引用**。
 8. **C9 参考图弹窗在 AGC 侧入口未确认**:全仓检索 `添加参考图` 只命中共享 `src/components/image-editor/*`,AGC 的 `ResourceCanvasGenerationPanelView` 未引用它,可能处于"组件已实现、AGC 入口未接"状态。建议真机点一次生成 / 编辑面板确认;若无入口,C9 不计入本轮主线。**注**:资源替换复用同一个 `ImageCanvasProjectAssetPickerDialog`,它在 AGC 侧是首次使用(同一个弹窗、不同的 opt-in 参数)。
 9. **运行视图存在「点选素材」按钮**,但 #309 的"不做"清单包含运行画面点选,口径冲突待定。
-10. **替换成功后运行画面不会立刻变**:按 C7 与本轮口径只做记录层 + UI 层,可见变化是版本下拉多一条「资源替换」、资源卡"当前使用"高亮与 `@` 面板当前版本素材更新;这不等于替换失败。
+10. **替换成功后运行画面不会立刻变**:按 C7 与本轮口径只做记录层 + UI 层,可见变化是资源卡"当前使用"高亮移到替换素材与 `@` 面板"当前版本素材"更新;**不会新增版本卡、也不切换版本**,这不等于替换失败。
 11. **替换候选弹窗不加载缩略图**:AGC 的素材预览要经带 scope 的原生读取器拿 Blob URL,弹窗内没有同步 `src`,因此候选行只渲染类型占位(不给 `` 喂空串、不挂破图)。
+12. **尺寸规格差异只提示、不拒绝**:`sizeSpecEqual` 的完整判据今天不存在(manifest 无 `width / height / durationMs`,实际只等于"媒体格式相等"),所以同分类同类型的 `png ↔ webp` 替换是**允许**的,弹窗里只给「格式与源素材不同」的提示。
+13. **替换历史不可回溯**:直接替换不产生版本记录,替换前身份只剩一条 `asset.version_binding.replace` 审计与 manifest 的 `.previous` 副本。这是当前口径的已知代价,不要报成"缺少替换历史功能"的缺陷(版本级替换属未来合同)。
 
 ### 7.4 文档与代码的偏差(需明确按哪个判)
 
@@ -255,5 +257,5 @@ api-server 是否本次重启:□ 是  □ 否
 
 ## 8. 验收边界
 
-- 本用例覆盖:资源总览 / 栏目分页画布、资源卡预览与本地受控读取、资源卡选择与多选、快速编辑派生、画布生成入口(3 类)、编辑标签、重命名、下载、删除三分支、版本切换与当前使用高亮、**资源替换(入口放行判据 / 候选禁用与原因 / 写入载荷 / 拒绝零副作用 / 成功后切版本不重载预览)**、聊天 @ 引用与原子 chip、AI 润色与发送前提醒、本地预览启动与退出收尾、两份布局 sidecar 台账。
-- 本用例不覆盖(另走专项或定向测试):双窗口 CAS 冲突、大规模 fixture 性能、素材创作无限画布阶段一至五的草稿 / 事务 / 恢复矩阵(见 `【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 与配套专题)、UI 编辑器子路由、主站图片编辑器回归(见 PRD §7.7)。资源替换的 Rust 定向矩阵(只追加守卫、两条绑定路径、CAS、四条拒绝路径、读时自愈口径)见 `apps/ai-game-creator-shell/src-tauri/src/tests/version_resource_replacement.rs`,前端矩阵见 `apps/ai-game-creator-shell/tests/resourceVersionReplacement*.test.ts(x)`。
+- 本用例覆盖:资源总览 / 栏目分页画布、资源卡预览与本地受控读取、资源卡选择与多选、快速编辑派生、画布生成入口(3 类)、编辑标签、重命名、下载、删除三分支、版本切换与当前使用高亮、**资源替换(入口放行判据 / 候选禁用与原因 / 格式提示 / 写入载荷 / 拒绝零副作用 / 成功后不切版本不重载预览)**、聊天 @ 引用与原子 chip、AI 润色与发送前提醒、本地预览启动与退出收尾、两份布局 sidecar 台账。
+- 本用例不覆盖(另走专项或定向测试):双窗口 CAS 冲突、大规模 fixture 性能、素材创作无限画布阶段一至五的草稿 / 事务 / 恢复矩阵(见 `【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md` 与配套专题)、UI 编辑器子路由、主站图片编辑器回归(见 PRD §7.7)。资源替换的后端矩阵(版本绑定改写放行的六条不变式与两组互斥、绑定改写两条路径、硬门禁与提示、CAS、四条拒绝路径、读时自愈口径、审计留痕)见 `apps/ai-game-creator-shell/src-tauri/src/project/manifest/version_binding_rewrite_tests.rs` 与 `apps/ai-game-creator-shell/src-tauri/src/tests/version_resource_replacement.rs`,前端矩阵见 `apps/ai-game-creator-shell/tests/resourceVersionReplacement*.test.ts(x)`。