Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.8 KiB
Plan: Provider blueprint (docs/providers.md)
Created: 2026-09-16 08:41
Context
The provider contract is spread across docs/prompts/__initial-prompt.md §5,
the comments in internal/provider/{provider,errors,check}.go, docs/architecture.md
§5 and §11, docs/kvm-provider.md, and plan Step 2/3/8. Many rules exist only in
code: providerID must be self-contained, UID/CreatedAt must be read back, Create
must survive a crash partway through, calls must stop when ctx is cancelled,
decorators are wired in cmd/main.go, and so on. With "~5 providers soon", the
next provider author needs one blueprint. It should say what a provider MUST,
SHOULD or MAY do, show which features each existing provider (kubernetes, gcp,
kvm) actually implements (with file:line evidence), give a checklist for adding
one, and list the gaps.
Decisions (user): store in docs/providers.md; scope = current state plus a
separate "Gaps and proposed features" section (nothing implemented); wait for
feat/provider-health to merge, then branch off main.
Step 0 — Save the plan; wait for the merge
- Right after ExitPlanMode, copy this plan to
docs/plans/2026-09-16-0841-provider-blueprint.mdand commit it on its own. The current branch isfeat/provider-health, so the plan reachesmainwith that merge. CLAUDE.md requires the plan commit to come before any branching. - Stop and wait for the user to confirm that
feat/provider-healthis merged. Thengit switch main && git pull, andgit switch -c feat/provider-blueprint.
Step 1 — Collect evidence (read-only, in parallel)
Run 3 Explore agents at the same time, one each for internal/provider/kubernetes,
internal/provider/gcp and internal/provider/kvm, including their tests. Each
answers the same questionnaire, citing file:line for every answer and writing
"not implemented" explicitly when that's the case:
- Identity: providerID format and parsing; what it carries (zone, host, namespace).
- Create: how it stays idempotent (name lookup, 409, DomainLookupByName); whether it returns before the VM is up or waits; what happens when an earlier attempt crashed partway; which Placement fields are used or ignored; how cloud-init is delivered; how the port is used; how GC labels/UID are attached.
- Get: native state → InstanceState mapping; IP discovery rules; UID and CreatedAt readback; how NotFound is detected.
- Delete: idempotency; what gets removed (disks, volumes, seeds); returns before or after the resource is gone; unknown/malformed providerID behaviour.
- ListByTag: scope (namespaces, zones, hosts); partial-failure behaviour; how managed resources are recognised.
- Error classification: table of backend error → NotFound/Quota/Transient/ Permanent; whether quota is detected at all.
- Health check (
Checker): targets, provider-specific Reasons, Details keys. - Config: YAML section, defaults, validation (
internal/provider/config*.go), credentials/Secrets, which settings are read once per process. - Connections and cancellation: pooling, reconnects, timeouts, ctx honouring.
- Observability: log keys and verbosity levels, spans (
kvm/trace.go, gcpwirelog.go), anything beyond the shared metrics/tracing decorators. - Testing: fakes, envtest/kind,
//go:build integrationtests, what is not covered. - Known gaps: TODOs, stale comments, documented limitations.
Meanwhile, read the shared layer myself: internal/provider/{provider,errors,check, name,config,metrics,tracing}.go, internal/provider/registry/registry.go,
cmd/main.go (registry wiring, decorator order, Checker collection), and the
places that consume the contract, so every MUST rule traces to a caller that depends on it:
internal/controller (error-class branching, ErrNotFound → replace/adopt),
internal/gc (UID, CreatedAt age skip, ListByTag errors),
internal/providerhealth. Then cross-check against the existing docs listed in Context.
Step 2 — Write docs/providers.md
Sections:
- What a provider is: a few sentences plus links to architecture.md §5/§11.
- The contract: per method (Create/Get/Delete/ListByTag), MUST/SHOULD/MAY rules, each followed by why: the reconciler or GC behaviour it protects, linked to code.
- Error taxonomy: what each class makes the reconciler do; how to map backend errors; "unclassified = transient" pitfall.
- Identity and GC labels: providerID guidance,
LabelManaged/LabelUID, CreatedAt, deterministicNameFromUID. - Optional interfaces:
Checker(shared reasons, never fails as a whole, collected before decorators). - Feature matrix: one row per questionnaire item, columns kubernetes/gcp/kvm,
cells
yes/partial/noplus a short note. Put the file:line evidence in a compact per-provider notes subsection under the table, not in the cells. - Adding a provider: checklist: package layout, config section and validation,
registry constructor,
cmd/main.gowiring, Checker, error mapping with tests,name/label tests, integration test behind a build tag, provider doc page, architecture.md rows, demo script (optional). - Gaps and proposed features: current-state gaps per provider (e.g. no kvm
quota detection, orphan volumes invisible to GC, Secret rotation needs a
restart, ListByTag partial-failure inconsistency, stale
mockreferences inprovider.gocomments), plus proposals that are clearly marked as not implemented. Only list them; don't design them.
Also: link it from docs/architecture.md (Components table → provider contract row)
and from the CLAUDE.md "Architecture" section. Leave per-provider docs where they are.
Follow the plan-execution convention: create docs/plans-executions/2026-09-16-0841-provider-blueprint.md
with the status checklist and step entries, and commit it with each step.
Step 3 — Verify, then open the MR
- A verification agent (Explore) re-checks each matrix cell and each MUST rule against the cited file:line and reports any mismatch. Fix what it finds.
- Check that every relative link in the new and edited docs resolves (grep the
](targets andlseach one). go build ./... && go test -short ./...as a sanity check (docs-only change, expected no-op).- Push
feat/provider-blueprintand open the MR againstmainvia the Gitea API, following the project's push/MR memory note. After the user confirms, add a CHANGELOG.md entry.
Critical files
- New:
docs/providers.md,docs/plans/2026-09-16-0841-provider-blueprint.md,docs/plans-executions/2026-09-16-0841-provider-blueprint.md - Edited:
docs/architecture.md(link),CLAUDE.md(link) - Read-only sources:
internal/provider/**,cmd/main.go,internal/controller,internal/gc,internal/providerhealth,docs/prompts/__initial-prompt.md,docs/kvm-provider.md,docs/gcp-vm-validation.md