Skip to content

GH-C72: P0 pure Turn Loop Controller transition contract #2432

Description

@Claisenn

Following the Turn Loop Controller plan in CONTRIBUTOR_TASKS.md (P0 slices), I would like to implement the first slice: the pure transition contract.

Scope (first PR, deliberately narrow)

A pure decision-table module, e.g. loopx/control_plane/turn_driver/loop_controller.py, exposing one function:

decide_next_disposition(turn_receipt, quota_decision) -> typed disposition

Input: one Turn receipt (loopx_turn_receipt_v0 result kind + validation status + terminal policy) plus a fresh quota/scheduler decision (loopx_turn_envelope_v0).

Output: exactly one typed disposition — run_now / wait / user_action_required / repair / replan / terminal — each with a reason code and a spends_quota: false marker.

The pure transition does not invoke a model, sleep, mutate a host scheduler, write state, or spend quota. Scheduler process management, host-specific wake APIs, and operator presentation stay out (later P1/P2 adapters).

Draft decision table (for review before implementation)

receipt fresh decision disposition
validated_completion (terminal postcondition met) any terminal
validated_progress, bounded budget remaining should_run + delivery allowed run_now
validated_progress, bounded budget exhausted any terminal (bounded stop)
repair_required result any repair
replan_required result any replan, and payload requires a bounded todo/vision delta before any successor Turn (never rerun the same stale todo just because a host session is resumable)
user_action_required (receipt or decision) user_action_required with the projected action, no host run, no spend
quiet_noop_allowed / cadence-only decision wait, no spend
stale receipt (lineage mismatch with fresh decision) fail closed: wait with stale_receipt reason (or contract error; happy to align on which)
malformed/unknown receipt or decision fail closed with contract error

Open question I would like maintainer guidance on: for the stale/malformed cases, should the disposition be wait with a reason code or a distinct contract_error disposition? The task board lists six dispositions, so I lean toward wait + explicit reason codes unless you prefer a seventh.

Validation plan

  • focused decision-table pytest covering each row plus boundary rows (progress at budget limit, replan without delta, stale lineage)
  • python -m pytest -q tests/test_loopx_turn_driver.py tests/test_loopx_turn_executor.py tests/test_loopx_turn_transaction.py
  • python examples/autonomous-replan-obligation-smoke.py
  • loopx check --scan-path CONTRIBUTOR_TASKS.md --scan-path CONTRIBUTING.md
  • git diff --check

Refs: #2366 (design), #2365 (host-mode selector), CONTRIBUTOR_TASKS GH-C72.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions