Fallout-build / Fallout-build/Fallout

Doctor target / [Diagnose] primitive — operator-side preflight surface

Open
#251 0 comments 0 reactions 0 assignees View on GitHub
enhancement RFC target/vNext
Dominant language
C#
Stars
154
Forks
19
Avg merge
1d 22h
Merged PRs (30d)
15

Description

## Motivation
A deploy command (`./build.sh Up`, `./build.sh Provision`) depends on operator-side state the build can't see:
- `~/.ssh/config` has the expected alias.
- The SSH key for that alias is offered by ssh-agent.
- `$CLOUDFLARE_API_TOKEN` has the required zone scope and isn't expired.
- The submodule providing the compose stack is populated.
- `docker compose` is installed remotely and the user is in the `docker` group.
- DNS resolves the deploy hostname to a reachable endpoint.

When one is missing, the deploy fails partway through with an error scoped to the *one* failing call, not the underlying preflight gap. The ErpForFactoryGames CD work deferred a `Doctor` target as Phase 3 ([ErpForFactoryGames#263](https://github.com/ChrisonSimtian/ErpForFactoryGames/issues/263)) because this kept biting in the last 24h of bring-up (missing SSH alias on the Mac dev box, file modes wedged from a prior run, etc.).

Every CD pipeline needs a preflight surface and almost none ship one well. Fallout can make it first-class because the framework already knows parameters, secrets, and targets — most diagnostic inputs are already declared.

## Proposal sketch

### 1. `[Diagnose]` attribute on parameters
```csharp
[Parameter] [Secret]
[Diagnose(typeof(CloudflareTokenProbe))]
readonly string CloudflareApiToken;

[Parameter]
[Diagnose(typeof(SshAliasProbe))]
readonly string DeployTarget = "erp-lxc";
```
`Diagnose` references an `IDiagnosticProbe` that gets the resolved value and reports a `DiagnosticResult` (status + actionable message). Probes are cheap, side-effect-free, independent.

### 2. `Doctor` target as a built-in
`./build.sh Doctor` enumerates every `[Diagnose]` parameter, runs the probes, and prints one status table:
```
┌──────────────────────────────┬─────────┬───────────────────────────────────────────────┐
│ Probe │ Status │ Detail │
├──────────────────────────────┼─────────┼───────────────────────────────────────────────┤
│ CloudflareApiToken │ ✓ │ scope=zone:read,zone:edit; not expired │
│ DeployTarget (ssh-alias) │ ✗ │ `erp-lxc` not in ~/.ssh/config. Add stanza: │
│ │ │ Host erp-lxc │
│ │ │ HostName │
│ │ │ User │
│ SshAuthSocket │ ✓ │ 1 key offered │
│ ComposeSubmodule │ ⚠ │ checked out, but 3 commits behind tracked tag │
└──────────────────────────────┴─────────┴───────────────────────────────────────────────┘
```
`Doctor` exits non-zero if any probe failed. CI can gate on it; humans run it before a deploy.

### 3. `[NeverLiteral]` is a special case
"This parameter must not be a committed literal" is just a probe — `LiteralLeakProbe` checks the resolved value's source (env / prompt / parameter / config file) and fails if it's a committed config. See #252 for the leak-prevention angle.

## Open questions
- **Execution model.** Sync vs async; how to surface long-running (network-bound) probes without blocking the table. Spectre's `LiveDisplay` could stream as probes complete, at some complexity cost.
- **Probe DI.** Probes needing `HttpClient` — DI'd by the host or self-instantiated? DI is more flexible but pulls the v12 plugin SDK in earlier than ideal.
- **External probe authoring.** Plugin authors will ship probes with their providers (`OctopusEnvironmentProbe`, `AzureSubscriptionProbe`). Needs a registration story.
- **Failed-probe discoverability.** A 60-row table is useless. Need "just the failing probes" output and a way to suppress known-not-applicable probes.

## Related
- #106 (CD-as-platform) — Doctor belongs in the platform's primitives.
- #167 (CD primitive review) — could feed the ADR set as a new primitive.
- #249, #250 — first probe consumers (reconcile + ssh primitives).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.