Skip to content

[#777][CODE] 门在自己的标准环境里跑不出真结果:整类枚举 + 环境咽喉 + 本地门与 CI 的对照断言 - #804

Merged
jinjunnn merged 5 commits into
alphafrom
feat/777-gate-env-truth
Aug 3, 2026
Merged

[#777][CODE] 门在自己的标准环境里跑不出真结果:整类枚举 + 环境咽喉 + 本地门与 CI 的对照断言#804
jinjunnn merged 5 commits into
alphafrom
feat/777-gate-env-truth

Conversation

@jinjunnn

@jinjunnn jinjunnn commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Fixes #777

大白话

一批质量门在它们被设计要跑的那个环境里跑不出真结果 —— 不是发现了问题,是跑不起来、或者
根本没被执行。恒红的门等于没有门(大家会习惯性 --no-verify / --admin);假绿的门更糟
(它主动告诉你"没事")。半个月内同一形态第四次,所以这次不逐个修:枚举整类 + 咽喉收口

票面第三个实例已证伪

票面说 alpha-check.sh 的 typecheck 步在 base 上红 202 条。实测三个包 typecheck 全部 exit 0,
bun test src 3756 pass / 0 fail;那 202 条来自依赖没链全的 worktree,真因是 #796
(worktree-link-deps.sh 不链 .bin),已于 alpha@10daf61b 修复。

今天真正在烧的是另一道门。

枚举结果

docs/architecture/quality-gate-environments.md —— 每道门 × 每个环境 × 真实状态,
两条互相独立的检索轴交叉验证。其中两条轴给出了不同答案(按文件 grep timeout 漏掉 6 个
数字第三参形态;按文件计数会数错,粒度必须是每条 test(...) 声明),都记在文里。

修了四个实例 + 两条连带伤害

# 病灶 修法
A unit tests (alpha packages)alpha 主线上自 2026-08-02 起连续两天全红(实测 8 个 run id,凡带代码的 run 无一例外);同一棵树开发机 0 fail 见 B/C/D
B 两条失败是 platform linux not supported by this entry — refusing before any disk write —— 生产 synthesizeManifestcompatibility.platforms 写死 ["darwin","win32"](ADR-026),runner 是 ubuntu preload 里钉平台 + 打印自陈 PLATFORM SIMULATED this run
C 三条失败是 timed out after 5000ms —— host 用 bun 默认 5s 去等一整套子 suite。基线实测 31 条 host 用例里 19 条从没声明过超时 bun-test-floor.sh--timeout + preload 兜单文件
D 一条失败是 TypeError: this.electron.ipcMain?.on is not a function —— electron 桩缺 ipcMain.on,而 electron-log 在模块顶层就调它(?. 挡不住"ipcMain 在而 .on 缺") 照装着的 electron-log@5.4.4 源码逐条补全桩
E 连带①:失败在第 9 步,第 10 步 assert gate files 因 GitHub 默认 success() 被 skipped ⇒ 77 个登记闸门连续两天一次都没跑(其中 llm/core/opencode 那几个只在这一步执行) if: ${{ !cancelled() && … }}
F 连带②:alpha-check.sh 自称与 alpha-ci「1:1」(三处文档),实测只跑 12 个代码步里的 9 步,其中 3 步是裸 bun test 的降级档 补到 12/12 + 逐步覆盖自陈 + 反向对照断言

咽喉:两处声明,覆盖仓内真实存在的两种运行形状

形状 谁是这个形状 声明在哪
A 单文件 31 条 host 用例 Bun.spawnSync([bun,"test",<abs>]) 起的子进程(argv 自己拼,传不进 flag) packages/ui-mac/scripts/test-preload.ts
B 多文件 CI 三条 test 步 + assert-gate-files.sh 的 77 次 + alpha-check.sh [4/7](所有闸门运行的唯一入口) scripts/bun-test-floor.shbun test --timeout

候选机制全部实测排除(bun 1.3.14,不是推断):bunfig.toml [test] timeout 不被读取;
BUN_TEST_TIMEOUT/BUN_TIMEOUT/BUN_TEST_TIMEOUT_MS 全部无效;
beforeAll(() => setDefaultTimeout(…)) 无效;
preload 里 setDefaultTimeout() 只对一次运行的第一个文件生效;只有 CLI --timeout 跨全部文件成立。

本票自己踩了最后那条。 第一版把 preload 当唯一咽喉,证据是"单文件探针 6 秒用例通过" ——
而闸门跑 257 个文件。这个假绿是新加的那道门自己在全量里抓出来的
((fail) 环境咽喉对子进程也生效 [5005.06ms]),不是靠人复查。修正见 commit 2。

新增两道门(均已登记 scripts/gate-files.tsv)

  • src/main/gate-environment.test.ts —— 咽喉的行为闸,两个子进程各验一半;慢用例排在
    第二个文件
    (占位文件 gate-environment-first.cases.ts 为此存在:让慢的当第一个,验的是
    本来就成立的那一半)。平台那一半按 os.platform() 自陈本次到底跑没跑到
  • src/main/local-gate-parity.test.ts —— 把"与 alpha-ci 1:1"变成断言:双向对照 CI 代码步、
    档位只允许 MIRRORED / SUPERSET:<理由> / DEGRADED:<理由>(没有"静默不跑"这一档)、
    #637 退出条件 3 的白名单防漂、assert gate files 必须带 !cancelled()
    两条解析自检(ciSteps ≥ 12ciExcludes ≥ 20)防止解析器退化后空对空全绿。

绕过实验(11 次,每次都先证明手段能测出已知的坏)

实验 结果
删 preload 的 setDefaultTimeout (fail) [形状 A 单文件子进程] … timed out after 5000ms
bun-test-floor.sh--timeout (fail) [形状 B 多文件闸门入口] … timed out after 5000ms
把 host 伪装成 linux + 摘掉平台钉桩 CI 那条原话逐字复现:expected authorization pause, got {"ok":false,"reason":"platform linux not supported by this entry — refusing before any disk write"},3 pass / 2 fail
同上但保留钉桩 5 pass / 0 fail + 打出自陈行
用真 electron-log@5.4.4 跑旧桩 / 新桩 THROWS: this.electron.ipcMain?.on is not a function… / onIpc OK
摘掉 !cancelled() (fail) assert gate files 不因前一步失败而被跳过
本地白名单少一条(#637 原始形状) (fail) #637 退出条件 3
CI 加一步而对照表没登记 (fail) alpha-ci 的每个代码步都登记在 CI_STEPS 里
对照表里把一档改成 SKIPPED (fail) 每一行的档位只能是 MIRRORED / SUPERSET / DEGRADED
清空一个登记闸门文件 bun exit=0(真的假绿)→ 被下界抓成 ::error::闸门文件失守
三种"跑了 0 条"逐个跑 只有"文件在、用例被清空"真的 exit 0;"文件不存在"/"目录零匹配" exit 1(更正了仓内既有注释的说法)

真环境实测:三轮 CI,每一轮都量出一个开发机上看不见的缺陷

CI 在这里不是"合并前等它变绿"的那个 CI —— 它是唯一存在的 Linux 环境,是本票两个
平台/解析相关修复的测量仪器。三轮各自的产出:

run 结果 量到了什么
1 30781793073 15 fail 原来那 4 条全 pass 了(electron 桩 / 平台 / 超时 ×2),assert gate files 在第 9 步红的情况下照跑了;但我自己引入两个回归:全局钉平台让 14 个 renderer 文件挂在 Cannot find module @rollup/rollup-darwin-x64(3752→3625),行为闸挂在 bun-test-floor.sh: line 55: bun: command not found
2 30782188831 全绿 Ran 3762 tests across 257 files / 0 fail / ✓ 79 个闸门文件全部在位且真的跑过;但绿的 run 里 grep 不到任何一行降级自陈 —— 子进程 stdout 被 host 吃进变量,只在失败时抛出
3 30782536774 全绿 自陈到位(见下)

第 3 轮(最终)六个 job 全 success,自陈行真的出现在运行输出里:

[alpha-test-env] host platform "linux" is not one this product ships on (darwin/win32).
  PLATFORM DEGRADED this run: … Such gates must opt in via pinShippedPlatform().
  ↳ [alpha-test-env] … process.platform pinned to "darwin" for THIS FILE … PLATFORM SIMULATED this run
  ↳ [gate-environment] host=linux(非发布平台)⇒ 平台钉桩这一半**真的被执行了**;process.platform=darwin

开发机上同一行是 host=darwin(本身就是发布平台)⇒ 平台钉桩这一半**本次没有被执行** ——
测不到就说测不到,不让本地的绿被读成"平台也验过了"。

本地门(真实输出,最终 commit)

▶ [1/7] … ✓ zero upstream package edits
▶ [2/7] … ✓ no literal NUL bytes
▶ [3/7] … ✓ typecheck
▶ [4/7] … Ran 3762 tests across 257 files. [102.49s]   ✓ tests
▶ [5/7] … ✓ 79 个闸门文件全部在位且真的跑过
▶ [6/7] … ✓ seed assets
▶ [7/7] … ✓ docs links (4 个 Markdown)
── 本脚本对 alpha-ci 的覆盖(12/12 个代码步)──
✅ all local gates green    real 2m52.467s    EXIT=0

base(alpha@10daf61b)同一棵树:3756 pass / 0 fail;本分支 3762 / 0(+6 = 新增两道门)。
base fail-set 为空,本分支 fail-set 为空。 本地门耗时 1m43s → 2m52s(补了 3 个此前没跑的步骤)。
--no-verify push:同一 commit 上刚跑完完整 alpha-check.sh,不重复跑第二遍。

边界

  • 不改 GitHub 分支保护。实测 required context unit tests (ui-mac) 与真实 job 名
    unit tests (alpha packages) 对不上(job 于 2026-07-22 ebd29cda 改名),每个 PR 都缺
    这一格 —— 归 #717,只把实测写进 runbook。
  • 不改 #649 的三份无人执行的 opencode 测试,只归类记录。
  • 不动 alpha-ci.yml / bun-test-floor.sh 里那两处被证伪的注释文字(范围外,记在勘破文档里)。

Refs #637 #649 #717 #796

🤖 Generated with Claude Code

jinjunnn and others added 5 commits August 2, 2026 23:09
Fixes #777

## 大白话

一批质量门在它们被设计要跑的那个环境里跑不出真结果 —— 不是发现了问题,是跑不起来
(或者根本没被执行)。恒红的门等于没有门,假绿的门更糟。半个月内同一形态第四次
(#754 / #769 / 本票原列的 alpha-check typecheck / 2026-08-02 起主线连红两天),
所以这次不逐个修,枚举整类 + 在咽喉点收口。

## 枚举结果

docs/architecture/quality-gate-environments.md —— 每道门 × 每个环境 × 真实状态,
两条互相独立的检索轴交叉验证(其中两条轴给出了不同答案,记在文里)。

## 修了什么

1. 环境咽喉 packages/ui-mac/scripts/test-preload.ts(bunfig preload,父子进程同时生效):
   · setDefaultTimeout(120_000) —— 基线实测 31 条 spawn host 用例里 19 条从没声明超时,
     bun 默认 5s 让机器速度替断言下判决(CI 上已炸 3 条)。
     bunfig [test] timeout 不被读取、BUN_TEST_TIMEOUT 系列全部无效、--timeout 传不进子进程,
     三条都是实测排除的,只有 setDefaultTimeout 在 preload 里对父子两侧都生效。
   · 平台钉桩 —— 本产品只 ship darwin/win32(ADR-026),alpha-ci 跑 ubuntu,生产安装闸
     在写盘前拒掉整个 runner。host 平台不在发布清单时钉到 darwin,并打印
     `PLATFORM SIMULATED this run` 自陈这是模拟不是覆盖。

2. electron 桩补齐(test-component/claude-plugin-intake.ipc.cases.ts):electron-log 在模块
   顶层就调 ipcMain.on,`?.` 挡不住「ipcMain 在而 .on 缺」。按装着的 electron-log@5.4.4
   源码逐条枚举补全,不是凭记忆。

3. alpha-ci 的 `assert gate files` 改 `if: !cancelled()` —— GitHub step 默认条件是
   success(),于是前一步一红,77 个登记闸门集体 skipped(其中 llm/core/opencode 那几个
   只在这一步执行)。已实际发生两天。

4. scripts/alpha-check.sh 从 9 步(其中 3 步降级)补到 alpha-ci 全部 12 个代码步:
   补 assert-gate-files / assert-seed-assets / check-doc-links,三条测试从裸 `bun test`
   换成 bun-test-floor.sh(裸的跑 0 条照样 exit 0),并在末尾打印逐步覆盖对照表。

## 新增两道门

· src/main/gate-environment.test.ts —— 咽喉的行为闸(一条 6 秒、不写超时的子进程用例;
  声明被删即红),平台那一半按 os.platform() 自陈本次跑没跑到。
· src/main/local-gate-parity.test.ts —— 把「与 alpha-ci 1:1」变成断言:双向对照 CI 代码步、
  档位只允许 MIRRORED/SUPERSET:<理由>/DEGRADED:<理由>、#637 退出条件 3 的白名单防漂、
  assert gate files 必须带 !cancelled()。

Refs #637 #649 #717

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
绕过实验里逐个跑了 bun 1.3.14 的三种形态:
· 文件在、用例被清空/条件注册成零条 → exit 0(**唯一的假绿**)
· 指定测试文件不存在 → exit 1
· 整个目录零匹配 → exit 1

仓内既有注释(alpha-ci.yml / bun-test-floor.sh)把第二种也算进 exit 0 那一档,
与实测不符。下界该立还是要立 —— 第一种恰好就是「有人把闸门文件清空」的形状。
本 PR 不动那两处注释(范围外),把更正记在勘破文档里。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
自己新加的那道门在全量里把上一版打红了:
  (fail) 环境咽喉对子进程也生效 [5005.06ms] ^ timed out after 5000ms
单跑该文件通过、`bun test src`(257 文件)里挂 —— 实测 bun 1.3.14 的
`setDefaultTimeout()` 从 preload 调用**只对第一个测试文件生效**,
`beforeAll(() => setDefaultTimeout(...))` 也无效,跨文件唯一有效的是 CLI `--timeout`。
上一版的证据是一个**单文件探针**,而闸门跑的是多文件 —— 假绿。

修法:两处声明覆盖两种真实形状。
· 形状 B 多文件(CI 三条 test 步 / assert-gate-files 的 77 次 / alpha-check [4/7]
  —— 所有闸门运行的唯一入口)→ scripts/bun-test-floor.sh 加 `bun test --timeout`;
· 形状 A 单文件(31 条 host 起的子进程,argv 自己拼、传不进 flag)→ 保留 preload,
  并把它的真实作用范围写进注释。

行为闸相应改成两个子进程各验一半,慢用例**排在第二个文件**(占位文件
gate-environment-first.cases.ts 为此存在:让慢的当第一个,验的是本来就成立的那一半)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
真环境(alpha-ci run 30781793073)量出来的两条,开发机上一条都看不到:

1) preload 里全局 `process.platform = "darwin"` ⇒ 14 个 renderer 文件整片挂在
   `error: Cannot find module @rollup/rollup-darwin-x64`
   —— vite/rollup 按 process.platform 选原生可选依赖,linux runner 上装的是 linux 那份。
   3752 pass 掉到 3625。**为了修 2 条而弄坏 14 个文件 = 把一处假红换成一片真红。**
   改法:preload 只保留「检测 + 自陈」(打 PLATFORM DEGRADED,并指名要 opt-in);
   钉桩挪到 test-component/pin-shipped-platform.ts,由真正走生产平台闸的
   ext-install-catalog-result.cases.ts 显式调用,同样自陈 PLATFORM SIMULATED。

2) 行为闸的形状 B 经 `bash scripts/bun-test-floor.sh`,而脚本里写的是裸 `bun`;
   CI 上挂在 `bun-test-floor.sh: line 55: bun: command not found`
   —— 从 bun 进程 spawn 出去的 bash 的 PATH 里没有 runner 装的 bun(开发机有,所以本地看不见)。
   改法:把正在跑本测试的那个 bun 所在目录前置进子进程 PATH。

同一次 run 已经证明前三个修复在 Linux 上成立(全部 (pass)):
  生产 ext-import-skill-folder …            ← electron 桩补齐
  真实 catalog MCP …不回显… secret canary    ← 平台
  package safe view … ExtensionHub …        ← 超时
  REQ-128 Phase 3 第 1→9 跳 …                ← 超时(含子进程内部两条)
以及 `assert gate files` 在第 9 步红的情况下**照跑了** ← !cancelled()

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
子进程打的 PLATFORM SIMULATED / [gate-environment] 被 host 吃进变量,只在失败时抛出 ——
于是「这次降级了什么」在**绿的那一次反而看不见**,而那正是需要它的时候。
实测:上一版在 alpha-ci 全绿的 run 里 grep 不到任何一行自陈。
gate-environment.test.ts 在成功路径上转述子进程的自陈行;运行级那句由 preload 直接打。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CI][P1] 「门在自己的标准环境里恒红/恒假绿」已是第三个实例 —— 枚举整类,别再逐个修

1 participant