Skip to content

Bug: autonomous replan no_followup can make the Goal terminal before its bound quota spend #4501

Open

Description

@shangzh0

Bug: autonomous replan no_followup can make the Goal terminal before its bound quota spend

Summary

An LHTB apex-ib244-matter run exposed two separate behaviors that should not
be conflated:

  1. A closed agent vision while the registry Goal remains active produces
    vision_successor_required and then autonomous_replan_required. This is
    expected fail-closed behavior.
  2. When that autonomous replan resolves the frontier with a coverage-backed
    no_followup, its durable writeback can derive terminal_no_followup
    before the same settlement identity records its quota spend. The strict
    terminal guard then rejects that pending spend. This is an ordering bug.

The result is an unnecessary control-plane self-repair turn after the benchmark
work itself is already complete.

Observed run

  • LoopX revision used by the run:
    1c7b40ea403f9949b22f32071eec237199e52554
  • Benchmark result: 38/38 stages submitted
  • Final reward: 0.993151
  • Scheduler wakes:
    1. normal_run
    2. autonomous_replan_required
    3. autonomous_replan_required
    4. scheduler poll returns terminal_no_followup

Wake 1: benchmark completion and Todo settlement

The agent completed all 38 stages. The first material refresh correctly
reported a missing required vision checkpoint. The agent then:

  1. recorded an evidence-linked vision_closed checkpoint;
  2. committed the Todo-bound durable writeback;
  3. committed exactly one Todo-bound quota spend;
  4. completed the Todo with --no-follow-up;
  5. read back heartbeat_settled_skip for that Turn.

The vision checkpoint gate and its repair were expected.

Wake 2/3: expected Goal-level replan

On the next fresh Turn, quota projected:

{
  "decision": "autonomous_replan_required",
  "effective_action": "autonomous_replan_required",
  "selected_todo": null,
  "autonomous_replan_obligation": {
    "triggers": [
      {
        "kind": "vision_successor_required",
        "text": "the current stage vision is closed while the registry goal remains active; establish a successor vision before continuing"
      }
    ]
  }
}

This replan is expected: Todo no_followup is not by itself Goal completion.
The Goal still needs either a successor vision or an evidence-backed terminal
frontier decision.

The first replan wake returned without settling the obligation, so the
scheduler correctly presented the same obligation again. The following wake
validated that 38/38 was complete and selected
coverage_backed_no_followup, with an agent vision whose state was
no_followup and whose path outcome was stop.

Failure

The autonomous-replan settlement plan was:

validation -> durable_writeback -> quota_spend

The durable writeback succeeded and derived Goal state
terminal_no_followup. The immediately following, correctly bound
quota spend-slot was rejected because quota accounting no longer admitted
delivery completion spend from a terminal state.

At the point of failure:

validation receipt:       committed
durable writeback receipt: committed
quota spend receipt:       absent
Goal state:                terminal_no_followup
effect identity:           unchanged and correctly replan-bound

This matches the documented terminal_settlement_ordering_gap: terminal state
became visible between two ordered steps of the same effect.

Why this is a bug

The terminal guard is correct to reject new work and unrelated spends after a
Goal is terminal. However, a writeback from the current typed settlement must
not make the remaining step of that exact settlement impossible.

The replan itself is not the bug. The bug is that final Goal-level
no_followup is applied as part of pre-spend writeback instead of as a
conditional post-spend closeout under the same effect identity.

Current main audit

Audited remote main at:

f97ba42219442e4b46819e4795050dd8c41d2389

Current main correctly retains the expected vision behavior:

  • tests/control_plane/test_goal_vision_succession.py requires a closed stage
    vision on an active Goal to produce vision_successor_required.
  • skills/loopx-self-repair/references/repair-patterns.md documents
    terminal_settlement_ordering_gap and recommends post-spend terminal
    closeout.

Current main also adds a conditional terminal_closeout step for Todo-bound
settlements. However, the exact autonomous-replan path remains uncovered:

  • build_turn_scoped_cli_settlement_plan() adds terminal_closeout only when
    todo_id is present; a replan_obligation_id plan still ends at
    quota_spend.
  • build_quota_slot_preview_for_decision() still admits delivery completion
    spend only from waiting, focus_wait, operator_gate, or eligible, not
    from terminal_no_followup.
  • The focused regressions created during the run are not present on current
    main.

Therefore this issue is recognized and partly addressed for Todo closeout, but
the observed autonomous-replan terminal path is not demonstrably fixed.

Expected behavior

For an autonomous replan whose accepted semantic outcome is
coverage_backed_no_followup, preserve the strict terminal guard while making
the settlement order explicit:

