Skip to content

feat(turn): report the managed executor and fail closed when it cannot launch - #4416

Closed
huangruiteng wants to merge 4 commits into
codex/default-turn-host-binding-20260915from
codex/managed-executor-readback-20260915
Closed

huangruiteng wants to merge 4 commits into
codex/default-turn-host-binding-20260915from
codex/managed-executor-readback-20260915

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A planned managed Turn now reports which executor it would run on and fails
closed when that executor provably cannot launch here. Stacked on the
credential-resolved default Turn host change.

Changes

  • managed_executor_binding projects the executor, its kind (managed,
    individual, generic), the credential env var name (never its value), a
    launchability verdict, and a typed reason when unavailable.
  • loopx turn plan and loopx turn run-once attach managed_executor to their
    payload.
  • The Turn executor stops before any effect when the planned executor is
    unlaunchable: status unavailable, typed reason, no journal write, no quota
    spend.
  • turn plan default execution mode follows the resolved host, so a managed
    default plans isolated-headless instead of an execution mode the outer
    controller rejects.

Validation

  • tests/test_turn_managed_executor_binding.py, executor fail-closed and
    plan-preview tests, tests/test_turn_default_host_binding.py CLI default-mode
    test; 93 focused tests then 290 across the turn driver/executor suites, green.
  • examples/loopx-turn-managed-executor-binding-smoke.py proves the four-step
    CLI behavior, including an import-blocked dsh runtime.
  • Live CLI readback (no provider calls): no credential -> codex-cli /
    individual; credential -> dsh / managed / available: true; blocked
    runtime -> dsh / available: false / dsh_runtime_unavailable.

Boundaries

  • No credential values are read or projected; only env var names appear.
  • No provider calls are made by tests or the smoke.

Review notes

  • Interface budget: loopx turn plan gains the semantic field
    managed_executor, attributed as managed_executor_binding_v0. The
    agent-facing CLI base/head differential grants one bounded, one-time growth
    allowance (512 chars / 512 bytes / 12 lines / 448 compact chars) bound to the
    declared none-to-v0 binding transition on loopx_turn_plan,
    loopx_turn_plan_transaction_detail and loopx_turn_run_once_preview only.
    Quota, status and every other agent-facing surface keep their ordinary budget,
    and a v0-to-v0 change receives no allowance.
  • Module budget: the fail-closed decision and the payload projection moved to
    host_binding.py, the binding owner, so the already-large
    turn_driver/executor.py does not grow (1507 -> 1496 lines; limit 1500).
  • Validation: tests/canary/test_maintainability_ratchet.py 8 passed;
    tests/control_plane/test_cli_output_differential.py 59 passed;
    examples/control_plane/cli-output-base-head-differential-smoke.py ok
    (base=102 candidate=102 review_required=0); 81 focused Turn tests passed.

…t launch

`loopx turn plan` and `loopx turn run-once` now carry a typed
`managed_executor` block naming the planned executor, whether it is bound to an
operator credential or to an individual CLI host, and whether LoopX can prove
it launches here. A `run-once --execute` whose planned host reports
`available: false` fails closed with status `unavailable`: it invokes no host,
writes no journal, and spends no quota slot, so a Turn never moves onto another
executor on its own.

The credential-resolved default also has to pair its host with a schedulable
execution mode: a managed default now plans `isolated-headless` instead of a
visible interactive mode that the `outer_controller` scheduler context rejects,
so the shipped default is usable end to end.

Coverage: a readback matrix for the binding, executor coverage for the
refusal and preview paths, CLI default-mode coverage, and a hermetic smoke that
runs both the readback and the fail-closed refusal through the CLI.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Describe the shipped `managed_executor` block, what `executor_kind` means, when
`available` is false versus null, and the fail-closed contract of an explicitly
executing Turn whose planned host cannot launch.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/default-turn-host-binding-20260915 branch from ca4f3cd to bcade15 Compare September 15, 2026 05:13
@huangruiteng
huangruiteng force-pushed the codex/managed-executor-readback-20260915 branch from 3eed1a4 to 5740c4f Compare September 15, 2026 05:13
…wner

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Superseded by #4443 (feat(turn): select the managed Turn host explicitly).

The value here is kept: managed_executor_binding, the managed_executor readback block on plan and run-once, the typed unavailable_reason values, and the fail-closed start (status unavailable, no host invocation, no journal write, no quota spend). The readback now reports the executor the operator selected rather than the one a credential implied, and operator_credential_bound is stated as the narrower claim it is.

#4443 is main-based and carries the CLI output allowance this PR also needed, so the two no longer have to be reviewed as two layers. Closing to compress the delivery chain.

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