# 构建副产物:`%SystemDrive%` 字面量垃圾目录(2026-10-26 两次复发 → 2026-10-28 定性并加守卫)(自 SKILL.md 外置) > 本文由 keil-build 的 SKILL.md「构建副产物:`%SystemDrive%` 字面量垃圾目录(2026-10-26 两次复发 → 2026-10-28 定性并加守卫)」一节逐字外置而来(渐进展开:主文件只留索引与指针)。步骤号沿用原文,未重编。 **症状**:`/keil-build`(或 `scripts/check_font_charset.py` 这类 fontTools 字体工具)跑完,仓库根 冒出未跟踪目录 `%SystemDrive%/ProgramData/Microsoft/Windows/Caches/`,里面是几个 `.db` (`cversions.2.db` + `{6AF0698E-…}` 图标缓存 + `{DDF571F2-…}` 字体缓存,合计约 1 MB)—— 就是本机 `C:\ProgramData\Microsoft\Windows\Caches` 那份缓存被**按字面量原地复刻**了一份。 **根因(2026-10-28 实测)**:Windows 的 known-folder 路径在注册表里是**可展开串**;展开不了, 它就变成一个**相对路径**,于是按「当前目录」(= 仓库根)建出来。三条现场证据: ```bash reg.exe query HKCU\Environment # 本机 TMP/TEMP = REG_EXPAND_SZ %USERPROFILE%\AppData\Local\Temp env | wc -l # ops_bash 里 = 74(完整环境) node -e "console.log(Object.keys(process.env).length)" # run_code 里 = 0(空环境!) ``` `run_code` 的 Node 进程 `process.env` 是**空的**,从它里面 `spawn` 出去的 UV4 / 字体脚本就拿不到 `SystemDrive`/`ProgramData`/`ALLUSERSPROFILE`;实测 `os.path.expandvars("%SystemDrive%\ProgramData")` 原样返回、且 `os.path.isabs()` = **False** → 目录就长在工作区里(同族还会冒出 `%USERPROFILE%/AppData/Local/Temp`)。**正解不是「让用户去设环境变量」**,是别在残缺环境里跑构建(见第 2 条)。 **清理(有安全阀)**: - ⚠ **绝不用 cmd / PowerShell 直接删**:`rd /s /q %SystemDrive%` 会被 cmd **展开成 `C:`**—— 等于对整块系统盘下令递归强删且不带确认。 - ✅ 只用 bash 引号形态(`%` 在 bash 里没有特殊含义):先 `find '%SystemDrive%' -type l` 确认不是 reparse point / 符号链接,再 `rm -rf -- '%SystemDrive%'`;或 Node `fs.rmSync("%SystemDrive%", { recursive: true, force: true })`。 - 它是**工具副产物**,不是谁在飞的改动——直接删,别 stash、更别提交(提交它 = 把本机缓存塞进历史)。 **让它不再污染工作区(两层,均已落地、可核验)**: 1. **进不了版本库**:`.gitignore:167` 的 `%SystemDrive%/`(2026-10-26 入库,注释里就写着复发证据)。 核验三步(2026-10-28 复跑全绿):造一份同名目录 + `.db` → `git status --porcelain` 零命中 → `git check-ignore -v <路径>` 落在 `.gitignore:167:%SystemDrive%/` → `git add -A --dry-run` 零暂存。 2. **根本别再长出来**:本 skill 脚本 2026-10-28 起在拉起 UV4 前跑 `harden_windows_env()`——回填 `SystemDrive`/`SystemRoot`/`windir`/`ComSpec`/`ProgramData`/`ALLUSERSPROFILE`/`ProgramFiles` 与 `USERPROFILE`/`APPDATA`/`LOCALAPPDATA`/`TMP`/`TEMP`,就地展开环境里未展开的 `%VAR%` 字面量, 并把 `TMP`/`TEMP` 指到真实目录;命中即打 `WARN: ENV_SPARSE:`。构建后再跑 `check_percent_literal_junk()`,看到 `%SystemDrive%`/`%USERPROFILE%` 一类字面量目录就打 `WARN: JUNK_DIR:`(**只告警不自动删**——删目录不该由构建脚本代劳)。守卫是兜底不是许可: **`/keil-build` 仍要走 `ops_bash` / PowerShell(继承完整环境)**,非在 Node 里 spawn 就把 `env` 传全。