Public: anyone can read this; nobody can change it.
A run reserves its share of the account's daily ceiling when it starts, so runs started together cannot overshoot it. #52
Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.
**Problem.** Two runs that start together on one account can each spend the full per-run ceiling, so the account goes past its daily ceiling. With daily $1.50 and per-run $1.00, two runs at the same time were each handed a $1.00 budget ($2.00 in total).
shipped merged
Sign in to join this conversation.
Problem. Two runs that start together on one account can each spend the full per-run ceiling, so the account goes past its daily ceiling. With daily $1.50 and per-run $1.00, two runs at the same time were each handed a $1.00 budget ($2.00 in total).
Root cause.
checkCeilingread only the spend already inusage. A run that has started but has not spent yet counted as zero, so the next run saw the whole day as free.Fix.
run.ceiling_reserved_usd(migration20261017195831-ceiling-reserved).reserveCeilingreplacescheckCeiling. In one transaction it computes what is left of the day: the daily ceiling, less today's spend, less what the account's otherqueued/runningruns reserved and did not spend yet. It writes the run's cap (smaller of per-run, left, and the run's own wanted budget) to the run. This is the same pattern as the subscription budget (budget_reserved_usd).queued/running. Its real spend stays inusage.runner.tscomputes the wanted budget before the call and passes the run id. The live meter (dailyLeft) is not changed.Test.
test/account-ceiling-reserve.test.ts: crew concurrency 2, daily $1.50, per-run $1.00, two runs held running together. The sum of the two handed budgets must be ≤ $1.50. On main: fails (received $2.00). With the fix: passes (first run $1.00, second gets only what is left).test/account-budget.test.tsusesreserveCeiling.Validate (fast). Result: flaky, no new failure.
contain.test.tsandweb-editor.test.tsare baseline (red on main).following.test.tsfailed one time and passes alone; it is not red on main. tsc passes.