Skip to content

fix(codex): 回写结构化回合失败状态 - #688

Open
hyperdai wants to merge 1 commit into
deepcoldy:masterfrom
hyperdai:codex/codex-turn-error-notice
Open

fix(codex): 回写结构化回合失败状态#688
hyperdai wants to merge 1 commit into
deepcoldy:masterfrom
hyperdai:codex/codex-turn-error-notice

Conversation

@hyperdai

Copy link
Copy Markdown
Contributor

背景

Codex 结构化回合可能以 event_msg/task_complete 结束,同时携带错误且没有 last_agent_message。旧逻辑只从 response_item 提取最终回复,因此限流或任务失败后不会形成终态,飞书卡片会一直停留在“工作中”。

改动

  • 将失败的 task_complete 解析为结构化失败终态
  • 对 429 限流复用已有的额度受限状态和重试提示
  • 对无正文的普通任务失败补充兜底结论
  • 通过现有发送标记继续避免重复回写
  • 增加 Codex transcript 与 bridge fallback 的回归用例

影响面

  • 主要影响 Codex JSONL transcript 和 worker 的结构化回合收尾
  • 公共 bridge fallback 仅新增“失败且无最终正文”场景,正常完成、已有最终回复及显式 botmux send 路径不变
  • 不改变 PTY/Tmux、路径、进程或平台相关逻辑
  • 普通飞书群/话题会话生效;local/adopt 会话仍按现有规则排除辅助回写
  • 卡片继续复用现有限流 UI,没有新增界面

验证

  • pnpm exec vitest run test/codex-transcript.test.ts test/codex-bridge-queue.test.ts test/bridge-fallback-gate.test.ts test/traex-worker-bridge-wiring.test.ts test/cli-usage-limit.test.ts test/card-builder.test.ts test/bridge-final-output-retry.test.ts
    • 7 个测试文件、311 个用例全部通过
  • pnpm build
    • 构建、domain audit 和 dist audit 通过
  • git diff --check
    • 通过
  • 使用本次事故 transcript 回放,能够识别 2 条结构化 429 失败事件
  • 开发机热修后 daemon、机器人进程和 dashboard 均恢复在线;本次遗漏结论已在原群补发并读回确认

未主动制造新的上游 429,以免影响正在运行的会话。

同步 Codex 持久化失败终态,避免飞书卡片长期停留在工作中。
@hyperdai
hyperdai requested a review from deepcoldy as a code owner July 31, 2026 10:18

@deepcoldy deepcoldy left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审结论:REQUEST_CHANGES。普通飞书回合的 429 可见链路本身不会双发,但还有一个 durable 429 阻塞问题;同时确认 Grok 共享路径存在未声明的行为变化。

1. 阻塞:Codex 429 在 durable VC delivery 中会快速烧完重试预算

emitReadyCodexTurns() 会把 429 回合最终作为 turn_terminal(status='failed', errorCode='codex_rate_limited') 发出(src/worker.ts:3976-3982)。普通 IM 回合没有 dispatchAttempt,确实不会重派;但 VC meeting 的 durable delivery 会带 dispatchAttempt

该终态进入 receiver 后,所有 failed 都被映射为 failed_retryablesrc/services/vc-meeting-delivery-receiver.ts:648-669)。同一个 frozen envelope 在后续会议 tick 会再次 POST;receiver 对 failed_retryable 会重新 dispatch,最多 3 次后转成 poison(同文件 :518-543,默认 tick 约 30 秒)。因此持续 429 时会在约一分钟内连续撞三次并把投递流毒化,而不是等待限流卡的 retry countdown。managed/silent delivery 又会抑制辅助卡片,所以这条路径甚至看不到倒计时。

建议让 codex_rate_limited 在 durable contract 中进入 cooldown-aware / 不立即烧预算的语义,并补一条覆盖 dispatchAttempt 的 receiver 集成测试;至少不能按普通瞬时失败每 tick 重派。

2. 确认:共享失败兜底改变了 Grok 主动取消的可见行为

shouldEmitFailedBridgeFallback() 是所有 structured bridge CLI 的共用门,而调用点只排除了 codex_rate_limited。Grok 的 cancelled 会产出空正文、terminalStatus='failed'terminalErrorCode='grok_turn_cancelled',因此非 adopt 的主动 Ctrl+C 现在会收到“执行失败 / 查看最后错误”提示。终态结算本身没问题,但这段措辞把用户主动取消说成错误,属于噪音且 PR 影响面未说明。

建议二选一:排除 grok_turn_cancelled 并加 worker/gate 回归;或提供取消专用文案,同时在 PR 影响面明确 Grok。真 error / 未知 stop reason 保留失败提示是合理改善。

429 双发核查

普通 Codex 回合中顺序是:先发 screen_update(limited),随后 ready turn 因 rate-limit carve-out 不发 final_output,但第二轮循环仍发 turn_terminal(failed)。daemon 的 turn_terminal 不操作卡片;没有 final_output 也不会触发 usage-limit 自愈清理。因此用户只看到一张限流卡,不会再多出失败提示,限流状态会保留,uuid 重读也有去重。

本地验证

  • pnpm build:通过(domain audit / tsc / dashboard bundle / dist audit)
  • pnpm exec vitest run test/codex-transcript.test.ts test/codex-bridge-queue.test.ts test/bridge-fallback-gate.test.ts test/grok-transcript.test.ts test/traex-worker-bridge-wiring.test.ts test/cli-usage-limit.test.ts test/card-builder.test.ts test/bridge-final-output-retry.test.ts
    • 8 files,332 tests 全绿
  • git diff --check:通过

未合并,等待作者修正并继续遵守“申晗确认前不合码”。

@deepcoldy

Copy link
Copy Markdown
Owner

本地 delta 复核(尚未 push,commit b879a434a):Grok carve-out 方向正确,未发现功能性问题。

  • grok_turn_cancelled 仅抑制失败兜底正文;grok_turn_error 与未知 stop reason 仍会显示失败提示;终态结算逻辑不变。
  • gate 使用本地 cancel-code 集合、producer 导出常量并由 drift-guard 测试锁定,避免生产 gate 引入 Grok transcript 的 fs/process 依赖链;这个放置可以接受。
  • 独立扫描本机 1542 个 Codex rollout:57 条 turn_aborted(reason=interrupted),8 条 task_complete.error,两组 turn_id 交集为 0,error 中 0 条含 interrupt/abort/cancel。现有 Codex 取消不会进入本 PR 新增的失败兜底,因此无需 Codex cancel carve-out。
  • 验证:pnpm build 通过;相关 8 文件 335 tests 全绿;git diff --check 通过。

非阻塞建议:再锁一条 worker wiring 断言,确认 gateInput 持续透传 terminalErrorCode: turn.terminalErrorCode;当前 producer↔gate drift-guard 若单独漏掉 worker 透传不会失败。

原阻塞项仍未解决:VC durable 的 codex_rate_limited 仍会落入 failed_retryable 并消耗自动重试预算。PR 继续维持 CHANGES_REQUESTED;本地 commit 未获交付授权前不 push。

@deepcoldy

Copy link
Copy Markdown
Owner

本地 delta 2148fb894 复核:新增 worker→gate wiring source assertion 的截取范围与断言写法正确;独立运行 test/traex-worker-bridge-wiring.test.ts,6/6 通过。此前唯一非阻塞测试建议已关闭。该 commit 仍未 push;VC durable 429 blocker 仍保持开放。

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