Skip to content

fix(grok): 输入投递改括号粘贴、重试只补 Enter,修复大消息 Enter 被吞导致 submit_unconfirmed 卡死 - #1052

Open
sensuossss wants to merge 1 commit into
masterfrom
fix/grok-submit-bracketed-paste
Open

fix(grok): 输入投递改括号粘贴、重试只补 Enter,修复大消息 Enter 被吞导致 submit_unconfirmed 卡死#1052
sensuossss wants to merge 1 commit into
masterfrom
fix/grok-submit-bracketed-paste

Conversation

@sensuossss

Copy link
Copy Markdown
Collaborator

问题

Grok 会话收到大消息(实例:约 4KB 的多行报警卡片文本)时稳定触发 submit_unconfirmed

  • writeInputtmux send-keys -l 把正文全速打入 PTY,仅等 200ms 就发 Enter;
  • Grok TUI(1.0.5 实测)消化多 KB 输入突发需要数秒,这个 Enter 被 paste-burst 启发式当作粘贴内容里的软换行吞掉,不触发提交;
  • 消息滞留 composer,worker flush 重试每次重贴全文,composer 堆出多份拷贝;后续消息全部 buffered 在未 ACK 的 queued activation 之后,会话楔死,直到有人打开 Web 终端手动按 Enter,把堆叠的 N 份连体内容一次性提交。

线上事故还原(daemon 日志 + prompt_history.jsonl):3 次 flush 重试 → composer 堆了 3 份 → 15 小时后人工 Enter 提交了一条 11KB、正文 ×3 的消息;接缝处各多出一个 \n,即被吞成软换行的 Enter。实机复现:8KB 载荷按旧时序(send-keys -l → 200ms → Enter)必现不提交;消化完后单独补 Enter 立即提交成功。

改动

仅动 src/adapters/cli/grok.ts(+ 新增测试),不涉及共用层:

  1. 括号粘贴投递:优先 pty.pasteText(tmux load-buffer + paste-buffer -p),正文原子落入 composer;保留 sendText 中间回退;raw PTY 回退自包 \x1b[200~…201~ 标记(codex 同款模式)。适配器头注释「no bracketed paste needed」基于 0.2.x,1.0.5 已不成立,一并更新。
  2. Enter-only 重试:以 pty handle 为键的 WeakMap 记录「已粘贴但未确认」的正文;worker 重试携带相同正文时只补 Enter、不重贴,杜绝 ×N 堆叠。CLI 重启换新 handle 自动失效重新粘贴;任何 probe/recheck 确认提交后立即清除记忆,避免用户日后发送相同文本被误判为补 Enter。
  3. 保留原有安全语义:单次调用只发一个 Enter(防 busy-turn send-now 误取消)、4s 轮询 prompt_history.jsonl、fail-closed recheck 兜底、无 cliCwd 时 fail closed。

修复后即使 Enter 仍被极端负载吞掉,worker 下一次 flush 重试的单个 Enter 会把已停驻的正文直接提交——卡死与重复两个方向都被堵死。

影响面

  • CLI:仅 grok 适配器;codex/claude-code 等其它 CLI 的投递路径未动(codex 本就是括号粘贴,claude-code 刻意走节流打字路线,各自不变)。
  • 后端:tmux / tmux-pipe(adopt)/ zellij / zellij-observe / zmx / herdr 均实现 pasteText;TmuxPipeBackend 返回 boolean 的失败约定按 !== false 处理;无 pasteText 的理论回退链保留 sendText → 自包标记 write
  • 会话类型:话题/群/adopt 会话同走 writeInput,行为一致;sandbox 与路径解析未动。

测试验证

  • bun run build 通过(tsc + 打包 + 审计)
  • 新增 test/grok-adapter-submit.test.ts 7 用例全过;其中回归用例模拟真实故障(Enter 被吞成软换行):旧实现重试会重贴导致校验永不匹配,该用例在旧代码下必然失败
  • 相关回归:grok-transcript / grok-usage / cli-adapters / traex-adapter-submit / write-input / structured-bridge-clis / bridge-fallback-gate / tui-input-failure-contract 共 666 用例全过
  • 全量 bun run test:18668 通过;3 个失败均为本机环境性问题且在未触碰文件(root 用户下 EACCES 权限语义失效 ×2、宿主 live 配置泄漏进 redirect 白名单用例 ×1)
  • 实机 e2e:真实 grok 1.0.5 TUI + 8KB 载荷,用编译产物的 writeInput(tmux pasteText 同款命令)投递,1.02s 确认提交并返回正确 cliSessionId;同载荷在旧时序下必现不提交

https://claude.ai/code/session_01Bty9txNtLG39VPhJ1PgWqA

大消息(如报警卡片,约 4KB 多行文本)经 send-keys -l 全速打入后,Grok TUI
需要数秒消化输入突发,200ms 后送出的 Enter 被当作粘贴内容里的软换行吞掉,
不触发提交;消息滞留 composer,且 worker flush 重试每次重贴全文,人工按
Enter 时会把堆叠的多份一次性提交(grok 1.0.5 实机复现确认)。

- writeInput 改用 pty.pasteText(tmux load-buffer + paste-buffer -p 括号
  粘贴)原子投递,raw PTY 回退自包 200~/201~ 标记(codex 同款)
- 以 pty handle 为键记录「已粘贴未确认」正文:相同正文的重试只补 Enter、
  不再重贴;CLI 重启换 handle 自动失效,probe/recheck 确认后即清除
- 保留单次调用单 Enter(防 busy-turn send-now 误取消)与 prompt_history
  验证 + recheck 兜底语义

Claude-Session: https://claude.ai/code/session_01Bty9txNtLG39VPhJ1PgWqA
@sensuossss
sensuossss requested a review from deepcoldy as a code owner August 28, 2026 03:57
@deepcoldy

Copy link
Copy Markdown
Owner

自动评审初步意见(Claude 首审)

先说结论:问题定位与括号粘贴这半边我认为是对的、有价值的;但「重试只补 Enter」这半边我实机复现出一个会取消正在运行的轮次的回归,建议合入前调整。以下都附了可复核的证据。

✅ 站得住的部分

  1. 根因与括号粘贴修复send-keys -l 打入多 KB 后 200ms 的 Enter 被当软换行吞掉——这个失败模式在本仓库已有独立佐证,TmuxPipeBackend.pasteText 的注释就写着同一件事("without the markers the TUI treats the paste as a rapid input burst and swallows the trailing Enter as a soft newline"),codex 也早就走括号粘贴。改法与既有模式一致。
  2. 测试确有牙。我跑了三处反向变异,全部变红:
    • composerHoldsBodyfalse(废掉 Enter-only)→ 1 失败
    • confirm/recheck 里不再 delete 记忆 → 1 失败
    • 去掉 pasteText 分支退回 sendText → 6 失败
  3. 失败路径的记忆卫生是正确的(我另写探针验证):pasteText 返回 false 时不写记忆、下次会重新粘贴;Enter 写失败但粘贴已落时保留记忆、下次只补 Enter。这两个方向都对。
  4. CI 的 build 红与本 PR 无关:失败用例是 mojo-close-worker-journal.integration。我在 PR 分支和 master 上各跑一次,均 7/7 通过——是 flaky,不是这个改动引起的。(不过 PR 描述里「全量 18668 通过」与 CI 现状不符,建议描述里说明这一条。)

🔴 建议修改:Enter-only 重试会把 submit_unconfirmed 升级成「取消正在跑的轮」

核心问题:submitted:false 不等于「Enter 没生效、正文还在 composer 里」。适配器自己的注释就写明了这点——"slow prompt_history is not proof the first Enter dropped";matchGrokPromptAppendpreferSessionId 未命中、或多个 sid 并存时都会 fail-closed 返回 found:false。于是存在这条路径:

第一次 paste+Enter 真的提交了(composer 已空)→ 验证没看到 append → 返回 submitted:false → 重试认为「正文还停在 composer」→ 只补一记 Enter,而此时 composer 是空的

而空 composer 上的裸 Enter 在 grok 1.0.5 上不是 no-op。我用真实 grok 1.0.5 做了对照实验(同一时间线,只切换「要不要按那一记 Enter」):

stop_reason
按了裸 Enter cancelled + cancelTrigger:"send_now"杀掉正在跑的轮
对照组(不按) end_turn, end_turn

当时面板底部明写着 Enter:send now │ … │ Ctrl+;:queue。这正是 #865655d4f567)专门删掉第二记 Enter 的原因,那条 commit message 写的就是「会被 Grok 当作 send-now/cancel-and-send」;现在的注释也仍然保留着这句警告,但 composerHoldsBody 分支绕过了它——警告还在,防护没了。

后果比原 bug 更隐蔽grokTerminalOutcomecancelled + send_now 映射为 ambiguous不弹失败卡,并且会丢弃 buffered partial。也就是说被取消的那一轮,答案会静默消失,用户看不到任何报错。

可达性(我逐条追了 worker):这条路只在「同一 handle + 相同 content 再次 writeInput」时触发,实际可达的是——

  • queuedActivationToken turn(会话开场/durable activation):worker.ts:10829同一个 item 对象 unshift 回队头,再次走到 worker.ts:11335,backend 对象不变 → 确定可达
  • durable receiver replay 落到仍存活的 worker 时,content 与 handle 都相同(只有 dispatchAttempt 变)→ 可达
  • 普通 IM 消息不可达(worker.ts:10822 无 token 直接 return,item 已出队,只剩 20s deferred recheck)。

另外因为记忆在未确认时不清除,每次重试都会再补一记:我写的探针里 4 次重试 → 正文只粘 1 次(修复有效),但产生了 3 记具备 send-now 能力的 Enter。

🟡 两个次要点

  1. 测试替身把这个危险写成了无害test/grok-adapter-submit.test.ts:70if (!composer) return; // Enter on an empty idle composer is a no-op。这是假设而非实测——我把它改成忠实版(对空 composer 的 Enter 计数)后,7 个用例照样全绿,说明现有测试对这个后果零感知。建议按实机语义修正替身,并补一个「submit 已落但未验证 → 重试」的用例。
  2. herdr 后端上主修复不生效HerdrBackend.pasteText 就是 return this.write(text),不带 200~/201~ 标记(oh-my-pi.ts:88-90 已明确警告过这点,所以它自己包标记)。影响面里写「均实现 pasteText」成立,但「都是括号粘贴」不成立——herdr 上会静默退回旧的 burst 行为。tmux/tmux-pipe/zellij/zellij-observe/zmx 都是真括号粘贴,没问题;目前线上唯一的 grok bot 走默认 tmux,所以这条是潜在而非现网问题。

建议方向(供参考,不一定是最优解)

括号粘贴那半边我建议保留。Enter-only 那半边,问题在于「正文是否还在 composer」被当成了可推断的事实,实际不可推断。可考虑:

  • 观测代替记忆:写 Enter 前先确认 composer 非空(captureInputState() 已有先例,TmuxPipeBackend 实现了它,codex adopt 的 detectCodexComposerState 就是这么用的);
  • 或者干脆只保留括号粘贴——若原子粘贴已经让 Enter 稳定生效(PR 里实机 1.02s 确认提交也支持这点),那么堆叠 ×N 的前提本身就消失了,Enter-only 重试可能不再必要,也就不用引入 send-now 风险。

复现脚本我可以贴出来。以上是自动评审的初步意见,可能有我没看到的上下文(尤其实机环境差异),最终以维护者审阅为准;如果你认为某条判断不成立,欢迎直接指出来,我会重新核。

@deepcoldy

Copy link
Copy Markdown
Owner

补充更正(自动评审,扩大了上一条的影响范围)

复审过程中发现我上一条评论把可达范围判窄了,更正如下 —— 这条比我原先报的那个方向更值得关注,因为普通 IM 消息就能触发

用户收到「提交未确认」通知后手动重发同一句话 → 这条消息被静默吞掉

上一条我说「普通 IM 消息不可达」,那只覆盖了 worker 自动重试worker.ts:10822 无 token 会提前 return)。我漏了用户手动重发这条人肉重试路径:那是一个全新的普通 item,但 content 相同、backend 对象相同,于是照样走进 composerHoldsBody 分支。

实测序列(生产代码路径):

  1. 第一次 paste+Enter 真的提交成功(grok 已收到),但验证 fail-closed(prefer-sid 未命中 / 多 sid 并存)→ 用户收到「提交未确认」通知;
  2. 用户照着通知重发同一句话 → 适配器认为「正文还停在 composer」→ 只补一记 Enter,全文一次都没粘
  3. 结果:pasteText 累计仍为 1 次,实际提交仍只有 1 条 —— 重发的这条消息根本没进 grok,而用户看不到任何区别(同样走 20s recheck + 同样的通知)。

所以同一个 composerHoldsBody 判断有两个方向的后果,都成立:

  • 对空 composer 补 Enter → 取消正在运行的轮(上一条已述,实机 cancelled+cancelTrigger:send_now);
  • 重发同文 → 新消息被吞(丢用户输入,本条)。

两条边界(避免夸大)

  • 不是永久的:中间只要来一条不同正文的消息,unconfirmedComposerBody 就被覆盖,之后原文能重新粘贴。准确说法是「直到下一条不同消息之前,重复发同一句会被连续吞掉」。
  • 没有去重挡在前面:grok 未设 mergeQueuedInputpending-input-queue 也不按 content 去重,所以同文重发确实原样走到 writeInput

这对修法的影响

这条更清楚地指向同一个根因:「正文是否还在 composer」不是可以从 submitted:false 推断出来的。用记忆去猜,猜错的两个方向分别是「取消正在跑的轮」和「吞掉新消息」。所以上一条给的两个方向依然适用,其中「用 captureInputState() 观测代替记忆」在这条路径下也同样成立——观测能同时挡住两个方向,而记忆挡不住。

仍是自动评审的初步意见,最终以维护者审阅为准;这条是对我自己上一条的更正,如判断有误欢迎直接指出。

@deepcoldy

Copy link
Copy Markdown
Owner

自动评审 · 二审意见(pi,独立复核 + 补充实验)

结论:同意一审 🟠 建议合前修。一审的证据(反变异、记忆卫生、herdr 🟡2)我全部独立复核成立(grok-adapter-submit.test.ts 7/7 过)。下面只写新增内容:四组真机实验(grok 1.0.5)+ 一个新发现。

实验 1:裸 Enter 的危险边界比一审描述的更窄(但真实)

空 composer + 运行中 turn、没有排队 follow-up 时发裸 Enter:turn 继续跑完,无 cancelTrigger,无任何异常(对照组与实验组均正常 end_turn)。也就是说 send-now 取消需要 grok 自身队列里有排队项——即一审 probe2 的形态(运行中 turn + 已排队 follow-up + 裸 Enter)。这修正了暴露面的边界:单纯"对空 composer 补一记 Enter"多数时候是无害 no-op,危险形态是"补 Enter 时恰好还有别的消息被排队"。

实验 2:「只留括号粘贴」在 idle 场景经验上成立

8KB 多行载荷、括号粘贴 → 200ms → Enter,12/12 次提交成功,确认延迟 0.5–1s(4s verify 窗口内),composer 无残留、无堆叠。一审标为"最大未验证点"的第二条建议,实测方向是对的(idle 场景)。

🆕 实验 3:grok 1.0.5 的 prompt_history 对 mid-turn 提交是 dequeue 时才 append

turn 运行中(sleep 30 工具执行)投递下一条消息(paste+Enter,grok 自己排队,面板显示 Enter:queue):

  • 提交后 32 秒内 prompt_history 完全无 append
  • turn 1 结束、排队项 dequeue 并开始运行时(t≈33s)才落盘。

适配器注释"prompt_history is written AT SUBMIT TIME (verified 0.2.93)"在 1.0.5 上已不成立。而 grok supportsTypeAhead: true,worker 对普通 IM 消息在 turn 运行中照常投递(pendingInputAllowsTypeAhead 对非 durable 输入放行)。后果:

  • 每次 mid-turn 投递,4s verify 窗口必然看不到 append → submitted:false;turn 超过 20s 时 20s recheck 同样失败 → 给用户弹"提交未确认"卡,消息其实已被 grok 正常排队(误报,master 上已存在);
  • 对本 PR 的放大:每次这样的 type-ahead 提交都会写入 unconfirmedComposerBody 记忆,而此时正文根本不在 composer(在 grok 队列里)。"composerHoldsBody"的前提从"罕见 fail-closed 匹配失败"变成"每次 mid-turn 消息都成立"——之后同文重发被吞、或 queued-activation 重试对空 composer 补裸 Enter 的暴露面被系统性放大。若重发时 grok 队列里还有排队项,正好命中实验 1 的危险形态(send-now 取消运行中的 turn)。

实验 4:后端事实核对

tmux / tmux-pipe 的 pasteText 是真括号粘贴(paste-buffer -p);HerdrBackend.pasteText 确认是裸 write()、无 200~ 标记——一审 🟡2 属实,herdr 上主修复退化为旧行为。

二审建议(供作者与维护者参考)

  1. 括号粘贴保留(实验 2 支持)。
  2. Enter-only 重试不要把"记忆"当事实。两个方向任选:
    • 改为观测:写 Enter 前用 captureInputState() 确认 composer 确实持有该正文(注意:只有 TmuxPipeBackend 实现了它,默认 TmuxBackend 没有,需要补实现);
    • 或提高记忆写入门槛:仅在有正向证据(如 paste 后 viewport 可见正文残留)时才允许 Enter-only 分支。
  3. 顺带修 grok 1.0.5 的 verify 语义:mid-turn 排队提交在 dequeue 前 prompt_history 不可见,现 verify/recheck 必然误报"提交未确认"。建议对 busy 期提交放宽判定(如结合 updates.jsonl 的 user_message_chunk,或延长窗口、去掉误报失败卡),否则失败卡会常态化、且持续制造脏记忆。
  4. herdr pasteText 补括号标记(或适配器侧自包,参考 oh-my-pi 的做法)。
  5. 同意一审对测试替身的批评:sendSpecialKeys 对空 composer 返回 no-op 是未实测假设,应按实机语义修正并补"verify 误报后重试"用例。

以上为自动评审二审意见,实验脚本可复现;最终以维护者审阅为准

@deepcoldy

Copy link
Copy Markdown
Owner

自动评审 · 三条补充(首审者复核二审后)

二审的四组实验我独立复核,结论一致;🆕(mid-turn dequeue 才 append)我单独量了一次,数据钉得更死。只补三点二审未覆盖的内容,其余不重复。

1. 🆕 的量化:两个时刻完全重合,所以是语义而非延迟

真 grok 1.0.5,turn1 用 sleep 40 保证在跑,mid-turn 投递后逐秒轮询:

mid-turn Enter → prompt_history append : +54.3s
mid-turn Enter → turn1 turn_completed  : +54.3s   ← 同一时刻
适配器 verify 窗口                      : 4s

两个时刻重合(不是「+54s 慢慢落盘」,而是恰好在前一轮结束、排队项 dequeue 的瞬间)。这把「dequeue 时才 append」从「观察到很慢」升级为确定的语义:无论把 4s 窗口放宽到多少,只要前一轮还在跑,就永远等不到。所以第 3 条建议(修 verify 语义)不能靠「延长窗口」解决 —— 上界是前一轮的时长,无界。

2. 危险面:🆕 与实验 1 是同源事件,净效果不是变窄

二审实验 1 测出「send-now 取消需要 grok 队列里有排队项」——这点成立(我首审 probe 的第一版正因 turn1 太快、队列已空而假阴性)。但要接着推一步:

mid-turn 投递这一个动作,同时制造了「错误的记忆前提」和「send-now 的触发条件」——它把正文放进 grok 队列(于是 composer 空 → 记忆被错误武装),而「队列非空」正是实验 1 认定的危险前置。两者不是独立事件相乘,是同一事件的两个后果。

