Skip to content

fix(quota): require compute allowance for fresh replan admission - #8576

Open
xiaobaifly7 wants to merge 1 commit into
loopx-project:mainfrom
xiaobaifly7:codex/quota-replan-budget
Open

xiaobaifly7 wants to merge 1 commit into
loopx-project:mainfrom
xiaobaifly7:codex/quota-replan-budget

Conversation

@xiaobaifly7

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Outcome basis / optional anchor: #8571, checked against main beff0f3e55d1f70eceebbd8e78c11f1cff34643b; the issue had no maintainer policy ruling.
  • Goal/source and gap: an exhausted positive compute window could admit fresh autonomous replan model work, including a missing Vision checkpoint, with should_run=true / run_now.
  • Observable before → after: fresh replan now shares remaining compute allowance and uses the existing typed throttled_skip action with an explicit reason when the window is exhausted. It resumes when allowance returns. The new production-entrypoint tests fail before the change (5 failures, 1 pass in the initial six-case characterization) and pass afterward.
  • Issue/task and intended base: Related to Clarify replan admission after compute quota is exhausted #8571; base main.

Author Declaration

  • Written by: model_agent — OpenAI Codex.

Implemented against

Criterion (spec clause) Disposition Symbol / path Test or command
Fresh replan cannot exceed an exhausted compute window implemented quota/run_decision.ts::applyGoalOverrides TS quota decision tests; test_replan_quota_exhaustion.py
Visible typed wait reason, with no extra budget setting implemented existing EffectiveAction.THROTTLED_SKIP and should-run reason live decision and CLI JSON cases
Window renewal / owner budget increase permits fresh replan implemented same shared TS owner two source-budget transition cases
Owner pause and exact original settlement remain authoritative implemented existing terminal and receipt/recovery owners unchanged zero-compute case, exhausted exact-Turn recovery case, File/SQLite no-debit CLI regressions
Maintainer selection of a different allowance policy deferred maintainer review of POLICY CHOICES below No policy ruling is claimed
  • Self-check before submission: read repository contribution/typed-owner/validation rules, issue and all comments, affected callers and current quota/interaction surfaces. Verified typed admission through the real local Effect runtime and CLI dispatcher. No installed runtime or external host qualification is claimed.

POLICY CHOICES

  1. Zero extra allowance for fresh autonomous replan after the shared compute window is exhausted. No new configuration or separate replan counter is introduced. Maintainers may instead choose a separately accounted, explicitly bounded allowance.
  2. The bound applies to all fresh replan triggers, including missing Vision baseline, periodic review and source/frontier replans. Available-budget replan precedence over monitor quiet and lane waits remains.
  3. Exhaustion uses the existing allowed/spent window counts even when focus/external wait masks the quota state; legacy packets without counts retain the existing throttled state fallback.
  4. This is fresh-work admission only. Owner Stop/zero-compute authority and original receipt-bound settlement, including qualified no-debit closeouts, keep their existing owners. It does not turn replan into settlement recovery or charge guard reads.
  5. Reuse throttled_skip and the existing reason projection rather than adding a new action vocabulary or UI/configuration.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope; the shared TS admission owner enforces the proposed policy. Python transports exact decimal quota facts only, preserving integer precision; it adds no decision owner.
  • Slice boundary / successor: no new capability, persistence, migration or RFC pair. Independent blocked-frontier and unsettled-recovery proposals can compose their gates in the same owner; exhausted quota must precede any one-shot baseline initialization. Upstream review, CI and merge remain maintainer-owned.

Validation

  • Tested revision: 0024b2ae5266599727fccd2b6cc0117e5405fa75.
  • Run state: finished.
  • Input classes: synthetic, public_fixture.
Check kind Result Public-safe evidence / limitation
unit passed node --no-warnings --experimental-strip-types --test tests/control_plane_ts/quota_run_decision.test.ts: 40 passed, including exhausted/masked windows, malformed counts and exact integer boundaries.
real_entrypoint passed python -m pytest -q tests/control_plane/test_replan_quota_exhaustion.py tests/control_plane/test_quota_run_decision.py tests/control_plane/test_effect_turn_live_quota_decision.py tests/control_plane/test_dated_vision_wait_cli.py --tb=short: 123 selected instances passed across the scoped runs. Includes real local Effect runtime, CLI dispatcher with synthetic status IO, exact original Turn recovery and 4 File/SQLite blocked-replan no-debit closeouts.
regression_parity passed Original six new characterization cases: 5 failed / 1 passed before the fix. Changed owner afterward passes exhausted/available budget and reset/increase cases.
static passed Control-plane TypeScript typecheck using the repository compiler/config and complete read-only development type dependencies; changed-Python Ruff, semantic diff advisory, full-tree semantic vocabulary smoke, maintainability, public-boundary scan, diff and bilingual RFC checks. No paired RFC changes.
static failed Scoped mypy reports the existing decision_summary.py:78 no-any-return; exact-base shadow-file comparison produces the same error. No unrelated typing repair included.
integration passed PYTHONUTF8=1 loopx canary premerge --from-git-diff --git-diff-base origin/main --tier quick: fixed-head gate passed, 6 direct checks + 4 executed checks, zero failures and manual holds. Validation used only a synthetic registry and disposable local runtime.
  • Coverage and gaps: the initial Windows run exposed GBK decoding in existing subprocess fixtures; exact-base quota-plan smoke reproduces it. Command-scoped PYTHONUTF8=1 resolves it; the two affected pytest instances passed on focused rerun. A quick run made concurrent with staging detected the new test's index transition as a tracked side effect, while its smoke returned success; final fixed-head quick validation is recorded above. No full Python suite, full TS suite, live model, installed host or sustained automatic-loop qualification was run.

