Skip to content

fix(control-plane): bind semantic replans to turn guards - #3840

Merged
huangruiteng merged 1 commit into
mainfrom
codex/turn-replan-settlement-coherence-20260902
Sep 2, 2026
Merged

fix(control-plane): bind semantic replans to turn guards#3840
huangruiteng merged 1 commit into
mainfrom
codex/turn-replan-settlement-coherence-20260902

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • persist the semantic replan target selected by the original quota guard separately from its causal Todo settlement binding
  • enforce only that exact replan generation during turn-scoped refresh; preserve later or newly derived obligations for the next Turn
  • keep unscoped refreshes and legacy guard receipts fail-closed

Refined design

The original change fixed a real causal race, but did not distinguish an old receipt with no semantic-replan field from a new guard that explicitly selected no replan. Treating both as “no replan” would silently weaken the gate for an in-flight legacy Turn.

The refined implementation makes receipt interpretation a TypeScript-owned three-state contract:

  • legacy_unscoped: the receipt predates the field, so current strict behavior is preserved;
  • turn_guard with no selected obligation: a replan created after admission is deferred to the next Turn;
  • turn_guard with an exact obligation id: that generation remains strict.

Python now consumes this typed readback instead of reinterpreting raw receipt shape. Malformed persisted ids fail closed.

Independent review / provenance

No linked issue, review discussion, or originating task/thread was present on the PR. The branch and commit are owner-authored, but the exact generation context could not be reconstructed. The change was therefore rebased onto current main and reviewed from the current control-plane invariants rather than relying on its original description or local validation claims.

Validation

  • LOOPX_PYTHON="$PWD/.venv/bin/python" .venv/bin/python -m pytest -q tests/capabilities/test_benchmark_toolkit.py tests/control_plane/test_refresh_state_replan_gate.py tests/control_plane/test_quota_settlement.py tests/control_plane/test_quota_settlement_cli.py — 215 passed
  • npm run test:control-plane — 453 passed, 1 skipped (LOOPX_TEST_POSTGRES_URL not configured; unrelated PostgreSQL integration)
  • npm run typecheck:control-plane — passed
  • changed Python compile and Ruff checks — passed
  • loopx canary premerge --from-git-diff --git-diff-base origin/main --format json --no-progress — passed; 17/17 selected canaries, no failures, warnings, or manual holds
  • public/private scan — clean; no private state, raw evidence, credentials, local paths, or generated logs in the diff

Merge decision

The final diff is cohesive, current-main based, backward-compatible, and covered across the causal race, exact-generation strictness, legacy receipts, malformed state, replay, and the broader quota/settlement surface. Owner authorization for self-review/refine/merge was provided in the current task.

@huangruiteng
huangruiteng force-pushed the codex/turn-replan-settlement-coherence-20260902 branch from e90c15c to 4d61b72 Compare September 2, 2026 17:15

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

No unresolved findings on the refined head 4d61b7251.

Resolved during review:

  • The original implementation correctly identified the causal race between Turn admission and later replan derivation, but it treated a legacy receipt with no semantic-replan field the same as a new guard that explicitly selected no replan. That could weaken an in-flight legacy Turn's strict gate.
  • Receipt interpretation now lives in the existing TypeScript settlement-readback boundary as a typed three-state contract: legacy/unscoped, guard-scoped with no selected replan, or guard-scoped to one exact obligation id. Python consumes that projection; malformed persisted ids fail closed.
  • Added end-to-end coverage for both sides of the race: an obligation created after admission is deferred, while a guard-selected obligation remains strict. Added legacy-receipt and TS contract coverage as well.

Product/architecture judgment: the change is valuable and appropriately scoped. A Turn should be judged against the semantic obligations admitted by its own guard, not against a newer projection computed during writeback. This prevents valid work from being retroactively rejected without allowing old or malformed receipts to bypass current safety. The TS companion refactor is at the existing receipt-decoding owner and avoids a new leaf runtime handler or a second Python source of truth.

Provenance: the PR had no linked issue, review discussion, or originating task/thread, so I did not rely on its original validation narrative. I rebased it onto current main and independently reconstructed the invariant from the live settlement and replan paths.

Validation:

  • focused Python control-plane suite: 215 passed;
  • complete TypeScript control-plane suite: 453 passed, 1 PostgreSQL integration skipped because LOOPX_TEST_POSTGRES_URL is not configured;
  • TypeScript typecheck, changed Python compile, Ruff, and diff hygiene: passed;
  • risk-based premerge: 17/17 selected canaries passed, with no failures, warnings, or manual holds;
  • GitHub checks: pytest, Windows PowerShell, DCO, dependency review, build, and both Sonar checks passed;
  • public/private boundary scan: clean.

Merge decision: self-merge is justified on this exact head under the owner's explicit authorization.

@huangruiteng
huangruiteng merged commit 5c06247 into main Sep 2, 2026
9 checks passed
@huangruiteng
huangruiteng deleted the codex/turn-replan-settlement-coherence-20260902 branch September 2, 2026 17:31
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