the clock= constructor param was stored (self._clock) but never read — the 429
retry_after wait uses asyncio.sleep directly. it was dead code, and the CLAUDE.md
wrongly claimed it made 429 timing test-controllable. remove the param + the unused
time import, and correct the doc (tests patch commons.retry's sleep + sender.asyncio
.sleep, not a clock seam). bump the commons pin to v0.2.1 (retry attempts floor).
verified: clock param gone, constructs fine, 18/18 fix harness intact.
Signed-off-by: disqualifier <dev@disqualifier.me>
- seam bug: _burn/get() only caught ProxiesExhaustedError, but aioproxies.burn()
raises ValueError ('proxy not in pool') which escaped send() and broke the
'never raises on send failure' contract. catch ANY exception across the
duck-typed provider seam and convert to a failed WebhookResult.
- 5xx hot loop: 5xx retries had no backoff (immediate retry, hammering the
endpoint). migrate 429/5xx retry onto commons.aretry (>=0.2.0) for correct
exponential backoff + cap.
- lost response: exhausted retries returned a synthetic status-0 result; now the
real last 4xx/5xx status + body is returned (aretry re-raises the carried
_Retryable, the loop unwraps it).
verified by execution: burn/get ValueError no longer escapes, 5xx backs off
(~1.9s over 3 retries vs ~0s hot loop), exhausted 5xx returns real 503 + body,
429 retry_after honored, 4xx/rotation/round-robin intact.
Signed-off-by: disqualifier <dev@disqualifier.me>