Fallout-build / Fallout-build/Fallout
Fallout.Reconcile — generic plan/apply primitive for CD targets
- Dominant language
- C#
- Stars
- 154
- Forks
- 19
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 15
Description
## Motivation
Building CD for [ERP for Factory Games](https://github.com/ChrisonSimtian/ErpForFactoryGames) as a real-world Fallout-as-CD dogfood ([ErpForFactoryGames#265](https://github.com/ChrisonSimtian/ErpForFactoryGames/pull/265)), we hand-rolled the same shape every CD target eventually needs:
- Fetch current state from the remote.
- Diff against desired state.
- Render the plan (dry-run, structured + tabular).
- Optionally apply.
Concretely: `ResourcePlan`, `FieldChange`, `PlanAction`, `PlanRenderer`, plus per-resource reconcilers (`TunnelReconciler`, `DnsRecordReconciler`, `IngressReconciler`) — ~250 LOC of pure scaffolding before any Cloudflare-specific code. The next CD target (K8s manifests, Docker compose, IAM policies, on-disk config) will hand-roll a sibling because the primitives aren't upstream.
## Proposal
A `Fallout.Reconcile` namespace with the generic primitives:
```csharp
public abstract record PlanAction { Create, Update, Delete, NoChange }
public sealed record FieldChange(string Field, string? Before, string? After);
public sealed record ResourcePlan(string ResourceKind, string Identifier, PlanAction Action, IReadOnlyList Changes, T Current, T Desired);
public interface IReconciler {
Task>> PlanAsync(T desired, CancellationToken ct);
Task ApplyAsync(IReadOnlyList> plans, CancellationToken ct);
}
public static class PlanRenderer {
public static void RenderTable(IEnumerable plans, IAnsiConsole console);
public static string RenderJson(IEnumerable plans);
}
```
A target composes reconcilers with the existing `[Parameter] DryRun` machinery — `./build.sh Provision --dry-run` becomes one-liner glue instead of 250 LOC of scaffolding.
## Why this fits Fallout (not a separate library)
- Needs to integrate with Fallout's `[Parameter]` / `[Secret]` flow for dry-run, credentials, output sinks.
- Plan rendering should use Fallout's `IAnsiConsole` so output stays consistent.
- Plan summarisation belongs alongside `Doctor`-style preflight (#251) — both are "tell me what would happen" surfaces.
## Open questions
- **Diff fidelity across resource types.** Cloudflare is easy (clean GET API). K8s, IAM, Terraform-state have defaults, server-side mutation, ordering quirks. The API needs an escape hatch (custom `IDiffStrategy`?) without becoming Cloudflare-only.
- **`T` vs untyped state.** Typed records are ergonomic for known shapes (DNS records, tunnels) but awkward for opaque server state (K8s objects, IAM docs). Generic over `T`, or over `JsonNode` / `IDictionary` with optional typed views?
- **Apply ordering.** Plans apply in production order today. Real CD needs ordering hints (tunnel before DNS for cloudflared). First-class `DependsOn`, or leave it to caller-side composition?
## Related
- #106 (CD-as-platform RFC) — this is a concrete piece of that vision.
- #167 (review ADRs 0001/0002) — slots under the "CD primitives" frame from ADR-0001.
## Reference implementation (to be replaced)
[`ErpForFactoryGames/src/Deploy/Erp.Deploy/Reconcile/`](https://github.com/ChrisonSimtian/ErpForFactoryGames/tree/main/src/Deploy/Erp.Deploy/Reconcile) — the hand-rolled version we'd delete once this lands upstream.
Contributor guide
Assessment
This issue has not been assessed yet.