Repository navigation
fix(quota): preserve deferred replan before execution preparation - #8066
Conversation
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
等待条件已满足、需要重新规划后续工作的 Agent,以及恢复中断 Turn 的 Host。旧路径把仍处于 deferred 的任务交给业务执行准备检查,规划请求会被“任务未开放”拒绝并在 replay 变成安静跳过;新路径保留规划或恢复指令,任务正式重新开放后仍须经过原有 claim 和 guard。同一任务从到期规划、再次等待到重新开放后能继续,原 Turn 的结算身份不被新到期任务抢走,未验证阶段不扣额度。本 PR 只修正执行准备的适用边界,不自动重开任务、授予 lease、完成任务或证明模型长程收益。不修复会让必要规划反复跳过,或让中断后的已发生结果缺少正确收口;这个共享边界修复有独立价值。
改动思路 / Approach
复用现有 typed lane 判定来限定执行准备;规划权与业务执行权不混用,canonical IO 和 lease 策略仍由原 owner 处理。当前 PR 只有共享 quota 执行准备的一条适用条件及其恢复测试;不新增模式、权限或存储。should_run=true 表示本轮需要尝试,normal_delivery_allowed=true 才表示可进入正常业务执行准备,两者不能互相替代。Python 仅组合既有判定,TypeScript 的 lane 与 lease owner 保持不变。
旧路径:到期规划 → 检查 deferred 任务是否可业务执行 → 拒绝/skip。新路径:到期规划保留原指令 → 真实等待仍停止 → 合法 reopen → 必要 claim → 同 Turn guard 为 ready。这里是源码推导的文字示意;验证依据是下述真实 CLI 对照。
具体改动 / Changes
审查 head bd8273d1e978c012f87f3d1b4eadecee0dd5fe3a,实际目标 base 6a92640346051b79d08fb369354180b613c8fa46,merge-base 886f2cdff4b2daad642f08f1b9bcffc0edf66359。PR 三点 diff 仅三个文件 +64/-7;head 尚未包含目标分支后来合入的 manager-return 改动,那些文件不是本 PR 删除。
规范 docs/heartbeat-automation-prompt.md,版本 6a92640346051b79d08fb369354180b613c8fa46:Agent Checklist 要求按 execution obligation 执行规划/恢复,通知安静不等于可跳过;Static semantics retained across hosts 要求中断工作保留原 Turn 身份、恢复选择幂等且无提前 spend。这两项在本范围 implemented;不把上层完整产品验收当作此维护修复的承诺。
关键代码讲解
apply_selected_todo_execution_preparation 在既有检查中加上 exact-true 的 normal_delivery_allowed 条件,避免业务准备覆盖非业务路线。project_selected_todo_execution_preparation 仍从 canonical Todo/lease 读取事实,再调用原 TypeScript readiness owner;它不会获取 lease。共享 packet builder 在 interaction contract 之前调用该边界。
测试保留原断言,并补上合法 claim、同 Turn ready 与完整 native full/delta capture 解码。heartbeat receipt 数从 1 改为 2 对应“准备不足的 guard + 准备完成的 guard”,结算 identity 仍是同一个;不是增加一次可花费工作,也不是删除去重要求。
对主干的风险 / Risks
PASS:四个完整模块共 203 项、0 跳过,覆盖 quota settlement、due successor identity、quota execution preparation 和 Codex preparation,使用隔离 File/SQLite authority 与合成 Host manifest。PASS:同一源码路由、同一隔离的六例 oracle,在 base 为 2 过/4 失败(到期规划的 should_run 变 false),head 为 6 过;File/SQLite × soft claim/hard lease 都覆盖到规划 replay、未来等待、reopen 和 claim/ready。新到期任务/80 条已完成记录不抢原身份、peer 不接管、提前 spend 为零也有完整模块验证。
保留全部失败观察:初次测试命令误写文件名,未收集测试;外部对照副本最初在函数默认 cwd 绑定后才替换根目录,错误指向原工作区,两次得到 2 过/4 失败。最终在绑定默认值前固定源码路由,并使用仓库隔离 fixture,才形成上述相同 base/head 对照;未删断言或放宽 oracle。
| 本地检查 | base / head 观察 | 处理 |
|---|---|---|
| 三个改动文件 Ruff | head PASS | 当前范围静态检查通过 |
| 宽范围 Ruff | 同一 E731,test_manager_context_roundtrip.py:289,完整失败文本一致 |
保留 FAIL |
mypy --no-incremental |
同一 task_orchestration_admission.py:110 no-any-return,17 文件,完整失败文本一致 |
保留 FAIL;默认增量 base 曾通过,不能据此认证实际源码 |
| 标准 premerge | head 6 direct PASS、catalog 8 PASS/1 FAIL、risk 8 PASS;失败 quota-plan-smoke 的 KeyError quota 在 base/head 完整文本一致 |
整体仍 HOLD |
语义与 CI 对齐
复用既有 normal_delivery_allowed 词汇与 TS owner,无 action 字符串/正文推断、领域特例或新 schema。上述红项的路径与因果链不由此三行改动产生;当前受影响不变量由真实入口正反例独立覆盖。严格 CQR cqr_9143e94ecd84cb7c34cb 仍为 fail,verify 为 invalid_receipt;premerge 当次的 stale receipt 与其他失败均保留,后来记录精确失败 receipt 也没有把它变绿。本次未查询 CI,不豁免合并检查。
我的整体评价 / Verdict
未发现当前可行动回归,局部修复 goal_achieved,代码结论 APPROVE。long_horizon 为 improved,限于反复 guard、等待、恢复与重新开放能继续且原身份/账目不丢;模型采用、完整成本净益和真实长期成果仍 UNVERIFIED。user_experience 为 improved:机器收到正确规划/恢复路线,无新增人工设置或确认轮次。视觉 not_applicable:只改变 CLI admission projection,没有渲染界面;已安装 Host/App 的采用及模型理解属于 unverified_scope,未声称验证。
这个修复使用一个现有派生字段,机制与问题相称;无需另建策略、状态或兼容分支。普通业务 hard lease 仍强制 claim 和 ready,规划不授予业务执行权限。批准不代表可合并:严格质量门禁和 premerge hold 仍有效,本次没有 merge、dismiss 或 resolve。
English verdict: APPROVE — Deferred planning and original-Turn recovery are preserved without bypassing normal execution leases; existing validation failures and strict merge holds remain explicit.
Goal And Delivered Outcome
Due deferred work needs a planning/recovery turn before it can execute again. The generic execution-preparation adapter was also preparing that planning route, replacing its runnable decision with a deferred-Todo refusal. The next replay could then settle as a skip instead of retaining the replan obligation.
This change applies execution preparation only when the existing typed
normal_delivery_allowedflag authorizes normal delivery. Deferred planning and recovery keep their original route; actual hard-lease execution still requires an ordinary claim and a fresh guard in the same Turn.main; branch created from886f2cdff4b2daad642f08f1b9bcffc0edf66359. Main subsequently advanced through fix(chat): reconcile worker returns with original App mirror receipts #8063 in disjoint manager-return files. The original validation below predates the separately scoped composition qualification reported later in this description.Author Declaration
Implemented against
The reproduced defect and the existing execution-preparation contract at
886f2cdff4b2daad642f08f1b9bcffc0edf66359are the implementation basis. No new product specification is introduced.apply_selected_todo_execution_preparationtest_quota_settlement_cli.pySelf-check: reviewed all three final files, repository instructions, lease/lifecycle boundaries and original assertion parity. This is author verification; independent review and merge readiness remain outstanding.
Scope And Continuation
One adapter condition and two existing workflow test modules change. The tests now enter through native capture decoding and ordinary lease prerequisites. A hard-lease timer rewrite follows the existing fresh-read → reopen → reviewed-deferral recovery; it gains no execution authority.
Original identity, recovery, authority and once-only settlement assertions remain. Two heartbeat-count assertions change from one to two because preparation and positive admission append separate receipts for the same effect. The adjacent module retains all 32 original assertions.
The repair is complete within this behavioral scope and reversible as one commit. Broader transport qualification remains with #7430/#8059, type/lint repair with #8050/#8059, and quota-plan smoke repair with #8061. Existing typed ownership is reused; further extraction would obscure a single condition. No schema, mode vocabulary, flag, default, store implementation or TypeScript lease rule changes.
Validation
bd8273d1e978c012f87f3d1b4eadecee0dd5fe3a. Earlier uncommitted runs are tied to byte-identical final production/test hashes where reused.tests/control_plane/test_recovery_due_successor_identity.py: 4 passed after restoring native reader/claim prerequisites; original assertions retained.tests/test_manager_context_roundtrip.py:289E731. Required mypy: existingtask_orchestration_admission.py:110no-any-return. These remain blocking.examples/control_plane/cli-output-budget-regression-smoke.py: immutable base probe lacks expected inline policy fields and fails before candidate measurement. Frozen criteria unchanged.canary premerge --from-git-diff --git-diff-base origin/main: all six direct checks passed; catalog 7 passed / 2 failed; eight risk-profile smokes passed. Hot-path payload is 20,509 / 20,500 characters; quota-plan smoke raises a native-navigationKeyError. Matched native-runner base/head both measure 20,509; direct base/head both measure 20,341. The extra nested temporary-path length explains this measurement difference; no payload field or obligation was removed. Both checks remain blocking.invalid_receipt, and premerge preserves that hold. No baseline waiver or quality-gate bypass.Coverage and gaps: source and packaged entrypoints cover the changed route and existing negative authority boundaries. Required failures above still prevent merge. This is a correctness repair; no long-horizon effectiveness, latency, token-cost or total-cost improvement is claimed.
Supplemental Composed-Source Qualification
The remaining integration question was exercised on a clean local composition of public main
0423908e9cf46afd7a765552323b842441bd6512followed, in order, by the exact public commits below:f5f9d70e3320ce4c5eaf549aa8d0e8f8c9895f61bd8273d1e978c012f87f3d1b4eadecee0dd5fe3a9b0dfe46e51943215b9a297da78a5f49b2c24893All six affected files byte-match their public component revisions. This composition introduces no additional source changes and has not been pushed as an integration proposal.
test_quota_settlement_cli,test_quota_execution_preparation,test_codex_execution_preparation,test_heartbeat_receipt,test_recovery_due_successor_identityandtest_settled_replay_construction, all undertests/control_plane/.quota-plan-smoke.pypassed. The native-runner hot-path budget smoke passed, including its oversized negative case: quota 20,509 / 21,000 characters, 565 / 575 nested keys and 54 / 55 top-level keys. Status remains 24,879 / 25,000, 339 / 350 and 26 / 27.interaction_contract,scheduler_hintandselected_todofields. Full Ruff still fails E731 attests/test_manager_context_roundtrip.py:289; required mypy still failsno-any-returnattask_orchestration_admission.py:110. The final exact-composition change-quality receipt records failure and verifies asinvalid_receipt.These are supplemental composition results. The historical 243-pass/4-failure run above remains a failed run, and the new 247-pass result does not qualify this PR's standalone exact head, current remote CI or merge readiness. Full repository pytest, PostgreSQL, installed App, model/peer-host adoption and independent exact-head review remain unqualified. No frozen output criterion was changed or waived; overlapping validation timings do not establish complete cost or a performance/effectiveness gain.
Remote CI Failure Attribution
Completed CI for the three existing public heads stops at the same shared lint gate:
f5f9d70e3320ce4c5eaf549aa8d0e8f8c9895f61886f2cdff4b2daad642f08f1b9bcffc0edf66359bd8273d1e978c012f87f3d1b4eadecee0dd5fe3a6a92640346051b79d08fb369354180b613c8fa469b0dfe46e51943215b9a297da78a5f49b2c248930423908e9cf46afd7a765552323b842441bd6512Each run has one successful job, five failed required checks and fourteen skipped jobs. The first failure is
kernel-static-checks / Lint test suite: one E731 attests/test_manager_context_roundtrip.py:289:5. That file and the workflow are byte-identical between each run's recorded base and public head.The existing workflow then skips
chat-bundle, runtime test shards, TypeScript and Stage 2C workers. Their required aggregate checks remain red;stage2c-correctness-e2eexplicitly receivesSTAGE2C_RESULT=skipped. Runtime tests did not execute in these runs.The existing #8059 proposal includes the lint repair and remains open at
eb4470126819b6131dc1b2db9282af814f999325. Preserve that owner's repair and requalify downstream jobs when the relevant integration changes. Frozen CLI-output qualification, type checks, strict change-quality and merge-readiness holds remain separate. This attribution does not certify the skipped tests or waive any failed gate.Frontend / Visual Evidence
UI impact: none. Existing CLI planning/recovery behavior is repaired; no frontend or Lark interface, presentation text or layout changes. Before/after viewport, preview, attention and craft review: N/A. Source data: none. The Chat build was a packaging prerequisite only.
Type of Change
LoopX Area
Technical Direction
Core control-plane recovery correctness. The existing typed lease owner remains authoritative; no shared-authority or TypeScript migration promotion is claimed.
Shared-authority RFC fixture impact
N/A: no store/routing promotion or compatibility-projection change. File and isolated SQLite workflow coverage is reported above; PostgreSQL promotion is not qualified.
Boundary Checklist