Skip to content

feat(cost): Vercel as a cost source - #2542

Open
Makisuo wants to merge 9 commits into
mainfrom
cost/vercel-source
Open

Makisuo wants to merge 9 commits into
mainfrom
cost/vercel-source

fix(cost): empty the cost on show when a source is removed, show the …

4c04724
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review succeeded Nov 13, 2026 in 2m 17s

Confidence 10/10 · No issues found

🟢 Confidence 10/10 · safe to merge. Every reviewed hunk is pinned by a test; what keeps this below 10 is the Vercel charges response shape, never run against a real team.
no findings · tests covered · risk high · 2/2 new units observable

Vercel becomes a cost source: an adapter streaming /v1/billing/charges, a source service behind cloudCost, and the Add/Remove plus group-by-resource wiring on /cost. The reviewed hunks hold up. The two VcsWebhookEnqueueFailure errors are untouched — http-graph.ts only registers the new route.

  • VercelCostProvider streams charges and sums FOCUS lines per day/product/project/region
  • upsertWithSource releases the cost source on a same-team token swap, deletes it on a team change
  • cost-reads names a Vercel source from its connection's team slug
  • /cost gains a Vercel add step, a Remove row action and the resource dimension

Before merge

  • Manual · Send one GET /v1/billing/charges from a real Vercel team and confirm the JSONL fields BilledCost, ChargePeriodStart, ServiceName land

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/queries/cost-reads.ts 18 CostReads.sources 18/day, 0.0% err
Telemetry this change adds and removes (13)
  • ➕ span name HttpVercelCost.status · apps/api/src/routes/internal/vercel-cost.http.ts:33
  • ➕ span name HttpVercelCost.add · apps/api/src/routes/internal/vercel-cost.http.ts:47
  • ➕ span name HttpVercelCost.remove · apps/api/src/routes/internal/vercel-cost.http.ts:59
  • ➕ span name CostSyncService.reconcileVercel · packages/backend/src/services/cost/CostSyncService.ts:211
  • ➕ span name VercelCostSourceService.status · packages/backend/src/services/cost/VercelCostSourceService.ts:130
  • ➕ span name VercelCostSourceService.add · packages/backend/src/services/cost/VercelCostSourceService.ts:143
  • ➕ span name VercelCostSourceService.remove · packages/backend/src/services/cost/VercelCostSourceService.ts:214
  • ➕ span name VercelCostProvider.read · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:116
  • ➕ attribute maple.cost.vercel.error · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:166
  • ➕ attribute maple.cost.vercel.status · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:167
  • ➕ attribute maple.cost.vercel.detail · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:168
  • ➕ attribute maple.cost.vercel.charge_groups · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:187
  • ➕ attribute maple.cost.error_reason · packages/backend/src/services/cost/providers/vercel/VercelCostProvider.ts:192
What was checked
  • cost_sources_org_provider_ref_idx on (orgId, provider, connectionRef) makes onConflictDoNothing cover a double add
  • Team change is decided from the row locked with forShare inside the transaction (VercelIntegrationService.ts:1236)
  • integration_connection_changed is the code the API emits, so the add dialog's re-read branch fires
Observability coverage: 2 of 2 changes observable
Change Kind Observable Evidence
Vercel charges read (outbound HTTP, streamed) client yes peer.service annotated on the request spans in providers/vercel/VercelCostProvider.ts, as call does
GET/PUT/DELETE /internal/cost/vercel server yes HttpVercelCostLive registered beside the instrumented OpenRouter cost routes (http-graph.ts:172)

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