fix(quota): name the retained selection and the replan obligation that owns the Turn - #4993
Conversation
…t owns the Turn A Turn whose receipt is bound to an autonomous replan obligation cannot hand its settlement to another Todo. The refusal reported that case as a plain selection conflict, calling the retained pending selection "the projection's current selection", and published neither the retained selection nor the obligation that owns the Turn, so a caller could not branch on either without parsing prose. The conflict now states that the requested Todo cannot replace the retained pending selection, names the autonomous replan obligation that owns the Turn, and publishes `retained_selection`, `retained_selection_todo_id` and `receipt_replan_obligation_id` in the failure payload. The recommended action points at settling that obligation instead of rebinding the retained selection. This is the last branch of the explicit-selection preflight that still carried no typed retention facts; the eligibility predicates are unchanged. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
中文评审(精确 head d75ebf7)
结论
建议合并(APPROVE),无阻断项。该改动只修正"保留选择"这一分支的成因表述与载荷字段,准入谓词一字未改。作者自有 PR,无法用 GitHub 的形式化 approve,因此以本评论作为该精确 head 的评审记录。
里程碑 / 基线
- 基线:origin/main
cc60e8b3c,分支codex/retained-selection-facts-0924由它拉出,PR base = main。 - 改动面:
loopx/control_plane/quota/error_codes.py、loopx/cli_commands/quota_action_selection.py、loopx/cli_commands/quota_failure_report.py与既有聚焦测试文件;控制面(loopx/**),仅提案不自动合并。
依据
- 该分支的语义是:Turn 的凭据绑在自治重规划义务上,因此请求的 Todo 不能替换该 Turn 已保留的待结算选择;旧文案却把那一个 id 称作"投影当前选择",既误导又不给出真正要结的东西。
- 新文案直说"请求的 Todo 不能替换本 Turn 保留的待结算选择",并点名拥有该 Turn 结算的自治重规划义务;失败载荷新增
retained_selection、retained_selection_todo_id、receipt_replan_obligation_id,调用方可以按字段分支;recommended_action 指向结算该义务或重读当前选择,而不是重新绑定保留项。 - 这是
_requested_quota_action_selection_preflight最后一个没有 typed 事实的分支(unqualified / not_admitted 已在此前落地),因此这条拒绝路径现在整体可机读。 - 验证:
tests/control_plane/test_quota_action_selection_conflict.py8 passed(含新增保留选择用例:理由点名保留 id 与义务 id,载荷三项字段齐备);test_quota_settlement_cli.py+test_quota_authority_settlement_journey.py+test_unadmitted_selection_construction.py106 passed;改动文件 ruff 干净。
缺口
- 新增字段只在该分支发布;若未来出现"凭据绑定重规划义务且请求的正是保留项"以外的组合,仍需各自给出 typed 事实(目前这些组合要么直接放行,要么走其它已有分支)。
- 未运行
loopx canary premerge --from-git-diff,交给 CI 与 maintainer。 - 本 PR 未附端到端 CLI 录像:保留选择分支在 CLI 层需要"凭据绑定义务 + 显式请求另一 Todo"的构造,聚焦测试直接驱动 preflight,端到端由既有 settlement CLI 套件覆盖其相邻路径。
下一步
- maintainer 决定合并。合并后可用同一条路径回归:凭据绑定义务、显式
--todo-id请求另一个 Todo 时,确认载荷含receipt_replan_obligation_id且 reason 明确说明"不能替换保留的待结算选择"。
English verdict
APPROVE for exact head d75ebf7072aea34463928e7888fbecb436b15d61. The retained-selection branch called the Turn's retained pending selection "the projection's current selection" and published neither that selection nor the autonomous replan obligation that owns the Turn's settlement. It now states that the requested Todo cannot replace the retained pending selection, names the owning replan obligation, and publishes retained_selection, retained_selection_todo_id and receipt_replan_obligation_id in the failure payload; the recommended action points at settling that obligation instead of rebinding. No eligibility predicate changes. Validation: 8 focused tests (including the new retained-selection case) plus 106 tests across the settlement CLI, settlement journey and unadmitted-selection suites; ruff clean. Author-owned, so this comment is the exact-head review record; not self-merged.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed exact head 9779cff7764ee9ab2011ac19d759d5000f581135 against the whole PR diff and current quota callers.
动机
同一 Turn 的 receipt 已绑定 autonomous replan obligation 时,后来传入的 --todo-id 不能替换结算身份。原实现把保留的 pending Todo 说成“当前投影选择”,且不给机器可读的 replan owner。独立复审还发现原 PR 的反例:没有 pending Todo 时仍输出 retained_selection=true 和空 Todo id,误导调用方去重读不存在的选择。
改动思路
以该 Turn 的现有 receipt 为唯一事实源,仍由原有 quota selection preflight 判定冲突,由原有 failure serializer 输出诊断;不新增 admission 规则、持久状态或第二套决策者。保留选择只在 conflict、replan id、pending Todo id 同时存在时成立;没有 pending Todo 时只说明 replan 义务及“结算后用新 Turn 选择 Todo”的下一步。
具体改动
关键代码讲解
quota_action_selection.py:132的_requested_quota_action_selection_preflight在原冲突分支按 receipt 中是否有 pending Todo 设置 qualification,而不是无条件称作 retained。error_codes.py:70的QuotaActionSelectionConflictError从已有 typed facts 推导retained_selection,删除冗余构造参数,并给无 pending Todo 的 replan 绑定分支单独的原因和建议。quota_failure_report.py:66的quota_failure_payload仅在确有保留选择时输出保留字段;replan obligation id 在两种分支都可读。- 两个测试文件覆盖直接错误封装和真实 CLI 重入;后者验证有/无 pending Todo 的反事实以及 receipt、spend 数量不增加。
对主干的风险
最强反例已在原 PR head 的真实 CLI 路径复现:无 pending Todo 却报告保留选择;修订 head 的对应断言及保留选择正例均通过。定向 11/11、扩展 quota 集成 117/117、Ruff、编译、diff 检查及本地 merge-tree 均通过。隔离测试运行目录后,先前共享 Effect runtime 的连接拒绝没有复现。补齐 Node 依赖后语义词汇检查通过;loopx canary premerge 的 18 项风险检查最终过关,唯一维护性 ratchet advisory 指向未改动的 Lark 模块,并在同一 main 基线复现。无手动 hold;未等待远端 CI(本 Goal 的 review 配置为 wait_for_ci=false)。残余风险是尚无生产环境读数,但改动限于拒绝诊断,无新增结算效果。
语义与 CI 对齐
复用现有 quota conflict 与 receipt 词汇,没有新状态机或默认 admission 变化。一次受控修订移除了重复的保留标志参数;没有找到还需拆出的相关抽象。
我的整体评价
就本 PR 的目标、整体 diff、负例及本地验证而言,没有剩余阻断项:给出 APPROVE 结论。此账号是 PR 作者,GitHub 不接受正式自批准,因此以 COMMENTED review 记录精确 head 结论。该 PR 修改 loopx/** 控制面;依仓库规则,即使审查和 premerge gate 通过,仍须由维护者合并,不能作者自合并。
English verdict: APPROVE - exact head 9779cff; false retained-selection diagnostic repaired, 117 quota tests and the premerge gate passed (one baseline-identical advisory); maintainer merge required.
Summary
A Turn bound to an autonomous replan obligation must not let a later
--todo-idreplace its settlement identity. Before this PR, the refusal mislabeled a retained pending Todo as the projection's current selection and exposed no typed replan owner. Independent review also found the converse case: when the Turn retained no pending Todo, the first patch incorrectly assertedretained_selection=trueand advised reading a nonexistent selection.What changed
Validation
main: passed.loopx canary premerge --from-git-diff --goal-id loopx-meta: merge gate passed; 18 selected canaries/risk-profile smokes ran. The maintainability ratchet reported one advisory about an unrelated Lark module, reproduced unchanged on the samemainbaseline. The semantic-vocabulary smoke passed after installing the checkout's Node dependencies with scripts disabled. No manual holds or skipped required checks.cqr_bf12811d66be038e41b9verified against the exact five-file diff.Boundary
This changes
loopx/**quota control-plane behavior. It is proposed for exact-head review and left for the maintainer to merge; author self-review, green validation, and admin bypass do not authorize self-merge under repository policy.