Skip to content

fix(quota): keep capture IO out of the settlement plan's cold import - #8054

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
keoyyo85:fix/cold-import-settlement-plan
Nov 4, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
keoyyo85:fix/cold-import-settlement-plan

Conversation

@keoyyo85

@keoyyo85 keoyyo85 commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Outcome basis / optional anchor: Reproduced defect on current main at d29ec8bf2; no issue is filed for it and none is invented here. The failing check is the repository's own guard, not a new convention.

  • Goal/source and gap: tests/architecture/test_control_plane_import_boundaries.py::test_settlement_plan_import_does_not_load_native_capture_io requires that importing the settlement-plan builder does not load loopx.control_plane.turn_driver.decision_capture, because "a command template needs the native output profile, not capture binding or the complete quota/Goal routing graph". Commit a5b742f19 fix(quota): unify private capture platform qualification added a module-scope from ..turn_driver.decision_capture import private_capture_supported, which loads the whole capture-IO owner — and with it bind_turn_decision_capture, the quota error-code surface and the content-digest pattern — every time the plan builder is imported. The guard therefore fails on main.

  • Observable before → after: before, python -c "import sys; import loopx.control_plane.quota.effect_program; assert 'loopx.control_plane.turn_driver.decision_capture' not in sys.modules" exits 1; after, it exits 0, while the generated plan payload is byte-identical (983 bytes, same identity, same four command templates, --max-page-output-bytes 64000 still emitted on a POSIX host). Proved by the unit, regression_parity and failing-before rows below.

  • Issue/task and intended base: Related to no issue. Base main at ce4cfc1ce.

Author Declaration

  • Written by: model_agent (Claude-family model behind an AI coding agent).

Implemented against

  • Specification and revision: the existing guard tests/architecture/test_control_plane_import_boundaries.py::test_settlement_plan_import_does_not_load_native_capture_io and its stated clause ("keep the typed kernel usable independently of those orchestration owners") on main at ce4cfc1ce.

  • Criteria:

Criterion (spec clause) Disposition Symbol / path Test or command
Importing the settlement-plan builder must not load capture binding or the quota/Goal routing graph implemented build_turn_scoped_cli_settlement_plan in loopx/control_plane/quota/effect_program.py pytest tests/architecture/test_control_plane_import_boundaries.py
The generated command and the CLI's private-capture check must share one platform qualification (no second predicate) implemented private_capture_supported stays defined only in loopx/control_plane/turn_driver/decision_capture.py pytest tests/control_plane/test_quota_settlement.py -k "private_capture_support"
The returned settlement commands are unchanged implemented command_templates, SettlementIdentity in loopx/control_plane/quota/effect_program.py base-versus-head plan payload comparison recorded in the Validation table
  • Self-check before submission: this branch was rebased from d29ec8bf2 onto ce4cfc1ce with git patch-id --stable equal before and after (55ef4334…), so the rebase changed no content; the suites above were re-run on the rebased revision. I read every reference to private_capture_supported across loopx/, tests/ and examples/ before choosing the shape. My first attempt moved the import into the function only; that version left patch.object(quota_effect_program, "private_capture_supported", ...) in test_settlement_command_uses_private_capture_support with no module attribute to patch, and the suite went red — so the same commit also retargets those two patches to the owner module, which is where the name is now looked up. I did not move the predicate into native_context_profile.py even though that leaf module is declared "independent of capture and quota IO", because decision_capture.py is concurrently held by in-flight PRs C1: unify work sources and validate recovery #7430, fix(qualification): restore Any ceilings and current workspace contracts #8013 and fix(context): make progressive reads independent of native delta #8044; relocating a definition there is the better end state but belongs to whichever of those lands first. I did not run anything on a native Windows or non-POSIX host.

