Reading tools and contents
Loop Engineering

Chapter 1 of 8

Loops turn observations into controlled progress

Chapter 1

About 5 minutes · includes examples, an exercise, and references

Chapter at a glance

  • Model a production loop as sense, interpret, compare, decide, act, and record across durable boundaries.
  • Define measurable desired state, progress, fixed points, budgets, and environmental assumptions.
  • Use stabilization and bounded retry policies to prevent delay and noise from creating oscillation.

Loop Engineering is the discipline of designing repeated decision-and-action processes so they converge, remain bounded, and leave evidence. The word loop is deceptively familiar. A programming loop repeats statements while a condition holds; a production control loop repeatedly compares observed reality with a desired condition, chooses a corrective action, observes its effect, and decides what to do next. The second kind runs across unreliable networks, durable state, external services, human delays, deployments, duplicates, and partial failure. Its correctness cannot depend on one process retaining a local variable.

Kubernetes controllers provide a concrete mental model: a controller watches state and attempts to move current state toward desired state. It does not assume an action succeeded because a request was sent. It observes again and reconciles. This pattern appears in infrastructure automation, payment workflows, data pipelines, approval processes, coding agents, support agents, and distributed jobs. Each has a target, an observation function, a difference or error signal, an action policy, effectors, and a new observation.

Write the loop as six explicit stages. Sense gathers external facts and timestamps them. Interpret normalizes facts into trusted state. Compare evaluates goal predicates, invariants, and remaining work. Decide selects one legal transition. Act executes a bounded command through an effect boundary. Record persists the event, result class, resource usage, and next wake-up. The stages may be combined in code, but keeping them conceptually distinct reveals where stale data, mistaken authority, or an ambiguous effect enters.

Desired state must be testable. “Improve the repository” is not a usable target. “The requested defect is covered by a failing test, the patch makes it pass, the regression suite remains green, and the diff changes only allowed paths” provides observable predicates. The controller may not know the full action sequence in advance. It needs a way to determine whether each observation reduces the remaining work. A progress measure can be numeric, set-based, or partially ordered: unresolved items, failing tests, unprocessed records, distance to a target, or state rank.

Convergence means repeated legal transitions eventually reach a stable accepted state under stated environment assumptions. A fixed point is a state where reconciliation requires no further corrective action. Not every fixed point is success: “blocked because approval expired” and “failed after retry budget” are terminal fixed points too. Define them deliberately so the loop does not spin. If external conditions change, a new event can make a formerly stable state actionable again.

Control loops face delay and noise. A write may not be immediately visible to the next read. Two sensors may disagree. A dependency may flap between available and unavailable. Acting on every transient difference can amplify instability. Production loops use debouncing, stabilization windows, confidence rules, rate limits, hysteresis, and backoff. These are control choices, not merely performance tuning. They determine whether the system oscillates or settles.

Boundedness makes the loop safe to operate. Give every run a maximum elapsed time, step count, retry count, write count, concurrency, and resource budget. Add a no-progress rule based on state fingerprints or the progress measure. Decide what happens at each boundary: verified completion, scheduled retry, request for missing input, escalation, compensation, quarantine, or permanent failure. “Try again” is incomplete until it names the condition, next time, budget owner, and terminal alternative.

An agent loop is one use of this structure. A model can propose the next action, but the controller still senses, validates, authorizes, records, and terminates. Loop Engineering deliberately separates the probabilistic policy from deterministic lifecycle rules. A better model may improve decisions; it should not be required to enforce an expiry, consume an approval exactly once, or prevent a duplicate charge. The same controller can be tested with a scripted policy and replayed without a model.

Nested loops require explicit ownership. A coding workflow may contain a top-level issue-resolution loop, a test-repair loop, and a package-install retry loop. Each needs a local budget and terminal contract. If the inner loop can consume the entire outer budget, or both layers retry the same timeout, load multiplies. Propagate deadlines downward, return typed terminal reasons upward, and place retries at the layer that knows whether an operation is safe.

The central design artifact is a loop contract: desired-state predicates, accepted observations, transition catalogue, effect boundaries, invariants, progress measure, budgets, wake-up triggers, and terminal outcomes. It should also state environmental assumptions, such as eventual visibility of a ledger write or guaranteed delivery of at least one queue event. These assumptions are test targets. Without them, a promise of convergence is only optimism.

Loop Engineering shifts the question from “What prompt should run next?” to “What state are we in, which transition is legal, what evidence will show its effect, and when must we stop?” That question produces systems that can survive process death, duplicate events, slow humans, upgraded code, and imperfect models while remaining understandable to operators.

Key points

  • Model a production loop as sense, interpret, compare, decide, act, and record across durable boundaries.
  • Define measurable desired state, progress, fixed points, budgets, and environmental assumptions.
  • Use stabilization and bounded retry policies to prevent delay and noise from creating oscillation.
  • Keep probabilistic action selection separate from deterministic authority, lifecycle, and termination.

A bounded reconciliation loop with a progress measure

Read the expected behavior in the surrounding walkthrough, then copy and run this reference implementation.

A bounded reconciliation loop with a progress measurepython
from __future__ import annotations

from dataclasses import dataclass

@dataclass
class Store:
    existing: set[str]

def desired(image_id: str, version: str) -> set[str]:
    return {f"{image_id}/{version}/{size}" for size in ("sm", "md", "lg")}

def reconcile(store: Store, image_id: str, version: str, max_steps: int = 4) -> str:
    target = desired(image_id, version)
    prior_missing: set[str] | None = None
    for _ in range(max_steps):
        observed = set(store.existing)
        if observed == target:
            return "verified_stable"
        missing = target - observed
        if not missing:
            return "unexpected_state"
        if missing == prior_missing:
            return "no_progress"
        prior_missing = set(missing)
        # Deterministic keys make repeated creation safe in this toy store.
        store.existing.add(sorted(missing)[0])
    # Observe once more after the final allowed effect before declaring exhaustion.
    return "verified_stable" if set(store.existing) == target else "step_budget_exhausted"

store = Store(set())
assert reconcile(store, "img-7", "v2") == "verified_stable"
assert len(store.existing) == 3
print(sorted(store.existing))

Worked examples

Toy

Thermostat with hysteresis

A heater should keep a room near 21°C even though the sensor fluctuates by a fraction of a degree.

The loop turns the heater on below 20.5°C and off above 21.5°C. Between those thresholds it preserves the last command. Hysteresis prevents rapid switching around 21°C. A sensor-stale terminal state disables heating rather than treating an old reading as current.

  • Desired range differs from action thresholds.
  • A timestamp is part of the observation.
  • The loop has a safe state for missing data.

Application

Thumbnail reconciliation

Every uploaded image must have three derived thumbnails for the current renderer version.

Desired state is a set of three rendition keys. Observation lists existing valid renditions. The controller creates only missing keys using deterministic names, then observes object storage again. A version change creates a new desired set without deleting the old set until verification succeeds.

  • Progress is the shrinking set of missing renditions.
  • Repeated create commands are idempotent by key.
  • Version migration has an explicit stable point.

System

Issue-resolution controller

A repository workflow must reproduce a defect, prepare a patch, verify it, and wait for publication approval.

The outer loop moves through evidence, patch, verification, and approval states. A bounded inner loop repairs failed tests. State includes revision, patch digest, test receipts, budgets, and approval. Publication is a separate effect and timeout returns an ambiguous state that must be reconciled.

  • Inner and outer loops have separate budgets.
  • Approval binds the verified patch digest.
  • Every terminal state has an operator-facing reason.

Exercise

Write a loop contract from an informal workflow

Select a workflow that currently relies on polling, retries, or a long prompt and express it as a controlled reconciliation loop.

  1. Define desired-state predicates, observation schema, progress measure, and at least four stable terminal states.
  2. List legal corrective actions and identify which ones create external effects.
  3. Set elapsed-time, step, retry, write, and no-progress budgets with terminal behavior.
  4. State two environment assumptions and how a test could falsify each one.

Success criteria

  • A verifier can distinguish success from blocked or exhausted fixed points.
  • Every action has a subsequent observation that confirms or refutes its effect.
  • Noise, delay, and duplicate delivery cannot create an unbounded loop.
  • Nested retry ownership and deadline propagation are explicit.

Reflect: What would the loop do if the environment never makes the expected effect visible?

References and further reading