Skip to content

feat(scripts): expire internal team free credits#4279

Open
iscekic wants to merge 1 commit into
mainfrom
chore/expire-free-credits
Open

feat(scripts): expire internal team free credits#4279
iscekic wants to merge 1 commit into
mainfrom
chore/expire-free-credits

Conversation

@iscekic

@iscekic iscekic commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

What

One-off maintenance script (apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts) that expires free credit grants belonging to internal team accounts.

Selection

Users whose kilocode_users.google_user_email ends in @kilocode.ai or @kilo.ai (case-insensitive suffix match, so it's independent of the nullable backfilled email_domain column). Per matched user, the affected set is every credit transaction that is:

  • is_free = true
  • organization_id IS NULL (personal)
  • amount_microdollars > 0 (a grant, not an adjustment/expiration row)
  • not already expired (no credits_expired / orb_credit_expired / orb_credit_voided record referencing it)

This includes grants with or without an existing expiry_date.

Behavior

For each affected grant, set expiry_date = now and expire it through processLocalExpirations(), so balance accounting matches the production expiration cron exactly:

  • Fully-spent grants expire $0 → effectively left untouched.
  • Partially-spent grants expire only their unspent remainder.

If expiring a user's grants drives their balance below zero (e.g. spend previously clawed back via total_microdollars_acquired), a one-off accounting_adjustment credit (is_free, positive) restores the balance to exactly $0. No user ends negative.

Mechanics

  • Dry run by default; --execute performs writes. --yes skips the confirmation prompt; --batch-size / --concurrency tunable.
  • Emits a per-user JSONL log, a mutation log (for rollback), and an error log under src/scripts/output/.
  • No schema changes. Reuses computeExpiration / processLocalExpirations from @/lib/creditExpiration.

Notes

  • The corrective accounting_adjustment is itself a free, non-expiring credit, so re-running the script would re-target it. Intended as a one-off.

Add a one-off script that expires every free, personal, positive credit
grant (with or without an existing expiry date) for users whose email
ends in @kilocode.ai or @kilo.ai.

Each targeted grant is tagged with expiry_date = now and expired via
processLocalExpirations, so the accounting matches the production
expiration cron. Fully-spent grants expire $0 (no-op); partially-spent
grants expire their unspent remainder. If expiring a user's grants would
drive their balance negative, a one-off accounting_adjustment credit
restores the balance to exactly $0.

Dry run by default; --execute performs writes. Emits per-user JSONL,
a mutation log, and an error log.
@iscekic iscekic self-assigned this Jun 26, 2026
Comment thread apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts
Comment thread apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts
@kilo-code-bot

kilo-code-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts 248 Execute mode can stamp grants as expired before the optimistic-lock-protected expiration pass succeeds
apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts 282 The $0 repair can commit an accounting_adjustment even when the guarded user update matches zero rows
Files Reviewed (1 files)
  • apps/web/src/scripts/d2026-06-26_expire-internal-free-credits.ts - 2 issues

Reviewed by gpt-5.4-20260305 · Input: 77.3K · Output: 10.3K · Cached: 695.6K

Review guidance: REVIEW.md from base branch main

@iscekic iscekic enabled auto-merge (squash) June 26, 2026 11:29
@iscekic

iscekic commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Script already ran against prod. @pedroheyerdahl has run output details in Slack DMs.

@emilieschario

Copy link
Copy Markdown
Contributor

Approved in concept, DNR

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.

2 participants