Skip to content

Reconciling Lifecycle

Drift detection tells you the cloud and your source disagree. Reconciliation closes the gap. There are two directions, and chant exposes each as an Op composite. Which one you reach for — and whether you reach for either — is the dial, chosen per environment.

observe → reconcile → authoritative
(report) (cloud→code (code→cloud
PRs) apply)

When the live system is ahead of source — someone created or changed a resource by hand — pull reality back into source so declarations track it. ReconcileOp does this by opening a PR:

import { ReconcileOp } from "@intentius/chant/op";
const { op } = ReconcileOp({
name: "prod-reconcile",
env: "prod",
schedule: "0 * * * *", // hourly
scope: { owned: true }, // only chant-owned resources
onDrift: "pull-request", // or "issue" | "report"
});
export default op; // discovered by `chant run prod-reconcile`

Phases: Snapshot -> Plan -> Reconcile, where the Reconcile phase’s reconcilePr activity regenerates source (live import) and opens the PR in one step. Run chant run prod-reconcile for a one-shot reconcile here. For the continuous form, give it a schedule and hand it to whatever fires the cadence: a generated CI workflow, chant operator, or a fountain Steward. The PR’s diff is the regenerated TypeScript, so review is a normal code review.

Reconcile never mutates the cloud. It only changes source — the safest reconciliation direction, and a good first step past pure observation.

When source is the intended truth and the cloud should follow, ApplyOp pushes declared source into the live system — a Kubernetes server-side apply, a CloudFormation deploy, or an ARM deployment, selected by target:

import { ApplyOp } from "@intentius/chant/op";
const { op } = ApplyOp({
name: "prod-apply",
env: "prod",
target: "kubectl",
delete: "gated", // "never" | "owned-only" | "gated"
gate: { signalName: "approve-apply" },
});
export default op;

Authority stays with the platform — chant hosts no state file. Deletes ride the target’s own delete path and are owned-only on every target: marker-scoped on kubectl, tag-scoped on arm, and bounded by the stack on cloudformation. See delete and what bounds it for the mechanism in each case. A destructive apply gets an approval gate and saga-style rollback; see Gates and compensation on a destructive apply for what each buys.

  • lifecycle-reconcile-aws example — the whole loop on a real stack: deploy -> drift -> diff -> reconcile / apply
  • Live Import — the cloud->code regeneration the reconcile workflow uses
  • OpsReconcileOp and ApplyOp in depth
  • Reconciliation — the dial as per-environment configuration, and when to pick reconcile vs. apply vs. observe