Repository navigation
fix(chat): deliver fresh replies during historical recovery discovery - #8369
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>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=GPT-6; provider=OpenAI; self_reported (host execution observation unavailable)
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
使用原有 Lark 私聊的用户在历史恢复积压期间发送新问题。 以前历史候选的慢读取会占住唯一扫描循环,已生成的原生答案仍等不到回传;修改后该历史读取保持阻塞时,新问题仍能完成原消息回传。 受控原生协议与真实 Core/文件日志用例已验证:历史读取未释放,新答案已由原 provider 路径写出并独立读回;不要求用户重发或额外确认。
本 PR 只修回传发现的队头阻塞,不宣称模型启动、全局上下文收集、FIFO 准入或 session 压缩问题全部解决。 完整业务恢复与安装后延迟仍由原服务验收;启动准备和模型耗时保持独立问题。 这是一项可以独立复现、验收和回滚的修复:发现历史待办需要继续,但它不应成为新答案回传的串行前置条件。
改动思路 / Approach
持久化请求和 Core 仍是唯一 authority;复用原四槽池与文件发现 owner,两个独立缓存只保存文件变化提示,避免跨线程共享可变缓存。 本 PR 的边界是历史发现与新答案回传之间的调度隔离,原授权、provider attempt 与读回检查不变。 没有增加消息消费者、执行器、模型重放或持久队列。源码装配仍从 chat_server 构建原 private transport 和原 service。
| 触发 | 原路径 | 此 head 的路径 |
|---|---|---|
| 历史恢复读取慢 | 扫描线程等待完整发现,当前答案也被挡住 | 完整发现占原四槽池的一个空闲槽;扫描线程继续读持久化消息元数据 |
| 新答案已有正文 | 等待历史发现返回才排入处理 | 沿原请求日志与原 provider attempt 进入剩余空闲槽,随后重新核验来源并读回 |
此表是对 exact head be7446e24b832afaa1c33a626419a99ab3324277 的源码解释,执行证据是后述原消息反例与完整 owner 回归。相比缩短轮询间隔或另建一个消费者,这个方案直接移除串行等待关系,并保留原四槽容量、历史覆盖和效果去重。历史发现仍可能在四槽都忙时延后,因此不能把这项修复当作全系统延迟保证。
具体改动 / Changes
规范依据是已接受的原会话异步收发契约:spec_ref: docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md;spec_revision: 5090afc2a3516ad678f29d2328d8b3295dc2653d。本 PR 未修改规范来迁就实现。
关键代码讲解
LarkGoalTopicRuntimeService._reconcile_private:扫描优先读取 body paths;单个历史发现 Future 也计入原四槽容量。完成时把发现的路径以 setdefault 合回原 attempted map,避免把“发现过但尚未提交”的请求误作已尝试;异常保留正常重查,关闭后不再提交。LarkPrivateConversations.pending_body_paths:复用现有 PrivateDeliveryDiscovery,使用独立缓存读取未送达文件及已经持久化的 App outbox。缓存只保存文件变化提示,不获得发送、执行或重放权限;pending 文件和效果前的 Core/source 仍重新读取。pending_delivery_paths:完整历史恢复与 App projection 发现的原规则保留,改由同池空闲槽执行。没有新增第二套来源校验或未知效果重试政策;不提供 body 方法的自定义 transport 仍走原入口。
规范映射:AC-four-slot-replies implemented(四槽内计入 history Future);AC-source-before-effects implemented(仍由原 reconcile_request/Core/provider verifier 核验原来源);AC-durable-once implemented(原 journal 和 provider intent/readback 不变);AC-fairness implemented(保留未提交历史提示、公平计数、当前正文优先和停机断言)。
本 head 共四个文件 +174/-12,主要是两个原消息/容量反例和六个已有公平性变体的测试准备调整。adapter 的行数回归预算 2012→2024,对应独立元数据缓存及读取入口的十二行;没有改变其他预算、实验门槛、状态词汇或 source scope。完整 semantic vocabulary 与维护性检查均通过,复用现有状态 owner。
对主干的风险 / Risks
未发现阻塞性问题。最强反例不是“Core 显示 completed”,而是历史 observer 保持阻塞、原生子进程确实完成时,原 provider 是否已经返回准确正文。相同最终用例在不可变旧实现上命中 delivered.wait(4) 失败;在此 head 的 Python 3.12.15 上通过,且只创建一个 Session、一次 turn/start。另一个反例让一个历史发现和九个持久消息竞争,断言只有三个正文任务开始、总容量为四,剩余六个不进入 executor,关闭后不补提交。
验证结果:完整 Lark owner PASS:424 passed;相关容量、公平、停机、扫描恢复与新回传用例 PASS:10 passed;standard premerge PASS(六个直接检查、五个 catalog 和八个 risk-profile smokes);Ruff PASS。首轮完整回归曾是 418 passed / 6 failed:两个旧 fixture 绕过构造器,且只驱动同步扫描一步;后续提交补齐独立缓存并驱动真实异步发现交接,原容量、优先级和两秒期限断言保留,最终完整重跑通过。先前中断的运行不计为通过。
仓库配置的 mypy PASS(17 files);单查两个修改模块仍有旧基线相同的 20 项类型债务,逐条归一比较无新增/移除,保留为已知限制。最初 standard 检查缺少 TypeScript dev dependency,按仓库命令安装后已完整重跑通过。按当前 Goal 的 wait_for_ci=false,未读取或等待远程 CI;CI 与 merge readiness 不替代本地不变量证据。
真实 provider IO 与人为延迟在回归中使用合成边界;生产整体延迟、模型准备和 session 压缩未由该合成反例证明。原四槽被持续占满时历史发现仍可延后;回滚沿正常安装路径恢复源码即可,持久请求与 provider attempts 无迁移。
我的整体评价 / Verdict
long_horizon=improved,user_experience=improved:历史覆盖继续保留,新问题不再以完整历史 pass 为回传前置条件,原消息、授权、去重及失败恢复保持原 owner,用户无需额外重发或确认。视觉检查 not_applicable:修改内部扫描调度,消息正文和渲染未变;unverified_scope 是生产整体延迟、模型准备和 session 压缩。此处是有实际反例支持的 justified_increment,后续正常安装和原服务采纳仍需独立验收。
持久化请求和 Core 仍是唯一 authority;复用原四槽池与文件发现 owner,两个独立缓存只保存文件变化提示,避免跨线程共享可变缓存。 本 PR 的边界是历史发现与新答案回传之间的调度隔离,原授权、provider attempt 与读回检查不变。 当前设计与成本相称,保留原 structural transport 兼容分支有现存调用依据;没有需要在本 PR 先拆除的第二 authority。评审针对 be7446e24b832afaa1c33a626419a99ab3324277 全量差异,而不是只看最后的 fixture 修正。精确 head 的评审通过不等于 GitHub 正式自批准;合并仍需紧邻操作的 readiness 与既有 maintainer 授权。
English verdict: APPROVE — bounded original-reply discovery isolation is justified and locally validated; installed latency and session compaction remain unqualified.
历史恢复候选的慢读取会占住唯一的消息扫描循环:新的原消息已经持久化、原生答案已经生成,仍可能迟迟无法回传。本次将完整历史发现放入既有四个 worker 中的一个空闲槽位,扫描循环只读取持久化消息元数据,使新消息能够继续使用其余槽位完成原受众回传。
沿用原请求日志、Core 校验、授权、失败去重和 provider readback;不增加消息消费者、执行器或模型重放。历史发现得到的未提交请求仍保留原公平计数,旧 transport 保持兼容。
验证:旧版本在受控历史读取阻塞时无法回传已生成答案;同一反例在此 head 通过。另一个回归验证历史发现加消息处理总计最多四个 worker、没有 executor backlog。两个新用例已通过,完整 Lark owner 回归与标准 premerge 正在执行,最终结果会记入 exact-head review。Ruff 与仓库配置的 mypy(17 files)通过;两个修改模块单独检查仍有基线已有的 20 个类型错误,未新增。
维护性:adapter 文件现有行数债务从 2012 调整为 2024(增加独立元数据缓存与读取入口),其余维护性门槛不变。该修复针对回传扫描阻塞,不宣称完整启动延迟或 session 压缩问题已解决。