# Task 3 — Wire ExecutionCircuitBreaker **Priority:** HIGH **Estimated time:** 1.5–2 hours **Depends on:** Task 1 (NT8StrategyBase changes) **Status:** TODO --- ## Problem `ExecutionCircuitBreaker` in `src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` is a complete, well-tested class. It is never instantiated or connected to any live order flow. Orders are submitted regardless of latency or rejection conditions. --- ## What Needs to Change ### File: `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` **Step 1:** Add `ExecutionCircuitBreaker` as a field on `NT8StrategyBase`. ```csharp private ExecutionCircuitBreaker _circuitBreaker; ``` **Step 2:** Initialize it in `OnStateChange` → `State.DataLoaded`: ```csharp // Use Microsoft.Extensions.Logging NullLogger for now (or wire to BasicLogger) _circuitBreaker = new ExecutionCircuitBreaker( new NullLogger(), failureThreshold: 3, timeout: TimeSpan.FromSeconds(30)); ``` **Step 3:** Gate ALL order submissions through the circuit breaker. In the method that calls `ExecuteIntent()` (or wherever orders flow from strategy intent to the adapter), add: ```csharp private bool TrySubmitIntent(StrategyIntent intent, StrategyContext context) { if (!_circuitBreaker.ShouldAllowOrder()) { var state = _circuitBreaker.GetState(); Print(string.Format("[NT8-SDK] Circuit breaker OPEN — order blocked. Reason: {0}", state.Reason)); return false; } try { _orderAdapter.ExecuteIntent(intent, context, _strategyConfig); _circuitBreaker.OnSuccess(); return true; } catch (Exception ex) { _circuitBreaker.OnFailure(); _circuitBreaker.RecordOrderRejection(ex.Message); Print(string.Format("[NT8-SDK] Order execution failed: {0}", ex.Message)); return false; } } ``` **Step 4:** Wire `OnOrderUpdate` rejections back to the circuit breaker. In `NT8StrategyBase.OnOrderUpdate()`: ```csharp protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError) { if (orderState == OrderState.Rejected) { if (_circuitBreaker != null) { _circuitBreaker.RecordOrderRejection( string.Format("NT8 rejected order: {0} {1}", error, nativeError)); } } // Pass through to adapter for state tracking if (_orderAdapter != null) { _orderAdapter.OnOrderUpdate( order != null ? order.Name : "unknown", limitPrice, stopPrice, quantity, filled, averageFillPrice, orderState != null ? orderState.ToString() : "unknown", time, error.ToString(), nativeError ?? string.Empty); } } ``` --- ## Acceptance Criteria - [ ] `ExecutionCircuitBreaker` is instantiated in `NT8StrategyBase` - [ ] All order submissions go through `_circuitBreaker.ShouldAllowOrder()` — if false, order is blocked and logged - [ ] NT8 order rejections call `_circuitBreaker.RecordOrderRejection()` - [ ] 3 consecutive rejections open the circuit breaker (blocks further orders for 30 seconds) - [ ] After 30 seconds, circuit breaker enters half-open and allows one test order - [ ] `verify-build.bat` passes --- ## Files to Modify | File | Action | |---|---| | `src/NT8.Adapters/Strategies/NT8StrategyBase.cs` | Add circuit breaker field, initialize, gate submissions, wire rejections | ## Files to NOT Change - `src/NT8.Core/Execution/ExecutionCircuitBreaker.cs` — complete and correct, do not touch - Any test files