The blueprint reduced tracing to "don't open per-operation spans", which reads as "nothing to do". Add an observability section: the operation spans the decorators give for free, the child spans per backend call a provider should add (parent-gated transport or a span decorator over the SDK seam), the ctx/logger rules that keep traceID on log lines, and the status per provider: kubernetes and gcp have child spans, kvm has none. Matrix rows, the checklist item, gaps and a kvm proposal follow suit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
129 lines
5.9 KiB
Markdown
129 lines
5.9 KiB
Markdown
# Execution: provider blueprint
|
|
Plan: [docs/plans/2026-09-16-0841-provider-blueprint.md](../plans/2026-09-16-0841-provider-blueprint.md)
|
|
|
|
- [x] Step 0 — Save the plan; wait for the merge
|
|
- [x] Step 1 — Collect evidence (read-only, in parallel)
|
|
- [x] Step 2 — Write `docs/providers.md`
|
|
- [x] Step 3 — Verify, then open the MR
|
|
|
|
## Step 0 — Save the plan; wait for the merge
|
|
|
|
The plan was committed on `feat/provider-health` (`80b2e9c`) and reached `main`
|
|
through PR #6. After the user confirmed the merge, the branch was cut from the
|
|
updated `main`:
|
|
|
|
```bash
|
|
git switch main && git pull --ff-only
|
|
git switch -c feat/provider-blueprint
|
|
```
|
|
|
|
Worth noting: `.claude/settings.json` has local, uncommitted permission edits
|
|
that carried over through the switch. They are deliberately left out of this
|
|
branch.
|
|
|
|
## Step 1 — Collect evidence (read-only, in parallel)
|
|
|
|
Three Explore agents answered the plan's 12-item questionnaire, one each for
|
|
kubernetes, gcp and kvm. Meanwhile I read the shared layer:
|
|
`internal/provider/*.go`, `registry.go`, the provider wiring in `cmd/main.go`,
|
|
`reconcileManaged`/`replaceInstance`/`reconcileDelete` in the controller,
|
|
`internal/gc/gc.go`, and how the monitor uses `Checker`.
|
|
|
|
Before relying on the agents' claims, I spot-checked them against the code. One
|
|
was wrong and did not go into the doc: the kvm agent said `Delete` skips volume
|
|
removal when `DomainDestroy` returns `ErrNoDomain`. In fact `removeDomain`
|
|
returns nil there, and `Delete` still calls `removeVolumes` afterwards
|
|
(`kvm.go:477-482`).
|
|
|
|
Rules that exist only in the callers, and not in any comment, were found by
|
|
reading the controller and GC. They went into the doc as MUST rules:
|
|
- A zero `CreatedAt` makes an instance immediately collectable (`gc.go:120`).
|
|
- `Get` returning `ErrPermanent` on the deletion path makes the reconciler call
|
|
`Delete` anyway.
|
|
- Replacement waits for `Get` to return NotFound before creating an instance
|
|
with the same name.
|
|
- `Stopped` and `Terminated` both lead to delete-and-recreate.
|
|
|
|
Worth noting, found outside this plan's scope and not changed here:
|
|
- `docs/gcp-vm-validation.md` filters on `labels.proxy-operator-managed=yes`,
|
|
but the value is `true`.
|
|
- According to the gcp agent, `docs/gcp-in-specific-project.md` holds a real
|
|
project ID, IAM output and an egress IP. The user was told.
|
|
|
|
## Step 2 — Write `docs/providers.md`
|
|
|
|
Wrote the eight sections the plan lists. Linked the new doc from the Provider
|
|
contract row in `docs/architecture.md` and from the CLAUDE.md "Architecture"
|
|
section.
|
|
|
|
Judgment calls:
|
|
- The file:line evidence sits in per-provider notes under the matrix, as
|
|
planned. The contract rules in §2 cite the reconciler and GC lines each rule
|
|
protects.
|
|
- The gap list includes documentation drift (kvm-provider.md's ARP order and
|
|
log keys, gcp-vm-validation.md's label value and its claim that async errors
|
|
reach status), as well as code gaps. Both would mislead the next
|
|
provider author in the same way.
|
|
- "Proposed features" stays a flat list with no design, as the user decided.
|
|
|
|
Worth noting: the line numbers in the doc are a snapshot. The doc says so and
|
|
asks readers to look for the named function when a line has moved.
|
|
|
|
## Step 3 — Verify, then open the MR
|
|
|
|
An Explore agent re-checked the doc against the code: about 150 claims,
|
|
including every matrix cell. It found four mismatches, and all four were fixed:
|
|
- **Startup dial:** I had listed kvm-provider.md's "connection kept open from
|
|
startup" as doc drift. It isn't: the pool dials lazily, but the provider
|
|
health monitor runs a check as soon as the leader starts
|
|
(`monitor.go:147`, default interval 1m), and that check opens the connection.
|
|
The bullet was removed and the kvm notes now say this.
|
|
- **Checker wording:** §5 said the monitor type-asserts `Checker`. It is
|
|
`cmd/main.go:216`; the monitor only sees nil or not.
|
|
- **Reasons, not conditions:** §3 called `QuotaExceeded` and `PermanentError`
|
|
conditions. They are reasons on `Provisioned`.
|
|
- **Latch lines:** the line range is `:133-139`, not `:130-135`.
|
|
|
|
It also noted that none of the providers assert `var _ provider.Provider`, and
|
|
that the kubernetes provider's RBAC markers live in the controller package. The
|
|
§7 checklist now says both.
|
|
|
|
Link check (every relative `](…)` target and anchor in the new and edited docs
|
|
resolves), then the sanity build:
|
|
|
|
```bash
|
|
go build ./... && go test -short ./...
|
|
# all packages ok
|
|
```
|
|
|
|
Worth noting: no CHANGELOG entry yet. Per CLAUDE.md it goes in after the user
|
|
confirms the doc.
|
|
|
|
### Follow-up — tracing was missing from the blueprint
|
|
|
|
The user pointed out, after the PR was opened, that the blueprint said almost
|
|
nothing about tracing. The plan's questionnaire item 10 had collected the
|
|
evidence, but the doc reduced it to a matrix row about logging and a checklist
|
|
line telling authors not to open spans. That line even suggests tracing needs
|
|
no work. A provider author needs the opposite message: the operation span comes
|
|
free, and child spans for backend calls are theirs to add.
|
|
|
|
Added a new §6, "Observability: tracing, logs and metrics", and renumbered the
|
|
matrix, checklist and gaps sections to §7–§9. It covers:
|
|
- **Three layers:** decorator operation spans; child spans per backend call,
|
|
with parent-gated HTTP transports or a span decorator over the SDK seam; and
|
|
logs.
|
|
- **The ctx and logger rules** that keep `traceID` on log lines.
|
|
- **A per-provider status table:**
|
|
- kubernetes: parent-gated `RestConfigWrapper` spans.
|
|
- gcp: the Google SDK's own `otelhttp`, never disabled by the provider.
|
|
- kvm: no spans. `trace.go` is a log decorator.
|
|
|
|
Also added two tracing rows to the §7 matrix, rewrote checklist item 8 as
|
|
"Tracing and logging" with an in-memory span-recorder test, and added gaps (kvm
|
|
has no child spans; only kubernetes is checked against Tempo, and only at
|
|
operation level). A proposal notes that the kvm `libvirtAPI` seam takes no
|
|
`ctx`, so per-RPC spans need that plumbed in.
|
|
|
|
The links were re-checked, including the new `architecture.md#10-tracing-internaltracing` anchor.
|