CLOSED -> OPEN -> HALF_OPEN state machine around outbound calls to the
target API (REQ-2.3.3). Opens after failure_threshold consecutive
failures; after reset_timeout, lets one trial call through
(HALF_OPEN) to decide whether to close again or re-open.
CircuitBreaker::execute’s error type: either the breaker itself was
open (call never ran) or the wrapped call’s own error E propagated
through. Generic over E rather than folding into McpifyError the way
targets::typescript’s CircuitBreaker.execute folds every rejection
into a re-thrown unknown, since Rust’s Result makes losing the
original error type a real, avoidable cost here.