/** * Change set: a typed, read-only projection of a live diff. * * `chant lifecycle diff --live` computes a three-way comparison — declared now / * last snapshot / live now — and prints it. `buildChangeSet` promotes that * same signal into a classified create/update/delete/adopt/runtime/noop set * that other tooling (reconcile, apply) can act on. * * Strictly read-only and pure: no I/O, no mutation. The classification reads * ownership from the live marker only (populated downstream); until ownership * exists, an undeclared live resource is `adopt`, never `delete`. The snapshot * is evidence, never the basis for a mutation decision — it must never become * load-bearing. */ import { type AttributeChange, type DiffLiveInput } from "./live-diff.js"; import { type UnobservedReason } from "../observation.js"; /** * What the projection proposes for a single resource. * * - `create` — declared in source, and the provider **confirmed** it absent. * - `update` — declared and live, but live config drifted. * - `delete` — a chant-owned resource that is live but no longer declared. * Only emitted once ownership is known (#121); never inferred from the * snapshot. * - `adopt` — live but undeclared, ownership not established → a candidate to * pull back into source, never an auto-delete. * - `runtime` — live but undeclared, and its owner-reference chain reaches a * declared entity (#1077): a Pod a declared Deployment's controller * created, for instance. Never a delete, never an adopt candidate — it is * not drift, just the runtime doing its job. `runtimeOwner` names the * declared entity it belongs to. * - `noop` — declared and live with no drift, or already reconciled. * - `unobserved` — declared, and the lexicon could not look (#1089). Not a * proposal at all: it is the plan admitting a hole. Never a create, never a * delete. Read `unobservedReason` for which hole. */ export type ChangeAction = "create" | "update" | "delete" | "adopt" | "runtime" | "noop" | "unobserved"; /** * Who answers "is this resource chant's?". `unknown` until a live ownership * marker is queried (#120). The change set never escalates `unknown` to a * delete. */ export type Ownership = "owned" | "foreign" | "unknown"; export interface ChangeSetEntry { /** * chant entity name for a declared entity. For an undeclared live resource * (`adopt`, `delete`, `runtime`) this is the lexicon's live key — not an * IR-joinable entity name; read `physicalId` for the provider id (#1674). */ name: string; /** Resource type, when known from either side. */ type?: string; /** * The lexicon whose observation produced this entry (#1674). Set when the * change set is built for one lexicon; `lifecycle plan` merges every * lexicon's change set into one `entries[]`, and this is what keeps the * attribution through the merge. */ lexicon?: string; /** * Provider-assigned physical id (ARN, resource id, pod name) from the live * observation's `ResourceMetadata.physicalId`, falling back to the snapshot's * when the resource is gone (#1674). Absent when neither side reported one. */ physicalId?: string; action: ChangeAction; /** The three-way evidence the classification was derived from. */ evidence: { /** Present in the current build. */ declared: boolean; /** Present in the last snapshot. */ inSnapshot: boolean; /** Observed present in the live system right now. */ live: boolean; /** * The lexicon actually looked at this entity (#1089). `false` with * `live: false` means "unknown", not "absent" — the distinction the whole * change set now rests on. Absent-and-looked-at is `observed: true, * live: false`. */ observed: boolean; }; /** Attribute-level changes, for `update`. */ deltas?: AttributeChange[]; /** Live-marker ownership. Defaults to `unknown`. */ ownership: Ownership; /** Why the entity could not be observed, for `action: "unobserved"` (#1089). */ unobservedReason?: UnobservedReason; /** Human-readable backing for `unobservedReason` (the failing command, the missing binding). */ unobservedDetail?: string; /** * The resolved address the live read was issued against (#1620), when the * lexicon reported one. On a `create` it says which address the provider * confirmed absent — the line between "not there" and "looked in the wrong * place" (a defaulted namespace, an endpoint override, the wrong region). */ queried?: string; /** The declared entity this resource's owner chain resolves to, for `action: "runtime"` (#1077). */ runtimeOwner?: string; } export interface ChangeSet { env: string; entries: ChangeSetEntry[]; } /** * Build a typed change set from the same inputs `diffLive` consumes. * * `create`/`update` are precise from declared-vs-live. `delete` is never * emitted here — an undeclared live resource classifies as `adopt` until * ownership is known. * * A declared entity the lexicon could not observe (`input.unobserved`, #1089) * classifies as `unobserved` and nothing else: no `create` is ever synthesized * from a read that did not happen. */ export interface ChangeSetOptions { /** Stamp every entry with the lexicon it was observed by (#1674). */ lexicon?: string; } export declare function buildChangeSet(env: string, input: DiffLiveInput, options?: ChangeSetOptions): ChangeSet; /** Count entries per action. */ export declare function summarize(cs: ChangeSet): Record; /** * GitLab MR plan widget report. * * GitLab renders an `artifacts:reports:terraform` artifact in the merge-request * UI as "N to add, M to change, K to delete". The format is generic — any tool * that emits this JSON gets the widget — and the chant plan maps onto it * directly. Only the mutating actions count: `adopt`, `runtime`, `noop` and * `unobserved` are excluded, since the widget has no column for "live but * undeclared", "expected runtime child" (#1077), "no change", or "could not * look" (#1089). The widget is therefore a floor, not a complete plan: read * the full change set when entities are unobserved or classified runtime. * * The widget label reads "Terraform" regardless of producer; that is GitLab's * fixed string, not a claim chant makes. */ export interface GitlabMrReport { create: number; update: number; delete: number; } /** Project a change set onto the GitLab MR plan widget shape. Pure. */ export declare function gitlabMrReport(cs: ChangeSet): GitlabMrReport; /** Human-readable render of a change set. Pure — returns a string. */ export declare function renderChangeSet(cs: ChangeSet): string; //# sourceMappingURL=change-set.d.ts.map