Skip to content

feat: core API — registry, capabilities, plans, Apply and retries - #2

Merged
imanimanyara merged 4 commits into
mainfrom
feat/core
Nov 3, 2026
Merged

imanimanyara merged 4 commits into
mainfrom
feat/core

Conversation

@imanimanyara

Copy link
Copy Markdown
Member

Summary

Phase 1 ("Core") of cloudkit: the provider-independent API that every adapter and both consumers build on. Standard library only; every network call goes through the caller's Transport via NewHTTPClient.

  • Registry (C9). NewRegistry(Options, ...Factory), Open, Descriptors. Refuses a nil or default transport (C2), a missing credential source or logger (C5, C10), incomplete descriptors, empty or non-slug provider IDs, and duplicate IDs. No package-level state.
  • Client per Open. Egress guard outermost (C3, C4), then retries, then a per-request bearer token from the CredentialSource (C5), sent only to API hosts and never on a redirect, then the caller's round tripper.
  • Capabilities. Capability, Access (Allowed, Denied, Unknown), CapSet; an unknown capability counts as a write.
  • Plans (C6, C7). NewPlan with a SHA-256 digest over provider, account, changes, Loses and live state; plan ID derived from the digest; 15-minute PlanTTL. Registry.Apply with the Applier interface refuses an altered, expired or drifted plan (ErrConflict / PlanError) and a destroy without its names typed back (ErrConfirmationRequired), before any request.
  • Retries. RetryPolicy (zero value: 3 tries, jittered backoff, Retry-After up to 30 s); never resends a non-idempotent request after an ambiguous failure; RateLimitError after the budget.
  • Guards. Policy tests for context-first signatures (C10), no package-level client or registry (C9), and no shipped exported name removed. Every new guard was proven red by planting its defect.
  • Docs. Getting-started and architecture guides, CHANGELOG [Unreleased].

All phase 0 exported symbols and behaviour are unchanged. release.yml is untouched; no tag.

Test plan

  • make ci (fmt-check, vet, race tests, policy) green locally
  • make lint (golangci-lint v2.15.0): 0 issues
  • A fake provider exercises create, destroy, drift, altered plans, unsupported providers, read-only tokens, redaction and every retry path

Phase 1 of the plan. The caller builds a Registry from Options and one
Factory per provider (C9); NewRegistry refuses invalid options, incomplete
descriptors, empty or non-slug IDs and duplicate IDs. Each Open hands the
adapter a fresh client: egress guard outermost, then retries, then a
per-request token that goes only to API hosts and never on a redirect, then
the caller's round tripper (C1, C3, C4, C5).

Every write is a Plan whose digest covers the provider, account, changes,
what a destroy loses and the live state. Apply refuses an altered or expired
plan and a plan whose live state moved (C6), and a destroy whose names were
not typed back (C7), before anything is sent.

A fake provider in the tests reaches its API only through the client it is
given and exercises every path.
…surface

Three policy tests read the package's syntax: every interface method, *Registry method and exported function field takes a context.Context first (C10); no package-level http.Client or Registry exists (C9); and no exported name the package has shipped disappears, so a removal has to be a deprecation instead. Each counts what it inspected and fails below a floor.
The getting-started guide covers building a registry, credentials, opening a provider, capabilities, plans, Apply and its refusals, and retries. The architecture guide explains the plan digest and the client's layering. CHANGELOG [Unreleased] lists the new API.
@imanimanyara
imanimanyara marked this pull request as ready for review November 3, 2026 13:29
Copilot AI balanced review requested due to automatic review settings November 3, 2026 13:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Every job skips drafts, and the pull_request trigger had no
ready_for_review type, so a PR opened as a draft and then marked ready
reported its required checks as skipped, which the branch ruleset counts
as passing. The policy test now fails when ci.yml skips drafts without
listing ready_for_review; proven red by removing the type.
@imanimanyara
imanimanyara merged commit 42cc64f into main Nov 3, 2026
8 checks passed
@imanimanyara
imanimanyara deleted the feat/core branch November 7, 2026 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants