Skip to content

docs(credits): the monthly refill is a floor, not an assignment - #300

Merged
sweetmantech merged 1 commit into
mainfrom
docs/credits-refill-is-a-floor
Aug 17, 2026
Merged

docs(credits): the monthly refill is a floor, not an assignment#300
sweetmantech merged 1 commit into
mainfrom
docs/credits-refill-is-a-floor

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Contract half of the refill fix in recoupable/chat#1960. Row 2 of that issue's PR matrix.

checkAndResetCredits SETs remaining_credits to the plan total once a monthly refill is due, rather than topping up to it. Any account holding more than its plan total is therefore cut on the next balance read. Measured on prod 2026-08-17: 119 accounts hold more than the 333 free-plan total, 50 of them with a reset already pending. Because the refill is lazy and read-triggered, the loss fires on a GET, so reading a balance is what destroys it.

Today's docs describe that reduction as intended behaviour and build a contract on top of it. This PR corrects the contract.

What changes

POST /api/admins/credits — the "A grant expires after one month, plan for it" paragraph is replaced. It told admins that a granted balance "is then silently overwritten on the first balance read after it" and to "grant it again" if the headroom needed to outlive a month. Once the refill cannot reduce a balance, that is false and actively causes admins to re-grant credits that do not need re-granting.

AdminGrantCreditsResponse.expires_at is removed (breaking, admin-only). The field's whole purpose was to report when the refill would destroy the grant. With a floor refill, it describes an event that never happens. required drops from 8 fields to 7.

credits.mdx — new ### Monthly refill subsection under ## Subscription, stating the floor rule and that the refill is lazy and read-triggered.

Verification

  • api-reference/openapi/accounts.json parses after editing; AdminGrantCreditsResponse now reports required: [status, grant_id, account_id, remaining_credits, previous_credits, reason, granted_by, granted_at] and the same 7 properties plus status, with no expires_at in either.
  • grep -n "expires_at" api-reference/openapi/accounts.json returns nothing.
  • Edits were made as anchored text edits, not a json.load/json.dumps round-trip: accounts.json does not round-trip byte-for-byte (it stores non-ASCII as \uXXXX escapes), so a rewrite would have produced a 200-line whitespace diff.
  • Deliberately does not touch credits.mdx line 44, which docs#299 edits, so the two docs PRs merge in any order without conflict. They touch disjoint regions of accounts.json (card-on-file and the auto-recharge path vs. the admin grant block).

Merge order

Merge this after the api refill fix reaches prod (row 5 of chat#1960), not before. It is the one place the docs-first convention inverts: until the api change ships, a refill still reduces balances, and publishing the floor rule early would document behaviour prod does not have. The POST /api/admins/credits half additionally needs the api PR that stops returning expires_at (row 6).


Summary by cubic

Clarifies that the monthly credit refill is a floor, not an assignment, and updates docs to match. Previously, refills overwrote balances to the plan total on the next read and grants above the plan total were cut; now refills only top up and never reduce, so grants do not “expire.”

Rollout and migration

  • OpenAPI: AdminGrantCreditsResponse removes expires_at (breaking, admin-only). Update admin tools and automation to stop reading or relying on expires_at.
  • POST /api/admins/credits description now states that refills never reduce balances; the “grant expires after one month” guidance is removed.
  • credits.mdx: adds “Monthly refill” subsection explaining the floor rule and that the refill is lazy and read-triggered.
  • Merge only after the API refill fix is live in production; merging earlier would document behavior prod does not yet have.

Written for commit 940e4bd. Summary will update on new commits.

Review in cubic

The monthly credit refill SETs remaining_credits to the plan total, so any
account holding more than its plan total is cut on the next balance read
(recoupable/chat#1960, 50 accounts currently in that state). The api fix
makes the refill a floor. This is the contract half.

- POST /api/admins/credits: replace the "A grant expires after one month"
  paragraph, which described the reduction as intended behaviour, and drop
  `expires_at` from AdminGrantCreditsResponse. A grant can no longer be
  reduced by a refill, so there is nothing to expire.
- credits.mdx: add a "Monthly refill" subsection stating the floor rule and
  that the refill is lazy and read-triggered.

Merge after the api refill fix, not before: until that ships, a refill still
reduces balances and this page would under-promise the old behaviour.
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 2 files

Re-trigger cubic

@sweetmantech

Copy link
Copy Markdown
Collaborator Author

Preview verification — local Mintlify dev server

Same method as docs#299's pass: local mintlify dev, driven with Chrome DevTools MCP at 1440×900. One difference in setup: since #299 has now merged, this branch's base (b10eecf) is behind main, so I tested the local merge of this branch onto current main (0b450e5) rather than the branch alone — that is what will actually ship. The merge is clean (GitHub also reports mergeable_state: clean); the two PRs touch disjoint regions of accounts.json and credits.mdx as intended.

Documented vs actual

# Check Documented intent Actual
1 credits.mdx new section ### Monthly refill under ## Subscription Renders between the tier table and ### Upgrade to Pro; page TOC shows Subscription → Monthly refill → Upgrade to Pro …
2 Floor rule stated "floor, not an assignment", never lowers, lazy/read-triggered All three present in the rendered prose
3 In-section links #one-time-top-ups anchor + credits-get page link Both resolve (anchor target exists; page fetch 200)
4 Grant endpoint description "A grant expires after one month" paragraph replaced Page text contains A grant is never reduced by the monthly refill, and 0 occurrences of expires after one month or silently overwritten
5 expires_at removed from response Gone from schema + generated example expires_at appears nowhere on the page. The generated 200 example is exactly the 8-field shape: status, grant_id, account_id, remaining_credits, previous_credits, reason, granted_by, granted_at
6 No regression on #299 content billingUrl intact, no checkoutUrl/auto-recharge resurrected by the merge /credits on the merged tree: billingUrl present, checkoutUrl 0, auto-recharge 0
7 Links + console Clean 4/4 internal links on the grant page 200; 0 console errors on both pages

Screenshots

1. ### Monthly refill — new subsection with its TOC entry nested under Subscription.

Monthly refill section

2. Grant endpoint — the replacement paragraph, and the generated 200 example ending at granted_at with no expires_at.

Grant page without expiry

Merge order reminder — this one waits

Unlike #299, do not merge this on the back of a green preview. This PR documents behaviour the api does not have yet: prod's refill still SETs the plan total, and POST /api/admins/credits still returns expires_at. It merges after api#837 and api#838 are live on prod — it is the one deliberate inversion of docs-first in chat#1960's sequencing.

@sweetmantech
sweetmantech merged commit 2107f8b into main Aug 17, 2026
3 checks passed
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.

1 participant