Skip to content

Settle blocked Turns without spend and back off the exact Todo - #5005

Merged
huangruiteng merged 8 commits into
mainfrom
codex/finance-blocked-settlement-5000
Sep 25, 2026
Merged

huangruiteng merged 8 commits into
mainfrom
codex/finance-blocked-settlement-5000

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Goal and resulting behavior

A managed Turn selected for a completion-validated Todo can hit an overlapping peer hard lease before it can implement or validate anything. Previously an exact blocked outcome_gap writeback persisted, but the returned quota-spend step was rejected by the terminal validator, leaving the Turn unsettled. This PR closes that exact typed Turn without spending quota and records a bounded retry for the same Goal/Agent/Todo. The original Todo remains open with its validator and lease rules intact.

For canonical File/SQLite authority, the blocked Agent need not mutate the peer-gated Todo: the committed Turn owns a five-minute retry. The next quota decision projects that wait into selection, may choose an independent eligible Todo, and cannot immediately reselect the blocked one. The wait expires automatically; a newer work Run on the same Todo supersedes it. An explicit pending Todo resume_at remains supported for legacy/agent-owned waits. The retry is derived from the full run-index semantic projection, so unrelated runs cannot evict it from a bounded display history. Scheduler cache reads also compare the cached run-index digest with the durable Goal run index; a new receipt forces a fresh status projection instead of replaying a stale selection.

Related to #5000.

Entry points and scope

  • CLI/managed Turn: refresh-state, exact settlement readback, quota spend-slot, and subsequent quota should-run now agree on the no-spend closeout and bounded selection retry.
  • Documentation: the quota contract now distinguishes ordinary spend settlement from the typed blocked no-spend closeout, including legacy and File/SQLite retry behavior.
  • Frontend and Lark: no companion control is needed for this path; neither currently initiates this Turn-bound quota settlement or consumes the blocked-retry receipt. No separate UI authority was added.
  • This is a control-plane change for maintainer review. It does not grant Todo completion, bypass terminal validation, or authorize unrelated Todo selection within the original Turn.

Validation

  • python -m pytest -q tests/control_plane/test_quota_settlement_cli.py — 74 passed on the final head after the cache-fence change (560.65 seconds). The real CLI regressions include an overlapping peer hard lease on both File and SQLite authorities, exact replay, no debit, unchanged original Todo validator, and next-Turn selection.
  • python -m pytest -q tests/control_plane/test_quota_blocked_retry_projection.py tests/control_plane/test_quota_settlement_cli.py::test_typed_blocked_retry_with_peer_hard_lease tests/control_plane/test_run_context_retention.py — 15 passed. This covers wait expiry, supersession, agent scoping, and a retry retained despite 40 newer display runs.
  • After the cache-fence change, the File/SQLite hard-lease test and an existing cache capability test passed (3 tests), as did the status-collection and capability-memory suites (14 tests). A subsequent focused 3-test run also verified both an unchanged scheduler cache hit and a run_index_changed miss after blocked writeback. The stale-cache scenario failed for both authorities before the fence.
  • After rebasing onto the coordination changes in main, focused Python File/SQLite, retention and capability-memory tests passed (7 tests), and the three TypeScript settlement/host/vision suites passed (91 tests). A later-subject scope regression passed separately; the blocked Run does not defer a Todo created after it.
  • TypeScript settlement/vision/recovery tests — 91 passed; npm run typecheck:control-plane, targeted Ruff lint, Python compile, and git diff --check passed.
  • loopx check public-boundary scans passed for all 23 changed files with zero errors. The scan reported two pre-existing, unrelated Goal state-projection warnings.

Tests use disposable fixtures; no production Goal, provider, exchange, or account was mutated. The retry is a minimum five-minute selection hold, not an immediate event-triggered wake on lease release. The existing host cadence supplies the next wake. CI and exact-head maintainer review remain required before merge.