我用探针把这条链固化在生产代码路径上:mid-turn 提交后 composer 为空、正文在队列、记忆仍被武装;紧接着同文再投递 → pasteText 仍为 1 次、send-now 取消计数 = 1。所以「暴露面比一审窄」这个判断建议改为:单看裸 Enter 是窄的,但制造该条件的正是最常见的 mid-turn 路径,合起来更宽。

3. 对二审建议 2 的一处更正:captureInputState 观测在 mid-turn 下也救不了

二审建议「写 Enter 前用 captureInputState() 确认 composer 确实持有该正文」——这条在首审设想的场景(fail-closed 匹配失败、正文真停在 composer)里有效,但在 🆕 揭示的 mid-turn 场景里会失效并反向致害

此时 composer 确实是空的(正文在 grok 队列里,这是事实而非误判)。观测得到「空」→ 于是判定「需要重贴」→ 又回到 ×N 堆叠,也就是这个 PR 最初要修的那个 bug。

所以观测方案并不能同时覆盖两个方向。结合第 1 点,我的建议是调整修法顺序:

先修 verify 语义(mid-turn 排队提交改用 updates.jsonluser_message_chunk 之类 dequeue 无关的正向证据,而不是延长窗口),再谈 Enter-only 这层。在语义修对之前,"正文在哪里"这个判断没有任何可靠依据 —— 无论用记忆猜还是用 composer 观测,都会在某一侧出错。

顺带:TmuxBackend(默认后端)确实没实现 captureInputState,需补实现才能走观测路线 —— 成本更高、而按上面的分析收益还不完整,可作为取舍参考。

以上为首审者复核二审后的补充,实验可复现;最终以维护者审阅为准

@deepcoldy

Copy link
Copy Markdown
Owner

自动评审 · 结论收口(首审 + 二审一致口径)

两轮评审已对齐,本条替换/收窄前述评论里的修法建议,供作者与维护者参考:

1. 一处必须写明的实测边界:目前所有「括号粘贴 + Enter 稳定生效」的实机数据(8KB×12,12/12 提交)均为 idle composer 场景。mid-turn(正文进 grok 队列而非 composer)下 Enter 是否稳定生效未测——而按已实证的 dequeue 语义,系统性问题恰好在那一侧。请勿据此认为括号粘贴已被完整验证。

2. 最小可合形态(如作者想快速收敛)只留括号粘贴,Enter-only 记忆整段删除。理由:

  • 原 bug(大消息逐字节打入 → Enter 被当软换行吞掉 → 重试堆 ×N)的触发前提已被括号粘贴消除;
  • Enter-only 的两类实机回归(空 composer 补 Enter 触发 send-now 取消运行中的轮;重发同文被静默吞掉)随之消失;
  • mid-turn 弹「提交未确认」误报卡是 master 既有问题(dequeue 语义所致),不应由本 PR 兜底,建议另开 PR 修 verify 语义。

3. 若保留 Enter-only,则必须先修 verify 语义:mid-turn 按 dequeue 时刻确认(或改用 updates.jsonl 的 dequeue 时刻证据)。延长 verify 窗口无效——上界是前一轮时长,无界。记忆与 composer 观测在语义修对之前都会在某侧出错(观测得「空」→ 重贴 → 回到 ×N 堆叠)。

无论走 2 还是 3,都建议先补 mid-turn 格的实测。自动评审意见到此收口,最终以维护者审阅为准

@deepcoldy

Copy link
Copy Markdown
Owner

自动评审 · 补上 mid-turn 那格实测(此前两轮共同标记的唯一未验证点)

前面两条评论都以「建议先补 mid-turn 格的实测」收尾。我用真机 grok 1.0.5 把这格补上了,结论对「最小可合形态」是支持的,但同时暴露一个比之前描述更强的事实。

方法sleep 300 的工具轮保证全程 mid-turn;每次 trial 用 8KB 多行正文(与事故载荷同形)走括号粘贴 → 1s → Enter;判据不看正文回显(会误匹配 grok 自己的 transcript 回显),只读 grok 面板底栏的状态机 + prompt_history + updates.jsonl

  • Enter:queue + Ctrl+Enter:send now ⟹ composer 持有草稿
  • Enter:send now + Ctrl+;:queue ⟹ composer 已空 + 队列非空

结果(6 次有效 trial,第 7 次前置条件已消失即停)

指标 结果
8KB 正文 mid-turn 被接受进队列 6/6(每次底栏都从 Enter:queue 翻到 Enter:send now
Enter 被吞(composer 仍持草稿) 0/6
turn 运行期间 prompt_history 出现这些正文 0(取消 turn1 让队列排空后才出现)

三点结论

1. 括号粘贴在 mid-turn 下同样可靠(0 次被吞)。 加上二审的 idle 12/12,「括号粘贴 + Enter」两种场景都有实测支撑了。这条支持「最小可合形态 = 只留括号粘贴、Enter-only 整段删除」——原 bug 的触发前提确实已被消除,而不只是在 idle 下被消除。

2. 但 submitted:false 在 mid-turn 下是 100% 必然,不是概率性的。 6/6 全部成功投递,prompt_history 却 0 命中——两件事同时成立,正是因为 append 发生在 dequeue 时刻。所以 mid-turn 消息的「提交未确认」不是偶发误报,而是每一条都会命中。这使前一条评论里「延长窗口无效(上界=前一轮时长)」的结论进一步收紧:不存在任何窗口值能让 mid-turn 的 verify 通过。

3. 对 Enter-only 的杀伤比之前描述的更强。 每次成功的 mid-turn 投递之后,底栏都停在 Enter:send now(6/6)——也就是说此刻任何一记裸 Enter 都会取消正在运行的轮。而这正是 unconfirmedComposerBody 被错误武装的同一时刻。之前说「若重发时队列里恰好还有排队项就命中」,实测表明:mid-turn 投递成功后,那个危险状态是必然状态,不是「恰好」

综上,我建议的取舍与二审收口一致,并且现在有了 mid-turn 侧的数据支撑:保留括号粘贴、删除 Enter-only 记忆;verify 语义(mid-turn 按 dequeue 时刻取证 / 用 updates.jsonl)另开 PR 修,因为它是 master 既有问题。

附一条方法学更正(也是给复核者的提醒)

我第一版探针得出「6/6 全部被吞」的相反结论,是探针自身两个 bug:① 用 grep 在整屏找正文 → 匹配到的是 grok 提交后在 transcript 里的回显,不是 composer;② 判定「失败」后发 Ctrl+C,把 turn1 取消了,导致后续 trial 根本不在 mid-turn 状态。当时的自相矛盾信号是「屏幕说被吞、prompt_history 却有 6 条 append」——两者不可能同时为真。改用 grok 自己的底栏状态机 + 落盘证据后结论反转。若要复核这格,建议不要用正文回显做判据。

以上为自动评审补充实测,脚本可复现;最终以维护者审阅为准

@deepcoldy

Copy link
Copy Markdown
Owner

自动评审 · 记录更新(两处措辞按补充实测收紧)

5449047688 补上了 mid-turn 格实测后,对本串前两条评论做两点修订,供维护者读时以本条为准:

  1. 5449016209 第 1 点「mid-turn 下 Enter 是否稳定生效未测」已关闭:mid-turn 6/6 接受、0 被吞。至此「括号粘贴 + Enter」在 idle(12/12)与 mid-turn(6/6)两侧都有实测。最小可合形态(保留括号粘贴、删除 Enter-only 记忆)从「大概可行」升级为两侧数据背书
  2. 5448963831 中「重发同文时恰好队列里还有排队项就命中 send-now」的措辞按实测收紧:mid-turn 投递成功后底栏必然停在 Enter:send now(6/6)——危险状态是必然,不是「恰好」。同理「延长窗口无效(上界=前一轮时长)」收紧为:不存在任何窗口值能让 mid-turn verify 通过(append 在 dequeue 时刻,100% 错过)。

自动评审到此定稿,共 7 条评论;最终以维护者审阅为准

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.

2 participants