Scope And Continuation

  • Overlap disclosure: in-flight PR fix(qualification): restore Any ceilings and current workspace contracts #8013 also edits tests/control_plane/test_quota_settlement.py, but at a different precondition-string assertion, and its decision_capture.py edits are typing-only, so the two hunks do not meet. Nothing in the open-PR set edits this guard or this import edge.
  • Completed scope and remaining work: the cold-import guard passes and the predicate keeps a single owner. The remaining gap is structural rather than behavioural: private_capture_supported() is a two-line platform qualification that sits in the capture-IO module, so every consumer of the answer must either import that module or resolve it lazily. Moving it to the declared leaf module would retire the lazy import, and needs coordination with the three in-flight PRs listed above.
  • Slice boundary / successor: this PR is independently testable and reversible on its own. The follow-up (predicate relocation) should be raised once fix(qualification): restore Any ceilings and current workspace contracts #8013 settles, since it also edits decision_capture.py for typing only.

Validation

  • Tested revision: bca2dbb5d
  • Run state: finished
  • Input classes: synthetic
Check kind Result Public-safe evidence / limitation
static passed ruff check loopx/control_plane/quota/effect_program.py tests/control_plane/test_quota_settlement.py under the repository configuration: All checks passed.
regression_parity passed Failing-before evidence on the parent commit: pytest tests/architecture/test_control_plane_import_boundaries.py::test_settlement_plan_import_does_not_load_native_capture_io fails at ce4cfc1ce (and at d29ec8bf2) with assert 1 == 0 from the child process, and passes at this revision; the whole guard file goes from 1 failed to 28 passed.
unit passed pytest tests/control_plane/test_quota_settlement.py tests/architecture/test_control_plane_import_boundaries.py → 110 passed, 1 skipped at this revision.
integration passed The plan builder resolves the predicate through the owner module and the spend step still carries the profile: the captured quota spend-slot template contains --max-page-output-bytes 64000 on a POSIX host, and the two patched-support cases in test_settlement_command_uses_private_capture_support prove the flag appears only when the owner says the host is supported.
regression_parity passed Behaviour was compared by generating the same settlement plan on both trees with PYTHONPATH pinned to each and verified to import from that tree: the JSON payload is byte-identical (983 bytes, diff clean) for identity, ordered steps and command_templates.
real_entrypoint blocked tests/canary/test_maintainability_ratchet.py::test_current_repository_debt_is_reviewed_without_line_count_pins fails identically at the base commit ce4cfc1ce and at this revision, so it is pre-existing main-side debt rather than a regression introduced here; I did not attempt to fix it in this scope.
  • Coverage and gaps: the guard covers the exact edge this change removes, the two retargeted patch cases cover the flag appearing and disappearing through the owner, and the base-versus-head payload comparison covers the four generated commands, so no rendering path is left unexercised. Untested: import weight on a Windows host (the predicate result differs there, but the edge being removed is host-independent), and the canary ratchet failure above, which needs its own recorded decision.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • First viewport and preview: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A — no presentation surface changed.
  • Craft review: N/A — no presentation surface changed.

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 (keep the typed settlement kernel independently loadable).

Shared-authority RFC fixture impact

  • Production-scale fixture schema: N/A
  • Semantic dimensions changed, or reviewed no-impact rationale: N/A — no fixture dimension or schema changed; only the import site moved.
  • Provider conformance arms run: N/A
  • Read-only legacy/file/PostgreSQL three-arm rehearsal (required for promotion, runtime-routing, or compatibility-projection changes): N/A — no routing, promotion or compatibility projection changed.

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.
  • Existing English/Chinese RFC pairs (including ledger entries) both have a diff, and the local premerge check python3 scripts/check_rfc_bilingual.py --base origin/main --head HEAD passes, or no paired RFC changed.
  • 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).

a5b742f imported private_capture_supported at module scope, so importing the
settlement-plan builder loaded loopx.control_plane.turn_driver.decision_capture
and failed the repository's own cold-import guard. A command template needs the
native output profile, not the capture-binding owner.

