jyk/voice-ime 分支:v0.4.134cce9f1140e2bbd2ce0efe209383996f46fc2f0 → 8065e2e4bd1299ada56e2ba50223c82ffe2f2ccb本次增量是一个小而聚焦的行为修复,共触及 3 个文件:
| 文件 | 变更性质 | 规模(约) |
|---|---|---|
docs/27-历史记录与失败语音.md | 文档:补充"同步校验"口径 | +3 行 |
internal/session/session.go | 源码:Retry 增加同步存在性校验;handleRetry 增加日志兜底 | -1 / +11 行 |
internal/session/history_test.go | 测试:新增 TestSession_RetryUnknownIDRejectedImmediately | +18 行 |
无接口签名变更、无新增依赖、无配置/前端变更。
Session.Retry —— 把"找不到记录"从异步改为同步拒绝(核心修复)变更前:Retry 只检查"历史是否启用 / 会话是否忙 / 队列是否满",然后就 accepted=true 把 id 投入 retryReqs;记录是否存在要等到 Run 协程执行 handleRetry 时才发现,用户看到的是"点了重试 → 浮窗闪一句找不到"。
变更后(internal/session/session.go:2127 起)在入队前增加一次同步读取:
if _, ok, err := s.deps.History.Get(id); err != nil {
return false, "读历史失败:" + err.Error()
} else if !ok {
return false, "找不到这条历史记录"
}
正确性评估:
cmd/voiceimed/ipc.go:796(IPC history.retry)原样把 (accepted, reason) 封进 HistoryRetryResult;托盘 cmd/voiceimed/tray.go:246 与前端 app.js:1779 都会在 accepted=false 时当场把 reason 显示给用户。这次修复正好让三处的"同步反馈"语义成立。History.Get(internal/history/history.go:205)内部 s.mu.Lock(),可从 IPC/托盘协程安全调用(注释亦有说明)。Get 排在"会话是否忙"检查之前。原先会话忙时不读盘,现在即便会话忙也会先做一次历史文件读取。属可接受的开销(历史文件读取有锁、量级小),但相较旧路径多一次 I/O。LatestFailed 一样,此处不做"记录必须是失败态"的判断——前端 HistoryRetry 可对成功记录发起重试,这是既有行为,本次未变。Session.handleRetry —— 对"排队期间记录消失"补日志兜底internal/session/session.go:2160 附近的 !ok 分支新增:
s.deps.Logger.Warn("重试识别:记录已不存在(可能刚被清除)", "id", id)
正确性评估:
Retry 的 Get 与 handleRetry 的 Get 之间,记录可能被"清除数据"删掉。此时 handleRetry 仍会走 retryPanel("找不到这条历史记录"),只多补一条 Warn 日志,避免该路径在日志里"隐形"。Get(Retry 一次、handleRetry 一次)。量级可忽略,若未来历史文件极大可考虑合并,但当前不构成问题。TestSession_RetryUnknownIDRejectedImmediatelyaccepted=false"且 reason 含"找不到",直接锁住本次修复的行为契约。TestSession_RetryRejectedWhenBusy 互补:一个测"忙",一个测"找不到"。docs/27 增补说明:"记录存不存在是同步校验的",并留下 2026-10-08 联调实测的背景(旧实现把本该同步的校验做成了异步)。文档与代码口径一致。
数据来源:
codescan_issues_diff(base34cce9f→ head8065e2e)
即:本次提交在质量引擎的规则地图上没有触发新增问题,也没有消除既有告警——这是正常的,因为本次修复的是一个行为/时序缺陷("同步校验被做成异步"),不属于现有静态规则(圈复杂度、耦合、重复代码、XSS 等)能捕捉的类别。该缺陷的"修复"证据来自代码 diff、commit 说明与新测试,而非质量引擎。
codescan_issues_diff:新增问题 0 条。handleRetry 本就命中既有告警「过度日志」(internal/session/session.go:2150,8 处 log 调用,超过阈值)。本次在其中又新增 1 处 Warn,会进一步靠近该告警。这属于可接受的取舍(该日志正是为消除"隐形路径"而加),无需处理,但记录在案。以下均为存量问题,随本次改动被"覆盖"到,并非本次回归,列出供后续排期参考:
internal/session/session.go(共 47 条,节选与本次相关者)
| 严重度 | 类型 | 位置 | 说明 |
|---|---|---|---|
| Medium | Complexity | session.go:305 | 上帝类:Session 有 80 个方法(>20) |
| Medium | Dependency | session.go:2150 | handleRetry 直接依赖 16 个函数(>10),高耦合 |
| Low | Maintainability | session.go:2150 | handleRetry 过度日志(8 处 log,本次 +1) |
| Medium | Concurrency | session.go:424 / 642 / 2314 / 2575 | 启动 goroutine 未带 context 取消 |
| Medium | Complexity | session.go:556 / 1137 / 1502 / 1630 / 1724 / 1963 / 2655 | 多处圈复杂度/函数过长 |
internal/session/history_test.go(共 4 条)
| 严重度 | 类型 | 位置 | 说明 |
|---|---|---|---|
| Medium | Dependency | history_test.go:59 / 125 | 测试函数高耦合(≥12 依赖) |
| Medium | Complexity | history_test.go:59 | 圈复杂度 14 |
| Low | Maintainability | history_test.go:31 | 重复代码块 |
internal/history/history.go(共 5 条,被 Get 间接引用)
| 严重度 | 类型 | 位置 | 说明 |
|---|---|---|---|
| Medium | Complexity | history.go:244 / 428 | 圈复杂度 12 |
| Low | Maintainability | history.go:197 / 238 / 432 | 重复代码块 |
总体结论:本次变更质量良好,逻辑正确、边界处理到位、有测试与文档配套,未引入静态质检新增问题。
Retry 同步校验)达成了 commit 声称的目标——让托盘/设置界面"当场"拿到"找不到",而不是排进队列后仅在浮窗闪现。三处调用点均已正确消费 reason。handleRetry 的二次 Get + 日志兜底覆盖,不会出现静默失败。Retry 与 handleRetry 的两次 Get 结果合并传递(如入队时携带 Entry 而非 id),同时消除双读与 TOCTOU 窗口;但当前实现已足够健壮,收益有限。handleRetry 的日志条数已偏高,若后续继续加日志,建议改为结构化字段合并而非新增 Warn 调用。internal/session 包测试,重点覆盖 TestSession_RetryUnknownIDRejectedImmediately、TestSession_RetryRejectedWhenBusy、TestSession_HistorySavesFailedAudioAndRetries 三条用例。注:本报告"修复/新增"章节严格采用 codescan_issues_diff 的真实返回数据(0/0);功能层面的行为修复结论来自代码 diff 与测试,未将其混入静态质量规则口径。