Reference solution
The findings below are ordered by priority.
Findings
1. Every caller can enter during the half-open probe
Location: src/circuit-breaker.ts:14-22
The first post-cooldown caller changes state to half-open, but the admission check handles only open. Every subsequent caller falls through and invokes the dependency while the probe is unresolved, turning one cautious probe into an unbounded recovery surge.
Reserve half-open ownership atomically for one caller and fail all other half-open admissions fast until that probe settles.
2. Stale completions can overwrite a newer breaker generation
Location: src/circuit-breaker.ts:23-39
Every admitted operation mutates the current state when it eventually settles. A slow success that began before another call opened the breaker can later close it, while a slow failure from an old generation can increment or trip a breaker already recovered by a probe.
Associate admission with a state generation and apply completion transitions only when that generation still owns them.
3. Uncounted errors change breaker health state
Location: src/circuit-breaker.ts:28-39
The catch path increments for every error and never calls isCountedFailure. In closed state, expected validation or caller errors can open the dependency circuit even though they say nothing about dependency health. In half-open state, an uncounted, inconclusive rejection is incorrectly treated as a failed health probe and reopens the circuit.
Classify the error before applying a health transition. Propagate an uncounted closed-state error without changing failures or state; for an uncounted half-open result, clear probe ownership but keep an idle half-open state so one later caller can perform the next probe.
4. Success does not reset the consecutive-failure count
Location: src/circuit-breaker.ts:23-27
The success branch closes state but leaves failures unchanged. Two failures, then a success, then one failure meet a threshold of three even though the final failure is only the first in a new consecutive sequence.
Reset the count on every valid closed-state success and on a successful half-open probe.
5. A counted failed probe reuses the expired cooldown timestamp
Location: src/circuit-breaker.ts:29-37
When open transitions to half-open, openedAt still contains the original trip time. A counted failed probe sets state back to open but refreshes the timestamp only when it is null, so the next caller sees an already elapsed cooldown and probes immediately again.
On every counted half-open failure, record a new trip time and begin a full cooldown.
Reasonable non-findings
- Failing open-state calls fast before invoking the operation is correct.
- Injecting the clock and failure classifier makes transition tests deterministic.
- Propagating the original operation error is appropriate for the single admitted probe or closed call.