fix(coordination): atomically defer owned leased work - #5386
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
结论:APPROVE。完整评审与独立验证未发现阻塞项。评审 head:334ad4ca47359cd404bb9b608745a74b5e85b7e2,对照 base:f49b4a00870604d39fa4318da24d6dd35e72bb6e。本结论只覆盖这个 exact head;控制面改动仍交维护者合并。
动机
当前租约持有者遇到依赖时,旧实现既拒绝把开放任务延期,也不能用“先释放再更新”绕过问题:释放后更新仍需要有效执行证明。legacy 模式下遗留已释放租约还会挡住恢复。这会让实际等待无法持久化,旧 Turn 也可能无法结算,反复检查证明仍不能推进独立工作。本 PR 对应共享 authority RFC 的 S3 延期生命周期缺口,交付的是可执行的“暂停—等待—恢复”闭环,不以通过测试或增加回执字段代替交付判断。
改动思路
继续沿用 Todo CLI、公共 authoring 和 TS coordination owner。共享准入先检查注册 actor、claim、排除关系及当前 lease key/version;只有完全不夹带任务编辑的延期意图才进入同一个 provider CAS,把 Todo 状态、租约释放和命令回执一起提交。恢复只打开任务,不授予执行权;下一次执行必须取得新租约。Python 仍负责传输,File、SQLite、PostgreSQL 仍负责持久化,没有第二个判断源。
延期与原 Turn 的因果阻塞结算相接,但结算不是完成:原 validator 和 Todo 身份保留,零扣额、零交付信用,新 Turn 才可选择独立工作。monitor_changed 的普通自动等待仍保持 open;pr_merged 是合法调度条件,但 PR 编号不能充当因果结算证明。
具体改动
完整 diff 共 12 个路径、226 行新增/32 行删除:五个 TS runtime 文件扩展准入、恢复、延期生命周期和因果等待;五个测试文件覆盖 native、真实 CLI 与 PostgreSQL;两份文档说明受影响的 legacy 路径、恢复步骤和验收边界。没有新 CLI 开关、配置 owner、provider 或默认能力启用。旧的内部 reopen 模块已迁移并删除,不保留无调用依据的兼容壳。
关键代码讲解
todo_deferred_lifecycle.ts:23 isOwnerDeferral只识别 Agent 的 open→deferred,要求非空 wait/reason、空 patch/clear_fields,字段集合限于 status/resume_when/reason。它不是权限判断;真正的 actor/claim/有效证明检查在准入层先执行,不能借这个谓词改内容或验收。todo_deferred_lifecycle.ts:59 planDeferredLifecycle复用既有 lease retirement:Todo 与 lease_upsert 共用一次提交,旧 version/epoch 只作为历史保留,回执明确execution_authority_granted=false。legacy 遗留租约和 hard-lease 路径复用同一规则。todo_update.ts:126 executeCoordinationTodoUpdate先处理精确 operation replay,再读取完整 canonical head、准入和公共规划,最后一次 CAS 提交状态及回执。相同身份改变 reason 会拒绝;dry-run 和精确重放均不追加状态效果。blocked_wait.ts:84 prepareBlockedWait重算唯一注册依赖及当前代际,而不是相信 caller 填写的等待字符串。unfinished deferred 普通任务可以关闭原 Turn;完成、归档、缺失、自引用或代际陈旧的依赖不能借用这份证明。PR-only 等待明确返回 monitor/todo 依赖恢复路径。
正向独立实测:延期释放 version3/epoch2 → 精确重放 → 显式 reopen → 旧证明编辑被拒绝 → 新 acquire 得到 version4/epoch3 → 新证明写入有效 note 并单独读回。真实 CLI 还验证原 completion validator 保留、零扣额与下一 Turn 独立选择。
对主干的风险
主要风险是窄延期被误用为权限绕过,或状态延期成功却残留活跃租约。独立 File/SQLite、legacy/hard_lease 对照覆盖外部 owner、陈旧或缺失证明、夹带文本/验收/clear fields、空 reason、dry-run、重复与冲突 intent;拒绝路径均单独检查无持久效果。monitor_changed 延期在 head 的公共 authoring 入口仍明确拒绝,要求 status=open;不是把 Monitor 任务藏成 deferred。真实 PostgreSQL integration 也验证原子延期、重放、竞争、回滚与响应丢失恢复。
对照不只比较 reason code:保留完整诊断、恢复指引、持久状态和回执。普通复制编辑的 omitted、empty、clear 行为保留基线;缺失/陈旧证明的恢复指引有意改为检查当前证明,合法延期与 legacy released reopen 有意从拒绝变为通过。81 项完整 canonical 数据与不同插入顺序不改变目标准入。
语义与 CI 对齐
复用现有 Todo/lease/resume 词汇和 TS owner;新 todo_deferred 只是本生命周期的派生回执事件,不宣称更广的 Agent 生命周期或授权。全文检查没有新增 substring denylist、领域特定的通用义务或把强制规则称作 guidance。变更已在双语 causal-closeout 协议和共享 authority RFC 披露。当前 capability 配置 wait_for_ci=false,未查询、轮询或等待远端 CI;评审使用独立本地证据,不因无归因的红 CI 请求修改。
独立验证:8 组 native TS 测试 131 通过;5 组真实 CLI/Python 测试 44 通过;隔离真实 PostgreSQL 16.15 的 integration 309 通过、零 skip;control-plane typecheck、mypy(19 个模块)、变更 Python 的 Ruff、diff hygiene、12 路径公开边界扫描、维护性 ratchet、semantic advisory 和全树 vocabulary drift 均通过。相同独立 delivery oracle 在旧 base 失败、在 head 通过,已证明能抓住原回归。
premerge 实际执行的 4 项 direct 和 19 项 selected 检查全部通过,零测试失败、零 skip;首次聚合门禁只因评审质量回执尚未写入而未放行,现同一未变更 head 的 exact-scope 回执已记录为 pass,并 verify 为 valid。这里保留首次门禁未通过的事实,不把补齐回执或 dry-run 称作合并就绪;已完成的验证不重复执行,真正合并仍须维护者检查当前 head 的 readiness。changed-surface 覆盖包含 lease、Todo、quota、scheduler、写入正确性及公开边界,足以支撑本次有界生命周期评审,不代表生产 rollout 或持续运行验收。
我的整体评价
这是完整且适度的现有状态机修复:长期推进上消除无法暂停/恢复和旧 Turn 无法关闭的循环;Agent CLI 体验上提供原有命令即可执行的路径和真实读回,没有新配置或多余确认。bounded future-facing pass 已由 PR 自身完成:把 reopen-only 模块扩展为统一延期生命周期,比复制一个 suspend owner 更容易维护和回滚。没有必要再为这次修复引入框架或平行 Python 规则。
产品边界是 Agent CLI/managed Turn,不宣称扩展人类 Chat 的租约权限或新增可视控件;我检查了现有 dashboard 状态字段及 Chat Todo transport,无新配置需投影。没有运行生产 tenant 或宣称整个 S3、SQLite 默认准入和通用 amendment 已完成。旧 runtime 回滚需先核对历史回执与 writer fence。此 exact head 可以批准,仍由维护者决定合并,不执行自合并。
English verdict: APPROVE - 334ad4c; no blocking finding. Independently verified atomic owner deferral, legacy retained-lease recovery, no-effect negative paths, fresh-grant continuation and original-Turn no-spend closeout; 131 native TS, 44 CLI/Python and 309 isolated real PostgreSQL tests passed. Maintainer merge only.
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed head: 334ad4ca47359cd404bb9b608745a74b5e85b7e2
Compared base: f49b4a00870604d39fa4318da24d6dd35e72bb6e
未发现本 PR 引入的阻塞问题。下面的结论覆盖整个 base-to-head 改动;合并留给维护者。
动机
持有有效执行租约的 Agent 需要等待一个真实依赖时,旧实现会拒绝把自己的 Todo 改成 deferred。先释放租约再改状态,也会被保留的租约历史挡住;已经延期的工作则无法完成原 Turn 的因果等待结算。这会把后续独立工作困在恢复路径中。本次验收是打通“延期并释放执行授权 → 原 Turn 无扣额结算 → 执行其他工作 → 明确重开并重新取租约”,不代表整个调度或主机回调生命周期已经完成。
改动思路
最小可用修复应留在既有 TypeScript Todo/lease owner 中。单独放宽 status 校验会留下活跃租约,拆成 release 和 update 两次写入又无法保证原子性,因此这里复用已有 deferred reopen owner,合并成一个延期生命周期计划,由现有 AuthorityStore CAS 同时提交 Todo 和租约变化。等待原因与恢复条件仍由当前 owner 明确提供;延期和重开都不授予执行权,也不冒充交付、完成或额度消费。
具体改动
关键代码讲解
isOwnerDeferral 只接受 open → deferred 的纯生命周期请求:非空 reason/resume_when、没有 copy patch、clear fields 或其他规划字段。它只是分类。todoUpdateAdmissionRejection 先验证注册 actor、claim/binding/exclusion 及当前 lease key/version,再允许这个例外;foreign actor 与 proof 的拒绝优先级保留。planDeferredLifecycle 产出 status 与 released lease 的共享生命周期计划,executeCoordinationTodoUpdate 将两者放进同一个 AuthorityStore CAS,保留租约版本与 epoch;显式重开后必须取得新的租约,旧 proof 不能再次执行。旧 deferred-resume receipt 字段继续可回放,原模块被迁移而没有留下重复决策入口。
projectReceiptBoundWait 与提交准备入口共享 quota 的因果条件,接纳 unfinished deferred Todo,继续要求真实、唯一且未就绪的依赖及原 Turn 绑定。仅写一个 PR 编号不足以获得因果 closeout;文档给出 registered monitor 或 Todo dependency 的修正路径。CLI 现有参数可以走完整流程,Dashboard 现有投影已经区分 deferred;没有新增配置、前端交互或 Lark 操作。没有把源码检查声称为已安装客户端验证。
独立验证从本 head 的源码 checkout 执行:真实 PostgreSQL 16 隔离实例的 provider integration 309 项通过;3 个 Python CLI/恢复模块 12 项通过;TypeScript typecheck、项目配置的 mypy、改动测试的 Ruff 通过。另用同一独立 CLI harness 对照不可变 base/head,覆盖 File/SQLite × legacy/hard_lease × 0/300 个无关 Todo,共 8 个场景:head 全部通过,base 全部在合法 owner deferral 被拒绝处失败。扩展同一场景还验证当前 lease 不会覆盖已有或后来通过 native add 创建的 peer Todo,foreign actor、陈旧/错误 proof、混合修改、dry-run 的拒绝与无写入,随后实际重开、取新租约并读回新 note 和原 validator。精确 12 个改动文件的 premerge 检查通过:3 个直接检查、Python compile、10 个 catalog canary、8 个风险 smoke 和 public/private boundary;无失败或 manual hold。
对主干的风险
语义与 CI 对齐
复用已有 TodoStatus 和 canonical lease 状态;新 todo_deferred 是已有 operation receipt 的词汇扩展,记录已提交的延期,没有新增执行权或第二份手工同步状态。请求的 Python/Node 两端同版部署;已持久化的 deferred_resume_transition 仍须保留回放兼容。语义 advisory 的零候选不能证明没有共享契约影响,因此另行核对了这些 owner、reader 和真实调用路径。当前配置的本地类型及静态检查通过,全量 TS 的红项按下面的不可变 base/head 证据处理;没有把未来 RFC 要求升级为本次门槛,也未查询远端 CI。
全量 npm run test:control-plane 并非全绿:head 为 3912 pass / 2 fail / 1 skip;同一 base 为 3560 pass / 4 fail / 31 skip。计数差主要来自 head 启用了隔离 PostgreSQL,不能据此宣称等价或修复。
head 的两项红项已按相同 case、相同失败细节及未改动的因果代码逐一对照:content_digest_single_owner 在 base/head 都指出 task_lease_workspace.ts:26 的重复 digest matcher;sqlite_capacity 在两版都于同一个 150 秒 child budget 返回 null,该固定 100/1000 history rehearsal 不走 Todo update、deferral 或因果结算。没有提高预算、缩小 workload 或隐藏失败。改动不修改这些路径,并有上述独立真实边界的通过证据,因此它们属于既有问题,仍需作为独立 merge-readiness 红项处理。base 另外两个 host-process/NoKV 失败保留在证据中,没有归功于本 PR。
唯一 head skip 是单独的 PostgreSQL service URL/auth profile 未配置;本次涉及的 PostgreSQL provider 已在真实隔离服务器验证。未验证 Linux/Windows、已安装产品、付费模型或外部通知;这些不是本次生命周期改动的完成声明。未查询或等待远端 CI,也未获得合并权限。
我的整体评价
APPROVE,针对这个有界的生命周期修复。长期推进与用户操作路径都得到改善:原等待 Turn 结算后能继续独立工作,原 Todo 恢复也无需重写验收约束。它解决了实际阻断后续工作的闭环,保留原验收声明与权限边界,代码量与故障成本相称。相关未来维护改进已经随本次完成:延期与重开共用一个 typed owner,删除原入口,Python 继续作为传输层;无需再建一层框架。全量 TS 的既有红项与这次代码评审结论分开,合并条件由维护者处理;本评审不执行合并、安装或 promotion。
English verdict: APPROVE - Atomic owner deferral, no-credit original-Turn closeout, and fresh-lease recovery are verified. The matched baseline failures remain separate merge-readiness holds; merge is left to the maintainer.
An agent holding a Todo lease could not defer its work: metadata admission rejected the status change, while releasing first made the same update demand another active proof. Even a deferred Todo with a real dependency could not close its original Turn because causal settlement only accepted
open.This change extends the existing TypeScript deferred lifecycle owner. A current claim/lease holder can submit a narrow
status=deferred,resume_when,reasonupdate with its live proof; one provider CAS records the wait and releases that execution generation. Reopening retained lease lineage follows the same no-live-holder rule in legacy and hard-lease modes. Original Turn binding, completion validation, stale/foreign proof rejection and receipt replay remain intact. No Python decision owner or new CLI switch is added.Causal blocked closeout now accepts unfinished deferred dependencies, without spending quota or crediting delivery. Monitor-driven automatic waits retain their existing
openrequirement. PR merge waits remain scheduling conditions rather than Todo-only settlement proof; their error now explains the registered monitor/Todo recovery route.Validation:
This advances the shared-authority RFC / roadmap S3 wait lifecycle. It does not claim SQLite default admission or general amendment completion. CLI/managed-Turn entrypoints reuse the existing state projections; no frontend configuration or controls change. Related refactor: suspension and resumption share the existing deferred owner and receipt/CAS machinery; the obsolete internal module path is removed. Maintainer merge remains required for control-plane changes.