服务端原先只有「回调」和「客户端轮询」两条推进路径,两条都没到时记录会永远 卡在 Transcribing,没有任何自愈——真机上卡了 8 分钟,直到用户杀 App 重开。 业务在服务端跑,不该由客户端在不在线决定它推不推进。 兜底做两件事(每分钟一次 cron): - 转写中且 60s 无人查询 → 主动 PollTranscribe;超 2h 未完成判 TranscribeFail, 否则第三方丢单的记录会被无限查下去; - 停在待总结/总结中超 5 分钟且**不在 AI 队列里** → 重新入队。「不在队列里」 这个前提不能省,正在跑的重复入队 = 两次大模型计费且后者覆盖前者。 顺带修两处: - getstucktranscribing 的时间条件补上 `lastquerytime IS NULL`。SQL 里 NULL 的 比较永远不为真,缺了这条,从未被查询过的记录一条都扫不到——正是最该救的那批。 - 三个拉取入口统一用 hideHalfDoneTranscribe:PollTranscribe 成功后先把 State 推到 AwaitSummarizing 落库、再异步写 Translate,于是响应里必然是「状态说转写完了、 Translate 还是空」的中间态。客户端据此 jsonDecode 会抛异常,把轮询循环整个掀掉。 只对本次真正轮询过的记录降级,否则 finishTranscribe 出错时会被永久钉住。 另加会议纪要的 ngram 全文索引(幂等、随启动自动建、失败只降级不阻断), 给 MCP 的 search_meeting_notes 用;默认解析器按空格切词,中文整段会变成一个 巨型 token 等于没索引,所以必须 WITH PARSER ngram。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>