跳转至

ISSUE-0092:.gitignore 裸 Icon 规则误伤生产资源

症状

主仓库一切正常,但任何人 clone 这个仓库后 pnpm compile 直接失败。

wxt prepare 生成的 PublicPath 类型里没有 /icon/128.png,而 5 处生产代码引用它, tsc --noEmit 报错。

根因

.gitignore 第 62 行是一条裸的 Icon

# ─── macOS 特有 ───
.AppleDouble
.LSOverride
Icon          ← 这一行
._*

它的本意是忽略 macOS Finder 的自定义图标残留(真实文件名是 Icon\r,带回车符)。 但 gitignore 里不带斜杠的模式匹配任意层级的同名文件或目录,加上 macOS 默认 大小写不敏感 —— 它匹配上了 src/public/icon/

于是 src/public/icon/128.png 从未进入 git:

$ git check-ignore -v src/public/icon/128.png
.gitignore:62:Icon  src/public/icon/128.png

$ git ls-files src/public/icon/
(空)

引用它的 5 处生产代码

位置 用途
src/utils/scrape-watchdog.ts:187 通知图标
src/utils/scrape-watchdog.ts:214 通知图标
src/utils/engine-manager.ts:127 通知图标
src/entrypoints/background/batch-controller.ts:678 通知图标
(第 5 处见 grep -rn 'icon/128.png' src/

为什么长期没被发现

主仓库能跑,纯粹因为文件躺在本地磁盘上。 这个仓库从没被真正 clone 验证过。

所有静态检查(pnpm verify 的 17 段、9 个 scanner、docs:check)都在本地工作区跑, 看到的是有文件的状态。CI 也没有「从干净 clone 构建」这一步。

发现过程

2026-08-31,为让 6 家外部模型并行改同一份代码,主控建了 6 个独立 clone 树。 k3(moonshot)在自己的树里跑 pnpm compile 时撞上此错,并主动声明: 「这不是我的回归也不是门禁作弊,是克隆环境缺资产,我生成了一张合法 PNG 补上」。

主控最初把它当环境问题(给后建的树手动 cp 补文件),追根因后才发现是仓库配置错误。

🔴 三路对抗审查(terra / dshf / 16 个 Claude subagent)都发现不了这类问题 —— 它们只审 diff,不 clone。只有真正建独立工作树才会撞上。

修复

-Icon
+# macOS Finder 自定义图标残留文件(真实文件名是 Icon\r,带回车符)。
+# 🔴 必须锚定并转义,否则裸 `Icon` 会匹配任意层级的同名目录
+Icon?

Icon? 中的 ? 匹配单个字符(即那个 \r),不会匹配目录名 icon。 同时把 src/public/icon/128.png 加入 git。

回归判据

git check-ignore -v src/public/icon/128.png   # 期望:无输出(不被忽略)
git ls-files src/public/icon/ | wc -l          # 期望:≥1

更硬的判据(尚未落地,见下):从干净 clone 跑一次 pnpm compile

未解决:没有「干净 clone 能否构建」的门禁

本次是偶然撞上的。同类问题(构建依赖未提交的本地文件)随时可能再发生, 而现有全部门禁都在本地工作区跑,结构上看不见。

可行做法:CI 或 pre-push 加一步「clone 到临时目录 + install + compile」。 本仓当前无 CI,此项登记为待办。