fix(grok): 把 #867 落到 main —— 含 #883(P0) 点名的修复,并修掉它自带的一处能力边界回归 - #1010
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
预跑今天这套门时,#867 这一层红了三条。三条都是真的,逐条修,没有走豁免。 ## 🔴 1. 能力边界回归(copresence-profile-pin) ::error file=agent-node/src/cli.ts,line=76::static import of grok-copresence/policy|runtime. ESM static imports are hoisted, so its top level runs BEFORE the profile pin at line 570 #867 加了一条**静态** import: import { retireStoppedGrokCopresenceRuntime } from "./runtime/grok-copresence/runtime-retirement"; ESM 静态 import 是提升的 —— 被导入模块的顶层会在 cli.ts 第一条语句之前执行,于是 `policy.ts` 顶层那句 `readPinnedGrokCopresenceCapabilityProfile()` 读到的是 **ambient 环境变量**,而不是启动时从节点配置钉下来的档位。**能力档位就此可以被环境变量绕过。** 改成动态 import,放在调用点、启动钉档位之后,与本文件里另外两处 grok-copresence 的取法一致:`static_imports 1 → 0,dynamic_imports 2 → 3`。 这道门(#937 建的)第一次抓到真东西,而它抓到的是一条**在 draft 里躺了三天**的回归。 ## 2. 公开仓里的真人 home 路径(home-path-baseline) 新文件 `docs/tests/report-grok-copresence-fatal-recovery-7914755a.txt` 有 3 处 `/home/<真人名>/`。承重的是 `.commhub/runtime-commdog-…` 那部分,前缀不是, 所以按门给的第一条修法换成 `~/`,证据一字不损,**不抬基线**。 ## 3. 行号 pin 第三次漂(doc-symbol-pins) `docs/message-lifecycle.md` 的 `shouldSkipMessage`:本层又动了 `cli.ts`(含上面第 1 条 的改动),`4669 → 4695`。文本和 URL 两处都改。 (这是它今晚第三次漂:4639 → 4662 → 4669 → 4695。我曾提议「去掉行号根治」, **那句已撤回** —— 实测去掉 `#L` 会让这条 pin 整个掉出那道门的正则: `扫到 15→14 / 判定 5→4 / rc 1→0`,是删覆盖不是修问题。) ## 复跑 home-path-baseline / copresence-profile-pin / doc-symbol-pins / test-suite-registration / doc-source-pins / no-escaped-comments / no-memory-slugs / l1-paths-sync 全部 rc=0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI 上 `doc source-pin floor (Docker)` 这个 job 红了(它同时跑 test813):
MUTATION_RED upload-tool-removed ← 我在 #1004 修好的那条空变异,现在真的会红了
MUTATION_RED stale-three-tool-doctor
PRODUCT_PATH_NEGATIVE_PASS registration=absent session=unchanged
FAIL: canonical-Bun product path did not reach TUI readiness
GrokCopresenceFailure: grok copresence pre-spawn audit failed:
grok copresence refuses any MCP server except its runtime-owned commhub stdio server
failureCode: 'spawn_audit'
## 为什么
`7914755a fix(grok): bind MCP audit to resolved Bun path` 把审计从
commhubRecord.target !== "bun"
改成把**解析后的绝对 bun 路径**传进去、两侧 `resolve()` 后再比。而生成那份 MCP 配置的
`resolveGrokCommhubMcpCommand()` 用的是 **`realpathSync()`(解析符号链接)**,
审计侧用的是 **`resolve()`(只归一化路径,不解析符号链接)**。容器里 `bun` 是符号链接时,
两侧就对不上 —— 于是 pre-spawn 审计把自己生成的那份配置也拒了。
## 处理:只摘这一个提交,其余照落
git rebase --onto <该提交>^ <该提交> <分支>
剩下 7 个提交,`runtime.ts` 那处比较回到 main 现在的写法(`target !== "bun"`)。
**#883 那条 P0 点名的 `b830403b` 和 #881 的修复 `a9df8dba` 都在保留的这 7 个里**,
本次落地的核心价值不受影响。
## 不在这里顺手修 `7914755a` 的理由
它要解决的问题是真的(裸 `"bun"` 比较挡不住指向别处的 bun)。但把它改对需要决定
**审计与生成两侧统一用哪一种解析**(`realpath` vs `resolve`),那是安全审计语义,
要有自己的见红证据;而且它已经被 #836 的核对牵扯进来(`fc221fc5` 是它的前身)。
**留作单独一条,不塞进这条含 P0 的 PR。**
## 顺带
摘掉这 6 行之后 `shouldSkipMessage` 的行号 pin 从 4695 变回 **4691**,已改(文本+URL)。
八道门在本地全 rc=0。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vansin
force-pushed
the
fix/867-grok-safe-navigation-landed
branch
from
August 18, 2026 15:16
07decf1 to
f0d2f40
Compare
This was referenced Aug 18, 2026
This was referenced Aug 18, 2026
vansin
added a commit
that referenced
this pull request
Aug 18, 2026
## 我造成了什么 - **#1004**(`89a6164e`,今天)把生成侧从 `'command = "bun"'`(硬编码)换成 `resolveGrokCommhubMcpCommand()` 的返回值 —— **realpath 之后的绝对路径**; - **#1010**(`f1208449`,今天)我把 `7914755a fix(grok): bind MCP audit to resolved Bun path` **外科式摘掉了**,而那正是同一次改动的**审计侧**。 ⇒ main 因此停在一对不匹配的半边:**生成侧写绝对路径,审计侧要求裸 `"bun"`。** 我当时摘它的理由(「它让产品拒绝自己生成的配置」)**方向反了**:真正会拒绝的是**缺了它**。 我读到的那次 CI 红来自**夹具**,不来自产品 —— 见下。 ## 真 grok 报什么(实测,不是推断) 容器里装钉死的 `0.2.93`、`--network none` 离线跑(宿主那份是 `1.0.5`,且其符号链接被 63 个在跑节点共用,没有动): 容器内 grok --version → grok 0.2.93 (f00f96316d) config.toml: command = "/usr/local/bin/fake-bun" $ grok inspect --json "mcpServers": [{ "name":"commhub", "transport":"stdio", "target":"/usr/local/bin/fake-bun", "source":{"type":"configToml","path":"/tmp/gh/config.toml"} }] ⇒ **`target` 逐字等于 config.toml 的 `command`。** 而生成侧那个解析器只可能返回 realpath 之后的绝对路径或抛错 ⇒ **拿裸 `"bun"` 去比永远不成立。** (顺带:同一件事三条命令三种形状。`mcp doctor --json` 顶层是 `sources`/`servers`, 它的 `target` 是 **command + args 空格拼串**;`mcp list --json` 的字段叫 `command`。 拿错一条就会得出错的结论。) ## 两件必须一起落,分开落任一半就是我今天犯的错 **① 审计侧**(`agent-node/src/runtime/grok-copresence/runtime.ts`) - || commhubRecord.target !== "bun" + || resolve(String(commhubRecord.target || "")) !== resolve(expectedCommhubCommand) 新增第三个参数 `expectedCommhubCommand`(默认 `"bun"` 仅为兼容尚未传参的调用点), `agent-node/src/cli.ts` 的生产调用点显式传 `commhubMcpCommand`。 **② 夹具**(`tests/test225-grok-preview-package-live/fake-grok.mjs`) - target: "bun", + target: inspectTarget, // ← 从它自己声称的 configToml 里读 command 不修 ②,①会再一次「看起来让 test813 红」,而红的仍然是夹具。 **原来那个写死的 `"bun"` 不是「夹具不够真」,是它让一个真实的不一致在 CI 里永远看不见** —— 审计要 `"bun"`、夹具就报 `"bun"`,两者恒相符,而产品写的是绝对路径。#1016 就是这么被藏住的。 ## 见红 / 见绿 `agent-node/src/runtime/grok-copresence/runtime.test.ts` 加三条,第三条就是 #1016 那个不一致: target=绝对路径, expected=同一个绝对路径 → 不抛 target=绝对路径, expected=另一个绝对路径 → 抛 "runtime-owned commhub" target=裸 "bun", expected=绝对路径 → 抛(#1016 本身) bun test src/runtime/grok-copresence/runtime.test.ts 54 pass 0 fail 把审计退回 main 的写法(target !== "bun")再跑 53 pass 1 fail ← 见红 还原 54 pass 0 fail 原有 5 条断言仍传 2 个参数、夹具 target 是 `"bun"` ⇒ 默认值让它们照旧通过,向后兼容。 ## 没做的 `bun build` 通过(276 modules),但**它不做类型检查**,所以那只证明能打包。 本机没有可用的 tsc(`npx tsc@5` / `typescript@5.9` 都取不到),**类型检查交给 CI**。 test813 的 Docker 套件也交给 CI 跑 —— 那是这次改动真正的验收点。 顺带:`docs/message-lifecycle.md` 的 `shouldSkipMessage` 行号 4691 → 4695(本次给 cli.ts 加了 3 行)。 Co-authored-by: t <internlmorg@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
vansin
added a commit
that referenced
this pull request
Aug 18, 2026
## 事实
4639 → 4662 → 4669 → 4691 → 4695 → 4713 → 4725 → 4728
八个值,对应 #987 / #1004 / #1006 / #1010 / #1017 / #1007 / #1023 / #1039。
规律:**任何往 `agent-node/src/cli.ts` 第 4600 行以上插代码的 PR 都会让它漂**,
那个 PR 就要多跑一轮 CI。这是每次都付的成本,不是偶发。
## 为什么现在才能这么修
`#1024` 里我提过「改成不可变 SHA」,但**当时实测证明它不成立** ——
`check-doc-symbol-pins.py` 的正则捕获了 ref 却从没用过那个捕获组,
SHA 和 `main` 一视同仁,一律拿工作树解析。单变量 A/B 两边逐字相同。
`#1025` 让脚本认了 ref(SHA pin 用 `git show <ref>:<path>` 取那个版本判)。
**这条路是那之后才通的。** 所以本 PR 是 #1025 的下游,不是 #1024 那个被推翻的提案的重提。
## 改动
- ✅ v1.4.0;当前在 [cli.ts:4725 `shouldSkipMessage`](.../blob/main/agent-node/src/cli.ts#L4725)
+ ✅ v1.4.0;截至 [`04f37800` 的 cli.ts:4725 `shouldSkipMessage`](.../blob/04f37800/agent-node/src/cli.ts#L4725)
**「当前在」也一起改成「截至 `<sha>`」** —— 这不是措辞洁癖:
钉到某个 commit 之后,「当前」这个词就不再被那个链接支持了。
只改链接不改这句话,等于用一个更稳的 pin 去支撑一句更弱的真话。
## 验证:两个方向都见证过,而且**判定数始终是 5**
未漂时 rc=0 扫到 15 判定 5 跳过 10 漂移 0
往 cli.ts 插 3 行(过去 8 次红的场景) rc=0 扫到 15 判定 5 跳过 10 漂移 0 ← 不再红
把 pin 的行号改成 100(错的) rc=1 扫到 15 判定 5 跳过 10 漂移 1 ← 门仍然咬得动
还原 rc=0
**第三行是本 PR 最该看的**:如果这个改法让门不再对错误 pin 判红,那就是把对象移出了取集 ——
「让门变绿」而不是「把问题修好」。它没有:判定数一次都没掉,错的 pin 照样红。
`docs-site` 取集同时核过:扫到 28 / 判定 8 / 跳过 20 / 漂移 0(#1025 之后它才在取集里)。
## 一个操作上的插曲,记一下
我第一次建 worktree 时目录已存在,`git worktree add` 失败 —— **但后面的 `cd` 成功进了那个陈旧目录**,
于是我在一份完全不相干的树上跑了检查,得到 `cli.ts:836` 和 `rc=2`。
**命令失败了,后续步骤照跑。** 后来加了 `cd ... || exit` 并先打印 HEAD 核对才发现。
Co-authored-by: t <internlmorg@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
grok 栈
#825 → #826 → #830 → {#836, #867}的第四层。前三层已落地并关闭:#825→#1004(
89a6164e)、#826→#1006(c85dca96)、#830→#1008(526163cd)。没有 force-push #867 那条共享 draft 分支 —— 本 PR 从我自己的分支发。
🔴 为什么这一层要紧:#883(P0)点名的修复就在里面
#883 正文原话:
b830403b正是本层 7 个提交之一:并重启那些共存节点 —— 那超出我的授权范围,已在 #883 上写明并留给 Vincent 拍板。
它同时是 #881 的修复(按内容核过,不是看标题猜的)
#881 的根因是「方向键把 composer 标成污染,回车被就地清掉,提示语却谎称是斜杠命令」。
本层对
runtime.ts的改动:把导航拆成
history/viewport两类,只有 history 触发那条 blocked 警告,方向键(viewport)改为写穿。
🔴 落地前预跑,抓到三处,全修,无豁免
1. 能力边界回归(
copresence-profile-pin)—— 这条最要紧原分支加了一条静态 import:
ESM 静态 import 是提升的 —— 被导入模块的顶层在
cli.ts第一条语句之前执行,于是policy.ts:22的readPinnedGrokCopresenceCapabilityProfile()读到的是 ambient环境变量,而不是启动时从节点配置钉下来的档位。能力档位就此可被环境变量绕过。
改成动态 import、放在调用点(钉档位之后),与本文件另外两处取法一致:
2. 公开仓里的真人 home 路径(
home-path-baseline)新文件
docs/tests/report-grok-copresence-fatal-recovery-7914755a.txt有 3 处/home/<真人名>/。承重的是.commhub/runtime-commdog-…那部分、前缀不是,按门给的第一条修法换成
~/,证据一字不损,不抬基线。3. 行号 pin 第三次漂(
doc-symbol-pins)docs/message-lifecycle.md的shouldSkipMessage:4669 → 4695。文本和 URL 两处都改。(今晚第三次:
4639 → 4662 → 4669 → 4695。曾提议「去掉行号根治」,已撤回 ——实测去掉
#L会让这条 pin 整个掉出那道门的正则,是删覆盖不是修问题。)门
在当前 main(
526163cd)上复跑,八道全 rc=0。栈还剩最后一层
#836—— 只有 1 个提交(fc221fc5),用 cherry-pick;range rebase 会撞它分支上那 48 个已合进 main 的提交。