合并 master 最新变更
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m57s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m35s
Project CI / Frontend tests (pull_request) Successful in 2m16s
Project CI / Repository checks (pull_request) Failing after 18s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m34s
Project CI / Native shell tests (pull_request) Successful in 6m45s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 14m9s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 14m23s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m57s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m35s
Project CI / Frontend tests (pull_request) Successful in 2m16s
Project CI / Repository checks (pull_request) Failing after 18s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m34s
Project CI / Native shell tests (pull_request) Successful in 6m45s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 14m9s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 14m23s
# Conflicts: # docs/project-memory/shared-memory/pitfalls.md
This commit is contained in:
@@ -8732,6 +8732,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 边界:锁定这些不变量的既有用例(`project_tools` / `command_runtime` / `parallel_actions` / `runtime_state` / `response_stream` / `direct_tool_bridge` / `ui_editor::persistence`)不得为了让锁语义通过而改写;用「同线程自持锁」模拟「另一个写者」的两条用例改为**在另一条线程持锁**,断言语义不变。同进程跨线程重入(持锁链在 `await` / `spawn_blocking` 后于其它线程再取锁)仍会等满预算,出现现场时按 2026-08-27 的既有处置改用 `*_locked` 入口,不放宽判据。
|
||||
- 关联文档:[项目客户端占用锁收敛里程碑](../plans/【里程碑】项目客户端占用锁收敛-2026-09-14.md)、[踩坑记录](pitfalls.md)。
|
||||
|
||||
## 2026-10-01 素材提交复用有界项目锁等待
|
||||
|
||||
- 本地素材导入、账户素材下载后的提交、资源编辑资产/版本提交及已完成结果清理复用既有类型化有界等待,跨进程排他、同线程重入和权限分类保持不变。
|
||||
- 同步等待与事务整体放入阻塞线程池;必须先取得项目锁,再取得平台身份租约,并在等待后验证原 WritePermit。不能在账号互斥锁内等待项目锁,也不能把项目锁 guard 跨线程搬到实际提交线程。
|
||||
- 资源编辑的 operation/project 异步互斥 guard 随阻塞任务持有,调用方取消等待不能提前释放。原账本、operation、幂等键及 staging 继续用于本地恢复,不因锁争用重复远端生成。
|
||||
- 关联:Issue #551;行为与证据见 AGC 实施计划“素材导入与资源提交的项目锁等待”。
|
||||
|
||||
## 2026-09-14 AGC 图片类生成后台化:提交即返回 + 项目内任务账本 + 本地排队
|
||||
|
||||
- 背景:栏目画布图片类入口原先是一条同步 IPC `generate_local_project_asset`,一次调用最长等 35 分钟;提交期间两块生成浮层把 × / 遮罩 / Esc /「取消」全部锁死,用户既关不掉面板也看不到进度。远端图片类生成当时共用 single-flight 输出槽(`standalone_platform_art_generation_runtime_context` 按 `outputPath` 派生 `run_id`)——**同一批次内该槽身份已改为精确动作指纹,见本文件 2026-09-14「放开 AGC 手工图片生成的本地并发」条目。**
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
- **原因**:Windows 的 `npm.cmd` 是批处理入口;Node `child_process.spawn('npm.cmd', args, { shell: false })` 会直接返回 `EINVAL`,还未执行根 `npm run dev`。
|
||||
- **处理**:`scripts/dev-all.mjs` 在 Windows 使用 `shell: true`、`windowsHide: true` 启动 npm 子进程;POSIX 仍使用独立进程组,退出时按进程组收束。
|
||||
- **验证**:Windows 实测根开发栈已启动并完成端口漂移(Web `3001`、API `8084`、worker `8085`、SpacetimeDB `3104`、后台 `3105`),之后 AGC 因当前工作区缺少 `@anthropic-ai/claude-agent-sdk` 退出;dev:all 已收束根栈进程。
|
||||
## 2026-10-02 固定试玩误判祖先的指针穿透样式
|
||||
|
||||
- `pointer-events:none` 不会强制禁用整棵子树;后代显式 `auto` 可以恢复命中。控件探针只检查目标的计算样式,继承未覆盖的 `none` 仍拒绝;可见性、遮挡、disabled 与 inert 保留各自检查。
|
||||
- 修复和回归必须经过生产输入入口及可信事件驱动的状态变化,不能用程序化点击证明真实可玩。双视口 generic 回归与真实触摸验收需要区分,详见 AGC 实施计划“固定试玩控件的指针命中边界”。
|
||||
## 2026-10-01 Rust 分片编译失败只剩汇总错误
|
||||
|
||||
- **原因**:`--message-format=json` 把编译诊断写到 stdout;只读取 `compiler-artifact` 的运行器会丢弃 `compiler-message`,CI 只能看到「due to 1 previous error」。
|
||||
@@ -53,6 +57,12 @@
|
||||
- **判据/取证**:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --bin genarrative-ai-game-creator-shell direct_thread_delta`——新增 `direct_thread_delta_sanitization_preserves_line_breaks` 钉住「逐段脱敏 == 整段脱敏」,去掉 `split_inclusive` 即红;真实文本的回归用渲染侧夹具复核(修复前 table/li/h2 全 0,修复后与整段脱敏一致:1 个 table / 3 个 th / 4 个 h2)。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs`、`.../agent/generation/prompt_context.rs`、`.../agent/thread_manager/wire.rs`、`apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directThreadChat.ts`、`#384`。
|
||||
|
||||
## 2026-10-01 文件列举被无关临时锁删除打断
|
||||
|
||||
- `read_dir` 返回名字后,文件可能在 `symlink_metadata` 前正常消失;`.agent/project.lock` 的正常释放就能触发这类竞态。不要先全项目扫描再按 Agent 的 `path` 和可见性过滤。
|
||||
- 项目内列举在元数据读取前裁剪范围和受保护路径,只进入目标子树及必要祖先;共享文件树保留自己的可见性策略。枚举后消失的文件/目录仅跳过 `NotFound`,其它 IO 错误仍可诊断,进入排队目录前复核链接/重解析点。
|
||||
- 并发回归用通道协调真实写锁的释放与元数据读取,不靠高频循环碰撞;分页按本次观察到的可见文件排序,不保证跨请求快照。完整合同见 AGC 实施计划“项目文件列举的范围与并发边界”。
|
||||
|
||||
## 2026-09-29 Game Agent 读工具被项目相对路径规则拦住
|
||||
|
||||
- 项目外读取不能只依赖末段 `O_NOFOLLOW`:父目录符号链接可隐藏 `.ssh` 等受保护名字。文件读取和目录列表在访问前逐段检查原始路径,拒绝符号链接与 Windows 重解析点;目录扫描对子目录再次检查。系统临时目录若含平台别名(例如 macOS `/var`),普通读取测试使用临时目录的 canonical 路径,不能通过 canonicalize 待读路径来抹掉待检测链接。
|
||||
@@ -6248,3 +6258,51 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **处理**:保留预检失败关闭语义,但提取 Rust 返回的安全错误码;对无错误码的 Tauri 调用故障显示独立 IPC 提示,并仅对这类瞬态调用失败重试一次。首页调用方必须透传该安全提示,不能重新覆盖为通用文案。
|
||||
- **验证**:`apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx` 覆盖 ready、具体宿主错误码、IPC 失败、无错误码 blocked 和 planning 绕过;同一 Windows 安装包 CLI 实测 Node `v22.22.2`、npm `10.9.7`、Edge desktop/mobile PNG 均通过。
|
||||
- **关联**:`apps/ai-game-creator-shell/src/features/app-shell/homeWebPreflight.ts`、`apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts`、`apps/ai-game-creator-shell/tests/homeWebPreflight.test.tsx`、`apps/ai-game-creator-shell/src-tauri/src/environment_check/web_creation.rs`。
|
||||
|
||||
## 2026-10-02 AGC 首页把创建失败覆盖成通用文案,「项目已建好」被说成「创建未完成」
|
||||
|
||||
- **现象**:首页自动创建在项目目录已经建好之后失败(策划运行时切换、附件导入、进入工作台抛错)时,浮层显示「创建未完成,请重试」,而同一页面同时列着「已创建的工作区:…」;用户会以为没建成功,再建一遍。
|
||||
- **根因**:`useHomeProjectCreation.ts` 把底层文本拼进「工作区已创建;未能进入项目开发:<原因>」再抛出,`src/view/home/index.tsx` 的 `catch` 又无条件覆盖成写死的通用文案。注释声称“详细错误已由工作区创建控制器记录”,实际只有一次 `setStatus`,紧接着就被覆盖,没有任何落盘;同一处的包装文案还写死成「首条需求投递失败」,把运行时切换、附件导入等失败都指认成“投递”这一步。
|
||||
- **处理**:新增 `homeCreationFailure.ts` 作为唯一出口:由宿主机器码(`project-revision-conflict` / `web-build-timeout` 这类连字符标识)、Tauri/WebView 传输形状(`Failed to fetch`、IPC 自定义协议失败)与专用兜底共同决定用户文案,并按“工作区是否已建好”分成两条;宿主原始文本不再上屏,改为 `appendWebviewLog` 写进 `application.log` 作为证据(脱敏沿用 `normalizeDiagnosticText`)。控制器抛出 `HomeCreationFailure`(带 `userMessage` 与 `diagnostic`),首页只透传它的 `userMessage`,对未知值一律落回专用兜底;包装文案改为中性的「未能进入项目开发」,不再指认某一步。
|
||||
- **验证**:`apps/ai-game-creator-shell/tests/homeCreationFailure.test.ts` 5 条覆盖机器码、传输故障、无码兜底、原始文本只进诊断、首页出口;`npx vitest run tests/appSurface.test.ts tests/homeCreationFailure.test.ts tests/homeWebPreflight.test.tsx tests/appUpdate.test.ts` 215 passed / 9 skipped;`npx tsc --noEmit -p tsconfig.json` 与 `npm run typecheck` 通过。
|
||||
- **关联**:`apps/ai-game-creator-shell/src/features/app-shell/homeCreationFailure.ts`、`apps/ai-game-creator-shell/src/features/app-shell/useHomeProjectCreation.ts`、`apps/ai-game-creator-shell/src/view/home/index.tsx`、`apps/ai-game-creator-shell/tests/homeCreationFailure.test.ts`、`apps/ai-game-creator-shell/tests/appSurface/home.suite.ts`。
|
||||
|
||||
## 2026-10-02 AGC 宿主预检把浏览器验证的多种原因压成一个 browser-failed
|
||||
|
||||
- **现象**:预检失败一律提示浏览器相关问题,但同一安装包 `--environment-check` 可能返回 `status=ready`;宿主侧真实原因可能是证据目录不可写、报告写盘失败、宿主取消或浏览器收束未确认。
|
||||
- **根因**:`environment_check/web_creation.rs` 把 `validate_local_preview_in_browser` 的所有 `Err` 统一映射成 `web-preflight-browser-failed`(验证层实际会返回“未发现可用浏览器”“启动浏览器超时”“启动浏览器失败:<OS 码>”“宿主已停止本轮浏览器验证”“browser-cleanup-unconfirmed”“evidenceRoot …”“页面导航失败”等)。同一文件的依赖准备收据又把任何失败都写成 `web-scaffold-preparation-failed`,而宿主返回的真实机器码就在手上,等于把唯一的诊断线索作废。
|
||||
- **处理**:按真实原因分流成 `web-preflight-browser-missing` / `-launch-timeout` / `-launch-failed` / `web-preflight-cancelled` / `-browser-cleanup-failed` / `-browser-environment-failed` / `-evidence-failed` / `-input-invalid` / `-page-check-failed`,未识别原因落回专用兜底 `web-preflight-unclassified`;收据改为保留宿主返回的真实机器码,只有确实拿不到码时才用专用兜底;首页无码兜底文案不再写「请检查 Node/npm 或浏览器」这种未证实的候选原因。
|
||||
- **验证**:`cargo test --features=cocos-editor-execute,unity-editor-execute,godot-editor-execute --bin genarrative-ai-game-creator-shell environment_check::` 19 passed(含 `browser_validation_failures_keep_their_own_reason_codes`、`scaffold_receipt_keeps_the_real_failure_code`)。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/environment_check/web_creation.rs`、`apps/ai-game-creator-shell/src-tauri/src/browser/process.rs`、`apps/ai-game-creator-shell/src/features/app-shell/homeWebPreflight.ts`。
|
||||
|
||||
## 2026-10-02 AGC 直连回合失败分类器拿具体码当兜底
|
||||
|
||||
- **现象**:同一条 `code=runtime-failure` 同时承载「Claude Code 返回失败终态」与「Claude Agent SDK sidecar 回合超时」两种完全不同的原因;任何新失败形态都会静默并入该桶,从标签上看不出分类覆盖率。
|
||||
- **根因**:`agent/runtime_error.rs` 的 `classify_direct_codex_error` 用具体码 `runtime-failure` 做 `else` 兜底,并且整条分类依赖中文子串嗅探,未识别原因既没有专用兜底槽,也不进入统计口径。
|
||||
- **处理**:`else` 改为专用兜底码 `runtime-unclassified`;把已有真实证据的原因提升为具体码 `sidecar-turn-timeout` / `sidecar-launch-failed` / `app-server-launch-failed` / `claude-code-failed`。前端 `direct-codex-failure:v1|v2` 解析本就接受任意 `[a-z0-9-]+`,不需要兼容层。
|
||||
- **验证**:`cargo test … agent::runtime_error::` 5 passed(含新增的 `known_sidecar_and_app_server_failures_keep_their_own_codes`、`unclassified_failures_get_a_dedicated_code`);`cargo test … direct_failure_diagnostic` 4 passed(断言已改为按实际原因分类)。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/runtime_error.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs`、`apps/ai-game-creator-shell/src/features/agent-runtime/model.ts`。
|
||||
|
||||
## 2026-10-02 AGC 子进程启动失败被报成「不支持子命令」/「Node runtime 不可用」
|
||||
|
||||
- **现象**:Codex CLI 可执行文件缺失、路径错误、权限不足或被安全软件拦截时,用户被提示「当前 Codex CLI 不支持 app-server 子命令,请升级 Codex CLI」,升级后仍是同一个错;Claude sidecar 的 Node 进程完全起不来时被笼统说成「Node runtime 不可用」,且丢掉 OS 错误码。
|
||||
- **根因**:`config.rs::check_game_creator_codex_app_server_available` 与 `agent/claude_code_cli.rs::game_creator_claude_code_cli_version_identity` 都把 `Command::output()` 的 `map_err(|_| …)` 归因到“子命令不支持”或“运行时不可用”。`output()` 失败只可能是 spawn/exec 失败,与“不支持子命令”是两码事。
|
||||
- **处理**:两处改为保留真实 OS 错误的「启动失败」文案;`output()` 成功但输出不符时仍保留原来的“不支持 app-server 子命令,请升级”判据,失败关闭语义不变。
|
||||
- **验证**:`cargo test … tests::configuration::` 45 passed(覆盖 LLM 配置状态链路);同一 `--bin` 编译通过。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/config.rs`、`apps/ai-game-creator-shell/src-tauri/src/agent/claude_code_cli.rs`。
|
||||
|
||||
## 2026-10-02 AGC 更新检查失败被显示成「当前已是最新版本」
|
||||
|
||||
- **现象**:「关于」页手动检查更新,在清单 404、渠道缺少当前平台条目、网络失败或签名校验失败时仍显示「当前已是最新版本」。
|
||||
- **根因**:`services/appUpdate.ts` 把更新插件的所有异常统一 `return null`(按“无更新”收口),而这个 `null` 同时表示“没有更新”和“检查失败”;`RuntimeConfigDialog` 里对应的 `catch` 分支因此永远不可达,失败被兜成成功。
|
||||
- **处理**:新增结果型入口 `checkForAppUpdateResult()`(`available` / `current` / `failed` / `disabled`),失败保留插件返回的原始原因;`checkForAppUpdate()` 退化为启动期投影(失败仍静默、不阻塞启动、不动更新提示);「关于」页按结果分别显示,失败显示具体原因,渠道未启用不再冒充“已是最新”。
|
||||
- **验证**:`apps/ai-game-creator-shell/tests/appUpdate.test.ts` 9 passed(新增失败/已是最新/有更新/未启用四组用例,并保留启动期静默断言);`npx tsc --noEmit` 通过。
|
||||
- **关联**:`apps/ai-game-creator-shell/src/services/appUpdate.ts`、`apps/ai-game-creator-shell/src/features/runtime-config/RuntimeConfigDialog.tsx`、`apps/ai-game-creator-shell/tests/appUpdate.test.ts`。
|
||||
|
||||
## 2026-10-02 AGC 测试夹具未跟随“执行器与协议正交”拆分,HEAD 上 Rust 测试无法编译
|
||||
|
||||
- **现象**:`cargo test --bin genarrative-ai-game-creator-shell` 在 HEAD 上直接编译失败,9 个错误全部集中在 `src/tests/configuration.rs`:`select_game_creator_model` 少了第 4 个协议参数、`GameCreatorAppConfig` 少了 `selected_model_protocol` 字段。
|
||||
- **根因**:`6bf57c1e5` 把执行器与线协议拆成正交维度时只更新了生产代码,测试夹具没有同步,于是所有 Rust 定向验证(包括随包预检与运行时分类)都被挡住。
|
||||
- **处理**:夹具补 `None` 协议参数与 `selected_model_protocol: None`,不改任何断言口径。
|
||||
- **验证**:`cargo test --features=… --bin … tests::configuration::` 45 passed。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/tests/configuration.rs`、`apps/ai-game-creator-shell/src-tauri/src/commands.rs`、`apps/ai-game-creator-shell/src-tauri/src/main.rs`。
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
- DirectProject 工具可并行调度,依赖由调用方等待,同资源事务与付费动作幂等不能放松。Web 创作先用客户端环境预检,分层验证共用持久的 `validation.maxRuns`,不改写 Provider 的 `llm.maxRetries`;成功证据按输入指纹复用,达标后交付。完整回合条目统一保存在 `project.jsonl`;旧平行审计和附属请求分段计时已退出生产入口,不能因残留实现或测试而恢复旧契约。界面生命周期耗时与独立模型使用记录继续有效,未知边界不补零。详见 AGC 主专题的“Direct 历史、审计与耗时的现行边界”。
|
||||
|
||||
- 用户可见失败必须与真实原因对齐:兜底只允许使用**专门的兜底码/兜底文案**(`*-unclassified` / `*-unknown` / `Other` / IPC 与未分类专用提示),任何一层都不得借用某个具体子系统的错误去兜住无关原因(把 Tauri IPC 断连说成「环境预检未通过」、把进程启动失败说成「不支持 app-server 子命令」、把更新检查失败说成「已是最新」都属此类)。下层已经算好的**用户文案**(宿主错误码、控制器整理过的提示)只能透传,不得被上层覆盖成通用文案;宿主原始文本(Provider 文本、IPC 报错、完整路径)不直接上屏,只作为证据写进 `application.log`、运行时错误事件或 analytics。分类器的 `else` 必须是专用未分类码,不能用已有具体码兼任。详见 pitfalls 的 2026-10-02 批次条目。
|
||||
|
||||
- DirectProject 源码修改走 `agc_apply_patch`、进度走 `agc_update_plan`:SDK 原生的 `apply_patch` / `update_plan` 注册会被按回合移除(全局串行单例),不要恢复它们或用伪造工具注解换取并发。补丁只在当前项目内、受当前回合 Write 许可和受控进程约束,失败可能已部分写入,未知结果不自动重放;计划完成不构成验收证据。
|
||||
|
||||
- 捆绑 Codex 版本只在 `build_support/codex_bundle.rs` 固定一次,不要在测试或脚本里另写字面量;升级 SDK 后必须重跑模型目录真实用例、宿主补丁往返、并发夹具与发行载荷 smoke。原生命令工具名随 SDK 版本变化(0.155 起为 `exec_command` / `write_stdin`),脚本与夹具应按真实目录取用,不要按旧名字硬编码。
|
||||
|
||||
Reference in New Issue
Block a user