补记三条踩坑:rustfmt 作用域、build-gate 代理假红、worktree 与 MSYS bash 不兼容

- 新增「裸 rustfmt 会把一个文件放大成整个模块树」:现象是本想改 1 个文件实际改了 src/agent/ 下 50 个;原因是裸 rustfmt 把传入文件当模块根并跟随 mod 递归;处理口径是改格式前先 git diff --stat 确认范围、先备份,精确到文件用 cargo fmt -p <pkg> -- <文件...>,并行工作树里禁止盲跑 cargo fmt --all,误伤后用 git apply -R 反向补丁还原而不是 git checkout --
- 新增「build-gate 的警告门被代理环境变量误伤」:NODE_USE_ENV_PROXY=1 / HTTP_PROXY 会让 Node 打印 UNDICI EnvHttpProxyAgent experimental 警告,而 build-gate.mjs 只忽略含 ExperimentalWarning 字样的行,于是构建成功却判红;判据是同一 commit 清空这些变量后 npm run build 即 exit 0;CI 无这些变量不会触发,若要让本地带代理也能跑需在忽略规则补 EnvHttpProxyAgent / UNDICI-EHPA(属改门禁规则,本次未改)
- 新增「worktree 里 MSYS bash 跑 git 脚本会失效」:check-repository-ci.sh 这类脚本在 worktree 里第一步就报比较基线不可用,根因是 bash 用 MSYS 的 /usr/bin/git、而 worktree 的 .git 存 Windows 绝对路径,解析成 /mnt/c/.../C:/Users/...;口径是按脚本同序同命令用 Windows git 逐条等价执行
- 只追加,未重排既有条目
This commit is contained in:
2026-09-11 12:28:58 +08:00
parent 66bb240115
commit 669c71d7e8
@@ -5238,3 +5238,26 @@
- **排查顺序**:① 先看失败耗时——几十毫秒说明该入口没等,是等待窗口缺失,不是锁没释放。② 看错误里的 `ownerIsSelf``true` 指向同进程另一条写通道,`false` 指向外部进程;该字段只比 PID,PID 复用会把外人报成自己人,只当线索、不当判据(回收判据另有 `processStartedAt` 兜底)。③ **锁文件在失败后通常已被 Drop 删掉,现场缺文件不否定争用**;同理 `agc_list_registered_assets``pendingOperations: []` 只表示没有在跑的付费生成,与项目写锁无关,不构成“锁没有持有者”的证据。④ `.agent/.manifest.json.lock` 是 manifest 的持久 OS 文件锁(Windows 不共享写句柄 / Unix `flock`),0 字节长期存在是设计如此,不是残留锁,也不要用项目写锁的回收判据去处理它。⑤ 看到“项目写锁路径权限被拒绝”时注意它的含义:这是**等满等待窗口后**的终态改判(Windows 上真实 ACL 拒绝就走这条路),不是某一瞬间的 metadata 观察;反过来,`项目正在被其他写操作占用:…(持锁方身份不可读:锁文件此刻不存在…)` 是零等待入口无法区分拆链窗口与 ACL 拒绝时的并列表述,两者不要互相否定。
- **验证**:Rust 定向覆盖同进程重叠写等待、同轮并行写、有界等待不占 runtime worker、活外部进程持锁带身份、权限拒绝不投影成争用,以及两条平台无关判据用例(重试性只由错误码决定、终态改判三条件);`runtime_project_write_lock_waits_for_delete_pending_target` 继续覆盖带句柄的 delete-pending 必须等到成功。
- **关联**`apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs``apps/ai-game-creator-shell/src-tauri/src/project/write_lock.rs``apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/project_gates.rs`
## 2026-09-11 裸 rustfmt 会把「一个文件」放大成整个模块树,并行工作树里不要盲跑整仓 fmt
- **现象**:只想按 `check:rustfmt` 的报错格式化 1 个 Rust 文件,跑完 `git diff --stat` 却显示 `src/agent/` 下 **50 个文件**被改动(`cargo fmt --all` 之后同样会扫到别人未提交的半成品)。
- **原因**:裸 `rustfmt <file>` 把传入文件当成**模块根**,会跟随该文件的 `mod` 声明递归格式化所有子模块;`cargo fmt -- <文件...>` 才只作用于列出的文件。两者作用域不同,`--check` 的报错范围也因此不同——只修 `--check` 报出来的那几行不够,要用同一作用域复核。
- **处理**:改格式前先 `git diff --stat` 确认范围并备份将被改动的文件;需要精确到文件时用 `cargo fmt -p <pkg> -- <文件...>`(只格式化列出的文件),或 `rustfmt --config skip_children=true`(注意 `skip_children` 下的折行口径可能仍与 `cargo fmt` 不一致,最终以 `cargo fmt -p <pkg> -- --check <文件...>` 为准)。**多人并行的工作树里禁止盲跑 `cargo fmt --all`**,它会格式化别人未提交的半成品。误伤后先备份、再用 `git apply -R` 反向补丁精确还原,**不要** `git checkout --`
- **验证**:本次同一批文件,裸 `rustfmt` 改 50 个;`cargo fmt -p genarrative-ai-game-creator-shell -- <5 个文件>` + `cargo fmt --all --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check` 均 exit 0 且范围恰好 5 个文件。非破坏性复核作用域可用 `cargo fmt -p <pkg> -- --check <文件...>`
- **关联**`rustfmt.toml``package.json``check:rustfmt`server-rs 与 AGC src-tauri **两条**命令,CI 常在第一条就退出,第二条从未跑到)。
## 2026-09-11 build-gate 的警告门被代理环境变量误伤:构建成功却判红
- **现象**`npm run build` 失败,但日志里主站与 `admin-web` 都打印了 `✓ built in …`,末尾是 `Build gate failed because warnings were emitted:`,列出的全是 `(node:PID) [UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.``(Use \`node --trace-warnings ...\`)`。
- **原因**:本机设了 `NODE_USE_ENV_PROXY=1``HTTP_PROXY` / `https_proxy` 时,Node 会启用 `EnvHttpProxyAgent` 并打印那条 experimental 警告;`scripts/build-gate.mjs:57-67` 的警告门逐行匹配 `/\bwarn(ing)?\b/i`、**只忽略含 `ExperimentalWarning` 字样的行**,这条不含该字样,于是没被忽略规则兜住。
- **处理**:本地跑这条门禁前清空 `NODE_USE_ENV_PROXY` / `HTTP_PROXY` / `http_proxy` / `HTTPS_PROXY` / `https_proxy` / `ALL_PROXY`(无需改代码)。若要让本地也能带代理跑,应在忽略规则里补 `EnvHttpProxyAgent` / `UNDICI-EHPA`——**属改门禁规则,本次未擅自改**。CI 无这些变量,不会触发。
- **验证**:同一 commit 只清空上述变量后重跑 `npm run build`**exit 0**(日志末段不再出现 `[build-gate]` 失败段落)。反过来,带变量重跑必然复现同一批 `EnvHttpProxyAgent` 警告。
- **关联**`scripts/build-gate.mjs``package.json``build``scripts/check-repository-ci.sh` 的第 12 步。
## 2026-09-11 worktree 里 MSYS bash 跑 git 脚本会失效,门禁要按同序逐条等价执行
- **现象**:在 `.worktrees/` 工作树里执行 `npm run check:repository-ci`(内部是 bash 脚本),第一步就报 `[repository-ci] 比较基线不可用: <sha>`;直接用 bash 诊断则是 `fatal: not a git repository: /mnt/c/.../<worktree>/C:/Users/.../.git/worktrees/<name>`
- **原因**bash 走 MSYS 的 `/usr/bin/git`,而 worktree 的 `.git` 是**文件**、内容为 Windows 绝对路径 `C:/Users/.../.git/worktrees/<name>`;MSYS git 把它当相对路径拼到当前目录后,解析成 `/mnt/c/.../C:/Users/...`。同一个 ref 用 Windows git 验证 `git cat-file -e <sha>^{commit}` 返回 0,所以这不是基线选错,而是 worktree + MSYS 不兼容。
- **处理**:在这类 worktree 里跑 script 门禁时,**按脚本同序、同命令用 Windows git / PowerShell 逐条等价执行**`SPACETIME_SCHEMA_BASE_REF=<base>` 之类环境变量照传),不要因为 bash 包装层失败就判定门禁本身红。
- **验证**`git cat-file -e "$(git rev-parse master)^{commit}"` 在 PowerShell 下 exit 0;逐条等价执行后 10 道门禁的通过与失败分布与脚本语义一致(本次仅 rustfmt / appSurface / build 三条红,各有独立归因)。
- **关联**`scripts/check-repository-ci.sh``scripts/run-bash-script.mjs`