Skip to content

fix(quota): preserve replan on selection reentry - #4868

Merged
huangruiteng merged 1 commit into
mainfrom
codex/fix-selection-replan-deadlock
Sep 21, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/fix-selection-replan-deadlock

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Goal/source and gap: fix a quota recovery loop where an explicit Todo selection was deferred by a hard replan frontier, but same-Turn reentry rebuilt the decision from the earlier compact status projection and lost the obligation that caused the deferral.
  • Observable before → after, with the validation row that proves it: before, the real CLI repeated selection required → selection deferred → selection required; after, retained-selection reentry refreshes the authoritative provider Todo fields and returns an executable replan obligation with settlement identity preserved. The real_entrypoint and regression_parity rows prove this transition.
  • Issue/task and intended base: user-reported heartbeat stall; base main.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope. The recovery path now uses the same provider-first Todo read as candidate discovery and admission, with a regression for stale compact status versus a fresh long-chain frontier.
  • Slice boundary / successor: N/A. The future-facing pass kept TypeScript action/replan semantics unchanged and reused its existing retained-selection reducer; Python only refreshes the authoritative input before invoking that owner. No new schema, state, compatibility facade, or follow-up abstraction was added.

Validation

  • Tested revision: adf93d5acb3d34f1b446e1544fd15f387469bde0
  • Run state: finished
  • Input classes: synthetic, authorized_private_read_only
Check kind Result Public-safe evidence / limitation
regression_parity passed uv run --extra test python -m pytest -q tests/control_plane/test_effect_turn_live_quota_decision.py tests/control_plane/test_selection_replan_reentry.py: 30 passed. The new counterexample failed before the fix because retained reentry performed no provider read, then passed after the condition was repaired.
real_entrypoint passed The checkout-installed loopx quota should-run completed the three-step initial/selected/reentry flow against an isolated runtime copy: the final call returned autonomous_replan_required, must_attempt=true, a non-empty obligation, and Todo-bound settlement. Live state was not modified; the authorized source state and identifiers are not published.
unit passed node --no-warnings --experimental-sqlite --experimental-strip-types --test tests/control_plane_ts/action_portfolio.test.ts: 13 passed, including retained-selection precedence.
static passed npm run typecheck:control-plane passed after installing the repository-declared Node dependencies.
static passed Ruff and Python compilation passed for both changed files; git diff --check passed.
static passed loopx check found both candidate public files clean. It also emitted unrelated local registry-state warnings outside this diff.
integration passed loopx canary premerge --from-git-diff --goal-id loopx-meta: standard tier passed 16/16 selected canaries, 5 direct checks, zero failures/warnings/manual holds.
manual passed Change-quality receipt cqr_402fab973c9f7ae02919 is valid for the exact committed diff.
  • Coverage and gaps: the tests exercise the stale-status/fresh-provider mismatch, retained-selection precedence, signed packet-free fallback, and the production CLI recovery path. No database writer, external provider, frontend, or Lark behavior changes, so a real database or UI check is not applicable. No skipped or failed final checks remain.

See validation disclosure guidance.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A; this changes an internal quota input refresh boundary only.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes)
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Benchmark boundary (adapters, runners, verifiers, scoring, evidence)
  • Capability or extension (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: core control-plane hardening; S2/S3 quota and replan recovery continuity.

Shared-authority RFC fixture impact

N/A. This PR neither claims TypeScript migration progress nor changes shared-authority storage, routing, or compatibility projection.

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng merged commit da49e49 into main Sep 21, 2026
20 of 26 checks passed
@huangruiteng
huangruiteng deleted the codex/fix-selection-replan-deadlock branch September 21, 2026 16:29

@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)

结论:APPROVE。本次审阅绑定的 exact head 是 adf93d5acb3d34f1b446e1544fd15f387469bde0;该 head 已合并为 da49e490b4a8be523de3514d2558991d51097319。未发现需要阻塞或补修的问题。

动机

