fix(desktop): 收口迟到 wake 终态泄漏的 pendingTaskWake 桥接,修复侧栏 spinner 永久转圈 - #2952
Conversation
主轮 Done 之后才到达的 wake 型任务终态(fork 会话收到父会话任务的终态、重连 重放等)会置位唤醒桥接,但设计中的两条消费路径(wake turn 启动 / wake-fail Done)在这类迟到/误投场景永远不会发生;pendingTaskWake 又不在 reconcileStaleRunningTasks 的对账覆盖内,活动熄灭对账沿的 running 候选粗筛 (迟到终态本身是 completed,候选恒空)还会把它挡在自愈门外 —— running 快照 被永久撑住,侧栏 spinner 永转、无自愈路径。 修复(全部复用既有的活动熄灭延迟对账机制): - agent_task_update:主轮 Done 已越过后置位的桥接,置位即调度一次延迟对账兜底; - 对账粗筛(调度沿 + 到点回调):pendingTaskWake > 0 时放行,不再仅看 running 候选; - seedBackgroundTaskSnapshots 新增 opts.reconcileWakeBridge:主 turn 不在跑且 main 权威表无任何 wake 型任务时清零桥接三元组;权威表仍有 wake 任务在跑或 wake turn 已启动(桥接已被消费)时不动,不误杀真实空窗。 回归:pendingTaskWakeBridgeReconcile.test.ts 4 例(泄漏复现+收口 / 权威表有 活任务不误杀 / 旧签名路径行为不变 / 正常 wake turn 消费链路不受影响)。 typecheck 通过;makerChatStore.ts 存量 lint 问题(9148 行 prefer-const,主干 同样报)未在本提交范围内。 Signed-off-by: mengfanyu9410-hub <282780248+mengfanyu9410-hub@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6807d3f784
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/lib/makerChatStore.ts | 为 wake 桥接增加单调代次、年龄闸和基于权威快照的延迟收口,当前 HEAD 已覆盖此前报告的旧快照与计数 ABA 场景。 |
| apps/desktop/src/main/maker-ipc/register.ts | 后台任务快照响应新增 pending continuation 数量,供 renderer 判断是否可以安全收口桥接。 |
| packages/maker-core/src/agents/claude-code/index.ts | 从 continuation claims 统计 awaiting 与 active 状态,为 IPC 提供权威计数。 |
| packages/maker-core/src/session.ts | Session 层公开 continuation 计数并为关闭或不支持该能力的会话提供零值回退。 |
| apps/desktop/src/renderer/lib/tests/pendingTaskWakeBridgeReconcile.test.ts | 覆盖泄漏收口、最小年龄、权威 continuation、在飞新增、计数 ABA 和多 wake 消费等关键时序。 |
Sequence Diagram
sequenceDiagram
participant Agent as Claude Code Agent
participant Main as Electron Main
participant Renderer as makerChatStore
participant UI as Sidebar
Agent-->>Renderer: 迟到的 wake 终态
Renderer->>Renderer: pendingTaskWake++, gen++
Renderer-->>UI: 保持 running
Renderer->>Main: listSessionBackgroundTasks
Main->>Agent: 查询任务与 continuation
Agent-->>Main: tasks + pendingContinuations
Main-->>Renderer: 权威快照
alt 代次稳定且无任务/continuation并已超龄
Renderer->>Renderer: 清零 pendingTaskWake
Renderer-->>UI: spinner 熄灭
else 仍可能存在合法 wake
Renderer->>Renderer: 保留桥接并重新调度
end
Reviews (3): Last reviewed commit: "test(desktop): 对账粗筛用例适配桥接放行语义(CI 失败根因)" | Re-trigger Greptile
MagicLizi
left a comment
There was a problem hiding this comment.
格式门未通过
以下问题需要修正后才能进入代码审查:
- PR Description 缺段落:请补充"这次改了什么 / 怎么验证的 / 风险"相关说明,参照
.github/PULL_REQUEST_TEMPLATE.md模板。
修正后推送新 commit 即可,下轮自动重新审查。
|
💡 本 PR 命中 UI 路径( |
review 意见(greptile Issue 1 / dash-s-cindy 场景 2-4)共同点:旧空快照可能 清除请求在飞期间新置位的桥接;「main 运行表为空」也不能独立证明合法 wake 不会稍后启动;多 wake 场景不能被一次清空。 改动: - state 新增 pendingTaskWakeArmedAt(最近置位时刻,置位刷新、清零置 null); - 对账回调在发起快照请求前捕获桥接代际(capturePendingWakeBridgeCount); - seedBackgroundTaskSnapshots 的 reconcileWakeBridge 由 boolean 改为代际计数, 收口四条件:计数与代际一致(在飞无新增无消费)+ 主 turn 不在跑 + 距最近 置位超过 WAKE_BRIDGE_RECONCILE_MIN_AGE_MS(10s)+ 权威表无 wake 型任务; 条件未齐且计数仍 >0 时重新调度下一轮对账复查,不做部分清除; - 回归测试 4→7 例:新增在飞代际、最小年龄闸、多 wake 依次消费三例; 同步补齐 makerQueueState.test.ts 状态构造器的新字段。 Signed-off-by: mengfanyu9410-hub <282780248+mengfanyu9410-hub@users.noreply.github.com>
|
已按 review 意见推送 @greptile-apps Issue 1(旧快照清除新桥接) — 已修。对账回调在发起 格式门(PR Description 缺段落) — 已按 UI 效果证据 — 本 PR 命中 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea8ebc4254
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
LGTM. The implementation correctly addresses all three concerns from the original review: Generation consistency (Issue 1): Minimum age gate: Early-return bypass: The two guard sites — The No outstanding concerns. The fix is well-scoped and the fallback behavior (worst case: spinner clears 10s late, then |
|
@mengfanyu9410-hub 👋 这个 PR 还有 3 条 review conversation 没 resolve(apps/desktop/src/renderer/lib/makerChatStore.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
|
⏸️ 本 PR 触发维护者确认门 (product: 命中 UI 路径)。 已开启讨论 issue,等待维护者在 PR 上 Approve 后自动放行。 维护者: @dashhuang @DavidShenXD @fmfsaisai @kirozeng @MagicLizi @xdanger @zqchris 讨论 issue:#2982 |
回应第二轮 review(codex P2 两条 / greptile P1): - codex P2:noteBackgroundTaskEvent 在任务终态立即将其移出 runningBackgroundTasks,listBackgroundTasks() 的空快照不能证明没有待启动 的 continuation。新增贯通链路:claude-code agent countPendingWakeContinuations()(awaiting+active claim 数,cancelled 不计) → base-agent 接口声明 → Session 透传 → LIST_SESSION_BACKGROUND_TASKS IPC 返回 pendingContinuations → renderer 收口第 6 条件:计数**明确为 0** 才允许 清桥接;信号缺失(旧 main)按不可用处理,只重试、不退化回空表判据。 - greptile P1(ABA):state 新增 pendingTaskWakeGen(仅置位自增),对账捕获 与收口比对代次 —— 在飞窗口内「消费后又置位、计数恰好回到捕获值」不再可能 被误认为同一代际。 - 回归测试 7→10 例:新增 continuation>0 不收口 / 信号缺失不收口 / ABA 代次 三例;makerQueueState 构造器补 pendingTaskWakeGen。 验证:新测试 10/10、makerQueueState 18/18、周边 48 例全绿;desktop typecheck 0 错;maker-core 直跑 tsc 与主干错误集完全一致(16 个,全为 codex/pi 测试 存量,本次改动的三个文件零新增)。 Signed-off-by: mengfanyu9410-hub <282780248+mengfanyu9410-hub@users.noreply.github.com>
|
已推送 Codex P2 ×2(空运行任务表 ≠ 无待启动的 continuation) — 接受,按建议改为以 provider continuation claim 为权威判据。新增贯通链路: Greptile P1(计数代际 ABA 碰撞) — 接受。state 新增 验证:新回归 10/10; 三条 thread 将随本评论一并 resolve;如仍有疑虑欢迎 reopen。 |
CI「Linux unit tests (2/2)」失败根因:既有用例『远程会话豁免;无 running 条目 不发 IPC』的第二段用 wake 型 completed 终态构造「无 running 条目」场景 —— 该帧 在本 PR 语义下会置位唤醒桥接并放行对账 IPC,而这正是修复目的(旧断言把泄漏 永转路径固化成了预期)。 调整:①原段改用 local_bash 终态(白名单外不置位),保留「没活不空跑 IPC」的 原验证意图;②追加 wake 终态段,固化「桥接置位 → 粗筛放行对账」的新语义,并 指向 pendingTaskWakeBridgeReconcile.test.ts 的收口条件测试。 本地实跑:该文件 11/11、桥接回归 10/10 全绿。 Signed-off-by: mengfanyu9410-hub <282780248+mengfanyu9410-hub@users.noreply.github.com>
|
CI 补充说明:昨日「Linux/Windows unit tests (2/2)」的真实失败点是既有用例 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a0c89ccad
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@mengfanyu9410-hub 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/renderer/lib/makerChatStore.ts),auto-review 因此暂时跳过、没法继续审查 / 合并。 如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。 |
MagicLizi
left a comment
There was a problem hiding this comment.
Code review passed. Solid fix for the spinner-stuck bug with well-designed reconciliation logic and thorough test coverage. The six-condition gate prevents false clearance effectively.
|
修得漂亮 — 六条件对账门(代际计数+生存期+authority continuation=0)把这种隐蔽的状态泄漏收得很干净,10 条新测试把每个守卫条件都单独验了一遍。 |
这次改了什么
摘要
修复侧栏 spinner 在会话完成后永久转圈:主轮 Done 之后才到达的 wake 型任务终态(fork 会话收到父会话任务的终态、重连重放等)会置位唤醒桥接
pendingTaskWake,但设计中的两条消费路径(wake turn 启动 / wake-fail Done)在这类迟到/误投场景永远不会发生,桥接又不在任何 reconcile 覆盖内 —— running 快照被永久撑住、无自愈路径(完整根因分析见 #2951)。本 PR 把桥接纳入既有的「活动熄灭延迟对账」机制:置位于主轮 Done 之后的桥接自动调度权威对账,四条件全部满足才收口(详见下文),否则重新调度复查。变更类型
fix缺陷修复feat新功能refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
makerChatStore.ts桥接收口逻辑(状态字段pendingTaskWakeArmedAt、代际捕获capturePendingWakeBridgeCount、seedBackgroundTaskSnapshots的reconcileWakeBridge收口)+ 回归测试 7 例 +makerQueueState.test.ts状态构造器补新字段。makerChatStore.ts存量 lint 问题(prefer-const,main 上原样报)。UI 变化
不涉及:改动命中
renderer/lib路径但无任何视觉/交互/文案变化 —— 修复的是 running 状态残留,spinner 组件、样式、布局均未触碰;修复前后差异仅为「泄漏场景下 spinner 是否永久转」这一状态行为,已由 store 级回归测试固化(泄漏复现 → 收口熄灭)。怎么验证的
自动验证
手工验证
不涉及:泄漏依赖「主轮 Done 后迟到终态」的时序,真机难以稳定手工触发;行为已由驱动真实 store 的回归测试覆盖(
__applyStatusUpdateForTest/__applyStreamEventForTest→getRunningSnapshot断言)。未执行的验证
风险
风险分类
影响与回滚
WAKE_BRIDGE_RECONCILE_MIN_AGE_MS,给慢机/高负载下合法 wake 留启动余量);另有主 turn 不在跑 + main 权威表无 wake 型任务两条件。极端情况下(合法 wake 超过 10s 才启动且期间对账恰好落地)桥接会被提前清零,后果限于 spinner 短暂熄灭 + 一次完成通知,wake turn 启动后isRunning立即重新撑起,非终局错误。reconcileWakeBridge仅活动熄灭延迟对账路径传入;挂载/面板水合等旧签名调用不受影响(有测试固化);远程会话沿用既有isRemoteSessionSticky多阶段豁免。