Skip to content

feat(cost): PlanetScale as a cost source, read through its integration - #2544

Open
Makisuo wants to merge 25 commits into
cost/cloudflare-sourcefrom
cost/planetscale-source
Open

Makisuo wants to merge 25 commits into
cost/cloudflare-sourcefrom
cost/planetscale-source

docs(cost): what a PlanetScale cost read does on a 401, and when a ne…

9ba0699
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review succeeded Nov 13, 2026 in 2m 8s

Confidence 10/10 · No issues found

🟢 Confidence 10/10 · safe to merge. Grant, tenancy and invoice-access paths each have behavioural tests, and the prior duplication is gone now the provider maps store errors through makeDbExecute.
no findings · tests covered · risk medium · 2/2 new units observable

Adds PlanetScale as a cost source read through the org's PlanetScale connection: provider, add/remove/status service, internal API and the Cost page step. Tests cover grant handling, org scoping and the dialog's four states. The open VcsWebhookEnqueueFailure errors are in apps/api/src/runtime/http-graph.ts, which this diff does not touch.

  • PlanetScaleCostProvider reads invoices through the org's grant, spreading each line over its branch's days
  • A cost read never stamps the shared PlanetScale grant revoked
  • Rebind and disconnect delete the org's PlanetScale cost sources in the connection's transaction
  • The Cost dialog's PlanetScale step reads status, adds and removes, with a refused add inline

Before merge

  • Manual · Confirm organization:read_invoices is ticked on Maple's PlanetScale OAuth application in every environment, not only prd

Fixed since the last review

  • ✅ F2 · toStoreFailure duplicates loadFailureOf's store-error mapping

Production impact

Open errors in the changed files (1)
Issue Service Occurrences File
@maple/api/routes/VcsWebhookEnqueueFailure (2 issues) maple-api 9 apps/api/src/runtime/http-graph.ts

After this merges, Maple checks whether they stop.

Production traffic of the changed files (last 7 days)
File Calls/day Busiest operations
packages/backend/src/services/auth/PlanetScaleOAuthService.ts 614 PlanetScaleOAuthService.withAccessToken 614/day, 0.0% err
packages/backend/src/services/cost/providers/planetscale/fake-planetscale.ts 330 POST /oauth/token 330/day, 0.0% err
packages/backend/src/services/cost/providers/planetscale/normalize.ts 183 branch 183/day, 0.5% err
Telemetry this change adds and removes (13)
  • ➕ span name HttpPlanetScaleCost.status · apps/api/src/routes/internal/planetscale-cost.http.ts:33
  • ➕ span name HttpPlanetScaleCost.add · apps/api/src/routes/internal/planetscale-cost.http.ts:47
  • ➕ span name HttpPlanetScaleCost.remove · apps/api/src/routes/internal/planetscale-cost.http.ts:61
  • ➕ span name CostSyncService.reconcilePlanetScale · packages/backend/src/services/cost/CostSyncService.ts:231
  • ➕ span name PlanetScaleCostSourceService.status · packages/backend/src/services/cost/PlanetScaleCostSourceService.ts:143
  • ➕ span name PlanetScaleCostSourceService.add · packages/backend/src/services/cost/PlanetScaleCostSourceService.ts:155
  • ➕ span name PlanetScaleCostSourceService.remove · packages/backend/src/services/cost/PlanetScaleCostSourceService.ts:222
  • ➕ attribute maple.cost.planetscale.error · packages/backend/src/services/cost/providers/planetscale/PlanetScaleCostProvider.ts:210
  • ➕ attribute maple.cost.planetscale.status · packages/backend/src/services/cost/providers/planetscale/PlanetScaleCostProvider.ts:211
  • ➕ attribute maple.cost.error_reason · packages/backend/src/services/cost/providers/planetscale/PlanetScaleCostProvider.ts:232
  • ➕ span name PlanetScaleCostProvider.read · packages/backend/src/services/cost/providers/planetscale/PlanetScaleCostProvider.ts:235
  • ➕ span name PlanetScaleCostProvider.check · packages/backend/src/services/cost/providers/planetscale/PlanetScaleCostProvider.ts:252
  • ➕ attribute maple.cost.planetscale.invoices · packages/backend/src/services/cost/providers/planetscale/pull.ts:54
What was checked
  • The pull refuses another org's, a missing or an unconfigured connection before any request (PlanetScaleCostProvider.test.ts:328)
  • withAccessToken is called with stampRevoked: false, so a 401 that outlives a refresh leaves the integration's grant intact
  • Reconcile deletes only planetscale sources whose connection is gone or reads another organization, and rebind/disconnect agree with it
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
PlanetScale invoice list and line-item reads outbound HTTP yes invoices-api.ts annotates peer.service: planetscale on the client span, inside Effect.fn("PlanetScaleCostProvider.read") with maple.cost.* attributes
Cost source add/remove/status and the sync's PlanetScale reconcile database yes makeDbExecute DB spans behind Effect.fn("PlanetScaleCostSourceService.*") and the sync's per-source span

9ba0699 · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.