The verdict model
The verdict model
One settled call, read differently by each policy. This table is the design:
| Outcome | Verdict | Breaker | Retry |
|---|---|---|---|
200 fast | success | healthy | done |
200 in 9 s | success | counts toward slow-rate | done |
404, 422 | answered | healthy | never |
429, 503 | overload | healthy | after Retry-After |
500, ECONNRESET, unlabelled | transient | failure | yes |
| our deadline elapsed | timeout | failure | once |
| we refused it | rejected | ignored | no |
That last row matters more than it looks. Our own shedding must never be recorded as evidence about the upstream — without it, an open breaker observes its own rejections and can never close.
Four ways to be refused
Every rejection arrives as RejectedError.reason and on the onRejection observer hook, so "why was I refused?" always has an answer.
| Refused by | reason | Means |
|---|---|---|
| breaker | circuit-open | the upstream looks wholly down |
| limiter | limiter-full | too many in flight for current latency |
| throttler | throttled | too many recent attempts were not accepted |
| bulkhead | bulkhead-full | a hard concurrency cap you configured |
| rate limiter | rate-limited | a fixed rate you configured |
| budget | budget-exceeded | the retry was refused; the first attempt was not |
| priority | shed-by-priority | lower-criticality work, shed under load |
| fairness | unfair-share | this tenant is furthest above its share |
The rule that follows from it
A policy may never learn anything from a call it did not make.
When resilix refuses a call, nothing was learned about the upstream — it was never contacted. The rejected verdict carries exactly that, and it has two halves that pull in opposite directions: as evidence it is ignored everywhere, and as bookkeeping it is always delivered, so a policy that reserved a slot still releases it.
This has been violated five times during development, always with the same shape: the two halves ran at different points in the call lifecycle and a rejection slipped into the gap. It is now enforced mechanically rather than remembered — see ADR-007.