合并:同步最新master
Project CI / Repository checks (pull_request) Failing after 44s
Project CI / Frontend tests (pull_request) Failing after 2m51s
Project CI / Backend tests (pull_request) Successful in 5m29s
Project CI / Native shell tests (pull_request) Successful in 13m32s

合并 origin/master 最新提交 7b075df39
保留当前分支的 BGM 优化与共享音频面板方案

# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	docs/project-memory/shared-memory/pitfalls.md
#	server-rs/crates/api-server/src/editor_generation_queue.rs
#	src/components/image-editor/useImageCanvasGenerationSurface.tsx
#	src/services/image-editor/editorProjectClient.ts
This commit is contained in:
2026-08-06 03:10:30 +00:00
90 changed files with 12219 additions and 916 deletions
@@ -3047,7 +3047,7 @@
"type": "array",
"items": {
"type": "string",
"description": "当前账号的 objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS 再提交。禁止 Data URL / Blob URL。普通生成最多使用前 5 张,数组上限为 9。"
"description": "当前账号的 objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS 再提交。禁止 Data URL / Blob URL。普通生成最多 5 张;kind=quick-edit 时 gpt-image-2 最多 5 张、nanobanana2 最多 9 张。超限返回 400,不会静默截断。"
},
"maxItems": 9
},
@@ -3241,7 +3241,7 @@
"type": "array",
"items": {
"type": "string",
"description": "当前账号的 objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。"
"description": "当前账号的 objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。sourceImageSrc 占用 1 张 provider 容量,因此 gpt-image-2 最多再提交 4 张、nanobanana2 最多再提交 8 张;超限返回 400,不会静默截断。"
},
"maxItems": 8
},
@@ -3372,7 +3372,7 @@
"type": "array",
"items": {
"type": "string",
"description": "额外图标素材参考图的稳定引用:objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。最多 8 张。"
"description": "额外图标素材参考图的稳定引用:objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。referenceImageSrc 占用 1 张 provider 容量,因此 gpt-image-2 最多再提交 4 张、nanobanana2 最多再提交 8 张;超限返回 400,不会静默截断。"
},
"maxItems": 8
},
@@ -3496,7 +3496,7 @@
"type": "array",
"items": {
"type": "string",
"description": "额外 UI 素材参考图的稳定引用:objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。最多 5 张。"
"description": "额外 UI 素材参考图的稳定引用:objectKey、项目资源 ID 或素材 ID;本地临时图必须先上传 OSS。禁止 Data URL / Blob URL。sourceImageSrc 占用 1 张 provider 容量,因此 gpt-image-2 最多再提交 4 张、nanobanana2 最多再提交 5 张;超限返回 400,不会静默截断。"
},
"maxItems": 5
},
@@ -67,6 +67,39 @@
---
## 2026-08-05 game-chat 当前 ready child 对 manifest Pending 漂移保持活性
- 背景:ready scheduler 已为当前根 Run 持久化并启动 `code-prototype`,但并发 hydration 持有的旧 manifest 快照随后把该节点从 running 覆盖回 pending。父 Run 只读取 manifest 时会在 child 仍运行的情况下误判固定 Graph 已停滞并先行失败;child 完成门又因 pending 连续拒绝真实交付,最终耗尽 loop。
- 决策:父 Supervisor 的“是否调度新节点”和“是否等待已存在 child”必须分开。派生视觉需要父规划修复时可以暂停新调度,但只要当前最新且仍活跃的根 Run 下存在确定性 runId、正确父绑定且 durable journal 非终态的 ready child,父 Run 必须保持 `waiting-for-manifest-tasks`。game-chat child 仅在同一当前根 Run、确定性 runId、可信 scheduler source、正确父绑定、journal 仍为 queued/running 且不处于确认、用户输入或 reconciliation 时,容忍 manifest 的 pending 漂移并继续走全部产物、静态检查和试玩门禁。
- 失败关闭:GUI/CLI、旧父 Run child、终态 child、错误/伪造绑定、非确定性 runId、WaitingForConfirmation、WaitingForUserInput 和 needs-reconciliation 都不得借用该容忍;创建更新的根 Run 后,旧 child 立即失去父 DAG 活性与 pending 完成资格。
- 玩法连续性:既有美术增量任务可跨可信 Supervisor 入口回溯同 Session 的最近具体试玩场景;只跳过纯继续和既有美术接入语义,遇到更新的详细 Generic 新目标立即停止,避免从更老项目错误借用 `tetris-v1`。
- 验证方式:覆盖当前 game-chat child 的 running -> manifest pending 漂移仍保持 DAG 活跃并可完成投影;更新根 Run 后旧 child 被拒绝;派生视觉需要修复但已有 child 活跃时父 Run仍持久化等待;GUI child 继续拒绝 pending;GUI 创建俄罗斯方块后从 game-chat 接入既有美术仍使用 `tetris-v1`。
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`、`docs/project-memory/shared-memory/pitfalls.md`。
---
## 2026-08-05 增量接入既有美术时复用已验收 Graph 节点
- 背景:game-chat 增量指令“把 UI 和方块替换成美术资源”会重置七项首版 Graph,把已有且已验收的 `art-director / art-asset-plan` 重新打开。`art-asset-plan` 确定性快车道同时因图集已存在而返回零 action,child 完成门又要求 `assets/manifest.art.json` 相对本轮 baseline 发生变化,最终连续六轮得到同一 `unchanged-from-run-baseline` blocker 并耗尽 loop;这不是 Provider 故障。
- 决策:只有 game-chat 用户明确表达替换、接入、使用或复用美术资源,项目已有非占位游戏,且 art spec、透明图集、Canvas 登记、私有图集合同、四类切片与 art manifest 全部通过现有严格验收时,Graph reset 才保留 `art-director / art-asset-plan=completed`,只重新打开设计、代码和试玩节点。根 Supervisor 完成门仅对该合法复用场景豁免 `assets/manifest.art.json(unchanged-from-run-baseline)`;文件存在、JSON、Canvas、私有合同、切片和代码可见使用门禁继续执行,任一证据失效即撤销豁免。普通新游戏、全新/重做美术、否定使用或占位项目一律把美术节点恢复为 pending。
- 玩法连续性:合法增量美术接入从同 Session 的可信 Supervisor 历史根 Run 继承最近一个非 Generic 试玩场景;只跨过纯继续与既有美术接入语义,遇到更新的详细 Generic 新目标立即停止。例如 GUI 创建的俄罗斯方块转入 game-chat 继续使用 `tetris-v1`,不能因为本轮文字只描述 UI/美术而降级成 Generic,也不能跨过后来的新游戏目标借用旧场景。
- 禁止替代方案:不得增加 loop 次数掩盖冲突,不得递增虚构的产物版本号,不得覆盖 art manifest 扩展字段,也不得重放历史图片生成 action。
- 影响范围:`runtime_driver/game_chat_fast_path.rs` 的意图与既有美术验收、`runtime_protocol/autonomous_completion.rs` 的 Graph reset、父完成门和试玩场景继承,以及对应 Runtime 回归测试;不改变 Provider、图片生成接口或普通新游戏 Graph。
- 验证方式:回归必须证明明确复用时两项美术节点保持 completed、父完成门不再报告 art manifest baseline 未变化、俄罗斯方块场景保持 `tetris-v1`;删除任一切片后豁免立即失效。另以普通新目标和“全新美术”请求证明旧美术不能被认领。
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`、`docs/project-memory/shared-memory/pitfalls.md`。
---
## 2026-08-05 专业 Agent ready-task 必须先确认 durable start 再异步执行
- 背景:AI 游戏创作首波 `design-director / art-director / code-director` 已全部写入 queued 与 scheduled,但 scheduler 把 per-Agent 执行锁直接移交 fire-and-forget Tokio future 后就返回成功;其中一个 child 未首次 poll 时会永久停在 `pending / queued`,而 recovery 又因执行锁仍被该 future 持有而无法接管。Runner heartbeat 与进程均正常,单靠“进程存活 / 锁已移交 / scheduled 已写”不能证明任务开始。
- 决策:在实际持有执行权的 Runner/进程内,ready scheduler 必须先释放项目写锁,再同步完成 child 的 `pending -> running`、`turn.started` 和 started journal,随后才把已经启动的 state 与执行锁交给已确认开始轮询的独立 execution worker。同步启动或 worker 接管失败时,必须在仍持有 per-Agent 执行锁期间依次把 child 落为 failed、把 manifest Graph 节点投影为 failed,再释放锁并向 parent 返回调度错误;`autonomous_ready_task.scheduled` 仅是诊断审计,写入失败不得阻断 durable child 启动。只负责投递的 external client 继续释放本地锁并 wake External Runner,不在客户端冒充执行。
- 可观测性:用户界面的“疑似停滞”只是 Runtime 活跃度投影,不改写正式业务状态。`startedAt` 由新 Run 的 durable queued/start 时间写入,旧 Run 从完整 task journal 的同一 `sessionId + runId` 最早记录恢复;从最新 task record 构造的 fallback state 必须保持 `startedAt=0`,不能把最近进度或终态时间冒充开始时间。运行态超过 5 分钟没有父 Run 或当前关联专业 Agent 的新事件时提示静默时长;等待用户、等待确认、Provider retry、视觉资产、进程会话、pausing 和 paused 均排除。父 Run terminal 后持续时间只冻结在父 Run 自身最后活动,关联 child 的晚到收口事件不能继续增加父 Run 时长。
- 对账取消续跑:ready-task 的未知工具结果仍禁止自动重放;人工核对并取消旧 child 后保留 cancel tombstone,旧 child 与旧父 Run 都按真实 cancelled/failed 终态收口。后续同 Session、同 source、同有效任务语义的 Supervisor continuation 建立新完成合同时,只把 manifest 中能由历史 `needs-reconciliation -> cancelled` child 与 tombstone 共同证明的对应 failed 节点恢复为 pending,并生成全新 child Run;manifest 读取、failed 节点筛选、每任务一次的 child journal 索引、证据重验和最终写回必须位于同一项目写锁域。较新的无 child 父 Run 只有在 durable root journal 明确记录为“固定 Graph 在调度前已无法推进”时才能跨过;普通失败、scheduler 持久化前失败、无 tombstone、无 reconciliation 历史或不同任务语义均不得借用更老凭证隐式重试,也不得把旧 action、observation 或 child 伪装为 completed。
- 完成门性能边界:Canvas 视觉验收在源码同时没有 `import` 与 `export` 关键字时不运行模块依赖分析,必须保留纯 `export ... from` / `export * from` 重导出依赖;当前脚本既不含目标资产文件名、也不含任一已绑定 DOM 图片元素 ID,且对 JavaScript `\\xNN`、`\\uNNNN`、`\\u{...}` 等转义做候选解码后仍不含二者时,不运行完整 Canvas 数据流与函数可达性分析。转义解码不确定时必须保守进入 parser,以保留 computed `src` 和转义 DOM 方法名;词法预检不能把命中当作通过,存在候选时仍执行原 parser、semantic binding、解码后的属性/StringLiteral 路径、可达性与目标 Canvas 检查。
- 影响范围:AI 游戏创作 `runtime_driver/task_start.rs`、`task_queue.rs`、自主构建 continuation 合同、Supervisor 进度卡与相应 Rust/AppSurface 回归;不改变 manifest DAG、Agent catalog、Provider 路由或项目产物合同。
- 验证方式:不预占 child locks,真实一次调度三项首波任务,并在有界时间内证明每个逻辑 Run 至少写入 running/`turn.started`;重复调度不得新增逻辑 Run。前端固定时钟覆盖正常运行、子 Agent 新活动、疑似停滞、各类合法等待与 terminal 冻结。
- 关联文档:`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`、`docs/project-memory/shared-memory/pitfalls.md`。
## 2026-07-31 图集切片按需编码并批量确认持久化
- 背景:`2026-07-29 图集切片必须受前置容量和有界 CPU 保护` 收口了连通域数量与 CPU 并发,但切片仍在一次循环里全部裁剪并编码,最多 64 份 PNG 字节连同整张 RGBA 同时驻留内存;持久化又按切片逐个调用 procedure,N 片至少 2N 次写入外加一次 cohort 完成,任一片失败都会留下已确认的部分记录。手动拆分入口另有一处重复鉴权:`get_editor_project` 已经取回并定位了来源资源,随后仍走 `parse_editor_reference_image` 按注册 ID 再解析一次,触发全账号项目与素材库扫描。
@@ -6470,6 +6503,23 @@
- 身份与 telemetry 扫描只消费可渲染文本、可执行 inline JavaScript 和已链接外部 unit,排除 inert/raw-text、HTML 注释、带 `src` body 与非 JavaScript script。资产路径比较保持大小写,Linux 文件身份不得经 ASCII 小写副本合并。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs`、`docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`。
## 2026-08-05 game-chat Canvas 区间证明与 parent wake 持久收口
- Canvas 目的区域证明以 Oxc symbol、调用实参、计数循环和所属 Canvas 身份为权威。大 classic script 的调用图保持整轮 visited;函数内 alias 重绑定必须按作用域和写入位置解析。格子坐标无法进一步化简时只可在 `COLS × ROWS × CELL` 唯一合同下建模为完整棋盘轴区间,已知调用参数或循环边界优先,越界调用继续失败关闭。
- 动态坐标只新增一种受限可见性证明:未遮蔽的全局 `Math.min(currentCanvas.width|height - size, Math.max(0, dynamic))`。尺寸成员必须属于创建当前绘图 context 的 Canvas;其它 Canvas、被遮蔽的 `Math`、缺少上下界或普通未知动态坐标均不得作证。
- autonomous parent wake 的瞬态重试预算耗尽后必须形成 durable reconciliation。lane 忙时先写 deferred recovery signal;获得同一 execution lane 与项目写锁后,重新读取原始 Runtime state、最新 task、cancel tombstone 和 DAG 进展。只有仍指向同一非终态根 Run 时才能以 CAS 追加 reconciliation task 并原子替换 state;manifest 已损坏时也不能让普通 hydrated writer 先阻断对账证据。
- autonomous 测试夹具必须先建立带完整 parent/delegation identity 的 linked Pending child,再由正式启动路径写第一条 Running;禁止先启动无父身份再补 journal,也禁止把 terminal runId 复活成 Running。Completed-only 深验按任务逐项执行:Pending 任务不深验,但同一 manifest 中已 Completed 的美术任务仍必须验证其切片合同。
## 2026-08-05 game-chat 完成阻塞修复与 child 生命周期闭环
- code-prototype 只有在本人当前 Run 已有 `status=ok` 的真实 mutation action、对应 mutation revision 已通过 `game.static_smoke`,且完整 `runtime.autonomous_completion` 完成门无阻塞时,才允许快车道返回确定性交付或把结构化计划全部标为 completed。verification gate 的 mutation revision 可能因保守失效策略在失败 patch 前推进,不能单独证明文件已修改。若 static smoke 已过但完成门仍报告素材、正式产物或其它诊断,计划尚有未完成步骤时用单一 in-progress 修复步骤替换首个非终态步骤,并把其余非终态步骤保持 pending;计划已全 completed 且仍有容量时才追加修复步骤。这样既保留 completed 单调历史,也不会因 steer 合并后超过 8 步而永久卡在 `runtime.plan_update`;不得重复返回同一交付计划直至耗尽 loop budget。
- game-chat manifest 被旧 hydration 快照从 Running 写回 Pending 时,收束前只接受当前最新活跃根 Run、确定性 child runId、合法父绑定,并且当前 state 与 durable child 同为 Running;终态投影只接受两者同为 Completed。queued Pending、waiting、failed、needs-reconciliation、旧父 Run、伪造绑定和 GUI/CLI 继续失败关闭。
- mutation ownership 以当前 run 的最后一条同工具调用和 Agent DB receipt 为联合权威;pending action 的 `plannedSteerCursor` 必须在 recent tool-call 与 receipt 中使用同一 fingerprint。结构化计划含 failed 步骤时 code-prototype 立即失败关闭;8 个 completed 步骤仍有 blocker 时不追加第 9 步,改走只允许读取、真实 mutation 与重新验证的外部 repair lane。
- 当前根 Run 有 durable active child 时,即使 manifest 快照把全部 seed task 写成 Completed,DAG 仍保持 in-progress;任一 seed task 为 Failed 时继续立即失败关闭。所有项目修改在取得项目写锁后再次核对 ready child 的确定性 runId、父绑定、durable Running 状态和当前活跃根 Run;新根 Run 建立后旧 child 不得推进 revision 或修改文件。
- 大 classic game script 的 direct function invocation graph 只建立一次;单次可达性查询使用整轮不回退的 visited 集合,每个 function node 最多访问一次,禁止只用递归栈去环后在扇入图中指数回溯。Canvas alias 的全 `None` 历史直接返回,单一稳定祖先 scope 的初始化只在该 scope 最后一次写入前没有同步调用时采用顺序快路。可见 Canvas 的整画布 `canvas.width / canvas.height` 绘制与能由唯一数值 `const` 证明落在 `COLS × ROWS × CELL` 画布范围内的格子绘制属于有效目标;普通 `player.x / player.y` 等无界动态坐标仍失败关闭。
- 根 Supervisor 的 manifest completion gaps 只对 status 已为 Completed 的 seed task执行正式产物与 Canvas 深验;pending/running/failed 本身已经构成完成阻塞,禁止提前扫描后续波次。自动唤醒 200 次瞬态重试预算耗尽后必须写入 `needs-reconciliation`,不能静默返回并留下假运行状态。
- parent wake 的 terminal reconciliation task 是 durable commit marker,state / queue / event / Agent DB audit 是可幂等重建投影;非瞬态 task journal 读取错误直接失败关闭。restart 只在 raw state 具有完整 Agent/task/Session/run/source/profile/binding/task 身份时修复其当前 run;state 缺失、损坏、空对象或关键身份为空时只取 journal 最后 logical run,完整有效的新 Run 阻止历史 marker 覆盖。event/audit 必须完整 payload 唯一匹配,同键冲突或重复失败关闭;旧 task 终态、Runtime 非 waiting 或新 Run 接管时,durable deferred signal 追加 resolved/superseded 后才返回 obsolete。
## 2026-08-04 静态视觉状态流与可见证据收口
- Canvas、2D context 与图片变量统一按 semantic symbol 记录声明和整体赋值事件;重新指向离屏 Canvas、无效 context 或新图片时立即失效旧视觉身份,只有绘制点可证明的当前状态才作证。
@@ -6615,6 +6665,14 @@
- 影响范围:`useImageCanvasProjectPersistence.ts` 的 `flushProjectPersistence`。不改服务端、不改契约。
- 验证方式:既有用例「flush 等待封面缓存」翻转为「flush 不等封面、但封面链照常跑完并完成上传与资源登记」;新增「封面永不 settle 时 flush 仍返回」——用永不 resolve 的 blob 模拟 `new Image()` 不 settle,并断言 `createProjectCoverSnapshotBlob` 确实被调用过以防用例空过。已实证:回退修复后新用例报 `expected 'false' to be 'true'`。运行 `npx vitest run src/components/image-editor src/components/platform-entry src/services`(101 文件 / 1241 项)、`npm run typecheck`、`npm run lint:eslint`、`npm run check:encoding`。
## 2026-08-05 编辑器生成请求与参考图权威契约
- 主站编辑器生成 POST 不做浏览器自动重试,避免 inline 模式在响应丢失后重复调用 provider;api-server 仍使用独立 namespace + owner + job kind + request id 生成队列 `dedupe_key`,让显式复用同一请求标识的队列重放原子返回已存在任务,并对同键不同 payload 返回 `409`。外部 v1 的 `Idempotency-Key` 保持独立 namespace。
- 参考图数量以产品上限与 provider 容量的较小值为准,前端添加 / 上传 / 提交、api-server 入队与执行、`platform-image` provider 边界均明确拒绝超限;任何层都不再用 `.take(...)` 把第 N+1 张静默丢弃。角色 / UI 从一开始预留主图槽位;并发上传计入在途数量并在持久化前复验。任一参考图上传批次在途时锁定模型切换、画布选图、提交生成、关联源图删除 / 剪切 / 素材删除及生成面板切换 / 关闭,并以原面板上下文标识在持久化前后复验,完成或失败并释放 reservation 后才允许继续操作;批量部分失败时仍挂接成功项并刷新素材库。模型降容或后补主图会超限时拒绝操作并保留现有引用。
- 图片类最终 `generationInputs.references` 不信任客户端输入;队列 payload、完美像素及直接创建资源 / 素材入口删除客户端 references,worker / inline 路径按本次真实参考源与 owner 范围内的项目资源、账号素材重建 `refType/refId`。只有 owned objectKey 但没有正式行时不生成伪 provenance。完美像素继续使用升级前 canonical 客户端输入计算 operation fingerprint;新操作只持久化权威重建值,历史同 task/resource 重放复用服务端既存 metadata 通过精确比较。
- 升级前 External 幂等任务可能仍在 payload 中保留客户端 references;重放比较只对白名单内已迁移的图片生成、图片修改、去背景、图标图集和 UI 提取任务,在旧侧有 references、当前侧已删除时移除旧字段,其他字段变化仍返回 `409`。音频 / 视频 / 角色动作等未迁移 job kind 始终完整比较,不能扩大兼容面。
- 本次复用既有 `external_generation_job.dedupe_key` 唯一索引和 `spacetime-client` 查询,不改 SpacetimeDB schema、迁移或 bindings。
## 2026-08-06 音效与背景音乐恢复共享音频 Composer
- 决策:图片画布的 `audio-sound-effect` 与 `audio-background-music` 只保留一个 `ImageCanvasAudioGenerationComposerView`,组件内以 `isSoundEffect = dialog.mode === 'audio-sound-effect'` 分流。撤销的是完整 `ImageCanvasBackgroundMusicGenerationComposerView` 这一层视图拆分,不撤销 BGM Prompt 纯模型、助手 controller、预设模型或预设跑马灯的独立职责。
@@ -14,6 +14,45 @@
- 关联:相关文件、文档、提交或 Issue
```
## manifest 被旧快照写回 Pending 时不能让父 Run 抛下真实运行中的 child
- 现象:`code-prototype` 已有确定性 child run、running journal 和工具事件,父 Supervisor 却在几秒后以 fixed graph stalled 失败;child 随后完成代码与静态检查,但 completion gate 持续报告 `task=code-prototype status=pending`,最后 `loop-budget-exhausted`。
- 原因:并发 hydration 或其它旧 manifest 快照把 scheduler 已写的 running 覆盖为 pending;父 Run 把“当前不宜调度新 child”错误等同于“没有 child 需要等待”,并只以 manifest 状态判断 DAG 活性。父先终态后,真实 child 也失去正常投影窗口。
- 处理:调度与等待分离。新调度可以被派生视觉修复等门禁阻止,但当前最新活跃根 Run 下,只要 durable child 具有确定性 runId、scheduler source、正确父链接且 journal 仍处于 queued/running,父 Run 就继续等待;同一 child 的完成门可容忍 manifest pending,但仍执行正式产物、revision、静态检查与试玩证据门禁。更新根 Run、GUI/CLI、终态/确认/reconciliation child 或绑定冲突全部失败关闭。
- 验证:人工把当前 child 的 manifest 状态回写 pending,断言父 DAG 仍 in progress、父上下文可持久化为 `waiting-for-manifest-tasks`、child 可投影 completed;随后创建更新根 Run,断言旧 child 不再保持 DAG 活性且 completion blocker 恢复 `status=pending`。不要靠增加 loop 次数或伪造 completed 掩盖竞态。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/autonomous_policy.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/main_loop.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs`。
## 既有正式产物不能同时被快车道视为已完成、被本轮 baseline 门视为未变化
- 现象:增量任务已有完整美术图集,`art-asset-plan` 每轮都返回零 action 和“已验证交付”,但 completion gate 每轮都报告 `assets/manifest.art.json(unchanged-from-run-baseline)`;最终 child `loop-budget-exhausted`,随后 Graph 和父 Run 失败。日志中没有本轮 Provider request、tool plan 或 action receipt。
- 原因:Graph reset 无差别重新打开稳定的美术 owner 节点;快车道按“当前产物有效”判断完成,owner 完成合同则按“本轮必须修改 baseline 产物”判断完成,两套语义互相冲突。增加 loop 预算、伪造版本号或机械改写 manifest 都不能消除冲突,还会引入 verification loop、字段丢失或错误复用旧主题。
- 处理:先在 Graph 层区分“复用已验收产物”和“需要重新生成”。仅对明确的既有美术接入意图、非占位游戏和整套严格有效的视觉合同保留美术节点 completed;根完成门只忽略这一路径的 art manifest baseline 相同,所有结构、Canvas、私有回执、切片和可见使用验收继续失败关闭。普通新游戏、全新美术或证据损坏必须重新打开 owner 节点。
- 验证:不要只断言 child 未被调度;还要直接经过父完成门,证明合法复用不再出现 art baseline gap,并证明删除切片后 baseline gap 与视觉合同 gap 重新出现。另覆盖普通新目标和全新美术请求不复用旧美术。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/game_chat_fast_path.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs`。
## 执行锁移交给未确认启动的异步 future 会制造永久 queued
- 现象:父 Supervisor 与 Runner 一直显示运行中、heartbeat 正常,专业 Agent 已有 `background_task.queued` 和 `autonomous_ready_task.scheduled`,对应执行锁也被 Runner 持有,但该 child 永远没有 running journal、`turn.started` 或后续 Runtime event;其它同批 Agent 可能已经完成。
- 原因:ready scheduler 把 per-Agent 执行锁直接 move 进 fire-and-forget Tokio future,并在 future 首次 poll 前返回成功。锁移交不是启动确认;future 未进入 start transition 时,常规 wake/recovery 又拿不到同一把锁,queued task 因而没有任何接管者。预先占用 child locks 的测试会绕过真实 spawn 路径,无法发现该缺口。
- 处理:实际 Runner 必须在项目写锁外同步完成 pending -> running 与 started journal,成功且 execution worker 已开始轮询后才移交执行锁;启动/接管失败必须持锁完成 child failed 与 manifest Graph failed 投影,再释放锁并让 parent 收到错误。scheduled 诊断审计失败不能阻断 child 启动,external client 只负责 wake Runner。UI 另以 durable `startedAt` 和父/子最大活动时间显示运行态时长及疑似停滞;task-record fallback 不得把最新 record 时间写成 startedAt,父 Run terminal 后也不得被 child 晚到事件继续增加时长。
- 验证:使用真实空闲 child lanes 一次调度 `design-director / art-director / code-director`,在有界时间内逐一断言 running/`turn.started`,并验证幂等重调度不新增逻辑 Run;禁止只断言 scheduled 记录、锁文件或 Runner heartbeat。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/task_start.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_driver/task_queue.rs`、`apps/ai-game-creator-shell/src/features/project-workspace/SupervisorChatOnlyView.tsx`。
## Canvas 视觉门不能在没有资产词法候选时运行整套 JavaScript 语义分析
- 现象:Supervisor 已写入 `turn.started`,但第一条 planning 进度长期不出现;Runner 无 Provider 连接,单个 Tokio worker 持续占满一核。对项目现场复现时,15 KiB 的经典脚本在检查一个根本未被引用的切片文件时,超过 60 秒仍未返回。
- 原因:视觉门先为每个候选切片无条件执行模块依赖分析和函数可达性分析,最后才判断图片 `.src` 或已绑定 DOM 元素是否能指向目标资产。没有 `import` 关键字、没有目标文件名且没有已绑定图片元素时,这些全程序分析不可能产生有效视觉证据,属于纯浪费;复杂闭包与 alias 图会把浪费放大成看似 Runtime 停滞。
- 处理:仅做单向安全短路:JavaScript 原文同时没有大小写精确的 `import` 与 `export` 字节序列时,跳过模块依赖语义分析;纯 `export ... from` / `export * from` 仍是模块图依赖,不能误跳过。当前脚本不含目标文件名或任一已绑定 DOM 图片元素 ID 时,先低成本解码 `\\xNN`、`\\uNNNN`、`\\u{...}`、简单转义和续行;解码后仍无候选才直接判定没有绘制证据,解码不确定则保守进入 Oxc。这样必须保留 computed `s\\x72c`、转义资产 URL 与转义 `getElementById/querySelector`,同时不能因 HTML 中存在某个绑定元素让所有无关 JavaScript 单元进入重分析。
- 验证:无候选现场的同一切片检查必须有界返回且保持 `missing-visible-art-slice-use` 结论;同时覆盖相对路径、转义 URL、computed/转义属性与 DOM 方法、绑定 DOM 图片元素、含无关正则转义的脚本单元、路径大小写、纯重导出模块图、动态 import namespace 写入、未调用函数、恒假分支和真实可达 `drawImage`,证明短路只拒绝不可能命中的输入,不扩大验收权限。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs`。
## ready-task 对账取消后不能让 successor 永久继承 failed Graph
- 现象:未知工具结果按安全边界进入 `needs-reconciliation`,人工核对后取消原 child;manifest 随即把该节点投影为 failed,父 game-chat 固定任务图明确失败。随后重试父 Run 虽创建同源 successor,却原样继承 failed manifest,几秒内再次失败,原项目无法继续。
- 原因:取消原 reconciliation Run 只负责安全释放 Agent 队列屏障,并不等于 manifest 任务完成;continuation 完成合同保留既有 Graph 进度,却没有区分“普通失败”和“已经人工核对、保留 cancel tombstone 的 reconciliation 取消”。
- 处理:旧 action 继续禁止重放或伪造 observation;旧 child 与父 Run 先真实终态。新 Supervisor continuation 仅扫描同 Session、同 source、同有效任务合同的历史根 Run,并要求对应 ready-task 同时存在 `failed / needs-reconciliation` 记录、最终 `cancelled` 记录和 durable cancel tombstone,才把当前 manifest 的同一 failed 节点恢复为 pending,让 scheduler 创建新 child Run。manifest 的读取、筛选、child 证据重验和写回放在同一项目写锁内;每个 task journal 只读取一次并按 parent Run 建索引。较新的无 child Run 默认阻断旧凭证,只有其 root journal 精确证明为旧 failed Graph 在进入 scheduler 前即失败时才允许向前查找;scheduler 自身失败不得被当成该兼容场景。
- 验证:构造 reconciliation child、人工 cancel tombstone、failed manifest 和终态父 Run,证明同源 continuation 只重排该节点;并列普通 failed 节点保持 failed,完成合同继续继承原任务 SHA 与项目 baseline,旧 pending action 不恢复。追加覆盖“旧 failed Graph 未调度”的中间 Run 可以跨过,而较新的 scheduler failure 即使没有 child journal 也会阻断更老 tombstone。
- 关联:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion_contract_tests.rs`。
## `timeout_at` 不能替代显式的预算耗尽预检
- 现象:给完美像素加端点级并发闸后,预算已经耗尽的请求仍然能拿到许可,白占一个名额继续去打几轮全账号 SpacetimeDB 扫描,直到下载那步才失败。
@@ -4160,6 +4199,38 @@
- 处理:使用完整 JSON Schema validator 校验原始 catalog schema,不手写 required/type 子集;native parser、fingerprint enrichment 与实际 MCP 调用边界复用同一校验器。enrichment 错误必须映射回 classified `arguments-schema` repair,不能以普通字符串直接终止 run;执行点重验用于阻断升级前已经落盘的 schema 外 pending。关闭网络和文件 `$ref` 解析,schema 无法安全编译时不广告或不执行。`serde` 类型错误会包含实际字符串值,catalog miss 也会包含模型提交的 server/tool,因此这两类错误同样只能返回稳定类别,不能拼接原始错误、参数值或 schema 内容。
- 验证:覆盖 required、additionalProperties、type、enum、本地 `$defs/$ref`、HTTP/file 外部引用、无效 schema、错误脱敏,证明 legacy wrapper 在注入 fingerprint 前进入 repair,并证明带旧有效 fingerprint 的历史 pending 在实际调用前仍被 schema 拒绝。
## 2026-08-05 不要把 static smoke 当作完整专业交付
- 现象:code-prototype 已通过 `game.static_smoke`,但完成门明确报告 `missing-visible-art-slice-use`;随后每轮 thinking summary 都是“已取得验证证据”,没有新 action,最终 loop-budget-exhausted。
- 根因:game-chat 快车道只看 verification gate 就返回确定性交付,完整 autonomous completion blocker 直到空 action 的最终收束阶段才被发现;Provider 因而永远拿不到下一轮修复机会。失败的 `file.patch` 也会因验证凭证保守失效而推进 revision,若快车道只比较 `mutationRevision`,会把“文件未修改”误认成本 Run 已修改。已有未完成计划收到 steer 后若再追加一整套新步骤,还会与 retained completed 步骤合并成超过 8 步,随后稳定重复 `runtime.plan_update blocked`。
- 处理:确定性交付与自动 plan completion 都必须先通过完整 completion gate,并要求当前 Run 最后一条同 mutation 工具调用与 Agent DB 中严格绑定当前身份的 `status=ok` receipt 一致;pending action 的 steer cursor fingerprint 也必须一致,失败 patch 或旧 Run receipt 不能取得交付资格。新 blocker 不回退旧 completed 步骤:已有非终态步骤时用明确 repair step 替换首个非终态步骤,其余保持 pending;只有全 completed 且仍有容量时才追加。8 步已满时进入外部 repair lane;计划已有 failed 步骤时立即失败关闭。回归同时覆盖失败 patch、跨 Run receipt、非零 steer cursor、8 个 completed 与 blocker,以及 failed plan 在 ownership/blocker 不同组合下都不会继续空转。
## 2026-08-05 Runtime 时间戳必须验证 Date 范围并保持来源身份
- 现象:极大但有限的持久时间值会让 `toISOString()` 抛 `RangeError`,或让界面显示 `Invalid Date`;实时回复又借用其它 Runtime 的最近活动时间,文字继续流入时仍显示几分钟前,缺失时还随前端定时器漂移。
- 处理:秒/毫秒归一化后必须再检查 `Date#getTime()`;不可表示的值统一显示“时间未知”并省略 `datetime`。实时回复只使用 response stream 自己的 `updatedAt`,不能借父/子 Runtime 活动时间或 `Date.now()`。
## 2026-08-05 Pending manifest 容错必须覆盖真实终态时序
- 现象:手工把内存 state 改为 Completed 的测试通过,但真实 finalization 先写 durable Completed、再投影 manifest 时仍被 Pending 状态门拒绝;或 stale manifest 全 Completed 后,父 Run 忽略仍在运行的真实 child。
- 根因:测试没有写 durable terminal record,Pending 容错只验证了非终态 journal;DAG 又把 manifest `completed=true` 放在 active child 之前。终态投影和收束前检查使用了不同事实时序。
- 处理:测试必须按真实顺序分别写 durable Running 和 durable Completed。Pending 漂移只允许 state/journal 的 Running-Running 或 Completed-Completed 对;queued/waiting/failed/reconciliation 一律拒绝。active child 在无 Failed 时独立保持 DAG 活跃,项目 mutation gate 在写锁内核对当前 root,防止旧 child 污染新根 Run。
## 2026-08-05 Canvas 可达性不能在扇入调用图中回退 visited
- 现象:game-chat 的 code-director 长期显示 queued,Runner 单核持续高 CPU,durable cancel 也无法被事件循环处理;manifest 已提前显示 running,用户看起来像“稳定卡死”。
- 根因:大 classic script 虽使用了 bounded direct-call graph,但 `javascript_named_function_is_reachable` 在递归返回时删除 visited,只阻止当前环,不记忆已经遍历的祖先。render/update 图的大量重复调用让同一节点指数重算;父完成门又在 code-prototype 未完成时提前深验四个 Canvas 切片,使第一次 wake 就同步阻塞,200 次外层重试预算完全没有机会推进。
- 处理:单次可达性查询每个 function node 最多访问一次;全 `None` alias 历史直接返回,稳定外层初始化使用有调用前置证明的快路。父完成门只深验 Completed seed task,wake 预算耗尽写入 reconciliation。格子游戏的符号坐标只在唯一数值 `COLS / ROWS / CELL` 与画布范围能共同证明时接受,普通无界动态坐标继续拒绝。
- 验证:永久 fixture 至少包含 48 层重复扇入调用、IIFE 外层素材初始化、格子常量绘制、无界坐标反例和整画布尺寸引用;真实项目的全部四个切片还要在同一轮秒级返回 true。禁止用延长 queued timeout、Tokio timeout 或 synthetic 小脚本通过来替代真实大脚本复验。
## 2026-08-05 Canvas clamp 与 parent wake 不能走字符串或易失兜底
- 现象:通用 game-chat fallback 明明把玩家坐标限制在当前 Canvas 内,完成门仍报 `missing-visible-art-slice-use`;反向放开任意动态坐标又会让离屏绘制或错误 Canvas 假通过。
- 根因:Canvas owner 收紧后正确禁用了含尺寸成员的字符串兜底,但 AST 数值区间器尚不认识嵌套 `Math.min / Math.max` clamp。若只查源码包含 `canvas.width`,无法证明该 Canvas 创建了当前 context,也无法排除局部伪造 `Math`。
- 处理:只在 semantic 证明未遮蔽全局 `Math`、上界读取当前 context 所属 Canvas、下界为 `0` 时生成有限区间;加入错误 Canvas、遮蔽 Math 和无界坐标负向回归。不要用字符串包含、变量名白名单或把未知动态值当 `0`。
- 现象:parent wake 的 200 次瞬态预算耗尽后 Runtime 仍长期显示 running,或 lane 忙、取消、child 前进、manifest 损坏时 reconciliation 被静默丢弃或覆盖新状态。
- 处理:预算耗尽错误必须向上传递;lane 忙先持久化 deferred signal,再在 lane + 项目锁内重检最新事实。结构损坏路径使用不依赖 manifest hydration 的专用 journal/state 写入,CAS 失败转为继续对账,绝不覆写并发取消或 DAG 进展。可解析的空对象/空 runId 仍是损坏身份,只有完整有效的新 Run 才能阻止旧 marker;event/audit 的同键记录必须完整比对并拒绝冲突或重复。旧 task 已终态、Runtime 非 waiting 或新 Run 接管时,deferred signal 必须写 resolved/superseded,不能留给后续 wake 永久重复 settle。
- 测试注意:autonomous child fixture 先 linked Pending、后正式 Running;终态 runId 必须拒绝复用。判断 Completed-only 诊断时按每个 seed task 的实际状态分析,不能因为 `code-prototype` Pending 就忽略已经 Completed 的 `art-asset-plan` 深验。
## macOS 安全路径测试必须使用规范化临时目录(2026-08-05)
- 现象:调用仓库上下文、Runtime context bundle 或 pending recovery 的 Rust 测试在 macOS 报“Repository root and its ancestors must not be symbolic links”,Linux CI 却可能通过;本地 HTTP 恢复夹具在完整串行测试中还可能偶发 `WouldBlock`。
@@ -4202,6 +4273,13 @@
- 处理:全部全局 sink 测试共用一把 test-only 串行锁,并由 RAII guard 在 `Drop` 中无条件清空;测试统一使用 `manifest_invalidation_sink_isolation_` 前缀。relay fixture 对 accept 和 payload 分别使用非阻塞轮询与总 deadline,不使用固定 sleep;生产 loopback、token、连接 / 写入超时和 payload 大小校验保持不变。
- 验证:用 `--test-threads=2` 重复运行统一 filter,覆盖正常 relay、无事件 accept 超时、不完整 payload 超时、panic 展开清理,以及 GUI owner attach 配置与 guard 清理。
## 编辑器生成不能把传输重试、参考图截断和客户端 provenance 当成独立小问题(2026-08-05)
- 现象:生成 POST 首次已经入队但响应丢失时,客户端自动重试产生第二个任务;第 6 张或更多参考图仍显示在 UI / 元数据里,却没有送给 provider;直接构造请求还能把任意资源 ID 写成最终素材引用。
- 原因:客户端虽在重试中复用 `x-request-id`,队列入口却用随机 job id 生成 dedupe key;前端允许无限追加,api-server 和 provider 用 `.take(...)` 静默截断;`generationInputs.references` 被当成可信持久 provenance。
- 处理:主站生成 POST 禁止自动重试,把显式复用的稳定 request id 接到队列唯一键并校验 replay payload;所有边界显式拒绝超限,前端还要预留主图槽位、统计在途上传,并在上传完成前拒绝模型切换、画布选图、提交生成、关联源图删除 / 剪切 / 素材删除和面板切换 / 关闭;reservation 必须绑定原面板上下文,批量部分失败时不能丢弃已经持久化的成功项。入队、完美像素及直接创建资源 / 素材时删除客户端 references,执行时按真实参考源和 owner 资源记录重建权威引用。历史任务比较必须兼容仅差已删除 references 的旧 payload,不能只保留旧 hash 却让 payload 比较误报冲突。
- 验证:覆盖同键同 payload / 不同 payload、普通图片第 6 张、带主图的 GPT-image-2 第 5 张额外引用、provider 6 / 15 张边界、伪造引用删除和 owned 资源 / 素材重建。
## 共享音频 Composer 架构冲突不能按单行选边(2026-08-06)
- 现象:master 的音频 composer 同时承载 SFX 与 BGM,并在组件内定义 `isSoundEffect`;功能分支把 BGM 拆成独立组件后,原组件变成 SFX-only。合并时只把 master 的条件占位表达式带回 SFX-only 组件,没有带回变量定义,最终在测试渲染阶段报 `isSoundEffect is not defined`。
@@ -34,6 +34,10 @@
- 画布底部工具栏 / 面板 Dock 提供“画布 Agent”入口。点击后打开右侧独立 Agent 对话面板;桌面端为右侧窄面板,移动端占满可用宽度。该面板只与右上角任务侧栏互斥;素材 / 图层侧栏允许与 Agent 同时展开,切换左侧栏不得关闭 Agent。Agent 面板不得在当前画布内容下方追加内联内容,也不默认展示大段功能说明文案。
- 所有会新建画布生成占位的入口必须先创建 draft,再统一经过 `ImageCanvasGenerationPlacementModel` 计算落点,禁止各入口自行使用当前视口中心裸坐标或原图右侧固定偏移。当前覆盖入口包括 `生成图片`、`生成规范`、`生成角色形象`、`生成图标素材`、`生成视频`、`生成UI设计图` 和 `生成角色动作`。placement 模型的避让对象为所有未隐藏画布图层,以及当前 active / inactive generation dialogs 中仍存在的 placeholder;每个避让矩形按 32px 画布世界坐标间距外扩。候选落点以当前视口世界中心为距离目标,优先选择离视口中心最近且不重叠的占位位置;若中心被占用,会按上下左右和环形候选继续寻找。打开生成面板时必须把避让后的 placeholder 写入 `openCanvasGenerationDialog(...)`,并立即调用 `centerViewportOnPlacement(...)` 居中到新占位中心,保持原 viewport scale 不变;图片快速编辑不属于新建占位入口,提交后覆盖源图。
- `generationInputs.references` 的 `refType/refId` 是服务端权威行引用:客户端提交的 references 只属于非权威展示候选,api-server 入队及直接创建资源 / 素材时删除,生成执行时按真实参考图和当前 owner 的资源 / 素材记录重建后再持久化;裸 owned objectKey 找不到正式资源或素材行时可以参与生成,但不得制造伪引用。`title/label` 只作为展示快照,不提升为资源身份。
- 普通图片生成最多选择 5 张参考图;带主图 / 规范图的图片修改、图标素材和 UI 素材提取需要从打开面板起预留这 1 张主引用,再与 provider 容量取最小值(GPT-image-2 总计 5 张,nanobanana2 总计 14 张)。画布选择、上传和最终提交都必须阻止第 N+1 张进入请求;并发上传要把在途批次计入容量,并在创建项目资源 / 账号素材前按最新模型复验。reservation 必须绑定发起上传的 dialog / 快速编辑 / UI 提取上下文;任一参考图上传批次在途时,所有图片模型切换、从画布添加主图 / 规范图 / 参考图、提交生成、删除 / 剪切关联源图、删除其来源素材以及生成面板切换 / 关闭都要明确拒绝,批次持久化前后还要复验上下文未变化。批次部分失败时要保留并挂接已经成功持久化的引用,不能因其中一项失败而丢弃整批成功项;完成或失败并释放 reservation 后才允许继续操作。模型降容或后补主图若在操作当下已经超限,应保留原模型 / 原参考图并明确提示用户先删除,不得用 `slice` 静默丢弃;旧 dialog 或直接 API 请求由后端返回明确超限错误。
- 主站编辑器生成 POST 在浏览器端不自动重试;队列模式仍按同一 `x-request-id` 幂等重放,External v1 使用显式 `Idempotency-Key`。inline 模式没有结果级幂等时,不得因 408 / 429 / 5xx 或传输异常自动再次调用 provider。
### 静态图片风格与像素规整边界
- 普通 `生成图片`、`生成角色形象` 和 `生成图标素材` 三个面板增加紧凑的 `像素艺术` 勾选项;移动端可独占一行,但不增加功能说明文案。当前生成对象以 `style: "none" | "pixelArt"` 保存选择并随现有请求 / 队列 payload 传递;该字段不写入用户可见 `generationInputs`,也不新增素材元数据字段。其它生成、编辑、UI 素材提取、角色动画及画布 Agent 入口不展示或设置该选项。
@@ -33,6 +33,11 @@
- 启动诊断:独立 release 的 `startup.log` 和 `agent-runner.log` 只记录有界、脱敏的阶段与 stdout / stderr 摘要,凭据、AppData 路径和其它绝对路径不得原样落盘;单文件达到 256 KiB 后只轮转保留一份 `.previous.log`。`startup.log` 优先写独立 AppData,目录不可写时回退到系统 TEMP 下的 `Genarrative-Game-Chat-Diagnostics`;Tauri context、窗口 URL、AppData、Runner 或 `.setup()` / `.build()` 初始化失败时,Windows 必须显示可见错误对话框并给出诊断日志位置,不能只在无控制台 release 中静默退出。
- 对话与事件:窗口固定使用 `project-supervisor + autonomous-game-build`,继续复用 active Session、External Runner、持久 conversation、流式回复、same-run steer、工具确认与用户追问。以 `/` 开头的输入必须继续走现有内置命令解析,例如 `/preview` 只能生成 `preview.start` 确认卡,不得作为自主构建任务投递给 Supervisor。界面聚合当前 Supervisor 父 run 及其直接委派专业 Agent 的最新原始事件,按时间倒序稳定去重并标注 Agent;默认显示 4 条,可展开至最新 20 条。原始 `summary / detail` 仍只作 Runtime 状态投影,不直接写入 conversation。需要进入聊天的事件必须由 Rust 同步生成唯一 `eventId` 与安全 `publicText`;前端只按这两个字段形成独立 assistant 消息,无 `eventId`、空 `publicText`、legacy 事件和内部 tool / Provider / Runner 协议一律忽略。
- Supervisor 进度播报:聊天消息流内保留且只保留一条当前 run 的 Runtime-owned 播报卡,由客户端从 manifest 任务图、Supervisor 结构化计划、`loopIteration`、当前动作、直接委派专业 Agent 及其持久事件确定性整理;显示当前轮次、任务 / 计划进度、活跃 Agent、最近试玩与静态检查、返工决定、代码修改和截图检查证据。同一 run 原位更新,切换 run 时替换,不调用额外模型、不追加持久 conversation,也不改变最终 assistant 回复的唯一性;任意详情必须有界且不展示绝对路径、Provider 元数据或内部指纹。
- ready-task 启动活性:`background_task.queued`、`autonomous_ready_task.scheduled`、Runner heartbeat 或执行锁已移交都不等于 child 已启动。实际持有执行权的 Runner 必须在释放项目写锁后同步写入 child 的 running task、`turn.started` 与 started journal,再把已启动 state 和 per-Agent 执行锁交给已确认开始轮询的独立 execution worker;同步启动或 worker 接管失败时,要在仍持有执行锁期间依次把 child 和 manifest Graph 节点明确落为 failed,再释放锁并让 parent 收到调度错误。`autonomous_ready_task.scheduled` 只作诊断审计,其写入失败不能阻断 durable child 启动;external client 只 wake Runner,不在客户端抢占执行。Supervisor 进度卡通过 durable `startedAt`(旧 Run 从完整 task journal 恢复,最新 task-record fallback 保持 0)显示真实持续时间,并以父 Run 与当前关联专业 Agent 的最大事件时间计算运行态活跃度:运行超过 5 分钟无新事件时显示“运行中 · 疑似停滞”和静默时长;等待用户、等待确认、Provider retry、视觉资产、进程会话、pausing 与 paused 不误报。父 Run terminal 后,持续时间冻结在父 Run 自身最后活动,不随 child 晚到收口事件增长。消息时间统一校验为 JavaScript 可表示的 Date;越界值显示“时间未知”且不写无效 `datetime`。实时回复只显示 response stream 自己的 `updatedAt`,缺失时同样显示“时间未知”,不能借用其它 Runtime 活动时间或随前端时钟漂移。该提示只提供可观测性,不改变 Runtime/manifest 正式状态。
- ready-task manifest 漂移:父 Supervisor 必须分别判断“能否调度新节点”和“是否存在必须等待的工作”。派生视觉需要父规划修复时不再调度新 child,但当前最新且活跃的根 Run 下,只要存在确定性 runId、scheduler source、正确父绑定且 durable journal 为 queued/running 的 ready child,父 Run 就保持 `waiting-for-manifest-tasks`,不能因旧 hydration 快照把 manifest running 覆盖成 pending 而提前 fixed-graph-stalled。game-chat child 可在相同严格身份下容忍 pending 漂移;正式产物、Canvas、revision、`game.static_smoke` 与 `preview.validate` 门禁不放宽。GUI/CLI、旧父 Run、终态、确认/用户输入/reconciliation、伪造绑定或非确定性 runId 全部失败关闭;更新根 Run 后旧 child 不得继续维持新 DAG 或投影完成。
- 增量既有美术复用:game-chat 用户明确要求把 UI、方块或当前画面替换、接入、使用或复用美术资源时,只有项目已有非占位游戏,且 art spec、透明图集、Canvas 登记、私有图集合同、四张语义切片和 art manifest 全部通过严格验收,Graph reset 才保留 `art-director / art-asset-plan=completed`,重新打开设计、代码和试玩节点。根完成门只在同一合法复用条件仍成立时忽略 `assets/manifest.art.json(unchanged-from-run-baseline)`,其余产物、视觉合同和代码可见使用验收不放宽;任一切片或私有证据损坏后豁免立即失效。普通新游戏、明确要求全新/重做美术、否定使用旧美术或占位项目必须把美术节点恢复 pending。该增量任务从同 Session 的可信 Supervisor 历史根 Run 继承最近的非 Generic 试玩场景,只跳过纯继续与既有美术接入语义,遇到更新的详细 Generic 新目标立即停止;GUI 创建的俄罗斯方块转入 game-chat 后仍使用 `tetris-v1`,但不能跨后续项目目标借用更老场景。不得以增加 loop 预算、伪造产物 revision、机械改写 manifest 或重放历史图片 action 代替 Graph 语义修复。
- ready-task 对账取消续跑:未知工具结果仍停在 `needs-reconciliation` 且禁止自动重放;人工核对后显式取消原 child,保留 cancel tombstone,旧 child 和旧父 Run 按真实终态收口。若随后创建同 Session、同 Supervisor source、同有效任务语义的 continuation,新完成合同只对同时具有历史 `failed / needs-reconciliation`、最终 `cancelled` 和 durable tombstone 的 ready-task,把当前 manifest 对应 failed 节点恢复为 pending,并由 scheduler 创建全新 child Run。manifest 的读取、failed 筛选、每任务一次的 child journal 索引、证据重验和写回必须位于同一项目写锁域;较新的无 child 根 Run 只有在 durable journal 精确表明为旧 failed Graph 在进入调度前即失败时才能跨过,scheduler 自身失败必须阻断借用更老 tombstone。普通失败、无 tombstone、不同 source/Session/任务语义或证据冲突均保持失败关闭;不得复活旧 pending action、补造 observation 或把取消任务标成 completed。
- 完成门静态分析预算:Canvas 视觉门必须先做只会提前拒绝的词法预检。经典或模块脚本同时不含大小写精确的 `import` 与 `export` 字节序列时,不运行模块依赖语义分析;纯 `export ... from` / `export * from` 仍须进入正式模块图分析。当前脚本不含目标文件名或任一已绑定 DOM 图片元素 ID 时,先低成本解码 `\\xNN`、`\\uNNNN`、`\\u{...}`、简单转义和续行;解码后仍无候选才不运行完整 Canvas alias / 函数可达性分析,解码不确定则保守进入 Oxc。存在任一候选时仍执行原 parser、semantic binding、解码后的 computed 属性/StringLiteral 路径、可达 `drawImage`、可见 Canvas、路径大小写和动态 namespace 写入门禁;HTML 中存在某个绑定元素不得使所有无关 JavaScript 单元进入重分析,禁止把词法命中当作通过条件。
- Provider 故障展示:Provider retry 的“是否可重试”继续使用 `upstream-5xx` 等稳定类别判断,但 durable retry record 保留安全的精确 `upstream-<HTTP status>` 身份。等待态必须从真实 record 显示 HTTP 状态、`nextAttempt/maxRetries` 与当前持久退避剩余秒数,例如“Provider 上游返回 HTTP 503,准备自动重试 1/3;预计 8 秒后重试”;不得以动画或前端自增计时伪造 attempt。重试耗尽的 Runtime 私有错误只保存 `kind/httpStatus/fingerprint/chars/retryAttempt/maxRetries/retryState`,前端和持久 conversation 仅在字段顺序、范围、状态一致且无尾随正文时派生“上游服务返回 HTTP 503;自动重试已耗尽(3/3)”;其它错误使用固定安全摘要。Provider 响应正文、URL/query、凭据、本地绝对路径、fingerprint、字符数和 `[redacted ...]` 占位符均不得进入用户可见消息。
- 跨轮阶段记录:game-chat 父 run 进入真实 completed / failed / cancelled 终态后,客户端等待 `design-director / art-director / art-asset-plan / code-director / code-prototype / preview-readiness / preview-playtest` 七项首版任务也全部投影到 completed / failed 终态,再把本轮、任务 / 计划完成度、最新试玩 / 静态检查、最近返工决定和已登记成果图片路径整理成一条 `【Supervisor 阶段记录】` 项目 assistant 消息。父 run 先终态而 manifest 仍在 hydration 时不得用陈旧 `0/7` 提前归档,要暂存终态 Runtime 并在 manifest 刷新后重试。页面初始 hydration 若直接读到缺少阶段记录的真实终态 run,也必须补写,但 `idle` 不是可归档终态。每个“项目 + 父 run”最多追加一次,进入现有 `conversation.write` 权限与项目 conversation 持久化链路,下一轮及重载后继续保留。阶段记录不是 Supervisor Runtime 正式回复,不写入 Agent Session、不增加 final assistant 数量,也不逐条复制原始事件或内部正文。
- 图片成果:当前 manifest 新增或恢复已登记的 PNG / JPEG / WebP 资源时,聊天消息流同步显示 Runtime-owned “Supervisor 成果图片”卡,最多展示最新 4 张并随 manifest 原位更新。图片必须通过现有 `read_local_project_image_preview` 读取,只允许当前授权项目中 `assets/` 下的已登记资源,继续执行 `file.read` auto 权限、真实格式、大小、尺寸、普通文件、祖先目录和项目根边界校验;前端只接受返回路径、媒体类型和 `data:` 前缀与请求完全一致的结果。缩略图点击后使用独立模态查看器,支持按钮与滚轮缩放、指针拖拽、双击 / 按钮复位、Esc / 按钮 / 遮罩关闭,移动端占满视口;不得在聊天卡下方追加展开区。图片卡不写入 conversation,不解析 assistant 文本中的任意 Markdown / 绝对路径,也不开放 `.agent` 验收截图读取。
@@ -893,6 +898,15 @@ game-project/
- game-chat release 在 `CloseRequested / ExitRequested` 前复用 Runner durable idle probe;只要存在 process session、pending/finalization/provider/tool-plan handoff 或非终态 Agent queue/phase,就阻止关闭并提示先完成、暂停或取消。不可撤销的最终 `Exit` 不再作为唯一保护点,Windows Job Object 的 child-owned 安全边界保持不变。
- 规范 Agent 默认推理档覆盖全部 21 个角色:核心规划、生成、设计/美术/代码原型和质量角色使用 `high`,协调与结构化交付使用 `medium`,确定性预览 gate、音频总监和发布策略使用 `low`;显式 `agentLlm.<id>.reasoningEffort` 始终最高优先。规范默认由 Runtime resolver 解析,模板与 GUI 初始草稿保持 `agentLlm` 为空,避免默认值被误判成角色独立 LLM 路由;GUI 必须显示每个角色的实际默认档。全局与逐 Agent status/CLI 必须同时显示实际解析后的 reasoning、request timeout、max retries 和 retry backoff,区分运行快照与后来配置。
## 2026-08-05 game-chat 修复计划与 manifest child 生命周期补充
- code-prototype 的确定性交付需要同时满足当前 Run 存在 `status=ok` 的真实 mutation action、本人当前 mutation revision 的 `game.static_smoke=passed` 与完整 autonomous completion gate 无阻塞;失败 patch 即使因保守失效旧凭证而推进 revision,也不能取得 mutation ownership。mutation ownership 使用最后一条同工具调用,并严格匹配当前 Agent/task/session/run/actionId/actionFingerprint/tool 的 durable receipt;pending action 的 `plannedSteerCursor` 必须进入 recent tool-call 与 receipt 的同一 fingerprint,不能因非零 steer cursor 把真实成功误判为外来动作。static smoke 通过但仍有素材或正式产物缺口时,Runtime 对尚未完成的计划用单一 in-progress repair 替换首个非终态步骤并保留后续 pending;只有计划全 completed 且未满 8 步时才追加 repair。下一轮交还 Provider 生成实际 `file.patch`,完整门未通过时禁止自动完成计划,也不得因 retained completed 步骤与 steer 新计划合并超限而进入空转;结构化计划只要已经包含不可改写的 failed 步骤,就在快车道入口明确失败关闭,不再依赖 mutation ownership 或完成门诊断是否仍存在。
- manifest Pending 漂移仅在当前最新活跃 game-chat 根 Run 内容忍,并要求确定性 child runId、父绑定及 state/durable journal 的 Running-Running;child 终态投影要求 Completed-Completed。queued、waiting、failed、needs-reconciliation、旧根 Run 和不可信 source 不得借用容错。
- durable active child 的权威性高于 stale Completed manifest 快照,但 Failed manifest 仍立即失败关闭。所有 ready child 的文件、patchset、命令产物和其它项目 mutation 在写锁内再次核对当前根 Run;新根 Run 建立后旧 child 只能安全收束/审计,不能再修改项目或推进 revision。
- 大 classic 游戏脚本的函数可达性查询必须对固定 invocation graph 使用整轮 visited,每个 function node 最多访问一次;递归栈只负责去环、返回时删除节点会在 render/update 扇入图中指数回溯并阻塞 Runner 事件循环。Canvas alias 全空历史、稳定祖先初始化、整画布尺寸引用和可证明的 `COLS × ROWS × CELL` 格子目标使用有界静态路径,普通未知动态坐标继续失败关闭。
- 根 Supervisor 只对 manifest 中已经 Completed 的 seed task执行正式产物、素材和 Canvas 深验;未完成状态本身已经阻塞根完成,禁止在 code-prototype 尚未开始时提前扫描四类素材。自动唤醒连续耗尽 200 次瞬态预算后进入 `needs-reconciliation`,不得静默保留 running。
- Canvas 可见性区间证明按 Oxc semantic symbol 与当前绘图 context 的 Canvas owner 解析:函数 alias 重绑定、可达调用参数、计数循环和作用域内数值常量都必须保持身份。无法化简的格子索引只在唯一 `COLS / ROWS / CELL` 合同下覆盖完整棋盘轴;已知越界实参继续拒绝。动态 clamp 只接受未遮蔽全局 `Math.min(currentCanvas.width|height - size, Math.max(0, dynamic))`,错误 Canvas、遮蔽 Math 和普通未知坐标失败关闭。
- parent wake 达到瞬态预算上限时先形成 durable reconciliation signal;lane 忙保留 deferred 状态,随后在同一 execution lane 与项目写锁内重读原始 state、最新 durable task、取消墓碑和 DAG 进展。manifest 结构损坏时使用不依赖 manifest hydration 的专用 CAS journal 与原子 state 写入,不能吞掉持久化错误,也不能用过期终态覆盖并发取消或 child 进展。durable terminal reconciliation task 是后续 state / queue / event / audit 的提交标记;重启恢复必须在其它 resume 动作前幂等补齐这些投影,task journal 读取损坏不得当作任务不存在。恢复只在 raw state 具有完整 Agent/task/Session/run/source/profile/binding/task 身份时选择其当前 run;state 缺失、JSON 损坏、空对象或 runId 等关键身份为空时只考虑 journal 最后一个 logical run,完整有效的新 Run 继续阻止历史 marker 覆盖。event 与 Agent DB audit 只有完整稳定 payload 唯一匹配时才视为已投影,同键冲突或重复必须失败关闭;旧 task 已 completed/cancelled、Runtime 已离开 waiting 或新 Run 已接管时,deferred signal 必须追加 run-scoped resolved/superseded 终局。
## 2026-08-04 manifest 与工作台一致性收口
- `.agent/manifest.json` 的存储写边界使用同目录持久文件锁跨线程、跨进程串行化;锁必须覆盖旧 manifest 读取、不可变版本前缀校验、临时文件安装和安装后回读一致性校验。锁文件拒绝符号链接、非普通文件和异常所有权 / 硬链接;Windows 使用不共享写句柄,Unix 使用 `O_NOFOLLOW + flock`。旧快照在新版本安装后只能被拒绝,不能覆盖已追加版本。
@@ -243,8 +243,10 @@ npm run check:server-rs-ddd
6. 编辑器图片生成 / 图片修改 / 图标 spritesheet / UI 设计图提取素材 / 视频 / 角色动作 / 音效 / 背景音乐必须在后端计算模型价格后使用 `execute_billable_asset_operation_with_cost` 预扣泥点;预扣失败必须 fail-closed,不得继续提交 VectorEngine、Ark、Suno 或 Vidu 上游任务。
7. 队列任务按 `job_id + claim_attempt` 使用独立 consume/refund ledger。新 attempt 结算旧 attempt 时必须先写 `asset_operation_wallet_settlement`:旧 consume 已存在则原子退款,尚不存在则写取消 intent;迟到 consume 在同一 SpacetimeDB 事务内看到 intent 后必须失败关闭。重复 consume/refund 只有用户、金额、来源和配对 ledger 全部一致时才可视为幂等成功。lease 过期时只有 `attempt < max_attempts` 才能递增并重领;最终 attempt 已耗尽时,claim transaction 必须直接把 job 收口为 `failed`、清理 lease、写失败事件并结算当前 attempt,不能再把任务返回 worker 或调用 provider。
8. 音频生成的编辑器链路虽然任务提交和结果发布分离,仍必须把提交时后端计算出的模型价格写入 `AudioAssetBindingTarget.billing_points_cost`,最终发布落资产时按该价格扣费;创作音频目标未提供该字段时才使用旧的创作音频固定成本。
9. 编辑器进入外部生成持久队列的图片生成、图片修改、去背景、图标 spritesheet、UI 设计图提取、角色动作和视频参考图,调用方必须提交 `objectKey` / `resourceId` / `assetId` 候选引用;BFF 只做内联媒体与 payload 门禁,登记状态和归属由 worker 统一解析。任务 `request_payload_json` / `result_payload_json` 任意层级都禁止 `data:` / `blob:`,并受统一字节上限保护。无效普通字符串可以入队,但必须在签名和 provider 调用前失败;本次不增加 API 侧数据库查询或同步 owner 校验。若以后要求无效引用同步返回 400,应作为独立改造。objectKey 最终必须归属于当前账号的 `editor_project_resource`、`editor_asset` 或 `asset_object`,由 worker 在解析后、签名读取 OSS 前完成归属校验。本地红框序号标注图必须先上传并确认对象,再把 objectKey 入队;不得把既有 objectKey 下载成 Data URL 后写入任务。图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照;图片快速编辑当前不开放额外参考图。UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,图标素材上限 8 张额外参考图。同步且不持久化的历史兼容入口即使仍能解析 Data URL,也不能把该值转存到工程、素材、元数据、审计或任务表。
9. 编辑器进入外部生成持久队列的图片生成、图片修改、去背景、图标 spritesheet、UI 设计图提取、角色动作和视频参考图,调用方必须提交 `objectKey` / `resourceId` / `assetId` 候选引用;BFF 只做内联媒体与 payload 门禁,登记状态和归属由 worker 统一解析。任务 `request_payload_json` / `result_payload_json` 任意层级都禁止 `data:` / `blob:`,并受统一字节上限保护。无效普通字符串可以入队,但必须在签名和 provider 调用前失败;本次不增加 API 侧数据库查询或同步 owner 校验。若以后要求无效引用同步返回 400,应作为独立改造。objectKey 最终必须归属于当前账号的 `editor_project_resource`、`editor_asset` 或 `asset_object`,由 worker 在解析后、签名读取 OSS 前完成归属校验。本地红框序号标注图必须先上传并确认对象,再把 objectKey 入队;不得把既有 objectKey 下载成 Data URL 后写入任务。图标素材、图片快速编辑和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照。普通图片生成最多 5 张参考图;图片修改、图标素材和 UI 提取的额外参考图上限还必须与所选 provider 的总容量共同取最小值:GPT-image-2 总计 5 张,nanobanana2 总计 14 张。前端添加和提交、api-server 入队 / 扣费前以及 `platform-image` provider 边界都必须明确拒绝超限,禁止用 `.take(...)` 静默截断。同步且不持久化的历史兼容入口即使仍能解析 Data URL,也不能把该值转存到工程、素材、元数据、审计或任务表。
10. 已有静态图片的 `POST /api/editor/images/pixel-art-snaps` 是免费 inline 派生操作,不调用外部 provider、不创建 `external_generation_job`、不读写泥点 ledger,也不进入任务侧栏。免费不放宽 owner、稳定引用、输入上限、持久化或处理阶段零持久化门禁。
11. 主站编辑器生成队列使用同一次前端请求稳定复用的 `x-request-id`,按 namespace + owner + job kind + request id 生成唯一 `dedupe_key`;首次请求已入队但响应丢失时,重试必须返回原任务。同一幂等键携带不同 payload 返回 `409`,不得创建第二个任务或串到旧结果。外部 v1 的 `Idempotency-Key` 使用独立 namespace,不能与主站请求标识碰撞。幂等 payload 比较只对本次已迁移 sanitizer 的图片生成、图片修改、去背景、图标图集和 UI 提取任务,兼容“升级前旧任务仍含客户端 `generationInputs.references`、当前请求已删除该字段”的单向形状;当前请求仍含 references,或 job kind 属于音频 / 视频 / 角色动作等未迁移任务时必须完整比较,其余请求字段始终完全一致。
12. `generationInputs.references` 是最终资产的服务端权威行引用,不接受客户端自报 provenance。图片生成类请求入队、完美像素及直接创建资源 / 素材时删除客户端 references;worker 和 inline 路径按本次真实参考图、当前 owner 的项目资源 / 素材记录重建 `refType/refId` 后再持久化。仅能证明 owned objectKey、但找不到对应资源或素材行时可以参与生成,不得制造虚假行引用;`title/label` 只作为展示快照,不提升为资源身份。完美像素为兼容升级前的未知结果重放,可继续用旧版 canonical 客户端输入计算 operation fingerprint;新操作持久化元数据只能使用服务端重建值,检测到 owner 项目中已存在同一稳定 task/resource 的历史结果时则复用该服务端既存 metadata 完成精确 compare-and-return。
## 外部服务与资产