From 960469db33f8419c91c56301da5465d0a0964732 Mon Sep 17 00:00:00 2001 From: ledger Date: Wed, 28 Oct 2026 14:14:46 +0000 Subject: [PATCH] beam: token_bucket blocking cell measures from the refill origin WHY: test_acquire_blocks_and_returns took t0 after the drain, so the cell timed only the part of the 0.05 s refill that happened after the scheduler returned to it. Observed red in a loaded full-suite run at 7c36185: 'assert 0.03909331373870373 >= 0.04' -- 10.9 ms of untimed prefix. Deterministic repro: pre-fix cell + 11 ms injected gap -> 0.03897/0.03912, rc 1. FIX: t0 now precedes try_acquire(1.0), which is where the bucket sets _last, so dt is >= 0.05 by construction (acquire cannot return before the refill origin is 1/rate old) and the 0.04 floor has ~10 ms of margin instead of 1 ms. MEASURED: repo cell 9 passed; pre control rc 1 dt 0.03897-0.03912; post control rc 0; same-gap in-process dt pre 0.039119 / post 0.050253; non-blocking-acquire mutant rc 1 (2 failed: blocks + timeout cells); controls/post 15/15 green under 4-CPU saturation; bash wizard-work/beam/CHECK rc 0 twice, 423 passed / 2007 subtests. CHECK: python3 /root/.hermes/wizard-outputs/volt/2026-10-28-q122/verify.py --- wizard-work/beam/test_token_bucket.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/wizard-work/beam/test_token_bucket.py b/wizard-work/beam/test_token_bucket.py index 1612d8e..3e54748 100644 --- a/wizard-work/beam/test_token_bucket.py +++ b/wizard-work/beam/test_token_bucket.py @@ -21,12 +21,20 @@ def test_capacity_cap(): def test_acquire_blocks_and_returns(): b = TokenBucket(rate=20.0, capacity=1.0) - b.try_acquire(1.0) # drain + # t0 must precede the drain: try_acquire() debits the last token and sets + # the refill origin (self._last) inside the call, so a t0 taken after it + # silently subtracts whatever the scheduler spent in between. Observed at + # 7c36185 as `assert 0.03909331373870373 >= 0.04` in a loaded full-suite + # run: ~10.9 ms of scheduler gap, i.e. 0.05 s of withheld tokens minus a + # prefix the cell never measured. dt from before the drain is >= 0.05 by + # construction (acquire cannot return until the refill origin is 0.05 s + # old), so the 0.04 floor has margin instead of sitting 1 ms from the edge. t0 = time.monotonic() + b.try_acquire(1.0) # drain; sets the refill origin ok = b.acquire(1.0, timeout=0.2) dt = time.monotonic() - t0 assert ok is True - assert dt >= 0.04 # had to wait ~0.05s for 1 token at 20/s + assert dt >= 0.04 # 1 token at 20/s = 0.05s withheld, measured from the origin def test_n_exceeds_capacity_raises():