fix(grok): resolve prompt_history across HOME symlink cwd - #1168
fix(grok): resolve prompt_history across HOME symlink cwd#1168TITOCHAN2023 wants to merge 4 commits into
Conversation
Grok names session buckets from getcwd() (physical path). Botmux often holds the logical cwd when HOME is a symlink, so encodeURIComponent(cliCwd) misses prompt_history.jsonl and every turn reports submit_unconfirmed.
Grok names session buckets from getcwd() (physical path). Botmux often holds the logical cwd when HOME is a symlink, so encodeURIComponent(cliCwd) misses prompt_history.jsonl and every turn reports submit_unconfirmed. Add unit tests for symlink cwd bucket resolution.
|
PR:#1168 结论:能修本机这条假阴性,建议合。 有 1 个测试可移植性问题和 1 个双桶优先级边角,都不挡 idle 短消息这条主路径。 改动在干什么
现在会依次试逻辑路径、 主路径我觉得是对的
问题
没测到、但不挡合
建议合入前补上 Windows skip;双桶优先级可以 follow-up。本机先靠软链;上游合了再 |
Empty encoded logical dirs no longer shadow the physical or hashed bucket that actually has prompt_history.jsonl. canonicalizeGrokCwd stays private, the stale 0.2.93 "submit-time while busy" header is gone, and symlink tests skip on Windows via a shared fixture helper.
|
感谢这个修复 —— 问题定位很准,我们做了独立复现和验证,核心改动是对的,结论是建议合入。下面是一条建议修改和两条可选 nit,供参考。 以下是自动评审的初步意见,最终以维护者审阅为准。 我们验证了什么不只是读代码。本机装了真实的 grok 1.0.13,直接拿它做了端到端对照:
反变异 4 枪 3 红(新旧 grok 测试合跑 30 条):去掉 realpath 变体 → 红;兜底改回预测逻辑路径 → 红;去掉 prompt_history 优先 → 2 红(说明上轮提到的双桶优先级,这次的修法是有牙的)。 门禁: 一、建议合入前修改(1 行)macOS 上新增的 5 条用例会红 3 条。 上一轮提到 Windows 的 我们把 仓库里 建议改法: import { mkdirSync, mkdtempSync, writeFileSync, rmSync, existsSync, symlinkSync, realpathSync } from 'node:fs';
// tmpdir() itself is a symlink on macOS (/var → /private/var); canonicalize so
// the scaffold's own root is not a confounder when asserting symlink
// normalization (see test/claude-code-cwd.test.ts).
const ROOT = realpathSync(mkdtempSync(join(tmpdir(), 'botmux-grok-paths-')));已验证:普通环境与软链 TMPDIR 下都 5/5 绿,且上面三枪变异在打过补丁的测试上仍然全红(没有把测试打钝)。 关于严重度,我们想说明白:CI 里两条跑单测的腿( 二、nit(可选):
|
| 桶数 | master | 本 PR |
|---|---|---|
| 25(我们本机的实际形态) | 1.6 µs | 44.6 µs(~28×) |
| 200 | 2.0 µs | 388 µs(~190×) |
这不在热路径上 —— writeInput 每次提交只解析一次,bridge tick 在未挂载时最多 1 次/秒。所以今天不构成实际问题,只是白付的、随桶数增长的成本。如果愿意收,建议加一条快路径:
// 编码目录存在且已有 prompt_history —— 绝大多数稳态。扫描不可能给出更优
// 候选,直接返回。(空目录仍然落到完整扫描,shadow 保护不受影响。)
for (const candidate of variants) {
const dir = join(root, encodeGrokCwd(candidate));
if (existsSync(dir) && grokBucketHasPromptHistory(dir)) return dir;
}实测降回 3.9 µs,30 条全绿。(我们先试过更简单的 variants.length === 1 && 目录存在 → 返回,但那个版本会重新打开一个 shadow 缺口 —— 已构造用例证实,所以推荐上面这版。)
四、关于 .cwd 的 realpath 比对(仅作说明,不必改)
grokCwdMatchesMarker 里 canonicalizeGrokCwd(marker) === canonicalizeGrokCwd(cwd) 这一行,把它改成 return false 时测试仍然全绿。我们查清了原因:variants[] 里已经包含 realpath(cwd),而真实 Grok 的 .cwd 写的就是 getcwd() 物理路径,两者字符串相等,在到达 realpath 分支前就已命中。
也就是说这一行只在 .cwd 内容本身非规范时才可达 —— 即不是当前 Grok 用 getcwd() 写的(更老/未来版本、手写 marker、其它工具)。作为纵深防御留着挺合理(错路径上多一次 realpath,很便宜),只是想说明:当前 Grok 版本下它不可达,所以别指望现有用例能覆盖它。真要补测的话,marker 必须写软链拼写才盖得到;写物理路径的用例(如现有第 3 条)永远盖不到。
再次感谢 —— 定位准确,prompt_history 优先那一版修法也确实把上轮的双桶优先级问题闭合了。建议先收下第 1 条(1 行),nit 两条随意。
本条为自动评审的初步意见,最终以维护者审阅为准。
- realpath mkdtemp so macOS /var → /private/var is not a test confounder - trim() only tests emptiness; realpath/encode keep the original cwd - return early when an encoded bucket already has prompt_history.jsonl
|
感谢复现和评审。三条都收下了,在 7cd89e7:
|
问题
Grok 会话每条飞书消息都会误报
submit_unconfirmed,即使 Enter 已经按下、模型已在跑。实机:HOME 是软链
/home/user->/data00/home/user(字节类开发机常见)。session.workingDir/cliCwd=/home/usergetcwd()建桶 =~/.grok/sessions/%2Fdata00%2Fhome%2Fuser/prompt_history.jsonlresolveGrokCwdBucketDir(cliCwd)去读.../%2Fhome%2Fuser/prompt_history.jsonlsubmit_unconfirmed这和 #1052 不是同一事件。#1052 修的是大消息 Enter 被粘贴突发吞掉;#1052 注释里的 busy 期 dequeue 延迟是另一个已知限制。这里是 idle 短消息也每次误报,因为桶路径根本对不上。
改动
src/services/grok-paths.ts的resolveGrokCwdBucketDir:encodeURIComponent(cwd),再查encodeURIComponent(realpath(cwd)).cwd标记也按物理路径比对getcwd()会创建的 encoded 物理路径writeInput仍走grokPromptHistoryPath(cliCwd),不用改适配器。影响面
cwd与realpath(cwd)相同时行为与现在一致测试
新增
test/grok-paths.test.ts:prompt_history.jsonl.cwd写物理路径时也能从逻辑 cwd 命中本机证据:workingDir=/home/... vs /proc//cwd=/data00/home/...;修软链前逻辑 encoded 桶不存在。