Documentation menu

Reconciliation

The reconciliation loop observes, diffs, plans, applies, and observes again — boringly, deterministically, and with every step recorded.

Reconciliation is the heart of Hostwright. It should be boring: deterministic, observable, and hard to corrupt. Every cycle treats desired state and observed state as separate inputs, computes a plan, applies actions idempotently, and records what happened.

Reconciliation cycle: observe actual state, diff against desired, plan actions, then the planned apply step, looping back to observe; dry-run stops after plan.
Re-running converges on desired state; it never duplicates work.

The loop

load desired state from the state store
observe runtime state through the RuntimeAdapter
build a runtime snapshot with timestamps
compare desired state to observed state
produce a deterministic diff
produce an ordered action plan
validate safety gates
persist plan and intent
apply actions idempotently
record events and status transitions
observe again

The diff and the plan are first-class artifacts. hostwright plan shows you the ordered actions before hostwright apply runs them.

Dry-run and apply

  • plan computes the diff and the action plan and prints it. Nothing in the runtime changes.
  • apply runs the plan, persisting intent before each mutation and the result immediately after.

Because intent is persisted before mutation, a daemon restart in the middle of an apply does not lose track of what was being attempted.

Idempotency

Applying a converged state is a no-op. The rules that make this safe:

  • Creating an already-correct container is a no-op or a clear “already converged” result.
  • Starting an already-running container is not an error.
  • Stopping an already-stopped container is safe.
  • Deleting a missing Hostwright-owned container is safe.
  • Resources created out-of-band are never deleted without ownership proof.

Drift

Drift is the gap between what you declared and what is running. Hostwright reports drift for resources that are missing, stopped, unhealthy, or modified out from under it. Drift is surfaced in hostwright status, not silently repaired in ways you cannot see.

Events

Every meaningful step emits a structured event so failures are explainable after the fact:

Event {
  type: planned | applied | failed | health_changed
        | drift_detected | restarted | cleaned
  severity: info | warning | error
  project, service?, instance?
  message, runtimeRef?, timestamp, correlationID
}

Open questions

  • Should rollback for a partial apply be automatic, manual, or plan-only by default?
  • How aggressively should the loop re-reconcile on drift versus waiting for an explicit apply?