[#796][FIX] worktree-link-deps:补链 .bin + 入参规范化为绝对路径 + 末尾自检 - #802
Merged
Conversation
两个洞都**不报错**,只是链少了/链坏了 —— 后果要到几百条测试少跑一半时才显形。 1. `for entry in "$src"/*` 的 glob 不匹配点开头的条目,`.bin` 正是点开头 ⇒ 整个 `.bin` 漏链,新 worktree 里 electron-vite / electron-builder / tsgo 全部 command not found(#783 打包真机 L2 为此手工补链)。跑 bun 的门不需要 `.bin`, 所以日常 typecheck / unit 全绿,洞一直藏着。 修法:点条目按**白名单**补(只补 `.bin`)。`.bun` 无需(顶层逐条链完即可解析); `.cache`/`.vite`/`.vite-temp`/`.ts-dist` 是**可写缓存**,链过去等于让 worktree 的 写落进主 checkout —— 正是本文件抬头说的坑 ②。白名单也是 fail-closed 的。 2. `WT`/`MAIN` 从未规范化 ⇒ 传相对路径时 `ln -sfn "$WT/…"` 写出**相对**软链目标, 而相对目标相对**软链自己所在目录**解析,得到 `…/@opencode-ai/.worktrees/foo/…` 这种鬼路径;`$MAIN` 若相对,自有包的前缀判定(与 realpath 的绝对输出比)还会恒假。 修法:`cd … && pwd -P`,对本来就绝对的入参是恒等变换。 3. 末尾自检:打印「node_modules dirs / entries」,并对①`.bin` 没链上、②任何新建的 坏软链 判红退出。两个分支都实测过能对已知的坏判红。 Fixes #796
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #796
大白话
scripts/worktree-link-deps.sh有两个洞,都不报错,只是链少了 / 链坏了 ——后果要到「几百条测试少跑一半」时才显形,而那时看着像主线红了。
.bin整个漏链。for entry in "$src"/*的 glob 不匹配点开头的条目,.bin正是点开头。⇒ 新 worktree 里
electron-vite/electron-builder/tsgo全部command not found。WT/MAIN从未规范化,ln -sfn "$WT/…"于是写出一个相对目标,而相对目标是相对软链自己所在的目录解析的。
改了什么(三处,
scripts/worktree-link-deps.sh一个文件)1.
.bin补链 —— 点条目走白名单,不是dotglob全收for entry in "$src"/* "$src"/.bin; do主 checkout 里点开头的条目实测枚举(
ls -a1 … | grep -a ^.,逐 dir 走了 41 个 node_modules):.bin/.bun/.cache/.vite/.vite-temp/.ts-dist。逐个判:.bin.bun$MAIN/node_modules相对指进去,逐条链完即可解析 —— 实测本仓 worktree 一直如此跑通(3756 条测试全绿),链它是多余的.cache.vite.vite-temp.ts-dist为什么是白名单而不是黑名单:黑名单对「将来新冒出来的点条目」默认放行 ⇒ 悄悄往主
checkout 写;白名单默认拒绝 ⇒ 最坏是「少了、末尾自检当场把条数打出来」。fail-closed。
实测这个决定是对的:在一次性 worktree 里跑了
bun run typecheck与npm run build之后,packages/app/node_modules/.ts-dist在 worktree 里新建(mtimeAug 2 22:05),主 checkout 的那份没被碰(mtime 仍是
Jul 26 04:18)。链了它就不是这个结果。2. 相对路径 —— 规范化成绝对物理路径(而不是响亮拒绝)
为什么选规范化而不是拒绝:①「拒绝」让所有习惯敲相对路径的人多一步,而修法只是一行
cd+pwd -P;②pwd -P对本来就绝对的入参是恒等变换(实测两条真实路径均不变),不改变任何既有调用的行为;③它顺手修掉了第二个更隐蔽的后果 ——
$MAIN若相对,[[ "$target" == "$MAIN/packages/"* ]]拿它跟realpath的输出比,后者恒为绝对物理路径⇒ 判定恒假,工作区自有包被静默指回主 checkout(那正是本文件存在的理由)。
顺带把
[ -d "$WT" ]挪到git -C "$WT"之前:原顺序下传一个不存在的路径会先炸在 git 上,拿不到脚本自己那句
worktree not found。3. 末尾自检(AC4)
打印
node_modules dirs: N, entries: M,并在两种情况下判红退出:.bin没链上、或任何新建的软链是坏的(ln对坏链不报错,建完立刻stat一次)。验证:每条判据都先证明它能测出已知的坏
在
.bin完全缺失的树上实测:bun / npm 都能从依赖的 package.json 的
bin字段找到可执行文件,不只看.bin。(对照:在一个完全没有
node_modules的目录里bunx tsgo会去 registry 找并 404 ——所以上面的绿确实来自本地解析,不是网络兜底。)
⇒ 用
bunx tsgo --version当判据会得到假绿。 真正能测出这个缺陷的探针见下。正反两向:
.bin(绝对路径,同一个一次性 worktree,先坏后好)./node_modules/.bin/tsgo --versionNo such file or directory,exit 127Version 7.0.0-dev.20251207.1,exit 0./packages/ui-mac/node_modules/.bin/electron-builder --versionNo such file or directory,exit 12726.15.2,exit 0command -v electron-vite electron-builder tsgo(按包脚本 runner 的 PATH)npm run --ignore-scripts build(#783 的真实路径)sh: electron-vite: command not found/ exit 127修复前脚本的输出(注意它exit 0,自称成功):
修复后:
正反两向:相对路径(同一个一次性 worktree,先坏后好)
修复前,
bash scripts/worktree-link-deps.sh .worktrees/tmp796-rel:修复后,同一条相对路径命令:
用户可观察的后果,同一棵 base 树(
b11be8ba)、同一条命令bun test src(packages/ui-mac):——「测试跑得少 + 一堆莫名其妙的红」,而脚本 exit 0。这就是票里说的「看着像主线红了」。
自检的条数不是好看的数字,是跟独立枚举对上的数字
脚本自报
node_modules dirs: 41, entries: 653。用另一套代码(python 直接走 MAIN 的目录树,不复用脚本任何输出)独立数:
自检本身不是空闸门 —— 两个分支各实施了一次绕过
A. 坏链分支:在一次性 worktree 里把
packages/session-ui改名藏起来 → 重跑新脚本:B.
.bin分支:把修复那一行改回for entry in "$src"/*(改的是 scratchpad 的副本,不动仓内文件),先确认变异真的落地(
grep到73: for entry in "$src"/*; do)再跑:653 − 615 = 38,恰等于独立数出来的「带.bin的 node_modules 目录数 = 38」。本地门(真实输出,
scripts/alpha-check.sh,跑在本分支的 worktree 上)pre-push 钩子在
git push时也真的跑了同一套并放行(没有--no-verify)。与 base 的 fail-set 差 = 空:base(
b11be8ba,干净一次性 worktree,正确链好)实测3756 pass / 0 fail / 255 files,本分支同样3756 / 0 / 255。北极星 diff 只有scripts/worktree-link-deps.sh一个文件,不碰任何UPSTREAM_PATHS。同类扫描:
scripts/下还有没有别的地方犯同一个 glob 漏点条目的错两条独立检索轴,全仓(排除 node_modules/.git/.worktrees):
:44(for scoped in "$entry"/*,遍历@opencode-ai/@alpha-code作用域目录内部)是同一类的潜在成员,但实测这两个作用域目录里当前没有任何点开头的条目,所以今天不是缺陷 ——
按票面「有就点名、不顺手改」,这里只点名。
另外点名一个不在本票范围内的既有缺口(同样不改):
.bin里唯一一条指回工作区自有包的链是packages/web/node_modules/.bin/opencode → packages/opencode/bin/opencode,它会解析到主 checkout的
packages/opencode。但这不是本 PR 引入的 —— 现有脚本对非@opencode-ai/@alpha-code命名的自有包(如
packages/web/node_modules/opencode)本来就是整条指向主 checkout 的。要不要收口是另一张票的事。
我主动没做的事
scripts/gate-files.tsv登记的是 bun 测试文件,这是个纯 dev 脚本、不在任何生产路径上;新建一个会真建 worktree 的测试是给这张窄票加一套设施。
代替品是脚本自带的自检(每次跑都执行、fail-closed,且上面两个绕过实验证明它不是空闸门)。
.bun,理由见上表(多余,且实测不链也全绿)。:44那处同类 glob(今天不是缺陷,只点名)。packages/web/node_modules/opencode指向主 checkout 的既有缺口(超范围)。docs/verification/2026-08-02-req128-phase3-packaged-l2.md(它是当时的观测记录,是历史证据,不该被后来的修复回写)。