feat(providers): registries + Cloudflare + onboarding tooling (+ Stripe Projects snapshots)#4
Merged
Merged
Conversation
The `stripe projects` plugin is versioned independently of the Stripe CLI and ships no changelog. Pin it and snapshot its surface so upgrades are reproducible and their git diff is the changelog: - plugin-version.txt, command-surface.txt, catalog.json — committed snapshots regenerated by one bless path (refresh_blesses_snapshots, gated on STRIPE_PROJECTS_REFRESH=1), reusing the typed driver + drift_report(); refuses to write on unmodeled catalog drift. - Enforced automatically, no manual ritual: fixtures_are_coherent runs offline on every PR (in `mise run test`); prek pre-commit/pre-push hooks auto-wired by `mise install`; smoke.yml gates the pinned surface against the live plugin; stripe-projects-watch.yml opens an upgrade PR nightly when upstream changes. clap was rejected for the refresh (mise + a bless-test fits the repo's conventions); both existing shell scripts stay shell. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ling
Make adding a Stripe-Projects-backed provider a one-registration-site change,
prove it by adding Cloudflare, and build tooling so the next provider is
frictionless.
Foundation (core never names a provider):
- Replace the `Host` enum with a binary-owned substrate registry
(`stackless/src/substrates.rs`); core takes the known-substrate list as input.
- Fold `spend_line`/`fetch_logs` into the `Substrate` trait (fixes Vercel
inheriting bogus local-file logs); move `RENDER_*`/`VERCEL_*` error codes into
the provider crates with a workspace-wide uniqueness test.
- Registry-driven integration dispatch via a `ProviderOps` object (no more
`match provider` / `is_clerk_resource`).
- New `stackless-cloud` crate: shared credential resolution + operator prepare
(de-duplicates the verbatim render/vercel copies).
Generalized resolution + Cloudflare:
- Generic `CatalogResource` trait + shared `provision_outputs` (handles Stripe's
dual `{RESOURCE}_X` / `{PROVIDER}_X` env-var naming); Clerk's single-blob path
stays the documented exception.
- Cloudflare catalog integrations: r2, kv, d1, queues, hyperdrive, workers,
workers-ai, browser-run (live-pinned envelopes; containers/registrar excluded
as paid/unknown-cost / non-disposable).
Onboarding tooling + tests:
- New `xtask` crate: `catalog` (offline schema explorer), `discover` (live
output-envelope pinning), `new-integration` (scaffold from catalog schema).
- Shared `test_support::provision_script` harness + a registry-completeness test.
- One shared `fixtures/smoke/run.sh` (always tears down, unique per-run names),
fixing the latent vercel/render down-skip-on-failure bug.
- Docs: `docs/ADDING-A-PROVIDER.md` (workflow + gotchas) and a root `CLAUDE.md`
indexing the project docs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This branch began as the Stripe Projects plugin snapshot/pinning framework and grew into a provider-extensibility refactor that makes adding a provider a one-registration-site change — proven by adding Cloudflare — plus the tooling to make the next provider frictionless.
72 files changed; the two parts are independent and each green on their own.
Part 1 — Provider extensibility, Cloudflare, and onboarding tooling
Foundation — core never names a provider
Hostenum with a binary-owned substrate registry (stackless/src/substrates.rs);stackless-coretakes the known-substrate list as input and names no provider.spend_line/fetch_logsinto theSubstratetrait —commands.rsno longer special-cases providers, and this fixes Vercel inheriting bogus local-file logs.RENDER_*/VERCEL_*error codes out of core into their provider crates, with a workspace-wide code-uniqueness test.ProviderOpsobject — no morematch provider/is_clerk_resource.stackless-cloudcrate: shared credential resolution + operator prepare (de-duplicates the verbatim render/vercel copies).Generalized resolution + Cloudflare
CatalogResourcetrait + sharedprovision_outputs, handling Stripe's dual{RESOURCE}_X/{PROVIDER}_Xenv-var naming. Clerk's single-JSON-blob path stays the documented exception.containers(paid / "pricing unavailable" = unknown cost),registrar:domain(one-time non-refundable purchase),workers:free|paid(plans). The Workers deploy substrate (--on cloudflare) is a separate future build.Onboarding tooling + tests
xtaskcrate →mise run catalog | discover | new-integration:catalog <provider>— offline schema/pricing explorer.discover <reference>— live: provisions into a throwaway env, dumps the real credential output env vars (the envelope the catalog doesn't describe), tears down.new-integration <reference>— scaffolds a provider module from the catalog schema.test_support::provision_scriptharness (collapses each provision test to ~5 lines) + a registry-completeness test.fixtures/smoke/run.sh(always tears down, unique per-run instance names) replacing three duplicated tasks — fixes the latent vercel/render down-skip-on-failure bug.docs/ADDING-A-PROVIDER.md(workflow + hard-won gotchas) and a rootCLAUDE.mdindexing the project docs.Net: adding a provider is now
catalog → new-integration → discover → paste fields + one PROVIDERS/SUBSTRATES row.Part 2 — Stripe Projects plugin snapshots
The
stripe projectsplugin is versioned independently of the Stripe CLI (v0.19.0), ships no per-version changelog, and every release is0.MINOR.0(breaking-eligible). Three committed snapshots undercrates/stackless-stripe-projects/tests/fixtures/whosegit diffis the changelog Stripe doesn't publish:plugin-version.txt— the pinned version of record (CI installs exactly this).command-surface.txt— everystripe projectssubcommand's--help; added/removed/renamed commands & flags show as line diffs.catalog.json— re-blessed/canonicalized; server-sidelast_updatednormalized so it only diffs on real service/schema changes.One bless path generates all three —
refresh_blesses_snapshots(gated onSTRIPE_PROJECTS_REFRESH=1), reusingStripeProjects/TokioRunner/drift_report(). It refuses to write if the live catalog has wire-format the typed model can't cover.Enforcement — no manual ritual:
mise run test(every PR) +prekhooksfixtures_are_coherent: header==pin, blocks==code'sTRAVERSAL, every banner command capturedsmoke.yml(nightly)stripe-projects-watch.yml(nightly)No
STRIPE_API_KEYneeded for snapshots (--version,--help,catalog --jsonare unauthenticated).Verification
mise run check✅ · workspace tests 200 passed ✅ · pre-commit + pre-push gates green on push ✅ · Cloudflare R2/KV/D1/Workers/workers-ai/browser-run live-pinned end-to-end ✅ · snapshot bless idempotent (byte-identical re-bless) ✅Setup needed before merge
GH_PATrepo secret (repo scope) so the snapshot watcher's auto-PR re-triggersci.yml(PRs from the defaultGITHUB_TOKENdon't). Falls back toGITHUB_TOKENif absent.🤖 Generated with Claude Code