# Phase 14: Rust Core -- Gap Fields + Conditional Reset - Context

**Gathered:** 2026-03-26
**Status:** Ready for planning
**Mode:** Auto-generated (infrastructure phase — discuss skipped)

<domain>
## Phase Boundary

The Rust processor produces bars with gap awareness metadata and conditionally skips midnight reset for Aion-mode symbols.

</domain>

<decisions>
## Implementation Decisions

### Claude's Discretion

All implementation choices are at Claude's discretion — pure infrastructure phase.

Key constraints from conversation:

- Gap fields on OpenDeviationBar struct: `has_gap: bool`, `gap_trade_count: i64`, `max_gap_duration_us: i64`, `is_exchange_gap: bool`
- Gap detection in processor: when `incoming_tid > last_tid + 1`, set has_gap=true and accumulate gap_trade_count
- max_gap_duration_us estimated from timestamp jump between last trade before gap and first trade after
- is_exchange_gap is set LATER by Python layer when REST backfill confirms no trades exist at source — NOT set by Rust processor during construction
- Conditional midnight reset: `maybe_reset_at_midnight()` in trade_dispatch.rs checks mode
- Aion mode: skip `reset_at_ouroboros()` call entirely
- Day mode: existing behavior unchanged (backward compatible)
- Gap fields must propagate through: Arrow export, PyO3 dict export, ClickHouse schema
- ClickHouse schema changes follow clickhouse-architect skill from ~/eon/cc-skills

</decisions>

<code_context>

## Existing Code Insights

### Key Rust Files

- `crates/opendeviationbar-core/src/types.rs` — OpenDeviationBar struct, OpenDeviationBarState
- `crates/opendeviationbar-core/src/processor.rs` — process_agg_trade_records(), reset_at_ouroboros()
- `crates/opendeviationbar-streaming/src/live_engine/trade_dispatch.rs` — maybe_reset_at_midnight()
- `src/helpers.rs` — PyO3 dict export (bar_to_dict)
- `src/arrow_bindings.rs` — Arrow export functions

### Key Python Files

- `python/opendeviationbar/clickhouse/schema.sql` — ClickHouse DDL
- `python/opendeviationbar/clickhouse/bulk_operations.py` — bar insertion

### Patterns

- Bar struct uses FixedPoint for prices, i64 for timestamps/IDs
- update_with_trade() in types.rs handles per-trade accumulation
- Arrow export uses StructArray with named fields
- PyO3 uses #[pyclass] and to_dict() for Python interop

</code_context>

<specifics>
## Specific Ideas

- CORE-04 note: is_exchange_gap CANNOT be set during Rust bar construction — the Rust processor doesn't do REST calls. It's set by Python after repair attempts fail.
- The Rust processor should set has_gap, gap_trade_count, max_gap_duration_us during construction.
- is_exchange_gap defaults to false in Rust and is overridden by Python.

</specifics>

<deferred>
## Deferred Ideas

- ClickHouse schema migration for gap columns (Phase 19 or separate)
- Python-side is_exchange_gap setting logic (Phase 17 Kintsugi)

</deferred>
