Skip to content

fix(settlement): classify quota refusals from typed actions - #6251

Open
songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/typed-settlement-failures-20261012
Open

songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/typed-settlement-failures-20261012

Conversation

@songoow

@songoow songoow commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Quota-spend callback failures were classified by whether their message contained budget: an unrelated transport error mentioning the budget became budget_rejected, while a real throttled quota refusal without that word remained generic.

The quota admission-refusal branch now transports its existing action as quota_rejection_action. The TypeScript settlement owner maps EffectiveAction.THROTTLED_SKIP to the existing budget failure kind. Missing, malformed, unknown or unrelated facts retain the stage-specific rejection. Previously persisted failure receipts remain unchanged; new callback results no longer infer their category from prose. The English and Chinese effect RFCs disclose this behavior change.

Refs #4447 for the bounded settlement source-evidence follow-up; this does not close the tracker. The source value reuses the existing effective-action owner, and the result reuses SettlementFailureKind. No new vocabulary or runtime bridge is introduced. The related refactor removes the text classifier within its current owner; a broader decision migration is deferred.

Validation:

  • Independent counterexamples failed before the fix and pass after it: translated quota messages, misleading budget prose, unknown/malformed actions, unrelated failures with a nested throttled snapshot, and stage separation.
  • 283 Python tests cover quota accounting, source witnesses, actual Turn execution/CLI, durable failed-result replay and retry without repeated writeback.
  • 205 TypeScript effect/settlement/readback tests pass; control-plane typecheck and changed-Python Ruff pass.
  • Development-time advisory and full semantic drift check pass. Premerge on the pre-rebase tree passed 7 catalog canaries, 8 risk-profile smokes, public-boundary validation, diff checks and compilation. After rebase onto current main, the affected Python/TS suites and full semantic check are rerun on the final head.

Changed entrypoints are quota refusal output and the existing Turn settlement result. No frontend or Lark consumer branches on this failure kind; no new interaction or authority is introduced. This is source-checkout and isolated synthetic validation, not installed-App or live-provider qualification. Remote CI and maintainer merge remain separate gates.

Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>

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

Reviewer: model_agent; model=GPT-6 family (Codex); provider=OpenAI; self_reported (runtime observation unavailable).

动机

维护者或 Agent 在已写回工作后读取扣费失败原因,需要区分配额用尽和其他拒绝。此前普通传输错误只要提到 budget 就会被归为预算拒绝,真正的限额拒绝没有这个词反而丢失分类;本次使用实际拒绝分支传来的类型化事实区分两者。同一错误更换说明文案不会改变分类,原有回执、重放和重试效果保持不变。本批仅修结算失败分类,不实现新的扣费策略、执行授权或完整 Goal 验收。全量词表来源验收仍由 #4447 的既有阶段负责,本 PR 不关闭该 tracker。

改动思路

拒绝事实由现有 quota 分支产生,TypeScript 结算 owner 负责唯一分类,Python 仅传输已有 action 值。当前 PR 只增加一项拒绝事实并删除文本分类,不新增运行时调用、存储或决策框架。我核对了真实 quota 入口、callback 传输、TS reducer 和 Python 解码:仅准入本身拒绝扣费时才附带 quota_rejection_action,其他先发生的绑定或工作区失败不会借用嵌套快照中的限额状态。说明文字继续完整传递,成功、拒绝和恢复仍由原有结算边界控制。

具体改动

评审 head:c773edef89273ccf4240b54da1f166667963d64e;基线:125db4201982a4bf1a10a330ba573ea52bf85096。规格依据为 docs/architecture/rfcs/agent-loop-effect-interpreter-v0.md,spec_revision 125db4201982a4bf1a10a330ba573ea52bf85096,使用修改前的已接受契约判断本次行为,而非让新文档自证正确。

关键代码讲解

  • build_quota_slot_preview_for_decision:仅在真实准入拒绝分支携带已有 action;无效决策不给出该事实。分配、检查及成功扣费规则不变。
  • callbackFailureKind / commitStepPayload:复用 EffectiveAction.THROTTLED_SKIP 与 SettlementFailureKind;预算拒绝只适用于 quota-spend 阶段。缺失、未知、格式错误或其他 action 保持阶段级失败,不再按文案猜测。
  • execute_turn_driver_settlement:原有 caller 无需改动,完整传输 provider payload,由 TS 返回保留原始 receipts 的结果。executor 回归使用真实 spend_quota_slot 拒绝,并验证失败重放与恢复。

规格映射:M7.1 的预算失败区分与部分执行/重试 characterization 在本次受影响路径实现;M7.2 的原始 effect identity、receipt 链与不重复 writeback/spend 保留并验证。全部 M7 和 #4447 的其他来源闭合不属于此批。英中文档同步披露新的 transient callback 分类规则与历史回执读取边界。

对主干的风险

行为变化是明确的:新输入只有说明文字、没有结构化拒绝事实时,保留 quota_spend_rejected,不会再因 budget 字样提升为预算分类。此前已保存的失败回执保持原样;旧 callback 若需要预算分类应提供现有 action 事实。不存在新的 opt-in 或默认关闭宣称,也没有新的用户确认步骤或权限来源。frontend/Lark 源码搜索未找到按该失败 kind 分支的消费者,CLI/Turn 的现有输出仍承载结果。

语义与 CI 对齐

相同四类输入经真实 Turn API、TS bridge 和隔离文件 journal 运行:基线将真实 throttle 分成普通拒绝,将误导文案分成预算拒绝;head 修正两者。逐字段比较只有这两类首次失败及其重放的 failure.kind 共四处改变,完整失败说明、receipts、effects 和调用次数一致;恢复均为 host/writeback 各一次、spend 两次。独立 oracle 在基线失败、head 通过,未用当前实现输出生成预期。

最终 head 上 283 项 Python、205 项 TypeScript、TS typecheck、Ruff 与完整语义检查通过;开发期 advisory 未发现支持形式的新词表,但不证明所有语义等价。premerge 在同一补丁的 rebase 前版本通过 7 个 catalog canary、8 个 risk smoke、公开边界、diff 与编译检查;rebase 后已重跑上述受影响测试与完整语义检查。远端当前为 1 success / 6 queued,没有已报告失败;排队是合并准备度的保留项。未做安装态 App、真实模型或外部 provider 验收,不据此声称全量上线资格。

我的整体评价

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

这个增量有完整真实调用方、独立反例及恢复读回,规模与诊断缺陷相称。long_horizon 判断为 preserved:失败后的原回执与恢复顺序未变;user_experience 判断为 improved:失败分类能反映结构化原因,未增加操作步骤。未来导向检查已应用于该分类边界:复用既有词表与 TS owner、删除 substring 规则;更广状态机迁移留给其既有 owner,不绑入此批。语义选择为 reuse_existing。CI 与维护者合并授权仍单独保留,评审不代表整个 Goal 已完成。

English verdict: APPROVE - c773ede; typed quota refusal fixes both diagnostic misclassifications while preserving receipts and retry effects; 283 Python and 205 TypeScript tests pass, remote CI remains queued.

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.

1 participant