Frontend / Visual Evidence

  • UI impact: none.
  • Before / After / First viewport and preview / States and viewports shown: N/A. This changes shared execution admission and existing CLI JSON, with no visual layout or new control. Existing compute settings retain their meaning.
  • Source data: none.
  • Attention review / Craft review: N/A; no frontend rendering changes.

Type of Change

  • Bug fix
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)

Technical Direction

  • Direction / acceptance reference: core control-plane hardening; existing TS quota decision owner. This is not a language migration or authority-provider promotion claim.

Shared-authority RFC fixture impact

N/A: no authority-provider routing, promotion, compatibility projection or RFC implementation claim. Existing real local File/SQLite settlement regressions remain covered.

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.
  • I did not duplicate maintainer-owned benchmark work.
  • I kept the change scoped to the linked issue/task.
  • No paired RFC changed; local bilingual diff checks pass.
  • UI impact is none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Signed-off-by: xiaobaifly7 <196511160+xiaobaifly7@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max

评审提交 0024b2ae5266599727fccd2b6cc0117e5405fa75。结论 REQUEST_CHANGES。

P2 额度耗尽拦截已准入原 Turn 的重规划接续

另一 Agent 用掉最后一槽后,真实 quota CLI 返回原回执 replayed,同时把原 Turn 判为 throttled_skip,省略了结算计划。 同一身份的 turn plan 从 replan_required 变为 wait。 传入由现有回执 owner 校验的正向准入事实,限定原 Goal、Agent、Turn、义务和未结算阶段。只有等待记录的重读仍按新准入处理。

动机 / Motivation

Goal owner 需要控制新重规划的预算,并让已准入的原始 Turn 继续履行结算职责。 共享算力用完后,主干仍会因缺失 Vision checkpoint 选择新重规划。 候选阻止新重规划超出窗口。共享规则也挡住已准入的精确 Turn,原身份的 Turn plan 从可启动重规划变成 wait。 检查覆盖真实准入、已有回执的接续和启动判定,执行范围到 CLI 输出。

改动思路 / Approach

传入已正向准入的原身份,使耗尽规则只作用于新准入,已有接续和结算继续由原回执协调。 额度判断继续由共享 TypeScript reducer 持有,已准入的原身份由现有回执协调校验。 设计问题 #8571

具体改动 / Changes

5 文件,+200/-2。生产 +25/-1,文档 +16,测试 +159/-1。 新默认策略仍需 maintainer 决定。NEW-ADMISSION 的首次决策通过。ORIGINAL-RECEIPT 的同身份接续在下述情形失败。OWNER-STOP 仍走既有前置检查。主干基线 beff0f3e55d1f70eceebbd8e78c11f1cff34643b。docs/quota-allocation.md

对主干的风险 / Risks

先以额度 1/0 提交原重规划 guard,再加入另一 Agent 的一条真实格式用量记录,额度变为 1/1。分别读取原 Turn 和新 Turn 的 guard,再用原身份调用 turn plan。 另一 Agent 用掉最后一槽后,真实 quota CLI 返回原回执 replayed,同时把原 Turn 判为 throttled_skip,省略了结算计划。

File、SQLite 在 1/1 时均阻止新重规划,重读被拒绝的新 Turn 仍需等待。额度提高到 2/1 后原身份可继续。普通等待和有额度的重规划对照正常。 TypeScript 40 项、控制面 typecheck、Ruff、quick premerge 6 项直接检查及 4 项选定检查通过。Python 默认运行 121 项通过,两个新增 CLI 用例在渐进式输出上直接读取顶层 should_run,触发 KeyError。以 LOOPX_CONTEXT_DELIVERY=off 重跑这两项均通过。建议用例显式指定原始输出,或沿默认上下文引用读取;实际回执复现使用显式原始输出。

合成数据通过真实 CLI 和 TypeScript Effect runtime,分别用 File 与 SQLite Todo authority 验证。安装后的宿主和远端 CI 尚未复验。

我的整体评价 / Verdict

传入由现有回执 owner 校验的正向准入事实,限定原 Goal、Agent、Turn、义务和未结算阶段。只有等待记录的重读仍按新准入处理。 用同一夹具验证原身份、新 Turn 和重复读取的结果。额度恢复后复验新准入,并保持真实原回执的结算可达。

English verdict: REQUEST_CHANGES for 0024b2ae5266599727fccd2b6cc0117e5405fa75. An exhausted window correctly blocks fresh replans and incorrectly suppresses the still-owed continuation of an already admitted exact replan.

&& facts.goal_health_ok && !facts.workspace_guard && !facts.automation_prompt_upgrade_required;
const quotaExhausted = facts.state === "throttled" || (facts.quota_allowed_slots !== null
&& facts.quota_spent_slots !== null && facts.quota_spent_slots >= facts.quota_allowed_slots);
decision.replan_decision_allowed = replanSelected && !quotaExhausted;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] 额度耗尽拦截已准入原 Turn 的重规划接续

另一 Agent 用掉最后一槽后,真实 quota CLI 返回原回执 replayed,同时把原 Turn 判为 throttled_skip,省略了结算计划。 同一身份的 turn plan 从 replan_required 变为 wait。 传入由现有回执 owner 校验的正向准入事实,限定原 Goal、Agent、Turn、义务和未结算阶段。只有等待记录的重读仍按新准入处理。

This branch has not been deployed

No deployments
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.

2 participants