# Orchestration Layer

**Parent**: [/python/opendeviationbar/CLAUDE.md](/python/opendeviationbar/CLAUDE.md) | **Hub**: [/CLAUDE.md](/CLAUDE.md)

Connects Rust core → Python API → ClickHouse cache → plugins. Extracted from `__init__.py` in Issue #46 for modularity and testability.

---

## Files

| File                            | Responsibility                                                                  |
| ------------------------------- | ------------------------------------------------------------------------------- |
| `open_deviation_bars.py`        | Main entry: `get_open_deviation_bars()` — routing, segment iteration, ouroboros |
| `open_deviation_bars_cache.py`  | ClickHouse helpers: `try_cache_read`, `try_cache_write`, `fatal_cache_write`    |
| `open_deviation_bars_enrich.py` | Post-processing: exchange session flags, column filtering                       |
| `tick_fetcher.py`               | `fetch_ticks_with_backoff()` — shared adaptive backoff tick fetch loop          |
| `count_bounded.py`              | `get_n_open_deviation_bars()` — exact-N bars for ML training                    |
| `precompute.py`                 | `precompute_open_deviation_bars()` — batch precompute to ClickHouse             |
| `helpers.py`                    | Date parsing, source/market validation, binance fetch helpers                   |
| `models.py`                     | `PrecomputeProgress`, `PrecomputeResult` data classes                           |

---

## Request Flow: `get_open_deviation_bars()`

```
get_open_deviation_bars()
  │
  ├─ Symbol registry gate (validate_symbol_registered)
  ├─ Start-date clamping (validate_and_clamp_start_date)
  ├─ Threshold resolution (resolve_and_validate_threshold)
  ├─ Ouroboros mode resolution (get_operational_ouroboros_mode)
  │
  ├─ [long range >30 days] → ClickHouse required (MEM-013 guard)
  ├─ [streaming mode] → _stream_open_deviation_bars_binance()
  │
  ├─ Cache fast-path: try_cache_read() → return if HIT
  ├─ Storage init: TickStorage(cache_dir)
  ├─ has_ticks() check → cache or network
  │
  ├─ MEM-010: Pre-flight memory estimation (if cached)
  │
  └─ Ouroboros segment loop (iter_ouroboros_segments):
       ├─ reset_at_ouroboros() at each boundary (if applicable)
       ├─ Load segment ticks (cache or network fetch)
       ├─ _process_binance_trades() → OpenDeviationBarProcessor.process_trades()
       └─ Accumulate segment bars
  │
  ├─ Plugin enrichment (enrich_bars)
  ├─ try_cache_write() → ClickHouse
  └─ filter_output_columns() → return DataFrame
```

---

## ClickHouse Cache Helpers (`open_deviation_bars_cache.py`)

### Three Write Functions

| Function            | When Used                    | Failure Mode                                 |
| ------------------- | ---------------------------- | -------------------------------------------- |
| `try_cache_read`    | `get_open_deviation_bars()`  | Returns `None` on miss or connection error   |
| `try_cache_write`   | `get_open_deviation_bars()`  | **Non-fatal** — logs warning, does not raise |
| `fatal_cache_write` | `populate_cache_resumable()` | **Raises** `CacheWriteError` on any failure  |

`try_cache_write` is correct for the API path: computation succeeded, bars returned to caller even if caching fails. `fatal_cache_write` is required for the populate path: ClickHouse IS the destination, not an optional cache layer.

### Circuit Breaker (`_fatal_write_breaker`)

Module-level `CircuitBreaker` protecting `fatal_cache_write`:

- **Failure threshold**: 3 consecutive `CacheWriteError`s → OPEN
- **Recovery timeout**: 60 seconds (auto HALF_OPEN probe)
- **On OPEN**: Sends Telegram alert via `opendeviationbar.notify.telegram`
- **Thread-local connections**: Each worker thread reuses one `OpenDeviationBarCache` (avoids reconnect-per-INSERT overhead). Connection cleared on error to force reconnect.

### Accessing the Breaker State

```python
from opendeviationbar.orchestration.open_deviation_bars_cache import get_fatal_write_breaker
breaker = get_fatal_write_breaker()
print(breaker.state)  # CLOSED | OPEN | HALF_OPEN
```

The sidecar `/health` endpoint uses this to report `circuit_breaker: "open"` or `"closed"`.

---

## Tick Fetcher (`tick_fetcher.py`)

`fetch_ticks_with_backoff()` — shared by both `get_open_deviation_bars()` (date-bounded) and `count_bounded.py` (count-bounded):

1. Reads existing cached months from `TickStorage`
2. Fetches new months from Binance (Vision or REST)
3. Merges and deduplicates on `agg_trade_id`
4. Doubles lookback window each attempt until `target_ticks` are found
5. Safety limit: `max_lookback_days` prevents unbounded backoff

Returns `FetchResult(ticks, oldest_timestamp_ms, total_ticks)`.

---

## Count-Bounded API (`count_bounded.py`)

`get_n_open_deviation_bars(symbol, n_bars, threshold)` — for ML training:

- Works backwards from now until N complete bars are collected
- Uses `fetch_ticks_with_backoff()` with adaptive window doubling
- Guarantees exactly `n_bars` returned (no more, no less)
- Higher-traffic symbols need far fewer calendar days than lower-traffic ones

---

## Memory Guards

| Guard   | Location                 | Mechanism                                                |
| ------- | ------------------------ | -------------------------------------------------------- |
| MEM-010 | `open_deviation_bars.py` | Pre-flight estimate for largest segment, warns or raises |
| MEM-013 | `open_deviation_bars.py` | Blocks >30-day ranges without ClickHouse cache           |

---

## Plugin Enrichment

After all segments are concatenated, `enrich_bars(bars_df, symbol, threshold_decimal_bps)` runs all registered `FeatureProvider` plugins. Plugins add columns but cannot modify existing columns. See [/python/opendeviationbar/plugins/CLAUDE.md](/python/opendeviationbar/plugins/CLAUDE.md).

---

## Related

- [/python/opendeviationbar/CLAUDE.md](/python/opendeviationbar/CLAUDE.md) — parent: API selection guide, caching architecture
- [/python/opendeviationbar/storage/CLAUDE.md](/python/opendeviationbar/storage/CLAUDE.md) — Tier-1 Parquet ticks (TickStorage)
- [/python/opendeviationbar/clickhouse/CLAUDE.md](/python/opendeviationbar/clickhouse/CLAUDE.md) — Tier-2 ClickHouse cache (store_bars_batch, schema)
- [/python/opendeviationbar/plugins/CLAUDE.md](/python/opendeviationbar/plugins/CLAUDE.md) — FeatureProvider enrichment
- [/CLAUDE.md](/CLAUDE.md) — project hub
