fix(desktop): steerMessageCore recovery path may lose paused-queue ack on epoch bump
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
## 来源
PR #1225 合并后由 auto-review 审查 agent 发现的潜在回归。
## 问题
`apps/desktop/src/renderer/lib/makerChatStore.ts` 约第 7767 行,`steerMessageCore` 的 post-failure recovery 路径:
```ts
const operation = beginInputProjectionOperation(sessionId);
const latest = await operation.api.input.getProjection(sessionId);
if (!applyInputProjectionOperationResponse(sessionId, operation, latest)) {
return false; // ← 新增的 early return
}
if (latest.pendingQueue.some((q) => q.clientId === queued.clientId)) { ...; return true; }
```
`applyInputProjectionOperationResponse` 在 authority epoch 被 bump 时返回 false(发生在 `stopSession()`、terminal `done`/`error` 事件、`/clear`、session purge)。
**触发场景**:用户 steer 得到 uncertain ack → coordinator 将其物化到 paused queue → 用户看到疑似卡住点了 Stop → Stop 调用 `supersedeInputProjectionRequests` bump epoch → recovery 中的 `getProjection()` 返回的 `latest.pendingQueue` 确实包含该消息 → 但 epoch gate 返回 false 导致提前退出 → composer 保留 stale draft → 下次发送产生重复。
## 影响
与 PR #1225 adjacent comment (lines 7760-7764) 明确禁止的 "draft + paused row coexist → resend duplicates" 不变量冲突。既有回归测试 `pendingQueueDefer.test.ts` 未覆盖 concurrent epoch bump 场景。
## 建议修法
`latest.pendingQueue.some(...)` 的判定应独立于 `applyInputProjectionOperationResponse` 的布尔返回值——仍调用后者(保留 mirror-write 副作用),但不让它 gate "composer 是否被告知 handled"。
## 严重度
P0(数据完整性:用户可见重复消息),但触发条件需要特定竞态时序(uncertain ack + 用户在 recovery 飞行期间点 Stop),实际命中概率中等偏低。
## 关联
- PR #1225
- 历史修复:review #939 round 5
Contributor guide
Research direction
Start in apps/desktop/src/renderer/lib/makerChatStore.ts around steerMessageCore and inspect the post-failure recovery path, then read pendingQueueDefer.test.ts. Add coverage for the concurrent epoch-bump scenario and verify that a queued message does not leave a stale draft or cause a duplicate on resend.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100