Repository navigation
fix(chat): keep source admission moving during native recovery reads - #7504
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
原 Bot 同时检查历史失败和接收新消息时,用户会遇到无关的路由锁超时。 旧请求等待原生读回时,新消息会等待同一共享锁;修复后新消息可受理,旧观测若已过时就不创建恢复工作。 真实 stdio 与文件后端对照证明新消息不再等待旧读回,原失败保留且未知效果不触发模型执行。 本 PR 不认证真实账号切换、任意进程重启或全部历史业务已完成。 生产安装采用、持续锁指标、真实认证切换和其余未回复业务仍需分别核验。
改动思路 / Approach
只把耗时的原生读取移出共享锁,继续复用原请求锁、完整来源库存和 TypeScript 判定;不新增状态库或恢复执行者。 本 PR 的边界是既有 Chat IO 的并发可用性与准确回执关联,生产采用和账号效果由原维护路径分别验证。 单纯延长 5 秒锁超时仍会让新消息排队,直接去掉来源锁又会失去提交前检查。当前方案保留每条原请求的锁,把原生只读 RPC 放到共享锁外;重新进入来源锁后,先核验当前身份和原消息,再比较完整本地事实。只有新恢复工作要求快照不变;已经入队的恢复按 TypeScript 证明的准确回执补关联,不要求后来输入和执行状态保持静止。
| 同一隔离 stdio / File 场景 | 基线 | 最终 head |
|---|---|---|
| 原生读取固定等待约 2 秒时受理新消息 | 约 2.1 秒 | 三次约 0.05–0.09 秒 |
| 未知执行效果 | 原失败保留,新增模型执行 0 | 相同 |
| 来源变化或已提交恢复 | 锁内串行;已提交回执可采用 | 新工作放弃旧观测;已提交回执仍采用 |
这是合成协议与真实本地存储的对照,不是生产 p95 或真实账号切换。原生读回本身仍约 2 秒,修复的是它对其他消息的阻塞;没有新增人工配置、确认或重试轮次。
具体改动 / Changes
精确 head:2d8f2f58b6ddb766711e0bc53eb57016a3f30153。独立基准规范为 docs/reference/protocols/manager-evidence-and-continuity-v0.md,spec_revision=47576fd81b52984f24360c31c78ad627b92c7373。MC-1 对应 Core 权威保持;MC-2 对应原来源、绑定、权限与纠正检查;MC-3 对应原路返回与业务完成分离,三项在本次所触及的恢复路径均为 implemented。编号是本审查对文档相应条款的映射,未把文档 staged 的全部产品路线称为本 PR 完成。
关键代码讲解
recover_failed_request仍先持有原请求锁并读取原失败。原生 IO 移到共享来源锁外;提交前在来源锁内重新读身份、消息和完整本地状态。新的恢复只接受稳定原事实,原失败 Turn、既有通知及确定的 client id 保持。source_requests复用pending()的完整原生 journal 读取,只比较同一 binding/source,没有历史页大小或固定 request id。独立来源不会挡住原恢复。实际 1108 个 journal 的只读测量为每次 0.105–0.415 秒;这是新增比较成本,未宣称未来所有规模都固定耗时。- 现有
_context_recovery_plan和 TypeScript 的admitted_turn_id仍拥有恢复资格。完整回归发现对已入队回执套用静止快照会丢关联,最终版本只对尚未入队的新工作做该比较;既有 queued-input/post-enqueue-crash 及七个新并发反例共同验证,不复制一套 Python 恢复政策。
完整改动为两个文件,生产代码 +32/-14,测试 +76。测试复用原 steward、真实文件队列与现有协议 fixture,没有加入生产入口、额外消费者、发布脚本或私有数据。
对主干的风险 / Risks
未发现本次变更的未解决阻断问题。最重要的反证是:在原生读取后、飞书来源读取期间才到达的网页纠正,仍必须拦住旧工作;而已经提交的恢复不能因为新的输入而被当成从未入队。两者都先复现失败,再通过当前边界修复。未知 native effects、撤权、同来源新请求和另一来源的并发更新都保持各自正确结果。第一次新增测试误用了状态回执断言,记录保留;后来的真实 queued-input 回归也保留,不能只选最新绿色结果。
PASS:20 项针对性恢复回归、真实 stdio/File 对照、Ruff、编译、双语 RFC 检查,标准 premerge 的 6 项直接检查与 2 项选定检查。完整三文件为 346 通过、1 失败;失败是既有长文投递的 10 秒 drain 断言。固定基线独立复现相同的测试、417→358 行、pending=1/recovery=0 和时限断言,基线及当前头各三次对照中,本次修改的恢复入口调用数均为 0;投递与拆分代码也逐字未改。此项按 pre_existing_unrelated 保留为失败,未放宽时限,也不把后来三次单独通过称为没有抖动。既有 App 投递维护路径继续负责该预算问题。原生账号、App 二进制和生产业务均未由合成用例代验。当前 wait_for_ci=false,未查询或等待 CI;change-quality 为 disabled,不冒称获得其 receipt。
我的整体评价 / Verdict
这是有实际受理调用者、历史缺陷和双向反例的 justified_increment;long_horizon 与 user_experience 在已测边界 improved。只把耗时的原生读取移出共享锁,继续复用原请求锁、完整来源库存和 TypeScript 判定;不新增状态库或恢复执行者。 本 PR 的边界是既有 Chat IO 的并发可用性与准确回执关联,生产采用和账号效果由原维护路径分别验证。 未修改渲染、文案和导航,因此 visual_review 不适用;未验证的是生产采用、长期时延与真实认证切换。原失败、原受众及未知效果都没有借此关闭,后续采用仍由正常原服务维护流程负责。
English verdict: APPROVE — 2d8f2f5; responsive source admission and exact accepted-receipt recovery are verified, with production adoption and account cutover assessed separately.
原 Bot 检查历史失败时,会在共享会话路由锁内等待原生只读 RPC;等待期间,同一原会话的新消息可能触发 5 秒锁超时。本改动保留原请求锁,将原生读回移到共享路由锁外,随后重新核对会话、失败 Turn 和来源请求集合;变化时放弃该观测,授权、原消息核验及恢复资格仍由原有 owner 在锁内决定。
验证:新增并发回归在基线复现相同锁超时,修复后七项并发用例及十三项既有恢复用例通过,覆盖新输入、撤权、未知效果及原会话一次恢复。隔离的真实 stdio 协议和 Chat 文件后端三次对照中,2 秒原生等待下的新消息受理从约 2.1 秒降至 0.09–0.13 秒;原失败 Turn 不变,未知读回不产生模型工作。完整既有 Bot 回归与标准 premerge 的结果纳入精确版本评审。
只调整既有 Python IO adapter 的锁范围;TypeScript 恢复判定、权限、失败预算、业务和消息消费者不变。来源在读回期间持续变化时,恢复继续等待下一次原服务检查。此修复不证明真实额度耗尽切换、任意客户端重启或全部历史漏答已闭环。
完整三文件回归为 346 通过、1 个既有长文投递 10 秒 drain 抖动失败;固定基线独立复现相同断言和待回状态,且两侧该变更入口的调用数均为 0。该失败保留,预算未放宽;标准 premerge 的 6 项直接检查和 2 项选定检查通过。