# Phase 4: Parallel fill_from_rest - Context

**Gathered:** 2026-03-19
**Status:** Ready for planning

<domain>
## Phase Boundary

Replace the sequential per-symbol loop in `fill_from_rest()` with `JoinSet` + `Semaphore(4)` for concurrent REST backfill. Increase WS channel capacity from 1,000 to 50,000 to prevent buffer overflow. Use Phase 3's `set_ceiling()` to set rate limit to 4800 during fill, 3000 after. Target: total fill time <90s (vs ~5 min sequential).

</domain>

<decisions>
## Implementation Decisions

### Claude's Discretion

All implementation choices are at Claude's discretion — pure infrastructure phase (~40 lines).

Key constraints from research:

- `JoinSet` + `Semaphore(4)` for bounded parallelism (4 concurrent fills)
- Each symbol's fill still processes sequentially within its task
- Shared `Arc<AdaptiveRateLimiter>` across all tasks (Binance limits per-IP, not per-symbol)
- `set_ceiling(4800)` before fill, `set_ceiling(3000)` after all fills complete
- WS channel capacity: increase from 1000 to 50000 (env var `OPENDEVIATIONBAR_MAX_PENDING_BARS` or hardcoded constant)
- Ring buffer analysis (Phase 2) recommends `OPENDEVIATIONBAR_MAX_PENDING_BARS=100000` for production
- Processors are Rust-owned stateful objects — parallelization must be in Rust, not Python

</decisions>

<code_context>

## Existing Code Insights

### Reusable Assets

- `fill_from_rest()` in `live_engine.rs` — current sequential loop
- `AdaptiveRateLimiter::set_ceiling()` from Phase 3
- `tokio::task::JoinSet` and `tokio::sync::Semaphore` from tokio

### Integration Points

- `fill_from_rest()` return type must remain the same (HashMap of processors)
- WS channel capacity constant (find where mpsc channel is created)
- `set_ceiling()` calls bracket the fill operation

</code_context>

<specifics>
## Specific Ideas

No specific requirements — infrastructure phase

</specifics>

<deferred>
## Deferred Ideas

None

</deferred>
