---
phase: 19-fleet-recompute-telemetry
plan: 02
type: execute
wave: 2
depends_on: [19-01]
files_modified:
  - scripts/fleet_recompute_aion.py
autonomous: false
requirements: [RECOMP-01, RECOMP-02, RECOMP-03, VAL-04]
user_setup:
  - service: bigblack-ssh
    why: "Fleet recompute runs on bigblack (remote GPU host)"
    env_vars: []
    dashboard_config:
      - task: "Ensure SSH access to bigblack"
        location: "ssh bigblack (must be reachable)"

must_haves:
  truths:
    - "All Day-mode crypto bar partitions are dropped from ClickHouse"
    - "Kintsugi recomputes all 18 crypto symbols as Aion with zero Stathera gaps"
    - "Stale Day-mode telemetry artifacts are wiped (kintsugi_log, population_checkpoints, backfill_requests for crypto)"
    - "Heartbeat Stathera audit confirms 0-gap 0-overlap for all Aion crypto symbols"
  artifacts:
    - path: "scripts/fleet_recompute_aion.py"
      provides: "Coordinated stop-drop-wipe-recompute script"
      contains: "DROP PARTITION"
  key_links:
    - from: "scripts/fleet_recompute_aion.py"
      to: "python/opendeviationbar/symbol_registry.py"
      via: "get_registered_symbols(asset_class='crypto') for dynamic symbol enumeration"
      pattern: "get_registered_symbols"
    - from: "scripts/fleet_recompute_aion.py"
      to: "ClickHouse system.parts"
      via: "Query actual partitions before DROP"
      pattern: "system.parts"
---

<objective>
Create a fleet recompute script and execute the Aion migration on bigblack: drop all Day-mode crypto partitions, wipe stale telemetry, and verify via Stathera audit.

Purpose: This is the actual fleet migration -- converting all crypto symbols from Day-mode to Aion in ClickHouse. After this, all crypto bars are continuous (no midnight orphan bars) and the heartbeat confirms zero gaps.

Output: `scripts/fleet_recompute_aion.py` -- a coordinated recompute script. Bigblack ClickHouse contains only Aion-mode crypto bars with 0-gap 0-overlap Stathera.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/19-fleet-recompute-telemetry/19-01-SUMMARY.md
@python/opendeviationbar/symbol_registry.py
@python/opendeviationbar/clickhouse/schema.sql
@deploy/opendeviationbar.env
</context>

<interfaces>
<!-- Key types the executor needs -->

From python/opendeviationbar/symbol_registry.py:

```python
def get_registered_symbols(*, asset_class="crypto", enabled_only=True) -> list[str]:
    """Returns e.g. ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', ...]"""

def get_symbol_entries() -> MappingProxyType[str, SymbolEntry]:
    """SymbolEntry has: .ouroboros_mode, .asset_class, .exchange, .market, .enabled"""
```

ClickHouse partition key: `(symbol, threshold_decimal_bps)`
Standard thresholds on bigblack: [250, 500, 750, 1000]

Telemetry tables to wipe crypto entries from:

- `opendeviationbar_cache.kintsugi_log`
- `opendeviationbar_cache.population_checkpoints`
- `opendeviationbar_cache.backfill_requests`

Local state files to clean:

- `~/.cache/opendeviationbar/heartbeat/stathera_counts.json`
- `~/.cache/opendeviationbar/checkpoints/` (crypto checkpoint files)
  </interfaces>

<tasks>

<task type="auto">
  <name>Task 1: Create fleet recompute script</name>
  <files>scripts/fleet_recompute_aion.py</files>
  <read_first>python/opendeviationbar/symbol_registry.py, python/opendeviationbar/clickhouse/schema.sql, deploy/opendeviationbar.env, scripts/detect_gaps.py</read_first>
  <action>
Create `scripts/fleet_recompute_aion.py` -- a coordinated Aion migration script for bigblack. This is a one-time migration script (not a permanent operational tool).

The script must implement the stop-drop-wipe-recompute sequence from the research doc:

**Phase 1: Pre-flight checks (--preflight or default first step)**

- Verify ClickHouse connectivity (`SELECT 1`)
- Query `system.parts` to discover actual crypto partitions on bigblack: `SELECT DISTINCT partition FROM system.parts WHERE table = 'open_deviation_bars' AND database = 'opendeviationbar_cache' AND active = 1`. Filter to crypto symbols only (use `get_registered_symbols(asset_class="crypto")` to enumerate).
- Display summary: N crypto partitions to drop, estimated bar count via `SELECT count() FROM open_deviation_bars WHERE symbol IN (...)`
- Exit with instructions for the user to proceed with `--execute`

**Phase 2: Execute migration (--execute flag required)**
Step 1: Stop services -- display `systemctl --user stop opendeviationbar-sidecar opendeviationbar-kintsugi opendeviationbar-kintsugi-catchup` command (do NOT execute systemctl -- that runs on bigblack, not locally). Instead, the script connects to CH directly.

Step 2: DROP PARTITION for all discovered crypto partitions. Use the pattern:

```python
client.command(f"ALTER TABLE opendeviationbar_cache.open_deviation_bars DROP PARTITION ('{symbol}', {threshold})")
```

Query `system.parts` AFTER to discover actual partitions (handles any threshold, not just the standard 4). Log each drop.

Step 3: Wipe telemetry -- batch DELETE from kintsugi_log, population_checkpoints, backfill_requests where symbol IN crypto_symbols. Use `mutations_sync=1` (required per CLAUDE.md Section 7). Also delete local heartbeat state file and crypto checkpoint files.

Step 4: Display instructions to start kintsugi catch-up (`systemctl --user start opendeviationbar-kintsugi-catchup`) and monitor.

**Phase 3: Verify (--verify flag)**
Run Stathera audit query (from research doc) against all Aion crypto symbols. Report gaps and overlaps per (symbol, threshold). Exit 0 if all clean, exit 1 if any issues.

**CLI interface:**

```
python scripts/fleet_recompute_aion.py --preflight   # Dry run, show what would be dropped
python scripts/fleet_recompute_aion.py --execute      # Actually drop + wipe
python scripts/fleet_recompute_aion.py --verify       # Post-recompute Stathera check
```

**Implementation details:**

- Use `clickhouse_connect` for CH operations (same as detect_gaps.py)
- Use `get_registered_symbols(asset_class="crypto")` for dynamic symbol enumeration (not hardcoded list)
- Query `system.parts` for actual partition discovery (handles any threshold configuration)
- All DELETEs use `mutations_sync=1`
- Use `OPENDEVIATIONBAR_MODE` env var for connection mode (local on bigblack, remote with SSH tunnel otherwise)
- Add `--dry-run` flag for non-destructive testing
- Add colored output for clarity (green for success, red for failures, yellow for warnings)
- Script header docstring explains it's a one-time v7.0 Aion migration tool

**Safety guards:**

- `--execute` requires explicit confirmation prompt ("Type YES to proceed")
- Pre-flight verifies no sidecar/kintsugi PID running (warn if detected -- user must stop manually)
- Log every DROP PARTITION and DELETE statement
  </action>
  <verify>
  <automated>cd /Users/terryli/eon/opendeviationbar-py && python -c "
  import ast, sys

# Verify script parses

with open('scripts/fleet_recompute_aion.py') as f:
ast.parse(f.read())

# Verify key patterns

with open('scripts/fleet_recompute_aion.py') as f:
content = f.read()
assert 'DROP PARTITION' in content, 'Missing DROP PARTITION'
assert 'get_registered_symbols' in content, 'Missing registry lookup'
assert 'mutations_sync' in content, 'Missing mutations_sync'
assert 'system.parts' in content, 'Missing system.parts query'
assert '--execute' in content, 'Missing --execute flag'
assert '--verify' in content, 'Missing --verify flag'
assert '--preflight' in content, 'Missing --preflight flag'
print('Fleet recompute script validates OK')
"</automated>
</verify>
<acceptance_criteria> - scripts/fleet_recompute_aion.py exists and parses without syntax errors - grep -q "DROP PARTITION" scripts/fleet_recompute_aion.py - grep -q "get_registered_symbols" scripts/fleet_recompute_aion.py - grep -q "mutations_sync" scripts/fleet_recompute_aion.py - grep -q "system.parts" scripts/fleet_recompute_aion.py
</acceptance_criteria>
<done>Fleet recompute script created with preflight/execute/verify phases, dynamic partition discovery, and all safety guards</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Execute fleet recompute on bigblack and verify Stathera</name>
  <files>scripts/fleet_recompute_aion.py</files>
  <action>
Human executes the fleet recompute on bigblack using the script from Task 1. The sequence is:
1. Deploy code to bigblack
2. Stop sidecar + kintsugi services
3. Run --preflight to confirm partition counts
4. Run --execute to drop partitions and wipe telemetry
5. Start kintsugi catch-up to recompute Aion bars (~1-3h)
6. Run --verify to confirm 0-gap 0-overlap Stathera
7. Restart sidecar for real-time streaming
  </action>
  <what-built>
Fleet recompute script (scripts/fleet_recompute_aion.py) with three phases:
1. --preflight: Shows what will be dropped (partition counts, bar counts)
2. --execute: Drops partitions, wipes telemetry
3. --verify: Runs Stathera audit post-recompute

After --execute, kintsugi catch-up must run to recompute all Aion bars (~1-3 hours).
</what-built>
<how-to-verify>

1. Deploy updated code to bigblack: `mise run deploy:bigblack`
2. SSH to bigblack: `ssh bigblack`
3. Stop services: `systemctl --user stop opendeviationbar-sidecar opendeviationbar-kintsugi opendeviationbar-kintsugi-catchup`
4. Run preflight: `cd ~/opendeviationbar-py && uv run --python 3.13 python scripts/fleet_recompute_aion.py --preflight`
   - Verify it shows the correct number of crypto partitions to drop
5. Run execute: `uv run --python 3.13 python scripts/fleet_recompute_aion.py --execute`
   - Confirm all partitions dropped and telemetry wiped
6. Start kintsugi: `systemctl --user start opendeviationbar-kintsugi-catchup`
7. Monitor via heartbeat or `journalctl --user -u opendeviationbar-kintsugi-catchup -f`
8. After kintsugi completes (~1-3h), run: `uv run --python 3.13 python scripts/fleet_recompute_aion.py --verify`
   - Must show 0 gaps, 0 overlaps for all Aion crypto symbols (VAL-04)
9. Start sidecar: `systemctl --user start opendeviationbar-sidecar`
10. Verify heartbeat: wait for next 5-min heartbeat cycle, confirm green status
    </how-to-verify>

  <verify>
    <automated>echo "Checkpoint: human verification required on bigblack"</automated>
  </verify>
  <done>All crypto symbols recomputed as Aion with 0-gap 0-overlap Stathera on bigblack. Heartbeat green. Sidecar and kintsugi running steady state.</done>
  <resume-signal>Type "verified" with Stathera audit results (0-gap 0-overlap for all crypto symbols), or describe issues</resume-signal>
</task>

</tasks>

<verification>
1. `scripts/fleet_recompute_aion.py` exists with preflight/execute/verify modes
2. Preflight shows correct crypto partition count
3. Execute drops all crypto partitions and wipes telemetry
4. After kintsugi recompute, `--verify` shows 0-gap 0-overlap for all Aion crypto symbols
5. Heartbeat confirms green status post-migration
</verification>

<success_criteria>
All crypto symbols recomputed as Aion on bigblack with zero Stathera gaps. Heartbeat confirms 0-gap 0-overlap. Day-mode telemetry artifacts wiped. Sidecar and kintsugi running in steady state with Aion mode.
</success_criteria>

<output>
After completion, create `.planning/phases/19-fleet-recompute-telemetry/19-02-SUMMARY.md`
</output>
