Codex 多会话自动推进:角色分流、回执续跑与有界修复
多会话协作最容易出现的假进展,是 Controller 已经批准,worker 却没有真正继续;另一个极端是 worker 一直修复周边小问题,主任务迟迟不能交付。这次维护围绕一个目标:在原有授权内,让任务实际续跑,并把非核心修复限制在明确预算内。
本文记录 HomeLab 的 task-tracker 两批小补丁与一次本地试跑,不是全部任务已收口的声明,也不是新增一套编排平台。
关于 Ralph、ULW 与 Superpowers 是否值得叠加到这套流程,以及为何最终只保留本地证据指针检查窄候选,参见 《Ralph、ULW 与 Superpowers 是否值得接入现有 Agent 工作流》。
关于“检索工具取回文档”与“Agent 实际使用证据”的区别,以及本地知识检索为何暂不全局接入,参见 《Codex 本地知识检索试点:从 SQLite 基线到全局 NO-GO》。
当前结论:机制通过,不等于运行权限已恢复
截至 2026-09-20 本次核对:
| 检查项 | 已验证结果 | 不能据此推断 |
|---|---|---|
| 原 Lease Broker | 能读;创建 registry 锁文件和回传消息被会话权限策略拒绝 | 独立租约分流已经恢复 |
| 唯一写权 | 不可用委派已撤回,MAIN g7 临时接管租约;Continuation Broker g2 保持独立 | 可以同时让两个会话写租约 |
| 批准后实际续跑 | 原 OC-08 worker 完成本地只读 status 试跑并回传证据 | OC-08 真实模型测试或业务任务完成 |
| 两批补丁 | 第一批 84/84;第二批 99/99 回归通过 | 所有活动会话已经加载新规则 |
| 其它工作区 | 通用 skill 文件已更新,本轮未改 SAIC/DPA 的 registry 或任务卡 | 其它工作区已经完成采用验收 |
OC-59 原始实现和 worker handoff 于此前完成;这次运行维护仍有 Broker 权限卡点。历史任务标记“完成”与运行维护尚未完成,可以同时成立,不能互相覆盖。
一、不要把所有消息都交给主 Controller
工作流保留三个职责,不再让主 Controller 承担日常租约、普通续推和用户命令的全部队列:
| 角色 | 负责 | 不负责 |
|---|---|---|
| MAIN Controller | 用户命令、新权限、范围变化、硬停止、生产额外尝试、最终收口 | 长时间等待某个 worker |
| Lease Broker | 精确资源租约的申请、续接、核对与释放 | 批准业务操作或管理 worker |
| Continuation/Permission Broker | 既有授权内的普通修复、定量预算、同 reviewer 复审、零副作用同语义换代 | 新增权限或重置已使用的生产动作预算 |
静态任务图回答“依赖和外部前置是否满足”;动态租约回答“这一刻谁能操作哪个对象”。任务卡声明可能使用 GPU、Docker 或挂载,不等于整个任务期间独占这些资源。
当前运行快照中的 Lease Broker 职责由 MAIN 临时承担。恢复独立会话时,必须先证明它能写事务锁、完成角色允许的操作并返回消息,再切换唯一写权;仅返回“只读就绪”不够。
各工作区保持自己的 inbox、role registry、lease registry 和 Controller。跨工作区只通过所属协调器或已委派 Broker 交换资源请求,不直接管理对方 worker。
二、从“已批准”到“真的继续”要有闭环
消息采用 sender-first:先把完整请求写入所属工作区的持久 inbox,取得 ACK,再发送只含 authority、request ID 和 receipt 的短唤醒。
1 | 原 worker → 持久 inbox → ACK → 按当前角色 registry 路由的短唤醒 |
这里至少有四件不同的事:请求已入队、请求已批准、消息已送达、worker 已执行。任何前一步都不能冒充后一步。只有 GRANTED 而没有匹配的进展证据时,观察状态仍为 GRANTED_AWAITING_RESUME。
task-tracker 的本次实现为任务卡投影 continuation 状态,并在提交唤醒时返回当前角色、会话和 generation。重复的同一请求保留原回执,但重新读取当前路由,避免继续把消息送给已经撤销的角色。
真实试跑只要求原 OC-08 worker 读取任务、执行一次本地只读 status 并回写 checkpoint。试跑成功证明这一条续跑链路可用;没有启动模型、访问远端或执行生产请求。与此同时出现的业务 reviewer 认证失败仍是独立阻塞,不由试跑成功豁免。
设计上借鉴了 Temporal 对只读 Query、异步 Signal 和可返回结果 Update 的区分:消息被接受与业务处理完成不是同一个事实。这里只迁移这个区分,不宣称自建 inbox 等同于 Temporal 的持久执行保证,也没有安装 Temporal。官方消息机制
三、失败后先对齐任务,再决定是否修
每次失败后的最小动作,是重读权威任务卡、当前阶段、原始目标、验收标准、有效授权和未完成前置条件,留下简短记录:
-
原目标和当前阶段是什么;
-
失败是否真正阻塞这个目标;
-
下一步为什么仍在原范围内;
-
本次明确不做什么。
这不是新增合同、哈希或审核流程,而是防止把路径、fixture、传输、租约或验收脚本的问题不断升级成新的主任务。
验收发现按影响分类,而不是见到任何问题都要求归零:
| 分类 | 含义 | 默认处理 |
|---|---|---|
SAFETY_BLOCKER |
认证、权限、数据安全、不可逆副作用、身份或恢复不可证明 | 阻塞;不能用修复预算耗尽来豁免 |
CORE_BLOCKER |
用户要求的主路径不可用或结果错误 | 在授权内修最小根因 |
BOUNDED_FIX |
不破坏核心可用性的兼容性、稳定性、维护性问题 | 同核心阶段最多两轮或累计 30 分钟,先到即止;任务可明确覆盖 |
FOLLOW_UP |
旁支、优化、外观或无证据的潜在问题 | 记录、去重、交给后续任务 |
预算是同一核心阶段的累计值,换 turn、模型、generation 或新发现一个非核心问题都不能清零。历史成本无法核实时保留 UNTRACKED,不能伪造为零;也不能据此声称还有完整剩余预算。
预算耗尽后记录影响、复现、可用替代路径、owner 与后续验收目标,保留可用主路径。核心或安全问题仍然阻塞;任务已有更严格的发布要求时仍按原要求执行。生产尝试次数、删除、外发和凭据范围不会因为自动续推而增加。
Temporal 的重试策略提供了明确上限、退避和不可重试错误的参考;本地“两轮或 30 分钟”是本工作区的任务政策,不是 Temporal 默认值。官方重试策略
四、关键事件留在任务日志,不收集完整会话
第二批补丁增加 record-event,把小型 TASK_EVENT 写入既有任务工作日志,主要记录:事件主键、阶段、事件类型、四类分类、脱敏摘要、决策回执、证据指针和实测耗时。
同一事件重复提交不重复计费;同一主键但内容不同会被拒绝。事件与已知预算使用既有锁和原子替换一起落盘,避免“日志已记、预算没加”或重复累计。只有 REPAIR_RESULT 中的 BOUNDED_FIX 增加非核心修复成本,核心修复不混入该预算。
这是记录与观察接口,不是自动执行引擎:写入事件不会自动授予权限、创建 session、继续 worker 或宣布任务完成。也没有新增全文 trace 数据库、哈希链或常驻监控平台。
阶段结束后,从少量重复案例中提取 skill 改进候选:重复索权、批准后停滞、长等待、非核心修复扩散、真正需要人工的硬停止。先由 Controller 判断通用性,再补小测试并更新 skill;worker 不因为一次失败就自行改全局规则。
五、同步修正容易制造假状态的说明
本轮还修正了三个直接影响调度判断的问题:
-
最新日志。 只在工作日志区选择日期、时刻最新的顶层条目,忽略代码示例、嵌套列表和附录;close 记录写回日志区顶部。旧版简单取第一条或全文末尾,可能把历史结论当成当前状态。
-
模型与会话复用。 显式模型选择优先,默认升级规则不能把用户指定的更高档位悄悄换成较低档;dispatch 优先返回既有 worker/reviewer 的复用建议,而不是默认创建新会话。模型组合仍以执行宿主实际支持能力为准。
-
Goal 与长等待。 Goal 属于 worker,创建需要明确请求;只使用当前工具实际提供且获准的暂停/恢复能力,不虚构 resume 接口,不把等待标为完成。长等待交给事件 hook 或一次性 ETA 检查,Controller 不长时间
wait_threads。记录WAIT_EVENT也不等于已经实际创建了 hook。
六、验证范围与剩余人工卡点
第一批在原 76 项回归基础上补进展、预算和动态角色路由案例,最终 84/84。第二批增加 15 个案例,最终 99/99;本次博客整理时再次本地复跑确认。覆盖重复消息、批准后未续跑、累计预算耗尽、长等待、人工硬停、并发重复事件、日志定位、显式模型和会话复用。
两批维护记录中的 skill 结构校验及 canonical 联合 archive 校验通过;37 张任务仍有 10 个既有 handoff warning,没有为了“全绿”在这次扩修。上述数字属于本地实现与合成验证,不能证明所有活动 worker 已采用,也不是生产服务的全量验收。
Lease Broker 的问题仍在会话权限层:读 registry 成功,创建事务锁和返回消息失败。MAIN 已接管为唯一租约写者,原不可用委派失效,没有留下两个 active 写者。
用户随后已允许更新权限,但本次可用工具没有单任务权限修改入口,界面控制工具也明确拒绝操作 Codex 自身,所以没有实际改成新权限。后续需通过受支持的设置入口调整原任务,覆盖既有 registry 事务所需的锁/临时文件与受限决策回传;先验写入和回传,再恢复委派。不用 sudo、chmod、修改产品内部数据库或新建替代会话来绕过它。
SAIC/DPA 的本轮采用继续由各自 Controller 决定,不把全局 skill 文件更新等同于各工作区已经完成迁移。HomeLab 也不能代写其它工作区的控制状态。
证据与文档边界
后续目录治理案例见《目录治理不是删除:一次会话备份的保留式归档》,展示对象级写租约释放、独立审核和文档交接如何分开完成。
本地维护证据位于 infra/agent/staging/OC-59/OC59-CONTINUATION-RELIABILITY-20260920.md,当前待办由 canonical tasks/OC-59.md 跟踪;动态角色仍以 controller-roles.json 为准。本文保留可复用结论、验证范围和未完成项,不复制完整会话 ID、内部请求正文或认证信息。
本文记录的是阶段性维护结论;后续运行状态以任务卡与角色 registry 为准。关于 canonical 记忆和跨工作区 skill 的基础,可参见 《Claude Code 记忆同步进阶——canonical 软链、白名单 .stignore 与跨工作区 skill》。
