Skip to content

Hand a dropping meter's block back under the registry lock - #13

Merged
alexy merged 1 commit into
mainfrom
fix/meter-drop-window
Sep 20, 2026
Merged

alexy merged 1 commit into
mainfrom
fix/meter-drop-window

Conversation

@alexy

@alexy alexy commented Sep 20, 2026

Copy link
Copy Markdown
Member

Fixes a spurious BudgetExceeded that PR #11's CI run hit once in two hundred rounds of many_meters_racing_for_the_last_of_a_budget_that_exactly_fits. The defect is on main, from my own exclusion fix in #10 (cec897f), which covered admission and refusal and missed the drop.

Cause. release_meter emptied the meter's balance and refunded it, and only then took the registry lock to deregister. Between the two steps the dropping meter's unspent block was in no balance and still in the shared counter, under no lock. A refusal is exact only if every admitted, unspent unit can be found, and in that moment one could not.

Fix. Take the registry exclusively first; empty, refund and deregister under it. I re-audited every transition that moves units between the counter and a balance; this was the only one outside the lock.

Test. a_meter_dropping_its_block_does_not_hide_it_from_a_refusal: fifteen threads create, charge and drop meters continuously while one spends down a budget equal to all the work. On main: 9 of 30 release runs fail. With the fix: 0 of 120, and 0 of 150 for the three existing racing tests with all cores saturated by other processes, which is the condition a CI runner is in and this laptop normally is not.

🤖 Generated with Claude Code

PR #11's CI run refused work that fitted once in two hundred rounds of
many_meters_racing_for_the_last_of_a_budget_that_exactly_fits, on code that
passed the same test twice before on CI and 360 times locally. release_meter
emptied the balance and refunded it before taking the registry, so for the
moment between those two steps a dropping meter's unspent block was in no
balance and still in the counter, outside any lock. A meter refused in that
moment could not reclaim it.

The hand-back now happens under the exclusive hold, with the deregistration.
A new contract test makes fifteen threads create, charge and drop meters
continuously while one spends the budget down: 9 of 30 release runs failed
before this change, 0 of 120 after, and 0 of 150 for the three racing tests
with every core of the host saturated by other work.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
alexy added a commit that referenced this pull request Sep 20, 2026
Documentation only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@alexy
alexy merged commit 0f64066 into main Sep 20, 2026
1 check 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