The plan builder now resolves the predicate at its owner when it builds the
spend step, so decision_capture stays the single platform qualification and the
plan kernel remains loadable on its own. The generated commands are unchanged:
the plan payload is byte-identical before and after on a POSIX host.

Signed-off-by: keoyyo85 <335569976+keoyyo85@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 | effort=max

动机 / Motivation

只需要导入结算计划构造器的 CLI 与内部调用者。调用者仅导入计划构造器,基线会加载捕获模块,候选将加载延至真正构造命令时。基线隔离测试失败,精确 head 的同一测试通过,完整计划载荷相同。这解决现有依赖隔离回归,范围止于导入边界。通用冷启动提速、平台权限变更、捕获格式及领域决策迁移不在本次范围。

验收依据为 tests/architecture/test_control_plane_import_boundaries.py 在基线 ce4cfc1ce74a2ffe0d685758b8d6e9233b467f41 的现成约束,以及两个平台支持分支。该约束允许 kernel 独立加载,命令生成时仍需使用原平台资格。采用作者提出的单一谓词归属,拒绝由此推导通用启动或整轮性能收益。

改动思路 / Approach

审阅 head bca2dbb5d333adaa28b7b0723dc2590a55978f3e 后,本次改变的是依赖真正被使用的时点。普通模块导入只留下计划构造的依赖,实际构造命令时才解析 decision_capture.private_capture_supported。平台资格依然由同一函数给出,命令模板保持原有身份、步骤和参数。

我用两个独立源码快照交替执行七对完整计划构造,逐字段对比返回字典。两边输出一致。完整构造的中位数均约90ms,因此这里可确认的是依赖隔离修复,整个构造过程的提速尚无观测结果。

具体改动 / Changes

effect_program.py 删除顶部的私有捕获支持导入,并在生成步骤模板前按需导入原函数。没有新增平台谓词,没有新增 RPC、持久字段或调用方参数。test_settlement_command_uses_private_capture_support 的两处 mock 改为实际 owner 模块,继续检验 false 时省略页输出参数、true 时保留参数。

本地验证采用精确 head 的两个完整测试文件,得到110 passed、1个已有平台 skip。基线的冷导入测试失败,候选的同一测试通过。ruff 和 diff whitespace 检查均通过。生成的整个计划载荷相同,包含原 claim、validation、writeback 和 spend 命令。CI 按本次评审配置未查询。

对主干的风险 / Risks

风险集中在导入和 mock 绑定时机。原测试目标曾是 effect_program 顶部属性,局部导入后它应改为原判据模块的属性,本补丁已经同步处理。测试覆盖了支持与不支持私有捕获的分支。原生非POSIX宿主未实际运行,此处沿用既有模拟分支的覆盖范围。

仍可另行协调把两行平台资格迁到更轻的 owner。该后续属于结构整理,当前结果已能独立回滚和验收。此次没有渲染页面变化,视觉评审不适用,检查路径为命令构造和现有CLI结算入口。

我的整体评价 / Verdict

本次达到其声明的导入边界修复结果,差异集中,复用了既有 owner,完整输出与权限边界保持。可以作为控制面维护候选;将它计作 benchmark 效率提升需要另外的实跑成本。批准仅针对上述精确 head。未执行合并。

English verdict: APPROVE — bca2dbb fixes the cold import boundary with unchanged settlement plans. Related tests and paired plan comparisons pass; full-builder speedup and native non-POSIX execution are not established.

本次架构判断采用 retain,理由为“保留原领域 owner 与 import 局部化。” 。当前PR边界为“无新的领域规则”。验收条目 cold-kernel 与 single-predicate 均在上述基线 ce4cfc1ce74a2ffe0d685758b8d6e9233b467f41 的现有导入及平台测试中逐项对照通过。

@huangruiteng
huangruiteng merged commit 886f2cd into loopx-project:main Nov 4, 2026
25 of 38 checks passed
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.

3 participants