How LoopXTurnRoute and LoopXTurnResultKind Enums Distinguish Turn Decisions from Prose Shorthand in LoopX
LoopXTurnRoute determines what action the Turn engine should execute next, while LoopXTurnResultKind describes the semantic outcome of a finished Turn, with prose shorthand providing human-readable labels for UI layers while the enums ensure type-safe programmatic control flow.
LoopX implements a rigorous type system to manage the lifecycle of autonomous agent Turns through two specialized enumerations. The LoopXTurnRoute and LoopXTurnResultKind enums work in tandem to separate routing decisions from execution results, ensuring deterministic control flow while supporting human-readable logging and user interfaces.
Understanding the Two Enum Systems
LoopXTurnRoute: Routing the Turn Engine
LoopXTurnRoute determines what the Turn engine should do next based on envelope validation, integrity checks, and agent state. Defined in loopx/control_plane/turn_driver/driver.py (lines 45-52), this enum includes:
READY_FOR_HOSTREPAIR_REQUIREDREPLAN_REQUIREDUSER_ACTION_REQUIREDWAITBLOCKEDCONTRACT_ERROR
The driver derives the route from the Turn envelope’s schema version, signature match, budget status, and the requested action type.
LoopXTurnResultKind: Capturing Execution Outcomes
LoopXTurnResultKind describes how a Turn actually finished, serving the Turn receipt and settlement layers. This enum, defined in the Turn driver result module (typically loopx/control_plane/turn_driver/result.py), includes:
VALIDATED_PROGRESSVALIDATED_COMPLETIONWAITUSER_ACTION_REQUIREDHOST_FAILUREVALIDATION_FAILEDWRITEBACK_FAILEDQUOTA_SPEND_FAILEDREPAIR_REQUIREDREPLAN_REQUIRED
How the Enums Work Together
The Turn lifecycle follows a strict sequence from envelope validation to execution settlement, with each enum governing a distinct phase.
Stage 1: Envelope Validation to Route Selection
According to the implementation in driver.py (lines 68-79), the driver inspects incoming Turn envelopes for contract violations. If any are detected, the route is immediately set to CONTRACT_ERROR. When validation succeeds, the driver examines the effective action:
- If the action matches replan tokens (
autonomous_replan,successor_replan_required), the route becomesREPLAN_REQUIRED - If the action ends with
_repairor matches repair tokens, the route becomesREPAIR_REQUIRED - If policy blocks delivery, the route is
BLOCKED - If the Turn requires user intervention, the route is
USER_ACTION_REQUIRED - For quiet no-ops, the route is
WAIT - Otherwise, the route defaults to
READY_FOR_HOST
Stage 2: Execution to Result Kind
After the host executes the chosen route, the system builds a Turn receipt. The result_kind field captures the semantic outcome—whether the Turn achieved validated progress, completed successfully, or encountered specific failure modes like QUOTA_SPEND_FAILED or WRITEBACK_FAILED. The settlement logic uses this value to determine whether to persist state, retry the operation, or surface an error.
Prose Shorthand vs. Structured Decisions
The LoopX architecture maintains a strict separation between programmatic enum values and human-readable representations.
Structured Decisions (Programmatic Layer)
The engine never relies on free-form text for control flow. All routing logic checks enum members directly—for example, comparing against LoopXTurnRoute.READY_FOR_HOST or LoopXTurnResultKind.VALIDATED_PROGRESS. This ensures deterministic, type-safe operations throughout the Turn lifecycle.
Prose Shorthand (Presentation Layer)
Values like "wait" or "user_action_required" appear in user-facing logs and markdown renderers as human-readable representations of the underlying enum values. This separation allows UI layers to display friendly phrases while the core logic remains strictly typed and deterministic.
Implementation in the LoopX Codebase
The following examples from the LoopX repository demonstrate how these enums function in practice.
Routing Logic
The driver logic in driver.py determines the route based on envelope state and action type:
# driver.py – decide which route a Turn should take
if should_run:
if not delivery_allowed or not must_attempt:
route = LoopXTurnRoute.BLOCKED
elif effective_action in REPLAN_ACTIONS:
route = LoopXTurnRoute.REPLAN_REQUIRED
elif effective_action in REPAIR_ACTIONS or effective_action.endswith(
("_repair", "_repair_required")
):
route = LoopXTurnRoute.REPAIR_REQUIRED
else:
route = LoopXTurnRoute.READY_FOR_HOST
Receipt Construction
After execution, the transaction layer builds receipts using the result kind:
# transaction.py – build a receipt after the host finishes
receipt = {
"route": {"kind": route.value},
"result_kind": LoopXTurnResultKind.VALIDATED_PROGRESS.value,
"payload": {...},
}
Test Validation
Unit tests verify that receipts carry the correct semantic result:
# test_loopx_turn_transaction.py – asserting the result kind
def test_turn_receipt_validation():
receipt = ValidatedTurnReceipt.from_execution(execution)
assert receipt.result_kind == LoopXTurnResultKind.VALIDATED_PROGRESS
Summary
- LoopXTurnRoute controls what happens next in the Turn lifecycle, derived from envelope validation and action analysis in the Turn driver at
loopx/control_plane/turn_driver/driver.py - LoopXTurnResultKind records how a Turn actually executed, used by settlement logic to determine persistence and retry strategies
- The separation between routing (decision) and result (outcome) allows LoopX to handle complex agent workflows with clear state transitions
- Prose shorthand provides human-readable labels for UI components, while the enum system ensures type-safe, deterministic control flow
- Key implementation files include
loopx/control_plane/turn_driver/driver.pyfor routing logic and the corresponding result module for outcome tracking
Frequently Asked Questions
What is the difference between LoopXTurnRoute and LoopXTurnResultKind?
LoopXTurnRoute determines the next action the engine should take based on the current state and envelope validation, while LoopXTurnResultKind describes the semantic outcome of a completed Turn. The route enum drives control flow decisions before execution, whereas the result kind enum categorizes the outcome after execution for settlement and logging purposes.
Where are LoopXTurnRoute and LoopXTurnResultKind defined in the LoopX repository?
LoopXTurnRoute is defined in loopx/control_plane/turn_driver/driver.py (lines 45-52), which contains the routing logic that maps envelope states to specific route values. LoopXTurnResultKind is defined in the Turn driver result module, typically loopx/control_plane/turn_driver/result.py, where it maps execution outcomes to semantic result categories used by the settlement layer.
How does LoopX handle user-facing messages differently from internal routing decisions?
LoopX uses prose shorthand such as "wait" or "user_action_required" for human-readable UI displays and logs, while the core engine strictly uses enum members like LoopXTurnRoute.WAIT or LoopXTurnResultKind.USER_ACTION_REQUIRED for all programmatic decisions. This ensures type safety and deterministic control flow in the engine while allowing flexible, user-friendly presentation layers.
What triggers a REPAIR_REQUIRED or REPLAN_REQUIRED route in LoopX?
The driver sets REPLAN_REQUIRED when the effective action matches known replan tokens such as autonomous_replan or successor_replan_required. It sets REPAIR_REQUIRED when the action ends with _repair or matches entries in a predefined repair token list, as implemented in the routing logic of driver.py. These routes signal the host to initiate recovery workflows rather than normal execution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →