From 886600b94d31794abdf2e2bd21fe140a20604dee Mon Sep 17 00:00:00 2001 From: jinjunnn Date: Thu, 13 Aug 2026 01:37:49 -0400 Subject: [PATCH 1/4] =?UTF-8?q?fix(#941):=20[8/9]=20=E9=97=A8=E7=9A=84?= =?UTF-8?q?=E5=8F=AF=E8=BE=BE=E6=80=A7=E5=88=A4=E5=86=B3=E5=85=88=E5=8F=96?= =?UTF-8?q?=E5=85=B1=E8=AF=86=E5=86=8D=E5=A4=8D=E6=A0=B8=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E5=8D=8A=E9=80=9A=E4=B8=8D=E9=80=9A=E8=90=BD?= =?UTF-8?q?=E6=9C=AA=E9=AA=8C=E8=AF=81=E6=A1=A3,=E6=81=92=20network=20?= =?UTF-8?q?=E4=BB=8D=E7=A1=AC=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 单发 curl 探测不构成「网络没问题」的地面真相:代理半通不通时(2026-08-11 夜实测, 同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2), [6/6](a) 与 [5/6] 的独立探测会与判别依据落在矛盾两侧,健康仓库被硬红成 「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。夹具复现:curl 桩 3~4 发 里抖掉 1 发,旧实现两个位点都 exit 1。 修法(#916 R2 的三档模型不动): - registry_reachability_consensus:对「此刻可达吗」连测 3 次(间隔 1s)取一致; 结果互相矛盾 ⇒ 本次测量作废,不给判决; - adjudicate_network_verdict:判别依据说 network 后先共识、再让判别依据复测、 再一轮共识 —— 前后两轮独立探测全可达且复测不改口才许硬红(恒 network 的退化 实现在健康网络下确定性硬红);任何一处矛盾 ⇒ 未验证 exit 2;真离线 ⇒ 未验证; - [5/6]/[6/6](a) 的判决位改走上述裁决;[1/6]~[5/6] 能力判据与 [6/6](b)/(c) 不动。 行为闸(worktree-probe-sweep.test.ts,10→13 条,gate-files.tsv 同步): - 方向一 ×2(序列取自真实复现):必须 exit 2 + 说「本次测量作废」,不打「能力 判据失守」—— 旧实现下两条都红; - 方向二 ×1:夹具里把生产脚本判别依据改成恒 network + 网络稳定 ⇒ 仍必须 exit 1 且点名「判别依据退化」—— 少这半,「结论不稳一律未验证」会把真退化也放行。 - #928 那条「脚本中途失败」用例补 30s 显式超时(共识探测让离线夹具确定性 +4s)。 Fixes #941. Refs #916、#754。 --- .../src/main/worktree-probe-sweep.test.ts | 119 +++++++++++++++- scripts/assert-worktree-bootstrap.sh | 130 +++++++++++++++--- scripts/gate-files.tsv | 2 +- 3 files changed, 226 insertions(+), 25 deletions(-) diff --git a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts index 6d1a1f4e671c..ab10adbcf0e5 100644 --- a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts +++ b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts @@ -47,7 +47,7 @@ // 而没有任何东西变红(泄漏本身是不可见的 —— 下一个人只会看见 `git worktree list` 越来越长)。 // 它因此登记在 scripts/gate-files.tsv 里,拿精确条数。 -import { existsSync, mkdirSync, writeFileSync } from "node:fs" +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs" import { mkdtempSync } from "node:fs" import { tmpdir } from "node:os" import { join, resolve } from "node:path" @@ -110,6 +110,8 @@ function initFixture(opts: { hooksPath: string typecheckScript: string install?: { corruptTo: string; holdSeconds: number } + /** 额外提交进夹具仓根目录的文件(`#941` 的可控 typecheck 要以文件形态进探针 worktree)。 */ + files?: Record }) { const root = mkdtempSync(join(tmpdir(), "alpha928-")) TEMP_ROOTS.push(root) @@ -122,6 +124,9 @@ function initFixture(opts: { const r = Bun.spawnSync(["cp", src, join(repo, "scripts", src.split("/").pop()!)]) if (r.exitCode !== 0) throw new Error(`夹具仓拷不进生产脚本:${src}`) } + for (const [name, body] of Object.entries(opts.files ?? {})) { + writeFileSync(join(repo, name), body) + } const rootPkg: Record = { name: "fx", private: true, workspaces: ["packages/*"] } if (opts.install) { rootPkg.scripts = { @@ -275,7 +280,9 @@ describe("生产接线:真跑 scripts/assert-worktree-bootstrap.sh(alpha-check expect(names.filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) expect(names).toContain("lane-620-continue") expect(hooksPathOf(repo, home)).toBe(".lane-928-hooks") - }) + // `#941`:可达性共识探测(两轮 × 3 发,发间隔 1s)让离线夹具里的完整一跑确定性多花 ~4s, + // 默认 5s 超时会被顶破 —— 与同组其余用例一致取 30s。 + }, 30_000) test("被信号打断(SIGTERM 落在探针已建出之后):同样零残留,且 core.hooksPath 还原", async () => { const { home, repo } = initFixture({ hooksPath: ".lane-42-hooks", typecheckScript: "sleep 3" }) @@ -426,3 +433,111 @@ describe("生产接线:真跑 scripts/assert-worktree-bootstrap.sh(alpha-check expect(hooksPathOf(repo, home)).toBe(".lane-91-hooks") }, 30_000) }) + +// ── `#941` —— 可达性判别依据:网络半通不通不许硬红,恒 'network' 仍必须硬红 ────────────── +// +// 2026-08-11 夜实测(票面):同一分支几分钟内,[6/6](a) 一次硬红(「明明可达,判别依据却说 +// 'network'」⇒ alpha-check 整体 ❌)、一次落降级档 —— 而同一时刻 `curl registry.npmjs.org` +// http=200(一次 0.9s、一次 7.2s),同窗 git fetch 撞 SSL_ERROR_SYSCALL、gh 两次 EOF。 +// 判别依据的探测是**单发** curl(--max-time 8,零重试),两个独立调用点相隔几秒采样同一个事实, +// 代理抖动时各落矛盾一侧 ⇒ 健康仓库被判「判据失守」(exit 1)⇒ 训练人 `--no-verify`(`#754`)。 +// +// 判据两个方向缺一不可(只做一边 = 把 [6/6] 换成摆设): +// 方向一:探测结果自相矛盾(半通不通)⇒ 必须落「未验证」档(exit 2)+ 说「本次测量作废」, +// 不得打出「能力判据失守」。夹具序列取自真实复现:3~4 发 curl 里抖掉 1 发。 +// 方向二:判别依据真退化成恒 'network'(独立探测前后两轮全可达、复测不改口)⇒ 仍必须 +// 硬红(exit 1)。少了这半,「结论不稳一律未验证」的错误实现会把真退化也放行。 +// +// 夹具:curl 桩按 FLAKY_SEQ 逐次给结果(对 127.0.0.1:9 恒败 —— 那是 [6/6](b) 的不可达注入, +// 必须仍判 network);typecheck 以「worktree 根有没有 node_modules」区分 bootstrap 前后, +// 让 [1/6]~[5/6] 在夹具里全部真实可绿 —— 否则 exit 2 的断言会被别处的红污染。 +describe("可达性判别依据(#941):半通不通降级,恒 'network' 硬红", () => { + const FAKE_TYPECHECK = [ + "#!/usr/bin/env bash", + "# cwd = <探针 worktree>/packages/ui-mac;bootstrap 过 ⇒ 根有 node_modules ⇒ 干净", + "if [ -d ../../node_modules ]; then exit 0; fi", + `echo "src/x.test.ts(1,1): error TS2307: Cannot find module 'bun:test' or its corresponding type declarations."`, + "exit 2", + "", + ].join("\n") + + const CURL_STUB = [ + "#!/usr/bin/env bash", + "# 对 [6/6](b) 的不可达注入(127.0.0.1:9)恒败;其余 URL 按 FLAKY_SEQ 逐次给结果,", + "# 序列耗尽后按 FLAKY_DEFAULT。每次调用把计数写进 FLAKY_STATE。", + 'for a in "$@"; do case "$a" in *127.0.0.1:9*) exit 7 ;; esac; done', + 'STATE="${FLAKY_STATE:?}"', + 'n=$(cat "$STATE" 2>/dev/null || echo 0)', + 'echo $((n+1)) > "$STATE"', + "seq=(${FLAKY_SEQ:-})", + 'if [ "$n" -lt "${#seq[@]}" ]; then r="${seq[$n]}"; else r="${FLAKY_DEFAULT:-ok}"; fi', + '[ "$r" = ok ] && exit 0 || exit 7', + "", + ].join("\n") + + function initFlakyFixture(hooksPath: string) { + const fx = initFixture({ + hooksPath, + typecheckScript: "bash ../../fake-typecheck.sh", + files: { "fake-typecheck.sh": FAKE_TYPECHECK }, + }) + const stubDir = join(fx.root, "stub-bin") + mkdirSync(stubDir, { recursive: true }) + writeFileSync(join(stubDir, "curl"), CURL_STUB, { mode: 0o755 }) + return { ...fx, stubDir } + } + + function flakyEnv(fx: { root: string; stubDir: string }, registry: string, seq: string, dflt: string) { + return { + PATH: `${fx.stubDir}:${process.env.PATH ?? "/usr/bin:/bin"}`, + BUN_CONFIG_REGISTRY: registry, + FLAKY_STATE: join(fx.root, "curl-calls.n"), + FLAKY_SEQ: seq, + FLAKY_DEFAULT: dflt, + ALPHA_WT_PROBE_NESTED: "1", + } + } + + test("方向一:[6/6](a) 的探测窗抖掉一发(ok ok fail)⇒ 未验证档 exit 2 + 「本次测量作废」,不得硬红", () => { + const fx = initFlakyFixture(".lane-941a-hooks") + // 序列取自真实复现:第 3 发 curl 抖掉,旧实现在这里打出 + // 「明明可达,判别依据却说 'network' —— 一律算网络 = 这道门永不失守」并 exit 1。 + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.flap-941a.invalid", "ok ok fail", "ok")) + expect(r.code).toBe(2) + expect(r.out).toContain("本次测量作废") + expect(r.err).not.toContain("能力判据失守") + expect(registeredWorktreeNames(fx.repo, fx.home).filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941a-hooks") + }, 60_000) + + test("方向一:[5/6] 的判别与复核落在矛盾两侧(fail ok)⇒ 未验证档 exit 2,本条如实说分不出", () => { + const fx = initFlakyFixture(".lane-941b-hooks") + // 旧实现在这里打出「被判别依据归成 'network',而 registry 这一刻是可达的 —— 豁免成了 + // 万能挡箭牌」并 exit 1;修后:复测改口 ⇒ 结论不稳 ⇒ 本次测量作废,不冤枉判红。 + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.flap-941b.invalid", "fail ok", "ok")) + expect(r.code).toBe(2) + expect(r.out).toContain("本条分不出 real / network") + expect(r.err).not.toContain("能力判据失守") + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941b-hooks") + }, 60_000) + + test("方向二:判别依据退化成恒 'network' 且网络稳定可达 ⇒ 仍必须硬红 exit 1", () => { + const fx = initFlakyFixture(".lane-941c-hooks") + // 把夹具里那份生产脚本的判别依据改成恒 'network'(票面点名的绕过形态)。改不上必须红, + // 不许静默测了个健康版本(测不出已知的坏 = 本次测量作废)。 + const probeCopy = join(fx.repo, "scripts", "assert-worktree-bootstrap.sh") + const original = readFileSync(probeCopy, "utf8") + const mutated = original.replace( + "classify_bootstrap_failure() {\n", + "classify_bootstrap_failure() { printf 'network'; return 0; }\nclassify_bootstrap_failure_dead() {\n", + ) + expect(mutated).not.toBe(original) + writeFileSync(probeCopy, mutated) + + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.solid-941c.invalid", "", "ok")) + expect(r.code).toBe(1) + // 独立探测前后两轮全可达、复测不改口 —— 只能是判别依据退化,这道门必须失守给人看。 + expect(r.err).toContain("判别依据退化") + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941c-hooks") + }, 60_000) +}) diff --git a/scripts/assert-worktree-bootstrap.sh b/scripts/assert-worktree-bootstrap.sh index 2af1b0e1c209..fc1aac4b01a0 100755 --- a/scripts/assert-worktree-bootstrap.sh +++ b/scripts/assert-worktree-bootstrap.sh @@ -46,7 +46,12 @@ # 半装的树留在那」满足)、**且判别依据把它判成 `real` 而不是 `network`**。 # 少了最后半句,「一律算网络」这个错误实现能满足前两句。 # [6/6] 判别依据**真的判别**,且网络档**不报绿**: -# (a) registry 可达时必须判 `real`(直接杀掉「一律算网络」); +# (a) registry 可达时必须判 `real`(直接杀掉「一律算网络」)。「可达」不许由**单发**探测 +# 断言(`#941`:代理半通不通时,两发相隔几秒的 curl 会落在矛盾的两侧,健康仓库被硬红 +# 成「判据失守」)——先对可达性测 3 次取共识,共识可达而判别依据说 'network' 时再复核 +# 一轮(判别依据复测 + 再一轮共识)才许硬红;任何一处前后矛盾 ⇒ **本次测量作废** +# (未验证档,exit 2),真离线 ⇒ 未验证。恒 'network' 的退化实现复测不会改口, +# 在健康网络下**确定性**仍然硬红 —— 两个方向都留着判据,[6/6] 不是摆设。 # (b) registry 指向不可达地址时必须判 `network`(杀掉「一律算真失守」——那等于没有豁免); # (c) 报告契约:把整个探针**套跑一遍**并注入不可达 registry,断言它 **exit 2**、 # 输出里**有「未验证」**、且**没有**那句「新建 worktree 自己就能跑出可信 typecheck」。 @@ -207,6 +212,57 @@ live_registry_reachable() { curl -sS -o /dev/null --max-time 8 --head "$url" >/dev/null 2>&1 } +# ── `#941`:单发探测不构成「网络没问题」的地面真相 ───────────────────────────────── +# 2026-08-11 夜实测:同一台机器几分钟内,`curl registry.npmjs.org` 一次 0.9s 成、一次 7.2s 成, +# 同窗 `git fetch` 撞 SSL_ERROR_SYSCALL、`gh` 两次 EOF —— 代理**半通不通**时,两发相隔几秒的 +# curl 会落在矛盾的两侧。而 [5/6]/[6/6](a) 原本拿**一发** `live_registry_reachable` 当真相, +# 再拿它硬红判别依据 ⇒ 一个健康的仓库被判成「判据失守」(exit 1),训练人 `--no-verify` +# (`#754` 的形态)。「判别依据退化成恒 'network'」与「网络在抖」在单次采样下**不可分**, +# 所以判决前先把「可达性」这一个事实测多次取一致;测不出一致 ⇒ **本次测量作废**(未验证档), +# 不给判决 —— 与本仓「观测手段自己有盲区」那张表同一条判据。 +# +# 对「registry 此刻可达吗」连续测 3 次(间隔 1s,把采样窗摊开)。打印一个词: +# reachable — 3/3 可达 +# unreachable — 0/3 可达(真离线) +# unstable — 结果互相矛盾(半通不通)⇒ 这一刻不存在可信的地面真相 +registry_reachability_consensus() { + local i ok=0 + for i in 1 2 3; do + [ "$i" -gt 1 ] && sleep 1 + live_registry_reachable && ok=$((ok+1)) + done + case "$ok" in + 3) printf 'reachable' ;; + 0) printf 'unreachable' ;; + *) printf 'unstable' ;; + esac +} + +# 判别依据说了 'network' 之后的复核:是判别依据退化,还是网络在抖?打印一个词: +# degraded — 前后两轮独立探测(各 3 次)registry **全部**可达,且判别依据**复测仍**说 +# 'network' ⇒ 只能是判别依据退化成恒 'network'(硬红 —— 这道门永不失守的那个形态)。 +# offline — 独立探测一致不可达 ⇒ 真离线,real/network 本来就分不开 ⇒ 未验证。 +# unstable — 任何一处前后矛盾(探测结果不一,或判别依据复测改口)⇒ 半通不通, +# 本次测量作废 ⇒ 未验证。 +# 「恒 'network'」的退化实现在健康网络下**确定性**落到 degraded(它复测还是 'network', +# 而 6 发独立探测全成);健康判别依据在抖动网络下落到 offline/unstable(不冤枉判红)。 +adjudicate_network_verdict() { + local c1 v2 c2 + c1="$(registry_reachability_consensus)" + case "$c1" in + unreachable) printf 'offline'; return 0 ;; + unstable) printf 'unstable'; return 0 ;; + esac + # 独立探测一致可达 —— 结论不稳时再探一次再下判断:让判别依据自己复测,并再取一轮共识。 + v2="$(classify_bootstrap_failure)" + c2="$(registry_reachability_consensus)" + if [ "$v2" != real ] && [ "$c2" = reachable ]; then + printf 'degraded' + else + printf 'unstable' + fi +} + note_bootstrap_failure() { local verdict url verdict="$(classify_bootstrap_failure)" @@ -342,15 +398,26 @@ else # `${FAIL}` 必须带花括号:紧跟其后的是 CJK 顿号,UTF-8 locale 下 bash 会把那几个字节 # 一起当成变量名 ⇒ `FAIL<0xe3><0x80><0x81>: unbound variable`(set -u 下当场炸)。 echo " ✓ 非零退出(rc=$boot_rc)、没留下 .worktrees/${FAIL}、且判成 real(会拦住)" - elif live_registry_reachable; then - # registry 明明可达,判别依据却把一个**非网络**失败说成 network ⇒ 豁免成了万能挡箭牌: - # bootstrap 真坏掉的那天也会被当成网络放行,这道门从此永不失守。 - red "非网络失败(bun 缺失)被判别依据归成 '$verdict_real',而 registry 这一刻是可达的 —— 豁免成了万能挡箭牌" else - # 这台机器这一刻真的连不上 registry:`real` 与 `network` 本来就分不开(判别依据只有 - # 可达性这一个输入)。如实降级,不许当绿,也不冤枉判红。 - unverified=1 - echo " ⚠️ 未验证:registry 这一刻不可达,本条分不出 real / network(判别依据只看可达性)" + # 判别依据把一个**非网络**失败说成 network。硬红之前先复核(`#941`):单发探测在代理 + # 半通不通时会与判别依据落在矛盾的两侧,拿它当真相会把健康的仓库判成「判据失守」。 + case "$(adjudicate_network_verdict)" in + degraded) + # 前后两轮独立探测全可达、判别依据复测仍说 network ⇒ 豁免成了万能挡箭牌: + # bootstrap 真坏掉的那天也会被当成网络放行,这道门从此永不失守。 + red "非网络失败(bun 缺失)被判别依据归成 'network' 且复测不改口,而前后两轮独立探测 registry 全可达 —— 判别依据退化,豁免成了万能挡箭牌" + ;; + offline) + # 这台机器这一刻真的连不上 registry:`real` 与 `network` 本来就分不开(判别依据只有 + # 可达性这一个输入)。如实降级,不许当绿,也不冤枉判红。 + unverified=1 + echo " ⚠️ 未验证:registry 这一刻不可达,本条分不出 real / network(判别依据只看可达性)" + ;; + *) + unverified=1 + echo " ⚠️ 未验证:可达性探测前后矛盾(网络半通不通)—— 本次测量作废,本条分不出 real / network" + ;; + esac fi fi fi @@ -364,20 +431,39 @@ if [ "$verdict_net" != network ]; then else echo " ✓ 不可达 registry ⇒ network" fi -# (a) 可达 registry 必须判 real —— 直接杀掉「一律算网络」 +# (a) 可达 registry 必须判 real —— 直接杀掉「一律算网络」。 +# `#941`:「可达」不许由单发探测断言(半通不通时它与判别依据各落矛盾一侧,健康仓库被硬红)。 +# 先对可达性取共识;共识可达而判别依据仍说 network 时,再复核一轮才许硬红。 live_registry="$(resolve_registry 2>/dev/null || true)" -if live_registry_reachable; then - verdict_live="$(classify_bootstrap_failure)" - if [ "$verdict_live" != real ]; then - red "registry($live_registry)明明可达,判别依据却说 '$verdict_live' —— 一律算网络 = 这道门永不失守" - else - echo " ✓ 可达 registry($live_registry)⇒ real" - fi -else - # 本机这一刻真的连不上 registry:判别力这一条**证不了**,如实降级,不许当绿。 - unverified=1 - echo " ⚠️ 未验证:registry 这一刻不可达,'可达 ⇒ real' 这一半本次证不了" -fi +case "$(registry_reachability_consensus)" in + reachable) + verdict_live="$(classify_bootstrap_failure)" + if [ "$verdict_live" = real ]; then + echo " ✓ 可达 registry($live_registry)⇒ real" + else + case "$(adjudicate_network_verdict)" in + degraded) + red "registry($live_registry)前后两轮独立探测全可达,判别依据复测仍说 'network' —— 判别依据退化,一律算网络 = 这道门永不失守" + ;; + *) + # 复核期间结论翻了(判别依据改口 real,或独立探测不再一致可达)⇒ 网络在抖, + # 不存在可信的地面真相 —— 本次测量作废,不给判决。 + unverified=1 + echo " ⚠️ 未验证:可达性结论前后矛盾(网络半通不通)—— 本次测量作废,'可达 ⇒ real' 这一半证不了" + ;; + esac + fi + ;; + unreachable) + # 本机这一刻真的连不上 registry:判别力这一条**证不了**,如实降级,不许当绿。 + unverified=1 + echo " ⚠️ 未验证:registry 这一刻不可达,'可达 ⇒ real' 这一半本次证不了" + ;; + *) + unverified=1 + echo " ⚠️ 未验证:可达性探测三次结果不一(半通不通)—— 本次测量作废,'可达 ⇒ real' 这一半证不了" + ;; +esac # (c) 报告契约:套跑一遍并注入不可达 registry —— 必须 exit 2 + 说「未验证」+ 不说那句全绿话 if [ "$NESTED" = "1" ]; then echo " · 嵌套运行:跳过报告契约自检(断递归)" diff --git a/scripts/gate-files.tsv b/scripts/gate-files.tsv index 59d3f492517d..a6dfcd580140 100644 --- a/scripts/gate-files.tsv +++ b/scripts/gate-files.tsv @@ -180,4 +180,4 @@ 1 packages/ui-mac src/renderer/extensions/local-package-renderer.test.ts - `#893` 子进程宿主:REQ-128 Phase 3 [T4-renderer](#784)整条用户可达竖线的九跳闸 —— 生产 renderer × 生产 main IPC 表,含真事务、真 CAS 提升、真账本落盘,判据在 test-component/local-package-renderer.cases.ts(子进程 22 pass,并断言 `Ran 22 tests across 1 file`)。GlobalRegistrator 必须先于任何牵出 solid-js 的模块注册,故只能独立进程。删掉本宿主:第 1→9 跳的端到端可达性再无判据,而 ui-mac 计数只掉 1。下界=实际条数 1,不留余量 5 packages/ui-mac src/renderer/surface-remount.test.ts - `#565` REQ-109 第四闪机制的回归闸:挂真实生产壳(上游路由树 + 生产 AlphaHome + 生产 AlphaComposer + 生产 use-projects/runtime-recovery 恢复链),断言引擎迟到 init、WSL 迟到就绪/整台更替、token-only 换血 ×2 之后,生产打点 renderer.composer.mount **恰好 1**、DOM 节点同一、草稿原样保留(控制组先驱动一次真实身份切换证明计数器数得到 2)。另把 index.tsx 里被 harness 逐行复刻的三处咽喉(`ready()` 整段、`effectiveDefaultServer` 的 key 计算、外层门→keyed→AppInterface 五行)按精确文本钉死 —— 复刻漂移或有人往 `ready()` 并进新的收敛源(REQ-088 当年那条路径)即红。删掉它:『收敛/换血不重挂 composer』这条命题重新无人守,而整包计数只掉 5。下界=实际条数 5,不留余量 1 packages/ui-mac src/main/cloud-dispatch-gate.test.ts - `#918` 子进程宿主:桌面派发信封在 alpha-platform 诚实门(ap#262)下的可达性闸,判据在 src/main/cloud-dispatch-gate.cases.ts(子进程 6 pass / 0 fail)。mock.module + 替换 globalThis.fetch 决定了只能子进程跑,而子进程条数不进任何整包计数 —— 删掉本宿主 ui-mac 只掉 1 条,而「桌面的信封会不会被平台 400」这条保证一次全没。下界=实际条数 1,不留余量 -10 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 10,不留余量 +13 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设 From 92a9e457dddfb32e9e2d67aa80d74414b5a6d841 Mon Sep 17 00:00:00 2001 From: jinjunnn Date: Thu, 13 Aug 2026 02:04:30 -0400 Subject: [PATCH 2/4] =?UTF-8?q?fix(#941):=20R1=20=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E6=AD=A3=E6=96=B9=E5=90=91=20=E2=80=94=E2=80=94=20[2/6]/[4/6]?= =?UTF-8?q?=20=E5=A4=B1=E8=B4=A5=E8=B7=AF=E5=BE=84=E7=9A=84=20'real'=20?= =?UTF-8?q?=E5=88=A4=E5=86=B3=E5=85=88=E5=8F=96=E5=8F=AF=E8=BE=BE=E6=80=A7?= =?UTF-8?q?=E5=85=B1=E8=AF=86=E5=86=8D=E7=A1=AC=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审计 Major(采纳):note_bootstrap_failure 拿单发 curl 当地面真相 —— install 被网络 打死(暴露面 = 拉几千个包)而那一发 8s HEAD 恰好成功时,verdict='real' 直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push(#754 训练 --no-verify 的形态, 票面退出条件第一条明令禁止)。2026-08-13 实测复现:call#1 成、其后 17 发全败,旧码 exit 1。 修法(三分支,复用既有 registry_reachability_consensus): - verdict='network' —— 原样不动; - fail-closed 的 'real'(registry 解析不出 / 无 curl)—— 照旧直接红,**不进共识**。 这是对审计建议「unreachable 走不到这里」的实测偏离:那两种前提下共识与判别依据 同样解析不出 ⇒ 结构上恒 'unreachable',一律降未验证 = 这种机器上这道门永远 exit 2 永不失守,文件头点名的「豁免变万能挡箭牌」原样复活; - 其余 'real' —— 共识一致可达 ⇒ 照旧红(不放松真失守);共识不稳或与那一发正面 矛盾 ⇒ 本次测量作废,落未验证档 exit 2。 判据:worktree-probe-sweep.test.ts 补 3 条(13→16,gate-files.tsv 条数锚同步): ①失败+单发成功+共识抖 ⇒ exit 2 不硬红;②失败+共识一致可达 ⇒ 仍硬红且红来自 [2/6] 本身;③fail-closed 不进共识,探测全败也硬红。 Co-Authored-By: Claude Opus 5 (1M context) --- .../src/main/worktree-probe-sweep.test.ts | 51 ++++++++++++++++++- scripts/assert-worktree-bootstrap.sh | 24 ++++++++- scripts/gate-files.tsv | 2 +- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts index ab10adbcf0e5..d3bdba052064 100644 --- a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts +++ b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts @@ -112,6 +112,11 @@ function initFixture(opts: { install?: { corruptTo: string; holdSeconds: number } /** 额外提交进夹具仓根目录的文件(`#941` 的可控 typecheck 要以文件形态进探针 worktree)。 */ files?: Record + /** + * 额外的根 lifecycle 脚本(`#941` [2/6] 失败路径:`preinstall: "exit 47"` 让探针 worktree 里的 + * `bun install` 确定性非零 —— 从门的视角它与「install 被网络打死」**同形**,门只看得见非零退出)。 + */ + rootScripts?: Record }) { const root = mkdtempSync(join(tmpdir(), "alpha928-")) TEMP_ROOTS.push(root) @@ -133,6 +138,9 @@ function initFixture(opts: { prepare: `git config --local core.hooksPath ${opts.install.corruptTo} && sleep ${opts.install.holdSeconds} && git config --local core.hooksPath ${opts.install.corruptTo}`, } } + if (opts.rootScripts) { + rootPkg.scripts = { ...(rootPkg.scripts as Record | undefined), ...opts.rootScripts } + } writeFileSync(join(repo, "package.json"), JSON.stringify(rootPkg) + "\n") writeFileSync( join(repo, "packages", "ui-mac", "package.json"), @@ -475,11 +483,12 @@ describe("可达性判别依据(#941):半通不通降级,恒 'network' 硬红", "", ].join("\n") - function initFlakyFixture(hooksPath: string) { + function initFlakyFixture(hooksPath: string, rootScripts?: Record) { const fx = initFixture({ hooksPath, typecheckScript: "bash ../../fake-typecheck.sh", files: { "fake-typecheck.sh": FAKE_TYPECHECK }, + rootScripts, }) const stubDir = join(fx.root, "stub-bin") mkdirSync(stubDir, { recursive: true }) @@ -540,4 +549,44 @@ describe("可达性判别依据(#941):半通不通降级,恒 'network' 硬红", expect(r.err).toContain("判别依据退化") expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941c-hooks") }, 60_000) + + // ── `#941` R1 审计的正方向:[2/6]/[4/6] 的失败路径(note_bootstrap_failure)──────────── + // 已修的 [6/6](a)/[5/6] 管「判别依据说 network 而网络其实可达」;这三条管反过来那侧: + // **install 被网络打死,而判别依据的单发 curl 恰好落在成功那一侧** ⇒ verdict='real' ⇒ + // 旧实现直接硬红 exit 1 —— 健康仓库被「bootstrap 自己非零退出」拦住 push(#754 形态)。 + // bun install 要拉几千个包,网络暴露面比一发 8s HEAD 大得多,这条的命中概率不低于 [6/6](a)。 + test("正方向:[2/6] install 死了而单发探测恰好成功、共识抖(ok + ok ok fail)⇒ 未验证档 exit 2,不得硬红", () => { + const fx = initFlakyFixture(".lane-941d-hooks", { preinstall: "exit 47" }) + // 序列:第 1 发(判别依据)成功 ⇒ 'real';随后的可达性共识 ok ok fail = 2/3 ⇒ unstable。 + // 旧实现在第 1 发之后就 red「bootstrap 自己非零退出」并 exit 1,根本不看共识。 + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.flap-941d.invalid", "ok ok ok fail", "ok")) + expect(r.code).toBe(2) + expect(r.out).toContain("可达性共识与那一发探测矛盾") + expect(r.err).not.toContain("能力判据失守") + expect(registeredWorktreeNames(fx.repo, fx.home).filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941d-hooks") + }, 60_000) + + test("正方向的反面:install 真失败且共识一致可达(全 ok)⇒ [2/6] 仍必须硬红 exit 1", () => { + const fx = initFlakyFixture(".lane-941e-hooks", { preinstall: "exit 47" }) + // 杀「verdict='real' 一律降未验证」的错误实现:网络被前后 4 发独立探测证实是好的, + // 失败就是真的 —— 这道门必须失守给人看,不许把豁免拓宽成万能挡箭牌。 + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.solid-941e.invalid", "", "ok")) + expect(r.code).toBe(1) + expect(r.err).toContain("bootstrap 自己非零退出") + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941e-hooks") + }, 60_000) + + test("fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识:探测全败也必须硬红 exit 1", () => { + const fx = initFlakyFixture(".lane-941f-hooks", { preinstall: "exit 47" }) + // 这半是对审计建议的实测偏离:声明了未收编 registry 时,`registry_reachability_consensus` + // 与判别依据**同样**解析不出 ⇒ 结构上恒 'unreachable' —— 把它也降未验证,等于这种机器上 + // 这道门永远 exit 2 永不失守(文件头点名的「豁免变万能挡箭牌」)。判据:红必须来自 [2/6] + // 本身(「bootstrap 自己非零退出」),而不是只靠 [6/6](b) 陪跑出来的红撑住退出码。 + writeFileSync(join(fx.home, ".npmrc"), "registry=http://registry.failclosed-941f.invalid\n") + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.failclosed-941f.invalid", "", "fail")) + expect(r.code).toBe(1) + expect(r.err).toContain("bootstrap 自己非零退出") + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941f-hooks") + }, 60_000) }) diff --git a/scripts/assert-worktree-bootstrap.sh b/scripts/assert-worktree-bootstrap.sh index fc1aac4b01a0..2297d4e8c84b 100755 --- a/scripts/assert-worktree-bootstrap.sh +++ b/scripts/assert-worktree-bootstrap.sh @@ -271,8 +271,30 @@ note_bootstrap_failure() { unverified=1 echo " ⚠️ 未验证:registry 不可达($url)—— bun install 这次装不上,本步什么都没证明。" echo " 这**不是绿**:worktree bootstrap 能力本次未被验证;网络恢复后重跑。" - else + elif ! resolve_registry >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then + # fail-closed 的 `real`(registry 解析不出 / 没装 curl):这不是网络状态,是「判别依据的 + # 前提不成立」—— 没有豁免可谈,照旧拦住。**不许**把它送进下面的可达性共识:那两种前提下 + # `registry_reachability_consensus` 结构上恒返回 `unreachable`(它与判别依据同样解析不出 / + # 同样没 curl),一律降未验证 = 这种机器上这道门永远 exit 2 永不失守,文件头点名的 + # 「豁免变万能挡箭牌」原样复活。 red "$1" + else + # `#941` 正方向(与 [6/6](a) 的反方向对称):verdict='real' 也可能是「install 被抖死 + + # 单发探测恰好落在成功那一侧」—— bun install 要拉几千个包,网络暴露面比一发 8s HEAD 大 + # 得多,半通不通时两者常落矛盾的两侧(2026-08-13 实测:call#1 成、其后 17 发全败)。 + # 硬红之前对可达性取一次共识:一致可达 ⇒ 网络是好的,失败是真的,照旧红(不放松真失守); + # 否则(共识不稳,或共识不可达 = 与刚成功的那一发正面矛盾)⇒ 这一刻不存在可信的地面 + # 真相 —— 本次测量作废,落未验证档,不硬红。 + case "$(registry_reachability_consensus)" in + reachable) + red "$1" + ;; + *) + unverified=1 + echo " ⚠️ 未验证:bootstrap 非零退出,判别依据说 real,但可达性共识与那一发探测矛盾" + echo " (网络半通不通)—— 本次测量作废,本步什么都没证明;网络恢复后重跑。" + ;; + esac fi } diff --git a/scripts/gate-files.tsv b/scripts/gate-files.tsv index a6dfcd580140..3221751e4fc4 100644 --- a/scripts/gate-files.tsv +++ b/scripts/gate-files.tsv @@ -180,4 +180,4 @@ 1 packages/ui-mac src/renderer/extensions/local-package-renderer.test.ts - `#893` 子进程宿主:REQ-128 Phase 3 [T4-renderer](#784)整条用户可达竖线的九跳闸 —— 生产 renderer × 生产 main IPC 表,含真事务、真 CAS 提升、真账本落盘,判据在 test-component/local-package-renderer.cases.ts(子进程 22 pass,并断言 `Ran 22 tests across 1 file`)。GlobalRegistrator 必须先于任何牵出 solid-js 的模块注册,故只能独立进程。删掉本宿主:第 1→9 跳的端到端可达性再无判据,而 ui-mac 计数只掉 1。下界=实际条数 1,不留余量 5 packages/ui-mac src/renderer/surface-remount.test.ts - `#565` REQ-109 第四闪机制的回归闸:挂真实生产壳(上游路由树 + 生产 AlphaHome + 生产 AlphaComposer + 生产 use-projects/runtime-recovery 恢复链),断言引擎迟到 init、WSL 迟到就绪/整台更替、token-only 换血 ×2 之后,生产打点 renderer.composer.mount **恰好 1**、DOM 节点同一、草稿原样保留(控制组先驱动一次真实身份切换证明计数器数得到 2)。另把 index.tsx 里被 harness 逐行复刻的三处咽喉(`ready()` 整段、`effectiveDefaultServer` 的 key 计算、外层门→keyed→AppInterface 五行)按精确文本钉死 —— 复刻漂移或有人往 `ready()` 并进新的收敛源(REQ-088 当年那条路径)即红。删掉它:『收敛/换血不重挂 composer』这条命题重新无人守,而整包计数只掉 5。下界=实际条数 5,不留余量 1 packages/ui-mac src/main/cloud-dispatch-gate.test.ts - `#918` 子进程宿主:桌面派发信封在 alpha-platform 诚实门(ap#262)下的可达性闸,判据在 src/main/cloud-dispatch-gate.cases.ts(子进程 6 pass / 0 fail)。mock.module + 替换 globalThis.fetch 决定了只能子进程跑,而子进程条数不进任何整包计数 —— 删掉本宿主 ui-mac 只掉 1 条,而「桌面的信封会不会被平台 400」这条保证一次全没。下界=实际条数 1,不留余量 -13 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设 +16 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设。`#941` R1 审计再补三条(正方向 —— [2/6]/[4/6] 的失败路径 note_bootstrap_failure):install 被网络打死而判别依据的单发 curl 恰好成功 ⇒ verdict='real' ⇒ 旧实现直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push —— bun install 拉几千个包,网络暴露面比一发 8s HEAD 大得多,命中概率不低于 [6/6](a)。①失败 + 单发成功 + 共识抖(ok + ok ok fail)⇒ 未验证档 exit 2、说「可达性共识与那一发探测矛盾」、不打「能力判据失守」;②失败 + 共识一致可达(全 ok)⇒ 仍必须硬红 exit 1 且红来自 [2/6] 本身 —— 杀「real 一律降未验证」的放松实现;③fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识、探测全败也硬红 —— 那两种前提下共识结构上恒 'unreachable',把它也降未验证 = 这种机器上这道门永远 exit 2 永不失守(豁免变万能挡箭牌) From 40c5b4bee4a3413a112858192afb999b8b3b920d Mon Sep 17 00:00:00 2001 From: jinjunnn Date: Thu, 13 Aug 2026 02:47:20 -0400 Subject: [PATCH 3/4] =?UTF-8?q?fix(#941):=20R1=20Minor=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20adjudicate=20=E7=AC=AC=E4=BA=8C=E8=BD=AE=E5=85=B1?= =?UTF-8?q?=E8=AF=86(c2)=E8=A1=A5=E5=88=A4=E6=8D=AE:=E9=9D=99=E9=BB=98?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=82=A3=E5=8D=8A=E5=BF=85=E9=A1=BB=E8=BD=AC?= =?UTF-8?q?=E7=BA=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审计实测:删掉 c2 连同 && [ "$c2" = reachable ],原 13 条一条不红 —— 三条 #941 用例 都进不到那个分支(A 共识本身 unstable、B 在 v2 复测改口、C 全程稳定 c2 恒 reachable)。 行为退化是真的:网络在第一轮共识之后才开始抖时,健康判别依据会被判成 degraded 硬红, 回到「健康仓库被硬红」。本仓失效形态⑦(可静默删除)。 新用例:恒 network 突变 + c1 全 ok(reachable)+ c2 抖一发(ok fail)⇒ 必须 unstable 落未验证档 exit 2;删 c2 那半 ⇒ degraded exit 1 当场红。尾段序列喂 [6/6](a) 外层共识, 隔离突变体在稳定网络下 (a) 处的 degraded 硬红。gate-files.tsv 16→17。 Refs jinjunnn/alpha-code#941 Co-Authored-By: Claude Opus 5 (1M context) --- .../src/main/worktree-probe-sweep.test.ts | 30 +++++++++++++++++++ scripts/gate-files.tsv | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts index d3bdba052064..29b3a432c954 100644 --- a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts +++ b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts @@ -589,4 +589,34 @@ describe("可达性判别依据(#941):半通不通降级,恒 'network' 硬红", expect(r.err).toContain("bootstrap 自己非零退出") expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941f-hooks") }, 60_000) + + // ── `#941` R1 合并前两条 Minor 的判据 ────────────────────────────────────────────── + test("R1 Minor:adjudicate 的第二轮共识(c2)被静默删除必须有人红 —— c1 全 ok、复测仍 network、c2 抖一发 ⇒ 未验证 exit 2,不得硬红", () => { + const fx = initFlakyFixture(".lane-941g-hooks") + // 钉的是 adjudicate 里 `c2` 那一半(本仓失效形态⑦:审计实测把 `c2=…` 连同 + // `&& [ "$c2" = reachable ]` 删掉,原有用例一条不红 —— A 的共识本身 unstable 进不了 + // adjudicate、B 在 v2 复测处改口、C 全程网络稳定 c2 恒 reachable)。删掉之后的行为退化 + // 是真的:网络在第一轮共识**之后**才开始抖时,健康的判别依据(这一刻真连不上所以说 + // network)会被判成 degraded 硬红 —— 又回到「健康仓库被硬红」。 + // 夹具沿用 C 的恒 network 突变让 v2 不改口;序列让 [5/6] adjudicate 的 c1 全 ok(3 发, + // reachable)、c2 落在矛盾对(ok fail ⇒ unstable)⇒ 只能走「本次测量作废」的未验证档。 + // 尾段的 ok fail 喂给 [6/6](a) 的外层共识,否则突变体在稳定网络下会在 (a) 处 degraded + // 硬红,污染对 c2 的判决;位点同时按「非 reachable 两发定局」与「恒 3 发整轮」两种共识 + // 排布,Minor 2 单独回退时本条仍绿 —— 两条 Minor 的绕过实验互不牵连。 + const probeCopy = join(fx.repo, "scripts", "assert-worktree-bootstrap.sh") + const original = readFileSync(probeCopy, "utf8") + const mutated = original.replace( + "classify_bootstrap_failure() {\n", + "classify_bootstrap_failure() { printf 'network'; return 0; }\nclassify_bootstrap_failure_dead() {\n", + ) + expect(mutated).not.toBe(original) + writeFileSync(probeCopy, mutated) + + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.flap-941g.invalid", "ok ok ok ok fail ok fail", "ok")) + expect(r.code).toBe(2) + expect(r.out).toContain("可达性探测前后矛盾") + expect(r.err).not.toContain("能力判据失守") + expect(registeredWorktreeNames(fx.repo, fx.home).filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941g-hooks") + }, 60_000) }) diff --git a/scripts/gate-files.tsv b/scripts/gate-files.tsv index 3221751e4fc4..cfbb5e042dc3 100644 --- a/scripts/gate-files.tsv +++ b/scripts/gate-files.tsv @@ -180,4 +180,4 @@ 1 packages/ui-mac src/renderer/extensions/local-package-renderer.test.ts - `#893` 子进程宿主:REQ-128 Phase 3 [T4-renderer](#784)整条用户可达竖线的九跳闸 —— 生产 renderer × 生产 main IPC 表,含真事务、真 CAS 提升、真账本落盘,判据在 test-component/local-package-renderer.cases.ts(子进程 22 pass,并断言 `Ran 22 tests across 1 file`)。GlobalRegistrator 必须先于任何牵出 solid-js 的模块注册,故只能独立进程。删掉本宿主:第 1→9 跳的端到端可达性再无判据,而 ui-mac 计数只掉 1。下界=实际条数 1,不留余量 5 packages/ui-mac src/renderer/surface-remount.test.ts - `#565` REQ-109 第四闪机制的回归闸:挂真实生产壳(上游路由树 + 生产 AlphaHome + 生产 AlphaComposer + 生产 use-projects/runtime-recovery 恢复链),断言引擎迟到 init、WSL 迟到就绪/整台更替、token-only 换血 ×2 之后,生产打点 renderer.composer.mount **恰好 1**、DOM 节点同一、草稿原样保留(控制组先驱动一次真实身份切换证明计数器数得到 2)。另把 index.tsx 里被 harness 逐行复刻的三处咽喉(`ready()` 整段、`effectiveDefaultServer` 的 key 计算、外层门→keyed→AppInterface 五行)按精确文本钉死 —— 复刻漂移或有人往 `ready()` 并进新的收敛源(REQ-088 当年那条路径)即红。删掉它:『收敛/换血不重挂 composer』这条命题重新无人守,而整包计数只掉 5。下界=实际条数 5,不留余量 1 packages/ui-mac src/main/cloud-dispatch-gate.test.ts - `#918` 子进程宿主:桌面派发信封在 alpha-platform 诚实门(ap#262)下的可达性闸,判据在 src/main/cloud-dispatch-gate.cases.ts(子进程 6 pass / 0 fail)。mock.module + 替换 globalThis.fetch 决定了只能子进程跑,而子进程条数不进任何整包计数 —— 删掉本宿主 ui-mac 只掉 1 条,而「桌面的信封会不会被平台 400」这条保证一次全没。下界=实际条数 1,不留余量 -16 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设。`#941` R1 审计再补三条(正方向 —— [2/6]/[4/6] 的失败路径 note_bootstrap_failure):install 被网络打死而判别依据的单发 curl 恰好成功 ⇒ verdict='real' ⇒ 旧实现直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push —— bun install 拉几千个包,网络暴露面比一发 8s HEAD 大得多,命中概率不低于 [6/6](a)。①失败 + 单发成功 + 共识抖(ok + ok ok fail)⇒ 未验证档 exit 2、说「可达性共识与那一发探测矛盾」、不打「能力判据失守」;②失败 + 共识一致可达(全 ok)⇒ 仍必须硬红 exit 1 且红来自 [2/6] 本身 —— 杀「real 一律降未验证」的放松实现;③fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识、探测全败也硬红 —— 那两种前提下共识结构上恒 'unreachable',把它也降未验证 = 这种机器上这道门永远 exit 2 永不失守(豁免变万能挡箭牌) +17 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设。`#941` R1 审计再补三条(正方向 —— [2/6]/[4/6] 的失败路径 note_bootstrap_failure):install 被网络打死而判别依据的单发 curl 恰好成功 ⇒ verdict='real' ⇒ 旧实现直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push —— bun install 拉几千个包,网络暴露面比一发 8s HEAD 大得多,命中概率不低于 [6/6](a)。①失败 + 单发成功 + 共识抖(ok + ok ok fail)⇒ 未验证档 exit 2、说「可达性共识与那一发探测矛盾」、不打「能力判据失守」;②失败 + 共识一致可达(全 ok)⇒ 仍必须硬红 exit 1 且红来自 [2/6] 本身 —— 杀「real 一律降未验证」的放松实现;③fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识、探测全败也硬红 —— 那两种前提下共识结构上恒 'unreachable',把它也降未验证 = 这种机器上这道门永远 exit 2 永不失守(豁免变万能挡箭牌)。`#941` R1 合并前两 Minor 再补两条:④adjudicate 第二轮共识 c2 可被静默删除(失效形态⑦,审计实测删掉 c2 连同判断原 13 条一条不红)—— 恒 network 突变 + c1 全 ok(3 发 reachable)+ c2 抖一发 ⇒ 必须 unstable 落未验证 exit 2;删 c2 那半 ⇒ degraded 硬红 exit 1 当场红。退化是真的:网络在第一轮共识之后才开始抖时,健康判别依据会被硬红 From 0652209e62be042d51ee389892edccb49f1cab21 Mon Sep 17 00:00:00 2001 From: jinjunnn Date: Thu, 13 Aug 2026 02:47:40 -0400 Subject: [PATCH 4/4] =?UTF-8?q?fix(#941):=20R1=20Minor=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E5=85=B1=E8=AF=86=E5=AF=B9=E9=9D=9E=20reachable=20?= =?UTF-8?q?=E7=BB=93=E8=AE=BA=E4=B8=A4=E5=8F=91=E5=AE=9A=E5=B1=80=E6=97=A9?= =?UTF-8?q?=E9=80=80,=E6=8C=82=E8=B5=B7=E4=BB=A3=E7=90=86=E4=B8=8B?= =?UTF-8?q?=E9=97=A8=2069.9s=E2=86=9251.8s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审计实测成立:+2~4s 只在 curl 快速失败(127.0.0.1:9 是 connection-refused,0.02s)时成立; 挂起代理(accept 后不回数据)下每发吃满 --max-time 8s,恒 3 发共识 26s/轮,整道门 +50s —— 门被拉长抬高外层工具超时 SIGKILL 打进 bun install 窗口的概率,正是 #928/#945 竞态的触发条件。 三条修法拿实测判:①max-time 3s 拒(自陈实测有 7.2s 慢成功,挂起形状造得出、真实抖动的 慢成功造不出,「3s 不误伤」结构上证不了;审计原文:证不出就选②/③);③复用 c1 拒(基线 curl 逐调用日志显示挂起形状下 c2 零调用、[6/6](a) 的 adjudicate 零进入 —— 没有可复用的轮, 省 0s;且它删的正是上一条 Minor 要钉的那半)。采②,带一处偏离:原文「前两发一致即返回」 会把 reachable 样本量 3→2,而 reachable 是唯一给硬红发许可证的共识(degraded 硬红、[2/6] real 硬红都以它为前提)—— 挂起形状里探针全 fail,fail 侧两发定局早退已拿走全部时间收益, 故 reachable 仍需 3 发全成,硬红许可证样本量不降;unreachable/unstable 在全部消费点同义 (都落未验证、都不发硬红许可),第三发翻不了案。 实测(本机挂起端口 127.0.0.1:8471):修前 69.9s/9 发,修后 51.8s/7 发,共识轮 26s→17s; exit 2 与全部未验证文案不变、零残留、hooks 还原。判据 = 探测计数钉死(全程不可达的一跑 恰好 5 发):回退恒 3 发 ⇒ 7 发红,砍到单发 ⇒ 3 发也红。gate-files.tsv 17→18。 Refs jinjunnn/alpha-code#941 Co-Authored-By: Claude Opus 5 (1M context) --- .../src/main/worktree-probe-sweep.test.ts | 23 ++++++++++- scripts/assert-worktree-bootstrap.sh | 40 +++++++++++-------- scripts/gate-files.tsv | 2 +- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts index 29b3a432c954..19a82063f879 100644 --- a/packages/ui-mac/src/main/worktree-probe-sweep.test.ts +++ b/packages/ui-mac/src/main/worktree-probe-sweep.test.ts @@ -288,8 +288,8 @@ describe("生产接线:真跑 scripts/assert-worktree-bootstrap.sh(alpha-check expect(names.filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) expect(names).toContain("lane-620-continue") expect(hooksPathOf(repo, home)).toBe(".lane-928-hooks") - // `#941`:可达性共识探测(两轮 × 3 发,发间隔 1s)让离线夹具里的完整一跑确定性多花 ~4s, - // 默认 5s 超时会被顶破 —— 与同组其余用例一致取 30s。 + // `#941`:可达性共识探测(两轮;非 reachable 两发定局早退,发间隔 1s)让离线夹具里的 + // 完整一跑确定性多花 ~2s,默认 5s 超时仍可能被顶破 —— 与同组其余用例一致取 30s。 }, 30_000) test("被信号打断(SIGTERM 落在探针已建出之后):同样零残留,且 core.hooksPath 还原", async () => { @@ -619,4 +619,23 @@ describe("可达性判别依据(#941):半通不通降级,恒 'network' 硬红", expect(registeredWorktreeNames(fx.repo, fx.home).filter((n) => n.startsWith("wtboot-probe-"))).toEqual([]) expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941g-hooks") }, 60_000) + + test("R1 Minor(hang 形状耗时):共识对非 reachable 结论两发定局 —— 全程不可达的一跑恰好 5 发探测,exit 2", () => { + const fx = initFlakyFixture(".lane-941h-hooks") + // `#928` 的因果链:挂起代理(accept 后不回数据,非 connection-refused —— 127.0.0.1:9 是 + // 后者,量不出这个形状)下每发 curl 吃满 --max-time 8s,恒 3 发共识 = 26s/轮,整道门 + // +50s ⇒ 抬高被外层工具超时 SIGKILL 打进 bun install 窗口的概率(#945/#928 竞态的触发 + // 条件)。实测(2026-08-13,本机挂起端口):修前 69.9s / 9 发,修后 51.8s / 7 发。 + // fail 侧早退不降任何判据:unreachable/unstable 在全部消费点同义(都落未验证、都不发 + // 硬红许可),reachable 仍要 3 发全成 —— 硬红许可证的样本量不降。 + // 本条用探测计数钉死早退真的发生:[5/6] classify 1 发 + c1 两发定局 + [6/6](a) 两发定局 + // = 恰好 5 发。两个方向都红:回退成恒 3 发 ⇒ 7 发(门被拉长);共识被砍到单发 ⇒ 3 发 + // (#941 的地基被拆)。 + const r = run(fx.repo, ["bash", "scripts/assert-worktree-bootstrap.sh"], fx.home, flakyEnv(fx, "http://registry.hang-941h.invalid", "", "fail")) + expect(r.code).toBe(2) + expect(r.out).toContain("registry 这一刻不可达") + expect(r.err).not.toContain("能力判据失守") + expect(readFileSync(join(fx.root, "curl-calls.n"), "utf8").trim()).toBe("5") + expect(hooksPathOf(fx.repo, fx.home)).toBe(".lane-941h-hooks") + }, 60_000) }) diff --git a/scripts/assert-worktree-bootstrap.sh b/scripts/assert-worktree-bootstrap.sh index 2297d4e8c84b..8d2b84e6df15 100755 --- a/scripts/assert-worktree-bootstrap.sh +++ b/scripts/assert-worktree-bootstrap.sh @@ -48,7 +48,9 @@ # [6/6] 判别依据**真的判别**,且网络档**不报绿**: # (a) registry 可达时必须判 `real`(直接杀掉「一律算网络」)。「可达」不许由**单发**探测 # 断言(`#941`:代理半通不通时,两发相隔几秒的 curl 会落在矛盾的两侧,健康仓库被硬红 -# 成「判据失守」)——先对可达性测 3 次取共识,共识可达而判别依据说 'network' 时再复核 +# 成「判据失守」)——先对可达性取共识(可达要 3 发全成;非可达两发定局早退,R1 Minor: +# 挂起代理下第三发只花 8s 不改结论,门被拉长会抬高外层超时 SIGKILL 的概率 `#928`), +# 共识可达而判别依据说 'network' 时再复核 # 一轮(判别依据复测 + 再一轮共识)才许硬红;任何一处前后矛盾 ⇒ **本次测量作废** # (未验证档,exit 2),真离线 ⇒ 未验证。恒 'network' 的退化实现复测不会改口, # 在健康网络下**确定性**仍然硬红 —— 两个方向都留着判据,[6/6] 不是摆设。 @@ -221,21 +223,27 @@ live_registry_reachable() { # 所以判决前先把「可达性」这一个事实测多次取一致;测不出一致 ⇒ **本次测量作废**(未验证档), # 不给判决 —— 与本仓「观测手段自己有盲区」那张表同一条判据。 # -# 对「registry 此刻可达吗」连续测 3 次(间隔 1s,把采样窗摊开)。打印一个词: -# reachable — 3/3 可达 -# unreachable — 0/3 可达(真离线) -# unstable — 结果互相矛盾(半通不通)⇒ 这一刻不存在可信的地面真相 +# 对「registry 此刻可达吗」串行采样(间隔 1s,把采样窗摊开)。打印一个词: +# reachable — 3 发全成。唯一会给硬红开门的共识(degraded 硬红与 note 的 real 硬红都以它 +# 为前提),样本量**不降** —— `#941` 的地基就是「单发不构成地面真相」,两发同理。 +# unreachable — 前两发全败,**两发定局早退**(`#941` R1 Minor)。挂起代理(accept 后不回 +# 数据,非 connection-refused)下每发吃满 --max-time 8s,恒 3 发 = 26s/轮, +# 整道门 +50s(实测 2026-08-13,本机挂起端口:69.9s → ~52s)。省掉的第三发 +# 不砍任何判据:unreachable 与 unstable 在**全部**消费点同义(都落未验证、 +# 都不发硬红许可),它只花 8s 不改任何结论。门被拉长的真实代价不是等待,是 +# 抬高被外层工具超时 SIGKILL 打进 bun install 窗口的概率(`#928`/`#945` 那条 +# 竞态的触发条件)。 +# unstable — 两发矛盾即定局(半通不通;unanimity 下第三发翻不了案,早退零语义变化)⇒ +# 这一刻不存在可信的地面真相;或前两发全成而第三发矛盾。 registry_reachability_consensus() { - local i ok=0 - for i in 1 2 3; do - [ "$i" -gt 1 ] && sleep 1 - live_registry_reachable && ok=$((ok+1)) - done - case "$ok" in - 3) printf 'reachable' ;; - 0) printf 'unreachable' ;; - *) printf 'unstable' ;; - esac + local a b + live_registry_reachable; a=$? + sleep 1 + live_registry_reachable; b=$? + if [ "$a" -ne "$b" ]; then printf 'unstable'; return 0; fi + if [ "$a" -ne 0 ]; then printf 'unreachable'; return 0; fi + sleep 1 + if live_registry_reachable; then printf 'reachable'; else printf 'unstable'; fi } # 判别依据说了 'network' 之后的复核:是判别依据退化,还是网络在抖?打印一个词: @@ -483,7 +491,7 @@ case "$(registry_reachability_consensus)" in ;; *) unverified=1 - echo " ⚠️ 未验证:可达性探测三次结果不一(半通不通)—— 本次测量作废,'可达 ⇒ real' 这一半证不了" + echo " ⚠️ 未验证:可达性探测结果前后不一(半通不通)—— 本次测量作废,'可达 ⇒ real' 这一半证不了" ;; esac # (c) 报告契约:套跑一遍并注入不可达 registry —— 必须 exit 2 + 说「未验证」+ 不说那句全绿话 diff --git a/scripts/gate-files.tsv b/scripts/gate-files.tsv index cfbb5e042dc3..e55745b1fb01 100644 --- a/scripts/gate-files.tsv +++ b/scripts/gate-files.tsv @@ -180,4 +180,4 @@ 1 packages/ui-mac src/renderer/extensions/local-package-renderer.test.ts - `#893` 子进程宿主:REQ-128 Phase 3 [T4-renderer](#784)整条用户可达竖线的九跳闸 —— 生产 renderer × 生产 main IPC 表,含真事务、真 CAS 提升、真账本落盘,判据在 test-component/local-package-renderer.cases.ts(子进程 22 pass,并断言 `Ran 22 tests across 1 file`)。GlobalRegistrator 必须先于任何牵出 solid-js 的模块注册,故只能独立进程。删掉本宿主:第 1→9 跳的端到端可达性再无判据,而 ui-mac 计数只掉 1。下界=实际条数 1,不留余量 5 packages/ui-mac src/renderer/surface-remount.test.ts - `#565` REQ-109 第四闪机制的回归闸:挂真实生产壳(上游路由树 + 生产 AlphaHome + 生产 AlphaComposer + 生产 use-projects/runtime-recovery 恢复链),断言引擎迟到 init、WSL 迟到就绪/整台更替、token-only 换血 ×2 之后,生产打点 renderer.composer.mount **恰好 1**、DOM 节点同一、草稿原样保留(控制组先驱动一次真实身份切换证明计数器数得到 2)。另把 index.tsx 里被 harness 逐行复刻的三处咽喉(`ready()` 整段、`effectiveDefaultServer` 的 key 计算、外层门→keyed→AppInterface 五行)按精确文本钉死 —— 复刻漂移或有人往 `ready()` 并进新的收敛源(REQ-088 当年那条路径)即红。删掉它:『收敛/换血不重挂 composer』这条命题重新无人守,而整包计数只掉 5。下界=实际条数 5,不留余量 1 packages/ui-mac src/main/cloud-dispatch-gate.test.ts - `#918` 子进程宿主:桌面派发信封在 alpha-platform 诚实门(ap#262)下的可达性闸,判据在 src/main/cloud-dispatch-gate.cases.ts(子进程 6 pass / 0 fail)。mock.module + 替换 globalThis.fetch 决定了只能子进程跑,而子进程条数不进任何整包计数 —— 删掉本宿主 ui-mac 只掉 1 条,而「桌面的信封会不会被平台 400」这条保证一次全没。下界=实际条数 1,不留余量 -17 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设。`#941` R1 审计再补三条(正方向 —— [2/6]/[4/6] 的失败路径 note_bootstrap_failure):install 被网络打死而判别依据的单发 curl 恰好成功 ⇒ verdict='real' ⇒ 旧实现直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push —— bun install 拉几千个包,网络暴露面比一发 8s HEAD 大得多,命中概率不低于 [6/6](a)。①失败 + 单发成功 + 共识抖(ok + ok ok fail)⇒ 未验证档 exit 2、说「可达性共识与那一发探测矛盾」、不打「能力判据失守」;②失败 + 共识一致可达(全 ok)⇒ 仍必须硬红 exit 1 且红来自 [2/6] 本身 —— 杀「real 一律降未验证」的放松实现;③fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识、探测全败也硬红 —— 那两种前提下共识结构上恒 'unreachable',把它也降未验证 = 这种机器上这道门永远 exit 2 永不失守(豁免变万能挡箭牌)。`#941` R1 合并前两 Minor 再补两条:④adjudicate 第二轮共识 c2 可被静默删除(失效形态⑦,审计实测删掉 c2 连同判断原 13 条一条不红)—— 恒 network 突变 + c1 全 ok(3 发 reachable)+ c2 抖一发 ⇒ 必须 unstable 落未验证 exit 2;删 c2 那半 ⇒ degraded 硬红 exit 1 当场红。退化是真的:网络在第一轮共识之后才开始抖时,健康判别依据会被硬红 +18 packages/ui-mac src/main/worktree-probe-sweep.test.ts - `#928`:跑门不许泄漏探针 worktree 的**行为闸**。alpha-check 第 [8/9] 步在**共享主 checkout** 里真建三棵探针 worktree、真跑 `bun install`(装好一棵 2.8 GB),跑完必须清干净;实测 2026-08-11 一晚四条 lane 跑五次门剩 **4 棵 6.3 GB**、另一次三跑剩三棵 8 GB,而且泄漏体是**注册在案的** worktree(`git worktree list` 越来越长,`worktree prune` 清不掉)。勘破跑出来的结论:`trap cleanup EXIT` 本身没坏(`bash -x` 全程录到 `+ cleanup` 真执行、零残留;TERM/INT/HUP 三者 EXIT trap 都跑,对整个 process group 发也一样),**只有 SIGKILL 结构上跑不了任何 trap** —— 对整组 `kill -KILL` 且落在 `bun install` 写盘时,复现出票面那个状态:一棵 496M **半装**的树,既注册在案又在盘上(票面四棵 533M/1.0G/2.1G/2.7G 对完整的 2.8G,全是半装 ⇒ 那几次都在 install 中途被杀,`-neg` 已删、`-fail` 未建,故只剩 `-pos`)。⇒ 修法只能是**开跑时清上一轮**。七条:A 组五条判清扫本体(无主残骸登记与目录一起消失 / 并发 lane 正在用的探针必须原封不动 / pid 复用时仍然清 / 不是探针的 worktree 与只是前缀长得像的一律不碰 / 只在盘上没登记的无主残骸也清),清过头与不清一样坏 —— 误删并发 lane 的树 = 别人的门在与他改动无关的地方变红 ⇒ `--no-verify` ⇒ 九道门一起关掉;B 组五条判**生产接线**,前四条隔着 assert 层,把 scripts/assert-worktree-bootstrap.sh 整条跑在隔离小仓里,分走「脚本中途失败」「SIGTERM 落在 typecheck 窗口」「SIGTERM 确定性落在 bootstrap 子进程仍在 install 的窗口(`#945` 的间歇红:父的 EXIT trap 立即跑且还原正确,**孤儿化的 bootstrap 子进程带陈旧基线晚 2s 覆写** —— 修法=cleanup 先收割飞行中的子写手再还原;信号用例断言前等 fixture 进程全部死透,否则迟到覆写落在读之后=假绿)」「SIGINT 落在同一窗口(bash 3.2 默认把 pid 级 INT 整个丢弃 ⇒ 无 INT trap 的实现会把后续步骤全部跑完;判 exit 130 + 不再出现 [4/6] + 还原)」四条路径;第五条**不经过 assert 层、直接 spawn scripts/worktree-bootstrap.sh**(runbook 点名的人手命令)并把 TERM 打进 install 窗口 —— assert 层的 reap_owned 会掩住 bootstrap 自己的还原,删掉它的 `trap boot_cleanup EXIT` 前九条照样全绿(审计 MUT4 实测);husky-sim 的 prepare 在 sleep 后还有第二次脏写 = 确定性的晚到写手,「只还原、不收割」的实现也当场红。各自单独断言跑完零 `wtboot-probe-*` 残留**且**共享 `core.hooksPath` 还是跑之前那个值(四条用不同字面量 `.lane-928-hooks` / `.lane-42-hooks` / `.lane-77-hooks` / `.lane-58-hooks`,husky-sim 的脏值也各不同且非 `.husky/_` —— 写死 husky 字面量才还原的错误实现当场红;此前两件事共用同一个 cleanup,一条路径不跑就同时丢掉,其中一件是共享配置 ⇒ 下一个人 git push 撞上 husky 那份恒红钩子)。不断言「代码里有 trap」—— 本票恰恰证明了有 trap 也可以不跑。删掉它:清扫可被整段删除、可只清一半、也可反过来吃掉并发 lane 的树,而没有任何东西变红。下界=实际条数 13,不留余量。`#941` 补三条(可达性判别依据):单发 curl 探测不构成「网络没问题」的地面真相 —— 代理半通不通时(实测 2026-08-11 夜:同窗 curl 一次 0.9s 成/一次 7.2s 成、git fetch SSL_ERROR_SYSCALL、gh EOF×2),[6/6](a) 与 [5/6] 的单发探测会与判别依据落在矛盾两侧,健康仓库被硬红成「判据失守」exit 1 ⇒ 训练人 --no-verify(#754 形态)。两条方向一(夹具序列取自真实复现,curl 桩 3~4 发里抖 1 发,分别打 [6/6](a) 探测窗与 [5/6] 判决窗):必须落未验证档 exit 2、说「本次测量作废」、不打「能力判据失守」;一条方向二(把判别依据改成恒 network 的绕过形态 + 网络稳定可达):独立探测前后两轮全可达且复测不改口 ⇒ 仍必须硬红 exit 1 —— 少了这半,「结论不稳一律未验证」会把真退化也放行,[6/6] 变摆设。`#941` R1 审计再补三条(正方向 —— [2/6]/[4/6] 的失败路径 note_bootstrap_failure):install 被网络打死而判别依据的单发 curl 恰好成功 ⇒ verdict='real' ⇒ 旧实现直接硬红 exit 1,健康仓库被「bootstrap 自己非零退出」拦住 push —— bun install 拉几千个包,网络暴露面比一发 8s HEAD 大得多,命中概率不低于 [6/6](a)。①失败 + 单发成功 + 共识抖(ok + ok ok fail)⇒ 未验证档 exit 2、说「可达性共识与那一发探测矛盾」、不打「能力判据失守」;②失败 + 共识一致可达(全 ok)⇒ 仍必须硬红 exit 1 且红来自 [2/6] 本身 —— 杀「real 一律降未验证」的放松实现;③fail-closed 的 real(HOME/.npmrc 声明未收编 registry)不进共识、探测全败也硬红 —— 那两种前提下共识结构上恒 'unreachable',把它也降未验证 = 这种机器上这道门永远 exit 2 永不失守(豁免变万能挡箭牌)。`#941` R1 合并前两 Minor 再补两条:④adjudicate 第二轮共识 c2 可被静默删除(失效形态⑦,审计实测删掉 c2 连同判断原 13 条一条不红)—— 恒 network 突变 + c1 全 ok(3 发 reachable)+ c2 抖一发 ⇒ 必须 unstable 落未验证 exit 2;删 c2 那半 ⇒ degraded 硬红 exit 1 当场红。退化是真的:网络在第一轮共识之后才开始抖时,健康判别依据会被硬红。⑤hang 形状耗时闸:挂起代理(accept 后不回数据,非 connection-refused)下每发吃满 --max-time 8s,恒 3 发共识 26s/轮、整道门 +50s ⇒ 抬高外层超时 SIGKILL 打进 bun install 窗口的概率(#928/#945 触发条件);修法 = 共识对非 reachable 结论两发定局早退(unreachable/unstable 在全部消费点同义,都落未验证、都不发硬红许可,第三发翻不了案),reachable 仍需 3 发全成 —— 硬红许可证样本量不降;实测挂起端口 69.9s/9 发 → 51.8s/7 发。判据 = 探测计数钉死:全程不可达的一跑恰好 5 发,回退恒 3 发 ⇒ 7 发红,砍到单发 ⇒ 3 发也红