makecindy / makecindy/cindy

fix(desktop): steerMessageCore recovery path may lose paused-queue ack on epoch bump

Open
#1,290 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.