@huangruiteng
huangruiteng marked this pull request as draft September 24, 2026 14:18
@huangruiteng
huangruiteng force-pushed the codex/finance-blocked-settlement-5000 branch from 63af166 to 76f6f31 Compare September 24, 2026 16:19
@huangruiteng huangruiteng changed the title Close typed blocked Turns without consuming quota Settle blocked Turns without spend and back off the exact Todo Sep 24, 2026
@huangruiteng
huangruiteng marked this pull request as ready for review September 24, 2026 16:20
@huangruiteng
huangruiteng force-pushed the codex/finance-blocked-settlement-5000 branch 2 times, most recently from 4eb8441 to ca0de4b Compare September 24, 2026 16:42
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/finance-blocked-settlement-5000 branch from ca0de4b to d2c8199 Compare September 24, 2026 16:49

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Exact head: d2c8199

动机

#5000 的实际故障是:Agent 对已选中且要求完成验证的 Todo 如实写入“被 peer 硬租约阻塞”,回执已持久化,随后配额扣减却被终态验证器拒绝,原 Turn 无法结算。这个 PR 让该精确 Turn 在不假装完成 Todo、也不扣额度的情况下闭合,并给同一 Todo 一个有界重试时间;下一轮可以继续做其他合格任务。

改动思路

权威仍分开:Todo 的完成、租约和验证规则保持在原 Todo 存储;已提交的 Turn Run 只记录本次阻塞与五分钟重试;TypeScript 结算读回判断它是否足以构成“不扣额度”的 closeout。调度器从完整 Run 索引导出等待,再投影进现有 resume_at 选择规则,不另建可写的调度状态。旧 Goal 使用已写在 Todo 上的有界 resume_at;File/SQLite 的 peer 租约不允许被阻塞者改 Todo,因此改由精确 Turn 回执持有等待。缺失或身份不匹配的证据仍拒绝。

具体改动

关键代码讲解

require_blocked_retry_wait 核对同一未完成 advancement Todo、时区与 1–30 分钟期限;对于已推广的本地权威,开放且未设恢复条件的 Todo 可得到五分钟 Turn 回执。readQuotaSettlementFromRequest 只在原写回与回执匹配、存在 typed blocker 和 bounded retry、且没有已提交或半提交的扣额证据时,返回 typed_blocked_writeback_no_spend;旧扣额仍保留。goal_semantic_history_from_runs 从完整 Run 序列提取尚有效的等待,避免展示窗口挤掉调度事实,overlay_active_turn_retries 仅影响同一 Agent/Todo 的选择。cached_goal_run_index_is_current 使用原有 sha256:<值> 格式,在新 Run 落盘后让旧状态缓存失效,未变化时保留缓存命中。host preflight、Vision checkpoint、回放阶段和公开配额文档同步了这一条结算语义。

对主干的风险

最强反例是旧状态缓存:首次实现的直接路径测试虽通过,下一轮读缓存仍会重新选中被阻塞 Todo;修复前 File、SQLite 两种真实 CLI 用例均能复现,现已同时验证“未变化命中”和“新 Run 后失效”。另一个风险是把无效阻塞写回当成免费执行,所以缺失恢复期限、错 Todo、半提交扣额与旧的真实扣额均保留严格失败或原读回。最终 head 的完整 74 项 Python 结算套件和 91 项 TypeScript 结算/恢复/愿景用例通过。23 个改动文件的公共边界扫描零错误;当前精确 head 的 DCO、依赖检查、两项构建及 PostgreSQL 真服务 CI 已通过,Python Tests 工作流仍在运行。生产中租约释放不会即时触发唤醒,仍由现有 host 节奏在到期后重查。

我的整体评价

我没有发现当前 head 的阻断性代码问题。改动横跨 23 个文件,但新增的 Run 字段、TS 读回、完整历史投影、缓存围栏和回归测试共同封闭 #5000 的实际链路;只放宽扣额验证或强改被 peer 持有的 Todo 都不能保持现有权威边界。旧扣额回执兼容保留,新的无扣额语义已写入配额文档。剩余限制是五分钟为最早重试期限,不保证准点唤醒;合并仍需独立维护者评审。

English verdict: APPROVE - d2c8199; exact blocked Turns close without spend, the stale-cache counterexample is fixed, and full local settlement plus focused TS validation passed. Python Tests CI and independent maintainer review remain required.

@huangruiteng
huangruiteng merged commit 1882feb into main Sep 25, 2026
22 of 29 checks passed
@huangruiteng
huangruiteng deleted the codex/finance-blocked-settlement-5000 branch September 25, 2026 03:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant