Skip to content

refactor(cli): extract quota action selection owner - #4818

Open
Duang777 wants to merge 4 commits into
loopx-project:mainfrom
Duang777:codex/repair-quota-module-budget
Open

Duang777 wants to merge 4 commits into
loopx-project:mainfrom
Duang777:codex/repair-quota-module-budget

Conversation

@Duang777

Copy link
Copy Markdown
Contributor

Summary

  • move quota CLI action-selection request normalization, receipt adaptation, preflight, deferred retention, and receipt annotation into quota_action_selection.py
  • replace the correlated five-value receipt tuple with typed immutable state and result objects
  • keep status collection, monitor writeback, rollout logging, rendering, and command dispatch in quota.py
  • update the semantic producer anchor and the direct unit-test import

Observable result

loopx/cli_commands/quota.py drops from 1,114 to 779 lines. The new owner is 415 lines, so both modules pass the existing 1,000-line CLI command budget without adding an exception. Action-selection branch order, payload strings, receipt writeback, replay, and settlement behavior remain unchanged.

This repairs the cli-command-module-size-ownership-command-modularization-smoke.py failure on current main and lets #4803 sync main without inheriting that failure.

Validation

  • python -m pytest tests/control_plane/test_quota_action_selection_conflict.py tests/control_plane/test_heartbeat_receipt.py tests/control_plane/test_quota_settlement_cli.py -q - 76 passed
  • semantic production and vocabulary tests - 219 passed
  • quota boundary and replan selection tests - 6 passed
  • CLI entrypoint and import-boundary tests - 32 passed
  • maintainability and M6 quality-gate tests - 16 passed
  • CLI argument diagnostics - 95 passed
  • python examples/cli-command-module-size-ownership-command-modularization-smoke.py - passed
  • Ruff on changed Python files - passed
  • new module target Mypy - passed; quota.py retains the same five pre-existing target errors as main
  • loopx canary premerge --from-git-diff on the exact merged-main head - 18/18 passed, no manual holds

Delivery boundary

This is a control-plane CLI ownership change. It is ready for independent review and is not self-merged.

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…dule-budget

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Contributor Author

@huangruiteng 请复审 #4818。远端 CI 已完成主要检查:静态、Dashboard、Node、Windows、E2E 和 3/4 pytest shards 全绿;唯一失败的 shard 只有两条 main@2caada69d 可复现的 post-#4771 旧断言,均已在独立小 PR #4819 修复。

本 PR exact head 的 quota 提取本地验证仍为:76 个冲突/heartbeat/settlement 测试、219 个 semantic 测试、6 个 boundary/replan、32 个 CLI/import、16 个 maintainability/M6、95 个 CLI diagnostics、Ruff、目标模块 Mypy、1000 行模块门禁和 premerge 全部通过。未自合并。

…dule-budget

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Contributor Author

同步记录:已用普通、带 Sign-off 的 merge commit 合入 main@0ef7ebd74,新 head 为 92c514793,无冲突。新 head 本地复验:quota action-selection + settlement 69 passed,Ruff、目标模块 Mypy、CLI 1000 行门禁通过,exact-diff premerge 18/18 passed。远端 CI 已自动重跑。

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>

@huangruiteng huangruiteng 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.

动机

这个 PR 解决的是一个真实且持续增长的维护问题:loopx/cli_commands/quota.py 同时承担命令分派、状态读取、渲染/日志,以及显式 Todo 选择与 heartbeat receipt 对账,已经超过仓库现行的 1000 行 CLI owner 预算。相比直接抬高预算或豁免该文件,把“action selection + receipt adaptation”作为一个完整变化原因抽出,能够让后续 quota 修改更容易定位、验证和回滚。

我按 exact head 92c5147934340debfd72f7c5ca6b4b9962e76d08 复核后,认为这不是为了过行数门禁而拆文件:新 owner 覆盖请求归一化、receipt 绑定读取、preflight、recovery、deferred retention 与最终 binding,形成了完整且已有生产调用方的边界;quota.py 保留 dispatch、status、stall writeback、rollout logging 与 rendering。该边界可独立审阅且没有新增用户协议、持久化字段或选择权限。

改动思路

入口仍是 handle_quota_command。它先通过 load_requested_quota_action_selection 把 CLI --todo-id 和同一 Turn 的 receipt 适配为 RequestedQuotaActionSelection,再把 receipt-bound/requested/retained 三种输入传给原有 build_live_quota_should_run_decision。live decision 仍是 eligibility/优先级的权威;新模块没有重建第二套决策。

live decision 返回后,reconcile_requested_quota_action_selection 保持原顺序执行:先校验 projected selection 与 receipt identity,再在 rejected/deferred 路径投影 recovery,必要时仅保留 pending_action_selection;只有 receipt reconcile/commit/readback 完成后,commit_requested_action_selection 才写入响应中的 selection_binding=heartbeat_receipt。失败和重试仍由既有的 typed error、recommended_actionhandle_quota_command 的 rendering/logging 负责。

我专门挑战了“这只是可达、但没有必要的新 helper”这一点。仓库搜索显示,新模块直接复用了 normalize_todo_id、heartbeat receipt typed accessors、QuotaActionSelectionConflictKindapply_action_selection_recovery 和 live decision;不存在第二个 eligibility、settlement 或 persistence owner。把预算提高或只拆一两个 helper 都会继续让 receipt 与 selection 的同一条状态机分散在 quota.py

具体改动

  • quota.py:删除原来内联的约 360 行 action-selection helper,改为持有一个 RequestedQuotaActionSelection,并在 live decision、automatic stall rebuild 和 receipt commit/readback 三处复用同一组绑定值。文件降到 779 行。
  • quota_action_selection.py:新增 415 行的内部 owner,集中处理请求规范化、receipt 读取、preflight、deferred retention 和结果适配。
  • vocabulary_v0.json:仅把既有 effective_action producer anchor 从旧文件路径迁移到新文件路径,没有新增词汇或改变语义。
  • test_quota_action_selection_conflict.py:把对私有 preflight helper 的直接导入迁到新 owner;断言语义未变。

关键代码讲解

  1. RequestedQuotaActionSelectionquota_action_selection.py:34)把过去相关的五元 tuple 变成具名状态。requested_todo_id_for_decision 在 receipt 已绑定 Todo 时抑制新请求;retained_todo_id_for_decision 只有在没有请求、Todo binding 或 replan binding 时才暴露保留选择,保持原互斥关系。
  2. load_requested_quota_action_selection:80)从真实 runtime root 读取 exact Turn receipt,并只从现有 typed accessors 派生 Todo/replan/pending binding;identity_upgrade 仍来自既有 receipt details,而不是引入新状态。
  3. _apply_requested_quota_action_selection_preflight:131)保留最敏感的分支顺序:settled Todo identity 冲突先 fail closed;autonomous replan replay 与 identity-upgraded retained selection 分开;只有 exact current obligation、pending delivery 或合法 workspace repair 才可通过。拒绝时仍生成相同的 quota_action_selection_deferred|rejected、reason 与重入建议。
  4. reconcile_requested_quota_action_selection:294)把原来的“preflight 后再 recovery/retain”两段编排收敛成 ActionSelectionPreflightResult;只有 rejected 分支会触发 recovery 或 pending receipt append。
  5. handle_quota_commandquota.py:322,主要接线在 :389-479:573-686)仍然是公共命令 owner,且 selection binding 仍发生在 receipt reconcile/append/readback 之后。

对主干的风险

最强回归场景不是 import 失败,而是抽取后不小心改变 branch order:例如在 receipt identity 对账前绑定新 Todo,或让 retained selection 抢占新出现的 monitor/user gate。其影响会扩散到所有 heartbeat host,并可能把工作或 spend 归到错误 Todo。

我使用同一组五个公共 CLI/真实临时文件后端用例分别跑了 main@0ef7ebd749ec97a698a8fc7f2a29844dd368689b 与本 head,覆盖:未绑定 receipt 后选择新 Todo、未投影 Todo 拒绝、首次拒绝不得产生假 receipt、新 due monitor 抢占、以及新 user gate 抢占;两边都是 5/5 通过。head 上另外完整执行 action-selection conflict、heartbeat receipt 与 quota settlement CLI 套件,76 passed in 461.70s

仓库质量证据:changed-path Ruff 通过;CLI module-size smoke 通过;semantic-vocabulary drift smoke 通过;相关 boundary/replan/CLI diagnostics 测试通过;loopx canary premerge --from-git-diff 为 18/18 passed、0 manual hold;merge-tree 对当前 origin/main 无文本冲突。

语义与 CI 对齐

这个 PR 复用现有 action-selection/receipt 词汇,仅迁移 producer symbol;没有创建或扩展协议。语义注册表与 smoke 同步通过。需要说明的非阻塞 caveat 是:仓库配置的 mypy 只覆盖固定文件清单,新模块不在该清单;若把它作为孤立 strict target 并跳过 imports,会暴露 _requested_quota_action_todo_id 的一条 no-any-return,而同一 helper 在基线中已有相同类型形状,因此它不是这次抽取造成的运行时漂移,也不影响当前仓库必需检查的通过结论。PR 描述若保留“target Mypy passed”,建议补出确切命令,避免把不同检查口径混为一谈。

我的整体评价

没有阻塞性 finding。这个改动把已有、相互依赖的一组 quota CLI 适配规则搬到正确的内部 owner,同时保持 decision、receipt persistence、failure/retry 与公共输出的权威边界不变;规模与原问题相称,也没有为了将来可能的扩展引入框架或第二套状态。

未来向检查我认为本 PR 已经做了合适的 bounded refactor:具名 dataclass 取代 loose tuple,semantic producer anchor 随 owner 一起移动;继续抽象会开始跨越 quota decision/receipt 的既有边界,当前没有必要。残余风险主要是 focused suite 未枚举的 receipt/frontier 组合,但 76 项 settlement 回归、基线/head 公共入口对照和 18 项 risk-based canary 已把该风险压到可接受范围。

English verdict: APPROVE - head 92c5147; the extraction gives quota action selection a cohesive owner without changing decision or receipt authority, with 76 focused tests, baseline/head CLI parity cases, Ruff, semantic/module-budget smokes, and 18/18 premerge canaries passing.

@Duang777

Copy link
Copy Markdown
Contributor Author

@huangruiteng #4819 已合入后,我已用普通、带 Sign-off 的 merge commit 同步 main@09f10c4e3,当前 head 为 98e976ccf。上一轮两个失败断言现已包含主干修复。

本地 exact-head 复验:quota action-selection、settlement 与两条 priority 回归共 117 passed;Ruff、目标模块 Mypy、CLI 1000 行模块门禁通过;premerge 18/18 passed。远端 CI 已重跑,请复审。本 PR 不自合并。

@huangruiteng huangruiteng 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.

动机

这个 PR 解决的是一个真实且持续增长的维护问题:loopx/cli_commands/quota.py 同时承担命令分派、状态读取、渲染/日志,以及显式 Todo 选择与 heartbeat receipt 对账,已经超过仓库现行的 1000 行 CLI owner 预算。相比直接抬高预算或豁免该文件,把“action selection + receipt adaptation”作为一个完整变化原因抽出,能够让后续 quota 修改更容易定位、验证和回滚。

我按当前 exact head 98e976ccff2ca41f9bfe5663a0326e2f0cf1960c 复核后,认为这不是为了过行数门禁而拆文件:新 owner 覆盖请求归一化、receipt 绑定读取、preflight、recovery、deferred retention 与最终 binding,形成了完整且已有生产调用方的边界;quota.py 保留 dispatch、status、stall writeback、rollout logging 与 rendering。该边界可独立审阅且没有新增用户协议、持久化字段或选择权限。

改动思路

入口仍是 handle_quota_command。它先通过 load_requested_quota_action_selection 把 CLI --todo-id 和同一 Turn 的 receipt 适配为 RequestedQuotaActionSelection,再把 receipt-bound/requested/retained 三种输入传给原有 build_live_quota_should_run_decision。live decision 仍是 eligibility/优先级的权威;新模块没有重建第二套决策。

live decision 返回后,reconcile_requested_quota_action_selection 保持原顺序执行:先校验 projected selection 与 receipt identity,再在 rejected/deferred 路径投影 recovery,必要时仅保留 pending_action_selection;只有 receipt reconcile/commit/readback 完成后,commit_requested_action_selection 才写入响应中的 selection_binding=heartbeat_receipt。失败和重试仍由既有的 typed error、recommended_actionhandle_quota_command 的 rendering/logging 负责。

我专门挑战了“这只是可达、但没有必要的新 helper”这一点。仓库搜索显示,新模块直接复用了 normalize_todo_id、heartbeat receipt typed accessors、QuotaActionSelectionConflictKindapply_action_selection_recovery 和 live decision;不存在第二个 eligibility、settlement 或 persistence owner。把预算提高或只拆一两个 helper 都会继续让 receipt 与 selection 的同一条状态机分散在 quota.py

具体改动

  • quota.py:删除原来内联的约 360 行 action-selection helper,改为持有一个 RequestedQuotaActionSelection,并在 live decision、automatic stall rebuild 和 receipt commit/readback 三处复用同一组绑定值。文件降到 779 行。
  • quota_action_selection.py:新增 415 行的内部 owner,集中处理请求规范化、receipt 读取、preflight、deferred retention 和结果适配。
  • vocabulary_v0.json:仅把既有 effective_action producer anchor 从旧文件路径迁移到新文件路径,没有新增词汇或改变语义。
  • test_quota_action_selection_conflict.py:把对私有 preflight helper 的直接导入迁到新 owner;断言语义未变。

