Fully abstract: MUST/SHOULD/MAY rules with the caller behind each one, 19 behaviour-profile axes with stable codes, credential hygiene, testing obligations, the checklist and the contract's known limits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3.3 KiB
Execution: Split the provider blueprint into contract, appendix, template and index
Plan: docs/plans/2026-09-16-1108-provider-docs-split.md
- Step 0 — Save and commit the plan
- Step 1 — Write
docs/provider-contract.md - Step 2 — Write
docs/provider-spec-template.md - Step 3 — Write
docs/providers-existing.md - Step 4 — Rewrite
docs/providers.mdas the index; link edits - Step 5 — Verification sweep
- Step 6 — Final summary, CHANGELOG after confirmation
Step 0 — Save and commit the plan
Committed as cf89ac4 on the existing feat/provider-blueprint branch, on
its own, before any document work. The pre-existing local modification of
.claude/settings.json was left out of the commit.
Step 1 — Write docs/provider-contract.md
2026-09-16 11:17. Written from scratch rather than edited down from the old
blueprint, so that nothing provider-specific could survive by accident. Every
MUST names its caller by function (reconcileManaged, replaceInstance,
reconcileDelete, providerFailure, deletionFailure, Sweeper.sweep,
Monitor.checkOnce, Monitor.run, registry.Build) and states what breaks.
Axis codes frozen (19, §4.1 to §4.19): readiness, create-return,
delete-return, ip-source, gc-mark, created-at, list-partial,
quota, not-found, primary-key, provisioning-state, async-ops,
secondary-resources, credentials, client-kind, timeouts, logging,
child-spans, backend-test. The appendix table and the template are keyed
on these strings; the §4.20 summary table's last column gives the template
entry number each axis maps to.
Two rules that were not in the old blueprint, both found by reading the callers while verifying:
Sweeper.sweeploops providers sequentially in one goroutine, and no caller puts a deadline on the context (onlyMonitor.checkOnceusesWithTimeout). So a hungListByTagstalls orphan GC for every provider. Recorded in §1.5 and thetimeoutsaxis.- The Stopped branch of
reconcileManagedcallsDeleteand requeues without clearingProviderID, then deletes again on every poll until NotFound. A backend that reports a freshly created, never started instance as stopped would have it deleted right after creation. Recorded as a MUST in §2.2 and as theprovisioning-stateaxis with three allowed profiles.
Checks run on the draft (all clean):
grep -niE "kubernetes|gcp|kvm|libvirt|squid|google|compute engine" docs/provider-contract.md
grep -n "—" docs/provider-contract.md
grep -nE '\.go:[0-9]+|:[0-9]+-[0-9]+' docs/provider-contract.md
grep -ohE "(internal|cmd|config|docs|api|hack|test)/[A-Za-z0-9_./-]+" docs/provider-contract.md | sort -u | while read p; do test -e "$p" || echo "MISSING $p"; done
The path check reports three expected misses: config/samples/proxy_<type>.yaml
is a pattern, docs/provider-spec-template.md is written in Step 2, and
internal/provider/providertest is a proposal named in §13.
Worth noting: the contract refers to "the operator pod" and "the cluster's
own API" rather than naming the platform, so that the abstractness grep stays
meaningful. The hack/providers-dev.yaml rule is phrased as "only if the type
needs no credentials" because that file exists for make run-dev without any
Secret.