コンテンツにスキップ

Python → Rust Migration: Python Deletion Plan

Status: draft — cutover-gated. File removals happen after the matching Rust binary passes its 5-business-day parity gate and the explicit cutover judgment has been recorded in WORK_LOG.

Created: 2026-04-10 (Claude). Source of truth: this file + the per-cutover WORK_LOG entries. Any deviation from this plan must be documented in WORK_LOG before any Python file is deleted.

Rationale

The goal of the 2026-04 migration is to delete all Python trading infrastructure and run the full live LT loop + data archive + quote collection + token refresh as Rust binaries. Each cutover (G4 → G1 → G3 → G2) retires a specific chunk of Python. This document is the explicit inventory: for every Python file in aegis_v3/aegis/ and aegis_v3/scripts/ that belongs to the live trading path, we record which cutover deletes it and what the Rust replacement is.

Categories:

  • DELETE @ G4 — Saxo token refresh (post G4 Day 4 cutover)
  • DELETE @ G1 — PT loop, multi-scenario, order manager, broker, shadow (post G1 Day 10 cutover). This is the largest chunk.
  • DELETE @ G3 — Live quote collector (post G3 Day 13 cutover)
  • DELETE @ G2 — LDAS EOD + intraday + writer (post G2 Day 15 cutover)
  • KEEP — BT-only code that has no Rust equivalent yet or is shared with the BT lane (Claude's work boundary). These stay until the BT → Rust migration lands in a future phase.
  • KEEP (shared) — Files consumed by both the trading loop and the BT; editing boundary applies (Codex LT lane vs Claude BT lane). These stay until the BT stops using them.

G4 DELETE — Saxo token refresh (post Day 4 cutover)

File Purpose Rust replacement
aegis_v3/scripts/token_keeper.py OAuth2 refresh daemon loop aegis-bt-rs/src/bin/lt_token_keeper.rs

The Python keeper writes /volume1/aegis/tokens/saxobank_tokens_live.json (canonical). The Rust keeper writes /volume1/aegis/tokens/saxobank_tokens_live_rust.json during parallel observation, then takes over the canonical filename at cutover.

Gate: 2 business days of saxobank_tokens_live_rust.json mtime updating every 15 min + 0 401 Unauthorized errors across all Rust containers.


G1 DELETE — PT loop + broker + shadow (post Day 10 cutover)

This is the largest chunk. Python aegis-wft + its supporting modules + the entire shadow observation architecture come down together.

Engine (24 files)

File Purpose Rust replacement
aegis/engine/paper_trading.py PT core scan loop aegis-bt-rs/src/engine/scan_cycle.rs
aegis/engine/multi_scenario_pt.py MultiScenarioPTEngine (11 scenarios) aegis-bt-rs/src/engine/multi_scenario.rs
aegis/engine/order_manager.py Pending/Active/Terminal order lifecycle aegis-bt-rs/src/engine/order_manager.rs
aegis/engine/paper_trading_state.py PtState JSON persistence aegis-bt-rs/src/engine/pt_state.rs
aegis/engine/paper_trading_clock_boundary.py Market clock helpers merged into scan_cycle.rs market-hours gate
aegis/engine/paper_trading_earnings_boundary.py Earnings calendar gate merged into strategy live gates
aegis/engine/paper_trading_heartbeat_boundary.py Heartbeat write helper aegis-bt-rs/src/bin/lt_scan_cycle.rs heartbeat writer
aegis/engine/paper_trading_hy_oas_boundary.py HY OAS lookup helper merged into scan cycle bear context
aegis/engine/paper_trading_no_option_cache_boundary.py No-option-cache reader aegis-bt-rs/src/quote/collector.rs no-option cache
aegis/engine/paper_trading_artifact_paths.py PT artifact path resolver merged into scan_cycle.rs state path defaults
aegis/engine/paper_trading_replay.py Replay log writer aegis-bt-rs/src/engine/scan_cycle.rs ParityLogWriter
aegis/engine/paper_trading_replay_loader.py Replay log reader aegis-bt-rs/src/bin/lt_wft_parity.rs latest-record reader
aegis/engine/paper_trading_replay_diff.py Replay diff helper aegis-bt-rs/src/bin/lt_decision_diff.rs
aegis/engine/lt_shadow_loop.py Legacy shadow replay loop RETIRED (Strangler shadow architecture)
aegis/engine/lt_shadow_observation.py Shadow observation rolling state RETIRED
aegis/engine/lt_shadow_observation_cycle.py Shadow observation cycle writer RETIRED
aegis/engine/lt_shadow_observation_daemon.py Shadow observation daemon RETIRED
aegis/engine/lt_shadow_compare_reports.py Shadow compare report generator RETIRED
aegis/engine/lt_shadow_live_paths.py Shadow live path resolver RETIRED
aegis/engine/lt_shadow_multi_scenario_cycle.py Shadow multi-scenario cycle RETIRED (native in multi_scenario.rs)
aegis/engine/lt_shadow_multi_scenario_observation_summary.py Shadow multi-scenario summary RETIRED
aegis/engine/lt_shadow_multi_scenario_preflight.py Shadow preflight check RETIRED
aegis/engine/lt_shadow_multi_scenario_targets.py Shadow scenario targets RETIRED
aegis/engine/lt_shadow_parity_triage.py Shadow parity triage RETIRED (replaced by lt-wft-parity)

Broker (8 files; protocol.py is kept until G3)

File Purpose Rust replacement
aegis/broker/saxo_adapter.py Legacy adapter aegis-bt-rs/src/broker/saxo/adapter.rs
aegis/broker/saxo/__init__.py Module re-exports N/A (delete with directory)
aegis/broker/saxo/adapter.py Broker adapter (new) aegis-bt-rs/src/broker/saxo/adapter.rs
aegis/broker/saxo/auth.py OAuth2 flow aegis-bt-rs/src/broker/saxo/auth.rs (+ lt-token-keeper binary)
aegis/broker/saxo/client.py REST client aegis-bt-rs/src/broker/saxo/rest_client.rs
aegis/broker/saxo/config.py Saxo env/config aegis-bt-rs/src/broker/saxo/config.rs
aegis/broker/saxo/models.py Saxo DTO models aegis-bt-rs/src/broker/saxo/{orders,position,quote}.rs
aegis/broker/saxo/streaming.py WebSocket subscriptions aegis-bt-rs/src/broker/saxo/streaming.rs

Note on aegis/broker/protocol.py: this abstract base class is still imported by live_quote_collector.py (G3 target), so it cannot be deleted at G1. It moves to "DELETE @ G3" below. No BT code uses it (verified 2026-04-10: grep for aegis.broker.protocol across the repo returns 11 files — all PT runtime, ops scripts, or unit tests, none in backtest.py or scripts/run_7yr_bt.py).

Scripts (6 files)

File Purpose Rust replacement
aegis_v3/scripts/run_paper_trading_v3.py Entry-point for legacy PT N/A (container uses lt-scan-cycle directly)
aegis_v3/scripts/run_pt.py Entry-point for PT N/A
aegis_v3/scripts/run_multi_scenario_pt.py Entry-point for MultiScenarioPT N/A (container uses lt-scan-cycle --scenario-multi-yaml)
aegis_v3/scripts/check_lt_multi_scenario_shadow_preflight.py Shadow preflight RETIRED with shadow architecture
aegis_v3/scripts/evaluate_lt_shadow_cutover.py Shadow cutover evaluator aegis-bt-rs/src/bin/lt_cutover_gate.rs
aegis_v3/scripts/notify_lt_shadow_parity.py Shadow parity notifier RETIRED (Rust parity gate is in-process)

Gate: 5 business days of clean lt_wft_comparison.jsonl + Python pt_wft_comparison.jsonl matching per-scenario (equity ±$50, closed_trades ±0), verified daily by lt-wft-parity.


G3 DELETE — Live quote collector (post Day 13 cutover)

File Purpose Rust replacement
aegis/engine/live_quote_collector.py BT fill_ratio calibration daemon aegis-bt-rs/src/quote/collector.rs + aegis-bt-rs/src/bin/lt_quote_collector.rs
aegis_v3/scripts/run_quote_collector.py Collector entry-point N/A (container uses lt-quote-collector directly)
aegis/broker/protocol.py Broker ABC aegis-bt-rs/src/broker/protocol.rs (deferred from G1 because live_quote_collector.py still imports it between G1 and G3)
aegis_v3/scripts/live_quote_test.py Legacy live quote test script N/A (replaced by Rust lt-quote-collector heartbeat + lt-wft-parity during observation)

Gate: 3-5 business days of collector_heartbeat.json (rust) updating every 30s + api_calls_per_minute within ±5% of Python baseline + no_option_symbols set overlap ≥95%.


G2 DELETE — LDAS EOD + intraday (post Day 15 cutover)

File Purpose Rust replacement
aegis/data/ldas_collector.py LDAS EOD + intraday collector aegis-bt-rs/src/data/ldas_collector.rs
aegis/data/ldas_writer.py LDAS parquet writer aegis-bt-rs/src/data/ldas_collector.rs (write_*_parquet fns)
aegis/data/polygon_provider.py Polygon REST provider for Python PT + LDAS aegis-bt-rs/src/data/polygon_live.rs (deferred from G1 because scripts/collect_eod_v3.py + collect_intraday_v3.py still import it between G1 and G2)
aegis_v3/scripts/collect_eod_v3.py EOD cron entry-point N/A (container uses lt-ldas eod)
aegis_v3/scripts/collect_intraday_v3.py Intraday daemon entry-point N/A (container uses lt-ldas intraday)
aegis_v3/scripts/compute_iv_rank.py Legacy IV rank compute aegis-bt-rs/src/ivrank/ + aegis-ivrank binary
aegis_v3/scripts/compute_iv_rank_parallel.py Parallel IV rank same (the Rust ivrank binary handles parallelism internally)

Gate: 2 business days of EOD parity + 2 business days of intraday parity (file count ±1, row count ±5, schema identical, GEX regime distribution within ±1 symbol per regime), verified daily by lt-ldas-parity.


KEEP — BT-only (no Rust equivalent yet)

These files are used by the BT lane (Claude's boundary) and have no Rust replacement yet. They survive the 2026-04 migration. A future BT → Rust migration phase will retire them.

File Why keep
aegis/engine/backtest.py Python BT engine (Rust BT is aegis-bt-rs main binary, but Python BT is still used for edge-case verification)
aegis/engine/regime.py Regime classification — backtest.py imports RegimeAdjuster (verified 2026-04-10). Must stay until BT → Rust phase retires backtest.py.
aegis/engine/decision_log.py Decision log writer (PT + BT shared; simple enough to keep)
aegis/engine/monthly.py Monthly analysis helpers (BT reporting path)
aegis/data/v2_parquet_provider.py v2 parquet reader (BT path)
aegis/data/pkl_cache_provider.py pkl cache for BT warm start
aegis/data/parquet_provider.py v3 parquet reader (BT path)
aegis_v3/scripts/run_7yr_bt.py 7-year BT runner
aegis_v3/scripts/analyze_*.py BT result analysis scripts (dozens)
aegis_v3/scripts/launch_fargate_*.py Fargate launchers for BT sweeps
aegis_v3/scripts/parity_diff.py Scan-level parity diff (still useful for shadow era)

Note: aegis/data/polygon_provider.py and aegis/broker/protocol.py were originally in this KEEP section but 2026-04-10 verification confirmed neither is used by BT code. They moved to G2 DELETE and G3 DELETE respectively (both deferred from G1 because of remaining G2/G3 callers). The deletion gate for both is "no more Python callers in the tree" plus the normal cutover gate for their primary retiring subsystem.


KEEP (shared) — Edit with boundary lock

These files are edited by both lanes (LT runtime via Codex, BT via Claude). Any edit must be synchronized per the boundary rule in .claude/CLAUDE.md. At G1 cutover, the LT usage drops away and only BT remains; then they move into the "KEEP — BT-only" category or get a BT-specific fork.

File LT usage BT usage
aegis_v3/aegis/data/models.py PT loop + broker BT engine
aegis_v3/aegis/strategy/protocol.py PT strategy invocation BT strategy invocation
aegis_v3/configs/base.yaml PT loop runtime knobs BT scenario defaults
aegis_v3/configs/scenarios/lt_rc.yaml LT_RC live scenario BT LT_RC verification
aegis_v3/configs/scenarios/pt_wft.yaml Python MultiScenarioPT
aegis_v3/configs/scenarios/pt_xw.yaml PT_XW scenario BT PT_XW verification

Removal procedure (when the gate passes)

For each cutover (G4 → G1 → G3 → G2), the removal PR follows this sequence:

  1. Verify the gate — latest lt-{wft,ldas}-parity --json run pinned to the cutover day shows overall=PASS, attached to the WORK_LOG entry.
  2. Verify the WORK_LOG approval — a line with explicit Ryo approval ("G1 cutover approved, remove Python PT files").
  3. Stop the Python container firstdocker stop aegis-wft (or the matching container), wait 30s for in-flight ops to flush.
  4. Run git rm for the listed files — one commit per cutover, titled chore(python-migration): remove G{N} Python files post-cutover.
  5. Update the runbook — the matching lt-{scan-cycle,ldas,quote-collector,token-keeper}-runbook.md moves from "parallel observation" section to "cutover complete" section.
  6. Update this file — move the deleted files from the "DELETE" table to a "DELETED @ YYYY-MM-DD" table at the bottom, so the history is visible.
  7. Re-run the Rust strict clippy CI — confirm nothing breaks from the removals.
  8. Leave the Python container image in the Synology registry for 1 week as a rollback safety net. After 1 week with no regressions, the image can be tagged -retired and eventually removed from the registry.

Open questions / follow-ups

All three 2026-04-10 open questions have been answered by verification against the live repo state:

  • aegis/engine/regime.py keep-or-delete: KEEP. Both paper_trading.py (G1) and backtest.py (BT, KEEP) import RegimeAdjuster from this file. When paper_trading.py is deleted at G1, regime.py stays because backtest.py still needs it. It moves into KEEP (BT-only) permanently until the BT → Rust phase retires backtest.py.
  • aegis/broker/protocol.py keep-or-delete: DELETE @ G3. No BT code imports it (verified against aegis/engine/backtest.py and scripts/run_7yr_bt.py). It stays through G1 because aegis/engine/live_quote_collector.py (G3 target) still imports it, and retires at G3 with the rest of the quote collector stack.
  • aegis/data/polygon_provider.py keep-or-delete: DELETE @ G2. All 4 Python callers (scripts/collect_eod_v3.py, scripts/collect_intraday_v3.py, scripts/run_multi_scenario_pt.py, scripts/run_pt.py) are already in G1 or G2 deletion targets. No BT script uses it. It stays through G1 because collect_eod_v3.py and collect_intraday_v3.py still exist between G1 and G2, and retires at G2 together with them.