关键代码讲解

  1. RequestedQuotaActionSelectionquota_action_selection.py:34)把过去相关的五元 tuple 变成具名状态。requested_todo_id_for_decision 在 receipt 已绑定 Todo 时抑制新请求;retained_todo_id_for_decision 只有在没有请求、Todo binding 或 replan binding 时才暴露保留选择,保持原互斥关系。
  2. load_requested_quota_action_selection:80)从真实 runtime root 读取 exact Turn receipt,并只从现有 typed accessors 派生 Todo/replan/pending binding;identity_upgrade 仍来自既有 receipt details,而不是引入新状态。
  3. _apply_requested_quota_action_selection_preflight:131)保留最敏感的分支顺序:settled Todo identity 冲突先 fail closed;autonomous replan replay 与 identity-upgraded retained selection 分开;只有 exact current obligation、pending delivery 或合法 workspace repair 才可通过。拒绝时仍生成相同的 quota_action_selection_deferred|rejected、reason 与重入建议。
  4. reconcile_requested_quota_action_selection:294)把原来的“preflight 后再 recovery/retain”两段编排收敛成 ActionSelectionPreflightResult;只有 rejected 分支会触发 recovery 或 pending receipt append。
  5. handle_quota_commandquota.py:322,主要接线在 :389-479:573-686)仍然是公共命令 owner,且 selection binding 仍发生在 receipt reconcile/append/readback 之后。

对主干的风险

最强回归场景不是 import 失败,而是抽取后不小心改变 branch order:例如在 receipt identity 对账前绑定新 Todo,或让 retained selection 抢占新出现的 monitor/user gate。其影响会扩散到所有 heartbeat host,并可能把工作或 spend 归到错误 Todo。

上一轮审阅使用同一组五个公共 CLI/真实临时文件后端用例分别跑了 main@0ef7ebd749ec97a698a8fc7f2a29844dd368689b 与旧 head 92c5147934340debfd72f7c5ca6b4b9962e76d08,覆盖:未绑定 receipt 后选择新 Todo、未投影 Todo 拒绝、首次拒绝不得产生假 receipt、新 due monitor 抢占、以及新 user gate 抢占;两边都是 5/5 通过。本次复审先做失效检查:当前 head 只是把 main@09f10c4e37b89c6ed25f2f2354f89d641662e83c 合入分支,quota.pyquota_action_selection.py、semantic vocabulary 和 direct unit test 四个 PR 自有文件的 blob id 与旧获批 head 完全一致,因此旧结论没有被 PR 自身改动推翻。

我仍在当前 exact head 上重新执行了 action-selection conflict、heartbeat receipt、quota settlement CLI 和此次主干合入涉及的 team-plan priority integration,结果为 91 passed in 488.15s;另有 semantic production/inventory/Python production 132 passed in 17.67s。这不是只凭“代码没变”复用旧审阅,而是把旧 head→新 head 增量和整个当前 diff 都重新落到了真实 CLI/临时文件 receipt 后端上。

仓库质量证据:changed-path Ruff 通过;CLI module-size smoke 通过;semantic-vocabulary drift smoke 通过;loopx canary premerge --from-git-diff 为 18/18 passed、0 manual hold;git diff --check 通过;merge-tree 1ce7936222a0b1bf338e1544321b06a57f0e407d 对当前 origin/main 无文本冲突;分支四个 commit 都带 DCO sign-off。能力契约设置 wait_for_ci=false,因此我没有等待或轮询仍在运行的远端 CI,也没有把 CI 作为本次 verdict 的替代证据。

语义与 CI 对齐

这个 PR 复用现有 action-selection/receipt 词汇,仅迁移 producer symbol;没有创建或扩展协议。语义注册表与 smoke 同步通过。需要说明的非阻塞 caveat 是:仓库配置的 mypy 只覆盖固定文件清单,新模块不在该清单;若把它作为孤立 strict target 并跳过 imports,会暴露 _requested_quota_action_todo_id 的一条 no-any-return,而同一 helper 在基线中已有相同类型形状,因此它不是这次抽取造成的运行时漂移,也不影响当前仓库必需检查的通过结论。PR 描述若保留“target Mypy passed”,建议补出确切命令,避免把不同检查口径混为一谈。

我的整体评价

没有阻塞性 finding。这个改动把已有、相互依赖的一组 quota CLI 适配规则搬到正确的内部 owner,同时保持 decision、receipt persistence、failure/retry 与公共输出的权威边界不变;规模与原问题相称,也没有为了将来可能的扩展引入框架或第二套状态。

未来向检查我认为本 PR 已经做了合适的 bounded refactor:具名 dataclass 取代 loose tuple,semantic producer anchor 随 owner 一起移动;继续抽象会开始跨越 quota decision/receipt 的既有边界,当前没有必要。残余风险主要是 focused suite 未枚举的 receipt/frontier 组合,但 91 项 exact-head settlement/priority 回归、132 项 semantic 检查、旧/新 head blob 等价性和 18 项 risk-based canary 已把该风险压到可接受范围。

English verdict: APPROVE - head 98e976c; the extraction gives quota action selection a cohesive owner without changing decision or receipt authority, with all PR-owned blobs unchanged from the prior approved head, 91 exact-head focused tests, 132 semantic tests, Ruff, semantic/module-budget smokes, and 18/18 premerge canaries passing.

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