Repository navigation
Conversation
…token An org's PlanetScale spend is read from its invoices: one list of invoices, then one line-item read per month. An invoice is a month, so each line item is spread evenly over the days of the month on which its branch existed, and a prorated discount line nets into the same day, database, branch and SKU as its charge. The database is the service, the SKU the usage type, the branch the resource. The open month's invoice is listed and its lines already carry the whole month, so its days so far are a share of it, marked as not final. The org saves a service token (its ID and the token) and the organization's name through PUT /internal/cost/planetscale. Maple checks it with PlanetScale first: the invoice list, then the newest invoice's line items, the two reads a pull makes. The pair is stored sealed in cost_connections as the Authorization header PlanetScale takes, and the organization is the source's account. A replacement must be for the same organization, and makes a failing source due again. PlanetScale answers 404 for a token it does not know as well as for an organization the token cannot see, so that refusal names both, on save and on a pull. A token without invoice access is told which access to add. The sync profile reads twelve months back and through today. No migration: the provider joins COST_CONNECTION_PROVIDERS and the shared reconcile.
… a late payment left open A day's share depends on every line of its month, so re-pulling only the last four days left the earlier days of the open month on the shares of an older pull until the weekly settle. A provider's profile now says what its head is, and PlanetScale's is the newest day's whole month, at no extra request. A month's days were not final for as long as its invoice was unpaid, and no pull comes back to a month after the tenth of the next one. An unpaid invoice whose month ended more than ten days ago is now written final. Listing invoices stops at a page holding one from wholly before the window, so an invoice that overlaps its neighbour is not missed. A blank amount is refused instead of read as zero. A month is capped at 5,000 line items, which the pull timeout leaves time to read.
…t/planetscale-source # Conflicts: # docs/cloud-cost-plan.md # packages/backend/src/services/cost/cost-connection-sources.ts
…page Add source lists PlanetScale. Its form asks for the organization and the service token's ID before the token: the shared credential step now takes the plain fields a provider declares before its credential, shown as typed, and hands them to the save with it. Nothing is sent until every field is filled, and a field too long for the request is refused in the dialog, naming which. Replacing the token starts the organization from the source that exists, since a replacement must be for the same one. The row in the list and the form's description say that PlanetScale days are a monthly invoice spread evenly over the days each branch ran. The sentence naming the providers whose requests are free listed three names with two ands. Provider names are now joined as a list, there and in the first-sync wait. The cost lab has PlanetScale in its fixture and a state for each dialog.
…s mark in the text colour The line under PlanetScale ended in an ellipsis before it said the invoices are spread over days. It is shorter now, and the form's description says the rest. The mark was drawn muted where the other one-colour mark is not.
…monthly invoice The form says it once, when the source is added. Beside the figures, where a flat line across a month needs explaining, the row now says it too.
…t/planetscale-source
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
This comment has been minimized.
This comment has been minimized.
… locks the organization A refusal can be about the organization, the token's ID or the token, but it stood under the token and marked that field wrong. With several fields it now stands under them all and marks none. On a replace the organization was editable, though only the source's own could be saved. It is shown, not asked. The token ID field named a description that was not on the page. A field's description is referenced only when it has one, and the token ID now says where PlanetScale shows it. The list line, the form and the source row say more plainly that a day is an even share of a month's invoice line.
This comment has been minimized.
This comment has been minimized.
…lls stopped over a month end Two cases left a closed month on what a pull saw while it was open. The head started at the new month on the first, so the closed month kept its last snapshot until the weekly settle: a branch deleted on the 30th after that day's pull showed its prorated discount up to a week late. A month head now covers the previous month too through the tenth. A settle after pulls had failed across a month end started at the previous month, saw no gap above the watermark, and never went back to the month before the watermark's, which the last settle had read before it closed. A settle of a month head now starts there when the last settle was before the eleventh of the watermark's month. Providers whose head is their trailing days plan as before.
…s not final A day is drawn lighter and counted in "not final yet" when any source marks it. PlanetScale marked every day of its unpaid month, so an org with another provider beside it saw nearly all its bars lighter all month, and a note that the last 28 days were not final. PlanetScale now marks today and yesterday only, as the other providers mark their newest days. That the open month's shares can move until the invoice closes is said on the source's row. The rule that wrote an unpaid month final after ten days has nothing left to decide and is gone, with the invoice's paid flag.
…t/planetscale-source
This comment has been minimized.
This comment has been minimized.
…t/planetscale-source # Conflicts: # apps/web/src/page/cost/view.ts
…page A PlanetScale account reads as "PlanetScale <organization>": the organization is a name its reader knows, so it stays in the label as an AWS account's number does. Its databases wear the PlanetScale mark in the table, the legend, the chips and the rail. A database's name is lowercase, where an AWS service's has a capital or a space, and it counts as PlanetScale's only where the org has that source: without one a lowercase service keeps the mark it had.
The web tracer puts a Command's arguments on its span, and its default policy exports any top-level argument whose name ends in Id. The save command took the token's ID as tokenId, so half of the stored credential would have been written to telemetry in clear on every save. The organization, the token's ID and the token now travel as one object argument, which the tracer never exports, and the ID is named tokenIdentifier inside it. A test runs every pasted-credential provider's save and remove command through the tracer on its default policy and finds no part of what was typed in the span's attributes. The scene tests follow the new argument, and gain the PlanetScale account's row on the reworked page: named by its organization, drilling into its databases.
This comment has been minimized.
This comment has been minimized.
…t/planetscale-source # Conflicts: # apps/web/src/page/cost/marks.test.ts # apps/web/src/page/cost/marks.ts
This comment has been minimized.
This comment has been minimized.
…ale's mark A plan or support line carries a capital or a space, so it fell through to the AWS logo in an org that reads only PlanetScale.
Maple review🟢 Confidence 10/10 · safe to merge. One info note on duplicated error mapping; the invoice spread, token flow, refusal mapping and replace path are all pinned by provider and connection tests. Adds PlanetScale as a cost source: invoices spread over the days each branch existed, a token-checked save/replace flow, the internal route and the Cost page wiring. Safe to merge. The
Findings🔵 Note · F2 ·
|
| 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.
d8ad880 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
…onnection A PlanetScale cost source no longer takes a pasted service token. It reads invoices with the OAuth grant of the PlanetScale integration the org already has: the source is a cost_sources row that points at the connection, with the connection's organization as its account. Adding makes the row, removing deletes it, and nothing is stored in cost_connections. The grant's own machinery fetches the access token: a 401 goes through its refresh, and a fresh token refused too stamps the grant revoked, after which no request is made. Maple's OAuth application now asks for the invoice scope. A grant made before that says so in its stored scopes, so a pull on it is held as not ready without a request, with "Reconnect PlanetScale to grant Maple access to invoices." A 403 from the API maps to the same. GET, PUT and DELETE /internal/cost/planetscale replace the token endpoints. An add reads one page of the invoice list first, refuses an organization other than the one connected, and answers a refusal only a reconnect fixes under its own code, so the page can link to the connection. The source follows the connection. Authorizing the same organization again keeps the source and makes it due at once, since the new grant may carry the scope. Binding another organization removes it, as does a disconnect, both in the connection's own transaction, and the sync removes one whose connection is gone or reads another organization. The invoice client, the spread and the sync profile are unchanged. The pasted-token service, its endpoints and PlanetScale's place among the pasted-credential providers are gone.
…org already has The dialog's PlanetScale step is no longer a form. It reads the org's PlanetScale connection and shows the organization with an Add source button. Nothing is typed. A connection authorized before Maple asked for invoices says to reconnect and links to the PlanetScale connection, an org with none is sent to connect it, and a refused add stays in the step with its reason, with the reconnect link only when a reconnect fixes it. The Sources row offers Manage connection and Remove, with no token to replace. Removing keeps the connection. The shared credential step is back to one field per provider: the plain fields before the secret and the locked organization are gone with their only user, as is PlanetScale's entry among the pasted-credential providers. The telemetry test covers the two providers that still paste a credential, and that no PlanetScale command carries one. The cost lab has a state for each face of the step. An audit entry for a cost source links to the Cost page.
… older grant needs
Stacked on #2541 (the Cloudflare cost source). It adds no migration. Retarget to
mainonce #2541 merges.What changed
PlanetScale is a cost source on
/cost, read through the PlanetScale integration the org already has. Nothing is pasted. Add source lists PlanetScale, its step shows the connected organization, and one click adds it. Maple then shows what PlanetScale invoices per database and branch.cost_sourcesrow that points at the org'splanetscale_connectionsrow, with the connection's organization as its account. Adding makes the row, removing deletes it. The connection itself is never changed from the Cost page.organization:read_invoicesis added to the default ofPLANETSCALE_OAUTH_SCOPES(it is ticked on Maple's OAuth application). A grant made before this lacks it. The stored grant records its scopes, so the page says "Reconnect PlanetScale to grant access to invoices" without a request, an add is refused under its own error code, and a pull is held as not ready. A 403 from the API reads the same.GET,PUTandDELETE /internal/cost/planetscale. An add reads one page of the invoice list first and names the organization the dialog showed: one bound since is refused. Audit entries arecost_source.createdandcost_source.deleted.Decisions worth a look
created/deleted, as on the GitHub cost source branch. The Vercel branch names themadded/removed: one of the two has to change when they meet.Verified
sync-plankeeps both month-end cases from review.cost.scene.test.tscovers each face of the step, the refused add with and without the reconnect link, the row and the removal.marks.test.ts,credential-tracing.test.tsand the lab fixture test pass (58 tests with the scene tests).credential-tracing.test.tsruns them through the web tracer on its default policy, and the two providers that still paste a credential export no part of it.domain,backend,apps/apiandapps/web. Lint is clean with the Effect config on the changed files. The anticipated-errors list is regenerated for the new error.read_invoices. Both closed months' daily rows add up to their line-item sums, and a window across two invoices reads both and fills every day.Not verified
read_invoicesin its scopes the way the stored scopes are read. If it reports none, the read decides.Screenshots
Lab states with synthetic data.
The PlanetScale step:
More of the page after: