Add script to expire non-expiring free credits#1269
Conversation
introduce configurable concurrency for expire-free-credits via p-limit parse --concurrency, defaulting to 50 and validate values increase default batch size to 10000 for throughput create timestamped output and error log files under output/ log created file paths and active concurrency for visibility
…edits exclude categories from expiration to avoid expiring credits exclude list: orb_migration_accounting_adjustment, credits_expired custom, usage_issue, feedback
…category first Instead of scanning all users and filtering, the script now takes a mandatory --category=<name> arg and queries credit_transactions by category directly, then groups by user. Much faster for targeted runs.
…ry-based filtering
…n pairs - Replace --category param with embedded (category, description) pairs copied from the reviewed spreadsheet - Empty description matches NULL or empty, specific description matches exactly — handles same category with different descriptions - Expiry date is now 30 days from runtime instead of hardcoded - Add per-category breakdown in summary output - Improve progress logging clarity
ignore runtime artifacts produced by the Kilo agent in prettier
Code Review SummaryStatus: 1 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Fix these issues in Kilo Cloud Other Observations (not in diff)No carried-forward issues. The previously reported baseline-direction bug is resolved in the latest commit. Files Reviewed (2 files)
Reviewed by gpt-5.4-20260305 · 199,957 tokens |
markijbema
left a comment
There was a problem hiding this comment.
I mean i cant verify correctness just by reviewing. I think I'd write some tests or run on a copy of the database to verify first
Covers: fully/partially/unspent users, any-description matching, non-free exclusion, org-scoped exclusion, already-expiring exclusion, wrong description, mixed credits, multiple matching credits, zero-amount, existing next_credit_expiration_at LEAST, and multi-block projected expiration correctness.
… comment the code comment now uses EXPIRY_DATE instead of a fixed date to clarify runtime behavior and enable easier configuration of the expiry date used by the script
…cases Verifies that original_baseline_microdollars_used correctly determines whether free credits are covered by prior usage: free credits granted after spending are not covered and expire fully, while free credits granted before spending are covered and nothing expires.
…its across batches Uses a subquery to select the next N distinct user IDs, then fetches all matching credits for those users in a single query. Prevents the previous row-level pagination from skipping credits when a user's rows span a batch boundary. Test runs with --batch-size=1 to exercise this.
…Orb double-deductions When Orb clawed back spent free credits (reducing total_microdollars_acquired), the expiration simulation would still try to expire the full credit amount, pushing ~1,610 users into negative balance. Now boosts expiration baselines on newly-tagged credits so total expiration never exceeds the current balance.
- Add src/scripts/ to testPathIgnorePatterns (integration tests need POSTGRES_SCRIPT_URL which isn't available in CI) - Replace non-null assertions with null checks / fallbacks
| id: t.id, | ||
| amount_microdollars: t.amount_microdollars, | ||
| expiration_baseline_microdollars_used: | ||
| (t.original_baseline_microdollars_used ?? 0) + (baselineBoosts.get(t.id) ?? 0), |
There was a problem hiding this comment.
CRITICAL: Baseline adjustment goes the wrong direction
computeExpiration() treats a larger expiration_baseline_microdollars_used as less of the credit having been consumed (usageEnd - baseline shrinks as the baseline rises). Adding the deficit here therefore increases the amount that expires instead of reducing it. In the new Orb clawback cases, 0 + 5 still expires the full $5, so the rerun can remain negative and the persisted baseline written below has the same problem.
…ve instead of boosting baselines Baseline boosting was wrong — increasing a credit's baseline shifts its claim window right, which *increases* expiration, not decreases it. With microdollars_used=0 (Orb users), no baseline prevents full expiration. New approach: simulate all expirations, compute headroom (balance minus existing expirations), then only set expiry on credits that fit within headroom. Credits that would cause over-expiration are skipped entirely.
| user_id: user.id, | ||
| next_credit_expiration_at: user.next_credit_expiration_at, | ||
| current_balance_microdollars: currentBalance, | ||
| projected_balance_microdollars: projectedBalance, |
There was a problem hiding this comment.
WARNING: Logged projected balance still includes skipped credits
projected_balance_microdollars is computed before creditsSkipped are removed from the plan. In the Orb clawback cases this field stays negative even though the script no longer tags those credits, so the JSONL audit output no longer matches the writes this run will actually make. Recompute the balance from creditsToExpire (or rerun the simulation with only those credits) before logging it.
Summary
d2026-03-18_expire-free-credits.tsscript that sets 30-day expiry dates on free, non-expiring credit transactions--executeto write changes; outputs JSONL log with per-user balances and projected expirations for rollbackTest plan
--executeflag