# Monthly Ouroboros Switchover Runbook

**Issue**: #134 | **Status**: Complete (all 7 phases shipped)

## What `ouroboros_mode` Controls

The ouroboros mode determines where the `OpenDeviationBarProcessor` resets its state, emitting an orphan bar and starting fresh. This affects:

- **Bar boundaries**: Where bars are forcibly closed (orphaned)
- **Checkpoint files**: Mode is encoded in the filename to prevent cross-mode resume
- **ClickHouse partitioning**: `ouroboros_mode` is part of the `ORDER BY` key
- **Cache isolation**: Same symbol/threshold with different modes produces independent data

| Mode    | Reset Points      | Orphan Bars/Year | Use Case                |
| ------- | ----------------- | ---------------- | ----------------------- |
| `year`  | Jan 1 00:00 UTC   | 1                | Legacy, minimal orphans |
| `month` | 1st of each month | 12               | Default, cache-friendly |
| `week`  | Sunday 00:00 UTC  | 52               | High-frequency analysis |

**Why monthly is the default**: Monthly resets produce manageable 12 orphans/year while keeping cache segments small enough for efficient per-year parallel population. Year mode produces only 1 orphan but creates very large cache segments that are slow to backfill.

## Environment Variable

```bash
# Set in .mise.toml (SSoT for all hosts)
OPENDEVIATIONBAR_OUROBOROS_MODE = "month"
```

The variable flows through:

1. `Settings.get().population.ouroboros_mode` (config singleton)
2. `get_operational_ouroboros_mode()` (resolver in `ouroboros.py`)
3. All populate/streaming/daemon paths

## Verifying Current Mode

```bash
# CLI (recommended)
opendeviationbar config show --section population

# Output includes:
#   ouroboros_mode = 'month'

# JSON output for scripts
opendeviationbar config show --section population --json | jq .population.ouroboros_mode
```

## Mixed-Mode Data Coexistence

Year-mode and month-mode bars coexist safely in ClickHouse because `ouroboros_mode` is part of the `ORDER BY` key in `schema.sql`:

```sql
ORDER BY (symbol, threshold_decimal_bps, ouroboros_mode, close_time_ms)
```

This means:

- Queries filter by `ouroboros_mode` automatically
- `CacheKey.hash_key` includes the mode, preventing cross-mode cache pollution
- No data migration needed when switching modes

## SIGHUP Runtime Switching

All three daemons support runtime mode switching via `SIGHUP`:

```bash
# 1. Update .mise.toml with new mode
# 2. Send SIGHUP to running daemon
kill -HUP <pid>
```

The SIGHUP handler:

1. Calls `Settings.reload_and_clear()` to refresh the config singleton
2. Logs the new `ouroboros_mode` value
3. Sends a Telegram notification to confirm the change
4. New bars use the updated mode immediately

**No restart required.** The daemon picks up the new mode on the next processing cycle.

## Bigblack Switchover Status

Bigblack has been running on `"month"` mode since Issue #126. The `.mise.toml` on bigblack sets:

```toml
OPENDEVIATIONBAR_OUROBOROS_MODE = "month"
```

All cached bars use `ouroboros_mode = 'month'`.

### Year-Mode Data Permanently Deleted (Issue #140)

As of v12.42, all year-mode data has been permanently deleted from ClickHouse on bigblack:

```sql
-- ~27M year-mode bars deleted from open_deviation_bars
ALTER TABLE open_deviation_bars DELETE WHERE ouroboros_mode = 'year';
-- Year-mode rows also deleted from auxiliary tables:
-- population_checkpoints, backfill_requests, kintsugi_log
```

The `OuroborosMode.YEAR` enum value is retained in Python for type system completeness,
but no year-mode data exists in any ClickHouse table. All 23 research scripts have been
updated to query `ouroboros_mode = 'month'`.

## CLI Override

The `populate` command accepts `--ouroboros-mode` to override the config default:

```bash
# Use week mode for a specific populate job
opendeviationbar populate BTCUSDT --start 2024-01-01 --end 2024-06-30 --ouroboros-mode week
```

The CLI resolves: `--ouroboros-mode` flag > `OPENDEVIATIONBAR_OUROBOROS_MODE` env var > config default (`"month"`).