这个修复针对 selection reentry 的一个真实语义断层:typed decision 已经保留了上一次 action selection,并要求执行 autonomous replan,但 Python live-quota 适配层只在“本轮显式请求 selection”时刷新 canonical Todo。结果是 decision plane 已经要求继续 replan,canonical Todo 却可能仍指向旧选择,形成执行义务与可领取工作之间的不一致。

改动思路

修复没有在 Python 侧重建第二套 selection/replan 判断,而是继续消费 TypeScript decision 的既有输出:只要当前没有 receipt-bound Todo,且 decision 表明 selection 是本轮请求得到的或从上一轮保留下来的,就刷新 canonical Todo。这样既覆盖 retained-selection reentry,又保留 receipt-bound continuation 的优先级。

这条边界是合适的:TypeScript 仍拥有 retained-selection 与 replan obligation 的语义权威;Python 只负责把已经作出的 decision 投影到 live quota/Todo 读取路径。没有新增持久状态、协议字段或字符串启发式。

具体改动

  • loopx/control_plane/quota/live_decision.py 将 canonical Todo refresh 条件从仅 requested_action_selection 扩展为 requested_action_selection or retained_action_selection,同时保留 not receipt_bound_todo 保护。
  • tests/control_plane/test_effect_turn_live_quota_decision.py 新增 retained-selection reentry 回归:证明 provider 会被读取一次,旧 selection 被保留,autonomous_replan_required 会投影,且 must_attempt_work 仍为真。
  • 回归敏感性已反证:把同一语义断言临时放到修复前基线会稳定失败(provider reads 为空),而 exact head 通过,因此测试不是仅复述当前实现。

关键代码讲解

  1. build_live_quota_should_run_decision 的条件变化很小,但修的是跨层语义一致性:retained_action_selection 不是“没有发生 selection”,而是 typed decision 明确选择了沿用既有 action,并可能同时要求 replan。适配层必须把它当作需要刷新 canonical Todo 的输入。
  2. reconcileRetainedActionSelection 仍是 retained-selection 判定的权威来源;本 PR 没有把 actor lifecycle、选择有效性或 replan 条件复制进 Python,因此避免了两套状态机逐渐分叉。
  3. 新测试同时断言 provider read、decision reason、replan obligation 和执行义务,覆盖的是完整行为链,而不只是一个布尔字段或文案。

对主干的风险

风险较低且边界清楚:行为变化只发生在“没有 receipt-bound Todo + retained selection”这一此前漏掉的 reentry 分支。已有 receipt 的 continuation 不受影响;普通 requested-selection 路径保持原语义;未选择 action 的路径也不会被放宽。

验证结果:

  • exact merged head:30 个相关 Python 测试通过;quota replan decision-plane smoke 通过;Ruff 与 git diff --check 通过。
  • 与最新主干重放后的同内容分支:47 个相关 Python 测试、mypy、control-plane TypeScript typecheck、13 个 action-portfolio TypeScript 测试均通过;change-quality receipt 有效;premerge canary 16/16 通过,无 warning 或 manual hold。
  • 完整 control-plane TypeScript 套件在正确的 uv 环境中为 2279 passed、20 skipped、1 failed;唯一失败是 sqlite_capacity.test.ts,在 origin/main 上可同样复现,和本 PR 的 Python quota diff 无关。该基线失败没有被计作通过或隐藏。
  • 按当前 capability 策略没有把 GitHub CI 轮询当作审阅证据来源。

我的整体评价

这是一个范围克制、架构方向正确的修复:它恢复 canonical Todo freshness,却没有把 TypeScript 的 typed decision authority 搬回 Python。测试覆盖了真实缺陷路径,也证明修复前会失败。面向下一步的重构检查后,我认为当前直接复用 retained-selection 输出比新增 helper、协议字段或抽象层更稳妥;本 PR 不需要为了“将来可能扩展”继续加结构。

English verdict: APPROVE - The exact merged head restores canonical Todo freshness for retained-selection reentry without moving typed replan authority or adding persistent state.

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