Repository navigation
fix(chat): preserve accepted requests during runtime activation - #7274
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; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
详细中文评审
动机
正在更新本机 LoopX、同时仍有原会话请求需要处理的使用者。
旧版更新会在请求运行或排队时强制重启服务,切断原执行;修复后保留原消费者,等它完成后再切换。
已验证忙时不重启、原请求字节不变、完成后可由同一更新入口重试;安装成功与服务切换未完成分别显示。
不重放效果未知的业务请求,不新增消费者或定时器,也不宣称所有历史漏答已经恢复。
旧消费者尚未使用新锁时,首次采用仍需独立确认空闲;已有中断请求的业务结果与完整周期任务产品验收继续单独跟踪。
改动思路
文件状态与进程切换留在已有 Python 平台接入层;共享锁属于正确性约束,更新结果是派生投影,不另建策略 authority 或执行器。
本 PR 只交付受管服务更新时的请求保护与诚实结果,不代替部署后的原会话独立验收。
普通更新仍沿原有 archive/PyPI/pipx 安装与 doctor 路径运行。服务切换前读取 LaunchAgent 的明确路由,再持有与消息接收相同的文件锁,完整检查原始 Session 与 Turn;不依赖只显示 active 指针的摘要。原始队列、执行中以及完成写入中的请求均会保留消费者。未知或损坏状态也不能被当作空队列。相比新增一个后台激活 Agent,此方案直接复用原更新 owner、原队列与原跨进程文件锁,新增结果字段来自现有事实,不需要另一份人工同步状态。
| 同一输入 | 主干 984691c | 修复 3e73580 |
|---|---|---|
| 已接收请求仍在执行 | 两次强制重启调用 | 零次调用,明确待激活 |
| 原消费者已完成请求 | 原服务切换 | 同一更新入口可继续切换 |
| 自定义安装目录 | 不拥有默认服务 | 保持相同的跳过行为 |
表格是同一真实文件存储夹具的执行结果;安装与 doctor 前置成功及正向 launchctl 回执为合成边界,并不冒充生产采用证明。
具体改动
评审目标为完整提交 3e73580d181ad3f23a0e22b0c4e4ba8ab3261e36。接受的原约束来自 docs/product/periodic-reports.md,spec_revision 984691c6ac54686d6747f4325564e68d81397f85 的 One persistent steward actor 段落,使用修改前的要求判断修改本身。
in-flight-idle-boundary:原请求在原 Turn 上完成、升级等待合适空闲点;本次用完整原始状态及共享接收锁落实,队列无 active 指针、并发接收和 completing 均有负例。original-identity-and-history:保留身份、历史、队列、交办与回传路由;更新只读取已有内容,夹具原文在前后对照中逐字节一致,不生成业务重放。
关键代码讲解
restart_managed_loopx_services: Read explicit routes, lock inputs, reject pending/unverified work, then switch original services.chat_runtime_activation_state: Strict full-store lifecycle check without initializing, recovering or replaying input.accept_managed_turn: Fence durable managed acceptance before its existing per-Session transaction._retain_pending_service_activation: Keep successful install distinct from pending or partially failed service switch.finish_upgrade: Stop combined App restart when Chat service activation remains pending.
原生回归覆盖了真实文件读写、两个接收入口的锁竞争、损坏状态、缺失引用、无法确定的运行目录,以及第二项重启超时的部分结果保留。原有原生消息队列和输入校验也一同运行。首次维护性检查暴露的大模块增长已通过移到现有 ingress owner 解决,没有调整模块预算。App 路径读取同一个 pending 状态,避免服务保护刚阻止重启、组合升级又从 App 侧绕过。
对主干的风险
没有发现当前范围内的阻断问题。新增共享文件锁会短暂串行化同一服务的接收提交;完整扫描成本位于低频更新阶段。服务状态未知会延后整个服务组,因此结果明确区分安装成功、服务待切换和部分重启失败,原更新入口保留同源重试。原消费者尚未使用此锁的首次采用不能单凭新 CLI 包存在就声称受保护,必须独立确认空闲并核验切换后的原服务。已中断且效果未知的业务 Turn 仍不能盲目重放。
语义与 CI 对齐
这是现有服务激活边界的有意修正:从“安装通过即强制重启”改为“已安装、原消费者未完成时保留运行”。自定义安装、未通过运行时校验和原始消息格式的边界保持。完整读取 103 个合成 Session 后,位于前 100 项之外的忙请求仍阻止切换;原消费者完成后同一入口恢复推进,新 Session 随后接收的队列也重新受到检查。规范状态复用既有原生 lifecycle,不增加 Goal、claim、权限或结算 owner。依 Goal 当前配置未读取、轮询或等待远端 CI。
我的整体评价
判定为有实际用途的 justified_increment,long_horizon 与 user_experience 均有改善:保护正在积累的工作,且使用者能读到真实未完成状态,不必重新输入原请求。文件状态与进程切换留在已有 Python 平台接入层;共享锁属于正确性约束,更新结果是派生投影,不另建策略 authority 或执行器。
本 PR 只交付受管服务更新时的请求保护与诚实结果,不代替部署后的原会话独立验收。
只改变更新 CLI 结果、文件锁与 App 重启控制;未改网页渲染或布局,无需新增网页截图。 未测范围:真实 App 新包升级与跨平台发布不在本次本地验证范围。
本定版提交的本地结果为 161 passed / 3 个原生 Windows 专用跳过,6 项直接检查和 17 项选择检查全通过,零失败、零手工 hold。原失败记录保留;早期 fixture 错拦 Node 探针、旧提交的大模块增长,以及在运行 gate 时并行编辑触发的恢复均不被改称成功,当前验证在冻结的最终提交上重跑。实现约束、安装与 App 控制是一个可回滚切口,完整周期任务产品和历史消息回传仍按原验收继续,不能凭本 PR 或合成正向回执关闭。
英文简短结论
English verdict: APPROVE — 3e73580d181ad3f23a0e22b0c4e4ba8ab3261e36 preserves accepted Chat work at the existing managed-update boundary, keeps install versus activation results honest and prevents combined App restart from bypassing the hold. Real file-store concurrency and a same-input base/head update counterfactual passed; 161 local tests and all 6 direct / 17 selected premerge checks passed, with 3 Windows-only skips. First adoption of an older consumer and original-audience business completion remain separately verified boundaries.
An update could force-restart managed Chat/status services while an accepted request was running or queued. Check each configured Chat store, and hold its durable input fence through service replacement; pending or unreadable work keeps the original consumer alive.
Archive and Python-package updates now distinguish a qualified installation from pending service activation, retain the same-source retry, and preserve partial restart outcomes. The combined App upgrade also defers its App restart. No business request is replayed and no additional activation worker is introduced.
Validation: 161 local tests passed, with three Windows-only skips; includes real file-store admission/queue concurrency, unreadable state, partial restart failure, archive/PyPI/pipx packet behavior and App deferral. A same-input base/head counterfactual reproduces the forced-restart defect. The repository premerge gate is recorded before merge.
The first adoption from an older consumer that does not yet share this fence still needs an independently established idle boundary. This does not claim automatic recovery of unknown-effect interrupted requests.