validation
-> durable writeback
-> quota spend
-> conditional terminal closeout

Requirements:

  • all four steps use the same typed effect identity and replan obligation;
  • terminal mutation requires matching writeback and spend receipts;
  • retrying terminal closeout must not repeat writeback or spend;
  • unrelated or unbound terminal spends remain rejected;
  • cancellation, failed validation, failed writeback, and rejected spend must
    short-circuit before terminal mutation.

Suggested regression coverage

  1. Active Goal plus vision_closed still produces
    vision_successor_required and autonomous_replan_required.
  2. A replan-bound, coverage-backed no_followup writeback does not strand the
    matching quota spend.
  3. Terminal closeout occurs only after matching writeback and spend receipts.
  4. Replay produces no additional spend or writeback.
  5. A terminal Goal still rejects an unbound spend and a mismatched replan
    obligation.
  6. The generic CLI heartbeat path reaches heartbeat_settled_skip without a
    model-authored self-repair worktree.

Activity

  1. YZJF commented on Sep 16, 2026

    @YZJF
    Contributor

    I re-checked the audit in this issue against current main (856dc9a38) and it still holds, but I think the fix is larger than "add the missing post-spend step". Posting before writing code, because it needs a direction call.

    The audit still holds

    • build_turn_scoped_cli_settlement_plan() still appends TERMINAL_CLOSEOUT only under if todo_id — now at loopx/control_plane/quota/effect_program.py:190 (was 188 at the audited f97ba42). A replan_obligation_id-bound plan still ends at quota_spend.
    • build_quota_slot_preview_for_decision() still does not admit the delivery-completion spend from terminal_no_followup.

    Why appending a post-spend closeout step is not sufficient

    The existing terminal_closeout command template is Todo-scoped:

    # effect_program.py:132
    terminal_closeout = (
        f"{cli_prefix} todo complete --goal-id {goal_id}{binding_arg}"
        f"{lifecycle_actor_args}{turn_arg} --evidence '<validated evidence>'"
        " --no-follow-up"
    )

    It needs a todo_id, and the failing settlement has selected_todo: null by definition. Grepping --no-follow-up across loopx/ finds it only in the Todo command family (cli_commands/todo_argument_validation.py, cli_commands/todo_registration.py), in adapters that shell out to todo complete (kunluncode_goal_mode/control_plane.py, goal_mode_mcp.py), and in cli_commands/lark_inbox.py. There is no Goal-level closeout command to hang on a replan-bound plan.

    More importantly, the terminal state is not missing from the end of the plan — it is produced in the middle of it. The durable writeback step runs refresh-state, which recomputes the frontier projection and feeds derive_goal_terminal_state() (control_plane/goals/goal_frontier/terminal.py:121, with goal_frontier_is_terminal_no_followup() at :165). Once all todos are closed, the frontier is empty and the no_followup is coverage-backed, that writeback writes terminal_no_followup itself. The spend that follows is then rejected by the strict terminal guard.

    So even with a post-spend closeout step added, the ordering bug would remain: writeback would still have made the Goal terminal before the spend ran. The defect is in the writeback step, not only in the missing last step.

    Two directions I can see

    1. Defer the terminal derivation. When the settlement is replan-bound and the matching spend receipt is absent, the durable writeback records a pending/intended terminal state instead of committing it; the post-spend closeout commits it once writeback and spend receipts both exist. Keeps one command surface, but changes what refresh-state writes.
    2. Add a Goal-level closeout. Introduce a Goal-scoped equivalent of todo complete --no-follow-up so the replan plan can carry a real post-spend TERMINAL_CLOSEOUT, and make the writeback path register the terminal intent rather than the terminal state.

    Both touch the goal-frontier projection, which scheduler, arbitration, and decision_summary read, so either way this needs the regression list already in this issue plus projection parity cases.

    What I am asking

    Which of the two (or a third option) matches the intended contract? I am happy to implement the chosen direction together with the six regressions listed here, but I would rather not pick the writeback semantics unilaterally. Not claiming the issue.

  2. yilin-succeed commented on Sep 16, 2026

    @yilin-succeed
    Contributor

    PR #4536 takes this on: an autonomous replan spend is now admitted from terminal_no_followup only when it is bound to the autonomous-replan settlement that owns the committed durable-writeback receipt and has not yet recorded its spend. Unbound, mismatched, and already-accounted terminal spends still fail closed.

    Reproduced on current main first with a coverage-backed no_followup replan fixture (writeback committed, spend rejected because the Goal was already terminal); both new regressions fail without the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions