docs(vrp): final VRP code-removal plan (discovery-workflow derived)

10-task subagent-driven removal: delete leaves first (7 vrp modules +
black_scholes + DVOL pipeline + 12 tests), then callers (vrp_nav asset,
XspOptionBarsRepo class, registry keys, CLI cmds, migration builder),
then comment scrubs. KEEP xsp_option_bars table/model/data + OPRA .dbn
(Constraint 1). Verified against tree: test_xsp_option_bars_repo.py does
not exist; test_vrp_rebalancer_yaml already red (dangling manifest ref).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 23:05:21 +00:00
parent fb14ddc75d
commit a263b676de

View File

@@ -0,0 +1,474 @@
# VRP Strategy Full Removal — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox tracking; delete leaves before callers so imports never break mid-removal.
**Derived from:** a discovery workflow (24 file classifications + 3 deep-traces) — `wf_ffbdc8b5-c02`. The
tricky shared-vs-VRP calls were resolved by trace: **DVOL pipeline = delete** (only VRP reads it),
**black_scholes.py = delete** (VRP-only), **surfer vendor = untouched** (docstring mention only),
**xsp_option_bars TABLE/MODEL/data = KEEP** (only the VRP-only `XspOptionBarsRepo` *class* is deleted).
## Goal
Fully delete the VRP (variance-risk-premium) strategy — the shelved/FALSIFIED equity-VRP
sleeve and its executed twin `vrp_exec` — from the fxhnt repo, leaving **zero orphaned code,
zero dead registry keys, and zero dangling imports**. The nightly Dagster pipeline, the cockpit
web app, live IBKR/UCITS execution, the Bybit paper book, and all four kept crypto edges must
remain fully functional and the pytest suite must be green at the end.
The removal spans four coupled clusters, all of which are VRP-exclusive per the deep-traces:
1. **VRP application modules**: `vrp_book`, `vrp_eval`, `vrp_defined_risk_eval`,
`vrp_exec_record`, `vrp_marking`, `vrp_pricing`, `vrp_research`.
2. **VRP option-math + IV plumbing**: `black_scholes.py` (VRP-only), the entire DVOL pipeline
(`deribit_dvol.py`, `dvol_ingest.py`, the `dvol` feature panel, the unused
`VolIndexClient.dvol()` port).
3. **VRP persistence/orchestration**: `xsp_option_bars.py` repo class, the `vrp_nav` Dagster
asset + its ~14 private OPRA-freeze/backfill helpers, the `backfill-xsp-opra` ingest path,
the `VrpStrategy` builder, and the `vrp`/`vrp_exec` registry entries.
4. **Comment/registry-string scrubs** across shared cockpit infrastructure that merely *names*
VRP as an illustrative example.
## Architecture
VRP was ARCHIVED 2026-07-15 (fails the LOO marginal-Sharpe gate; see
`pearl_fxhnt_diversifier_hunt_2026_07_15`). The two registry entries already carry
`archived: True`, and `vrp_nav` is already **de-wired** from `definitions.py`'s nightly asset
graph — so no live nightly asset materializes VRP today. What remains is dead weight plus two
active-but-purposeless CLI/CronJob ingest paths (`ingest-dvol`, `backfill-xsp-opra`) and a set
of stale registry keys/comment references.
Dependency direction (leaf → root), which dictates task order so imports never break mid-removal:
```
black_scholes.py ────────────► vrp_defined_risk_eval.py ──┐
deribit_dvol.py ─► dvol_ingest.py ─► (dvol panel) ────────┤
xsp_option_bars.py (repo class) ──► vrp_book.py ──────────┤──► cli.py commands
vrp_pricing.py / vrp_marking.py ──► vrp_book/eval/exec ───┤ migration_builders (_build_vrp)
└──► assets.py vrp_nav + helpers
registry.py vrp / vrp_exec
forward_ingest _REF_ALIAS
sim_curves / dashboard_service /
app.py / definitions.py (scrub)
```
Rule: delete leaf modules **and their tests together** first, then the callers that referenced
them (asset graph, registry, CLI, migration builder), then the pure comment-scrub edits last.
## DVOL and black_scholes — resolved decisions (per deep-traces)
- **DVOL pipeline → DELETE (do not keep).** Exhaustive grep confirms the only readers of the
`dvol` feature panel (`store.read_panel(..., "dvol")`) are `vrp_eval.py` and
`vrp_defined_risk_eval.py`. `VolIndexClient.dvol()` (`ports/market_data.py:22`) has **zero**
callers. DVOL is not a Dagster asset. DVOL is the Deribit IV index — a data source entirely
distinct from the OPRA `xsp_option_bars` data being kept; there is no keep-carve-out for it.
Delete `deribit_dvol.py`, `dvol_ingest.py`, the `ingest-dvol` CLI command, the
`VolIndexClient.dvol()` port method, and their tests. The `dvol` warehouse rows in
`bybit_features` are inert once nothing reads them — no migration needed; they can age out.
- **black_scholes.py → DELETE (VRP-only, not shared math).** The only importers are
`vrp_defined_risk_eval.py` and its own unit test `tests/unit/test_black_scholes.py`.
`vrp_pricing.py` defines a *separate* `bs_put` (different signature) and does **not** import
from `black_scholes.py`, so there is no hidden cross-file sharing. Delete both files.
- **`xsp_option_bars` TABLE + `XspOptionBarRow` model + OPRA `.dbn` → KEEP.** Only the
`XspOptionBarsRepo` *repo class* (`adapters/persistence/xsp_option_bars.py`) is VRP-only and
gets deleted. The ORM row model `XspOptionBarRow` in `cockpit_models.py`, the physical table,
the 13-year OPRA data, and `ForwardNavRepo.xsp_freeze_max_date()` (raw `SELECT max(date)`)
all stay untouched.
## Global Constraints
1. **KEEP the OPRA data.** Do **not** drop or migrate the `xsp_option_bars` table, do **not**
remove `XspOptionBarRow` from `cockpit_models.py`, do **not** delete OPRA `.dbn` files, and
do **not** touch `ForwardNavRepo.xsp_freeze_max_date()`. Only the VRP *ingest/consumer*
machinery (`XspOptionBarsRepo` class, `_backfill_month`/`_freeze_*` helpers, `backfill-xsp-opra`)
is removed. The freeze-staleness health axis (`_FREEZE_SOURCES = {"opra-pit"}`) stays generic.
2. **Real-money paths must err false-WAIT, never false-EXECUTE.** VRP execution
(`execute-vrp`/`vrp_exec_record`) is being deleted, not disabled — but during the removal no
edit may cause any *surviving* real-money path (multistrat/UCITS IBKR, Bybit paper) to
silently promote/execute on missing state. After removing the `vrp`/`vrp_exec` registry keys,
confirm the cockpit gate and `forward_ingest` promotion loop still default to WAIT for every
surviving strategy and never KeyError into a false-PASS.
3. **Full pytest suite green before finishing.** Run `uv run pytest -n auto` (or
`python -m pytest -n auto` per `pyproject.toml addopts = "-n auto"`) from the repo root and
confirm 0 failures / 0 errors before the final commit. Per-task commands below are the fast
local gate; the full-suite run in the final task is the release gate.
4. **The false VRP STALE health alarm must be gone.** After removal, verify **no `vrp` key
remains in `STRATEGY_REGISTRY`** (`vrp` and `vrp_exec` both removed) so the forward-health
freeze/staleness axis and `dashboard_service._active_ibkr_account_sids()` can no longer
surface a ghost VRP STALE row. Verification command in the final task.
### Pre-flight note (already-broken test)
`tests/unit/test_vrp_rebalancer_yaml.py` asserts the existence of
`infra/k8s/jobs/fxhnt-vrp-rebalancer.yaml`, which **no longer exists** in the tree. This test is
already failing/erroring at HEAD; it is deleted in Task 1 alongside the other VRP tests, which
also removes that pre-existing red.
---
## Task 1 — Delete VRP application modules + their tests (leaves first)
**Files to delete (whole file):**
- `src/fxhnt/application/vrp_book.py`
- `src/fxhnt/application/vrp_eval.py`
- `src/fxhnt/application/vrp_defined_risk_eval.py`
- `src/fxhnt/application/vrp_exec_record.py`
- `src/fxhnt/application/vrp_marking.py`
- `src/fxhnt/application/vrp_pricing.py`
- `src/fxhnt/application/vrp_research.py`
- `src/fxhnt/application/black_scholes.py`
- `tests/unit/test_vrp_book.py`
- `tests/unit/test_vrp_pricing.py`
- `tests/unit/test_vrp_exec_helpers.py`
- `tests/unit/test_vrp_exec_ladder_cap.py`
- `tests/unit/test_vrp_exec_record.py`
- `tests/unit/test_vrp_rebalancer_yaml.py` (also clears the pre-existing red — see pre-flight note)
- `tests/unit/test_registry_vrp.py`
- `tests/unit/test_black_scholes.py`
- `tests/integration/test_vrp_eval.py`
- `tests/integration/test_vrp_defined_risk_eval.py`
- `tests/integration/test_vrp_nav_asset.py`
- `tests/integration/test_cockpit_vrp_render.py`
**Rationale:** every one of these modules is imported only by other `vrp_*` modules or by the
`cli.py`/`assets.py`/`migration_builders.py` callers handled in later tasks. Deleting the tests
in the *same* task prevents collection-time `ImportError` on the deleted modules. Do NOT yet
touch `assets.py`, `cli.py`, `registry.py`, or `migration_builders.py` — those still reference
these modules only via **lazy (in-function) imports**, so the module tree still imports cleanly
after this task (the broken imports are inside function bodies not executed at import time). They
are removed in Tasks 35.
**Covering test command** (must import-clean and not collect the deleted files):
```
uv run pytest tests/unit tests/integration -q --co 2>&1 | tail -20
```
Expect: collection succeeds with the deleted VRP tests absent and no `ImportError`.
**Commit:** `refactor(vrp): delete VRP application modules + black_scholes + their tests`
---
## Task 2 — Delete the DVOL pipeline + its tests
**Files to delete (whole file):**
- `src/fxhnt/adapters/data/deribit_dvol.py`
- `src/fxhnt/application/dvol_ingest.py`
- `tests/integration/test_deribit_dvol.py`
- `tests/integration/test_dvol_ingest.py`
**Edit `src/fxhnt/ports/market_data.py`:**
- Remove the `VolIndexClient` Protocol (the `dvol()` method block, ~lines 2124). Confirmed
zero implementers and zero callers repo-wide; it is dead scaffolding.
**Do NOT touch:** `deribit_funding.py` and the `ingest-deribit-funding` CronJob/command —
that is the *funding* (cross-venue carry) edge, a separate kept data source that reads the
`funding`/`deribit_funding` features, never `dvol`.
**Rationale:** `ingest_dvol` and `DeribitDVOL` are consumed only by the `ingest-dvol` CLI
command (removed in Task 3) which fed only the two VRP evaluators (deleted in Task 1). The
`dvol` feature panel now has no readers.
**Covering test command:**
```
uv run pytest tests/integration -q --co 2>&1 | tail -20
grep -rn "VolIndexClient\|import.*deribit_dvol\|import.*dvol_ingest" src/ | grep -v "/cli.py"
```
Expect: no collection errors; the grep returns only the (still-present, removed next task)
`cli.py` lazy imports.
**Commit:** `refactor(vrp): delete DVOL pipeline (deribit_dvol, dvol_ingest, VolIndexClient port) + tests`
---
## Task 3 — Delete VRP + DVOL commands from `cli.py`
**File to edit:** `src/fxhnt/cli.py`
**Exact edits (delete each command block in full, including its in-function lazy imports):**
- Delete `@app.command("execute-vrp")` `execute_vrp` (lines ~439499), including the lazy
`from fxhnt.application.vrp_exec_record import plan_and_record_vrp`. **Keep** the module-level
and other commands' use of `ForwardNavRepo` — only remove this command's local import line if
it has one; the `ForwardNavRepo` module itself is reused by `execute-multistrat` and others.
- Delete `@app.command("ingest-dvol")` `ingest_dvol_cmd` (lines ~12171266), including the lazy
`from fxhnt.adapters.data.deribit_dvol import DeribitDVOL` and
`from fxhnt.application.dvol_ingest import ingest_dvol`.
- Delete `@app.command("vrp-eval")` `vrp_eval` (lines ~21932288), including the lazy
`from fxhnt.application.vrp_eval import (verify_vrp_edge, vrp_metrics_from_store, walk_forward_vrp)`.
- Delete `@app.command("vrp-defined-risk-eval")` `vrp_defined_risk_eval` (lines ~22912403),
including the lazy `from fxhnt.application.vrp_defined_risk_eval import (...)`.
- Delete the private helpers `_print_vrp_verify` (~24062446) and `_print_vrp_walk_forward`
(~24492469) — called only by the two eval commands above.
**Decision — `backfill-xsp-opra` (lines ~578623): DELETE this command too.** It calls
`_backfill_month` and `XspOptionBarsRepo`, both of which are deleted in Tasks 4/5, and its sole
purpose is freezing OPRA marks into `xsp_option_bars` **for VRP recompute**. Keeping the OPRA
*data* (Constraint 1) does not require keeping the *ingest path* — the data already exists and
the only consumer of freshly-frozen marks was VRP. Delete the `@app.command("backfill-xsp-opra")`
`backfill_xsp_opra` function and its `from fxhnt.adapters.orchestration.assets import _backfill_month`
+ `from fxhnt.adapters.persistence.xsp_option_bars import XspOptionBarsRepo` local imports. (If
the executor finds a documented non-VRP consumer of freshly-frozen OPRA marks, stop and flag —
none was found in the trace.)
**Covering test command:**
```
uv run python -c "import fxhnt.cli" # module must import clean
uv run fxhnt --help >/dev/null # Typer app builds with commands gone
grep -n "vrp\|dvol\|backfill-xsp\|VrpStrategy\|black_scholes\|XspOptionBarsRepo" src/fxhnt/cli.py
```
Expect: import + `--help` succeed; grep returns no hits.
**Commit:** `refactor(vrp): remove execute-vrp/ingest-dvol/vrp-eval/vrp-defined-risk-eval/backfill-xsp-opra CLI commands`
---
## Task 4 — Remove the `vrp_nav` asset + OPRA-freeze helpers from `assets.py`
**File to edit:** `src/fxhnt/adapters/orchestration/assets.py`
**Exact edits (delete code):**
- Delete the `@asset`-decorated `vrp_nav` function (lines ~686718), including its inline
imports of `DatabentoDataProvider`, `XspOptionBarsRepo`, `VrpStrategy` (~line 694).
- Delete the exclusive private helper chain (lines ~492683), all VRP-only and now callerless
after Tasks 1/3: `_iso_date`, `_forward_from_marks` (+ its inline
`fxhnt.application.vrp_pricing.parity_forward` import ~502), `_band_contracts`,
`_band_rows_from_marks`, `_day_marks`, `_xsp_forward_estimate`, `_freeze_xsp_slice`,
`_freeze_day`, `_prev_trading_day`, `_DEGENERATE_FORWARD_MARKERS`,
`_is_degenerate_forward_error`, `_freeze_latest_session` (+ its inline
`DatabentoRangeUnavailable` import ~614), `_rough_forward`, `_backfill_month`.
- Delete the trailing `# vrp_nav ARCHIVED 2026-07-15 — de-wired (fn kept below)` comment
(~line 1131) — the function no longer exists below.
- Reword the module docstring (~line 4): drop the trailing `/vrp` from the forward-track asset
enumeration.
**Do NOT touch:** `deribit_funding_bars` (~825856, unrelated Deribit perp *funding*, kept for
cross-venue-carry), and all other assets (`futures_bars`, `bybit_*`, `multistrat_*`,
`sixtyforty_nav`, `positioning_nav`, `xsfunding_nav`, `unlock_nav`, `cockpit_forward`, …). The
RETIRED-track comments at ~721 and ~748 do not mention vrp — leave as-is.
**Covering test command:**
```
uv run python -c "import fxhnt.adapters.orchestration.assets"
uv run python -c "import fxhnt.adapters.orchestration.definitions" # Dagster code-location loads
grep -n "vrp\|Vrp\|_backfill_month\|_freeze_\|XspOptionBarsRepo\|vrp_pricing" src/fxhnt/adapters/orchestration/assets.py
uv run pytest tests/integration/test_orchestration_definitions.py -q
```
Expect: both modules import clean, grep returns no hits, definitions test passes.
**Commit:** `refactor(vrp): delete vrp_nav Dagster asset + OPRA-freeze/backfill helper chain`
---
## Task 5 — Remove `XspOptionBarsRepo` class + the `_build_vrp` migration builder
**File to delete (whole file):**
- `src/fxhnt/adapters/persistence/xsp_option_bars.py` (the `XspOptionBarsRepo` repo class).
All callers (`vrp_book.py`, `vrp_exec_record.py`, `vrp_marking.py`, the `vrp_nav` asset, the
`backfill-xsp-opra` command) are gone after Tasks 1/3/4.
- **VERIFIED 2026-07-20: `tests/integration/test_xsp_option_bars_repo.py` does NOT exist in the tree** —
do not attempt to delete it. If a repo-class test surfaces under another name during removal, delete it;
otherwise there is no test file for this class.
**KEEP (Constraint 1):** `cockpit_models.XspOptionBarRow`, the `xsp_option_bars` table, and
`ForwardNavRepo.xsp_freeze_max_date()` — none of these import or depend on the repo class.
**File to edit:** `src/fxhnt/adapters/orchestration/migration_builders.py`
- Delete the `_build_vrp` closure (lines ~7176) and its `builders["vrp"] = ("vrp_state",
_build_vrp)` registration (~78), plus the preceding `# ---- vrp_nav: ...` comment banner (~71).
**Covering test command:**
```
uv run python -c "import fxhnt.adapters.orchestration.migration_builders"
grep -rn "XspOptionBarsRepo\|_build_vrp\|builders\[.vrp" src/
uv run pytest tests/ -q -k "migration or migrate" 2>&1 | tail -20
```
Expect: import clean, grep returns no hits (the `XspOptionBarRow` model in `cockpit_models.py`
is a different symbol and must still be present — verify separately:
`grep -n "class XspOptionBarRow" src/fxhnt/adapters/persistence/cockpit_models.py` returns 1 hit).
**Commit:** `refactor(vrp): delete XspOptionBarsRepo class + _build_vrp migration builder (keep table + XspOptionBarRow)`
---
## Task 6 — Remove `vrp`/`vrp_exec` registry keys + `forward_ingest` alias
**File to edit:** `src/fxhnt/registry.py`
- Delete the `"vrp"` `STRATEGY_REGISTRY` entry (lines ~161172) and its preceding comment
block (~157).
- Delete the `"vrp_exec"` `STRATEGY_REGISTRY` entry (lines ~177186) and its preceding comment
block (~173176).
- Keep the dict itself and all 9 non-VRP entries and the `FUND_INSTRUMENTS` import/re-export.
**File to edit:** `src/fxhnt/application/forward_ingest.py`
- Remove the `"vrp_exec": "vrp"` pair from `_REF_ALIAS` (line ~45), leaving
`{"multistrat_exec": "multistrat", "bybit_4edge_exec": "bybit_4edge"}`.
**Rationale + Constraint 4:** removing the `vrp` key is what actually kills the false VRP STALE
health alarm — with no `vrp` in `STRATEGY_REGISTRY`, the forward-health freeze/staleness loop
and `dashboard_service._active_ibkr_account_sids()` can no longer iterate a ghost VRP row.
(Note: `dashboard_service._IBKR_ACCOUNT_SIDS` hard-codes `"vrp"`; that literal is fixed in
Task 7 in the *same PR* so the window where the key is gone but the literal remains never ships.)
**Covering test command:**
```
uv run python -c "from fxhnt.registry import STRATEGY_REGISTRY; assert 'vrp' not in STRATEGY_REGISTRY and 'vrp_exec' not in STRATEGY_REGISTRY, STRATEGY_REGISTRY.keys(); print('registry clean')"
uv run pytest tests/unit/test_forward_definition.py tests/integration/test_forward_health.py tests/integration/test_dashboard_service.py -q 2>&1 | tail -20
```
Expect: assertion passes; forward/dashboard tests green (these confirm surviving strategies
still WAIT-by-default — Constraint 2).
**Commit:** `refactor(vrp): remove vrp/vrp_exec registry entries + forward_ingest _REF_ALIAS`
---
## Task 7 — Fix the one behavioral literal + `sim_curves` book pill (data edits)
These are the two non-comment edits that gate on `vrp` being a *present* registry key and would
misbehave once it is gone (Task 6). They ship together with — or immediately after — Task 6.
**File to edit:** `src/fxhnt/application/dashboard_service.py`
- Line ~30: change `_IBKR_ACCOUNT_SIDS = frozenset({"multistrat", "vrp"})` to
`frozenset({"multistrat"})`. **Why this is behavioral, not cosmetic:** `_active_ibkr_account_sids()`
computes `not STRATEGY_REGISTRY.get("vrp", {}).get("archived")`; once the `vrp` key is gone
this becomes `not None` = `True`, wrongly treating `vrp` as an ACTIVE ibkr-account sid and
rendering a ghost/broken VRP row on the IBKR account page. Removing the literal eliminates it.
**File to edit:** `src/fxhnt/application/sim_curves.py`
- Line ~15: remove the `"vrp"` string from the `SIM_BOOKS` tuple, leaving
`("bybit_4edge", "bybit_4edge_levered", "multistrat", "multistrat_levered")`. **Why:** once
the `vrp` registry entry is gone, a `vrp` Backtest-page pill would `KeyError`/500 at request
time in `app.py` (`registry_backtest_kind("vrp")`). The dispatch logic in `sim_returns_for`
is generic and unchanged.
**Covering test command:**
```
uv run pytest tests/unit/test_sim_curves.py tests/integration/test_dashboard_service.py tests/integration/test_ibkr_account_detail_web.py tests/integration/test_dashboard_ibkr_holdings.py tests/integration/test_paper_books_web.py tests/integration/test_ibkr_sim_web.py -q 2>&1 | tail -20
```
Expect: green; no VRP row/pill; surviving books render.
**Commit:** `fix(vrp): drop vrp from _IBKR_ACCOUNT_SIDS and SIM_BOOKS so ghost VRP row/pill can't render`
---
## Task 8 — Delete the now-purposeless VRP/OPRA CronJob manifest
**File to delete:**
- `infra/k8s/jobs/fxhnt-opra-backfill.yaml` — invokes `fxhnt backfill-xsp-opra` (deleted in
Task 3). With the command gone this CronJob would crash-loop; its only job was freezing OPRA
marks for VRP recompute. (The `fxhnt-vrp-rebalancer.yaml` manifest is already absent from the
tree — nothing to delete there; its dangling test is removed in Task 1.)
**Do NOT touch:** `fxhnt-deribit-carry-job.yaml` (funding/carry, not DVOL),
`fxhnt-bybit-*`, `fxhnt-ucits-rebalancer.yaml`, `fxhnt-ibkr-rebalancer.yaml`, and all other
manifests.
**Covering check:**
```
grep -rln "vrp\|ingest-dvol\|execute-vrp\|backfill-xsp-opra" infra/ # expect: no hits
```
**Commit:** `chore(vrp): remove fxhnt-opra-backfill CronJob (backfill-xsp-opra command deleted)`
---
## Task 9 — Comment/docstring scrubs (no logic change) — LAST
Pure prose edits that dangling-reference the deleted `vrp` strategy id. No imports, logic,
registry entries, or types change. Batched last because none affect importability.
**Files + edits (reword to drop the `vrp` example, keep meaning):**
- `src/fxhnt/adapters/orchestration/definitions.py` — lines ~1012: drop the
"vrp_nav ARCHIVED … KEPT in assets.py but DE-WIRED" paragraph (the "KEPT" claim is now false);
replace with a one-line "VRP removed entirely 2026-07-20" note or delete outright.
- `src/fxhnt/adapters/persistence/cockpit_models.py` — line ~46 (drop the `(… that would have
caught vrp)` parenthetical or generalize to "a dead strategy"); line ~228 (drop `/vrp` from
`(multistrat/vrp …)`).
- `src/fxhnt/adapters/persistence/forward_nav.py` — lines ~146147 (generalize "the vrp freeze
table" / "a vrp recompute is bounded by this max date" to opra-pit-anchored/strategy-generic
wording; the `xsp_freeze_max_date` query stays); line ~199 (drop the "shelved/FALSIFIED
vrp/vrp_exec" example from the `archived: True` registry note).
- `src/fxhnt/adapters/persistence/paper_repo.py` — line ~519 (drop `vrp` from the
`(multistrat/vrp …)` recompute-replay parenthetical).
- `src/fxhnt/adapters/web/app.py` — lines ~449, 453, 473, 482, 551, 567, 728, 752, 810: drop the
`/vrp` example from each `multistrat/vrp` phrase. No code change (the archived-filter
comprehension already yields one fewer element once `vrp` left `SIM_BOOKS`/registry).
- `src/fxhnt/adapters/web/templates/_macros.html` — line ~61 ("2-week vrp rot"): generalize.
- `src/fxhnt/adapters/web/templates/cockpit.html` — line ~78: drop `/vrp` from
"two IBKR real-account books (multistrat/vrp)".
- `src/fxhnt/application/dashboard_service.py` — comment-only lines ~27, 55, 89, 390, 416, 417:
drop/generalize the `vrp` examples (the code literal was already fixed in Task 7).
- `src/fxhnt/application/sim_curves.py` — lines ~2, 12, 22: drop `vrp` from the
`multistrat/vrp` recompute-replay examples (the tuple was already fixed in Task 7).
- `src/fxhnt/application/forward_health.py` — docstring lines ~3, 11, 13, 14, 15, 24, 31 and the
inline comment at ~147 ("for the vrp freeze axis"): generalize away from naming `vrp` as the
mechanism's reason for existing; the `_FREEZE_SOURCES = {"opra-pit"}` logic and
`xsp_freeze_max_date()` call are unchanged.
- `src/fxhnt/application/display_names.py` — lines ~2 and ~51: drop the `vrp` example id /
option-contract example from the illustrative prose.
- `src/fxhnt/application/em_asia_marginal_eval.py` — lines ~6, 19, 71: replace "VRP" in the
Stage-1 kill-gate precedent comments with a VRP-agnostic phrase ("prior failed diversifier
candidates"). No logic change.
- `src/fxhnt/config.py` — line ~215: drop `(… that would have caught vrp)` from the
`stale_after_business_days` comment; keep the setting + default.
- `src/fxhnt/ports/dashboard.py` — lines ~72 and ~190: drop the `vrp` example from the
`multistrat/vrp` IBKR-real-account docstrings. (Line ~34 is unrelated carry — leave.)
- `src/fxhnt/vendor/surfer/__init__.py` — lines ~1113: compress the `surfer_poc`/
`MomentumVrpStrategy` retirement note to a plain historical line without the VRP signpost.
**Do NOT edit** as part of scrubbing (already covered / must not change): the `xsp_option_bars`
query, `_FREEZE_SOURCES`, `XspOptionBarRow`, any settings field, or any Protocol field.
**Covering test command** (broad — scrubs must not have touched logic):
```
uv run python -c "import fxhnt.adapters.web.app, fxhnt.application.dashboard_service, fxhnt.application.forward_health, fxhnt.config, fxhnt.ports.dashboard, fxhnt.application.display_names, fxhnt.application.em_asia_marginal_eval, fxhnt.application.sim_curves"
uv run pytest tests/unit/test_display_names.py tests/integration/test_dashboard_service.py -q 2>&1 | tail -20
```
Expect: all import clean; tests green.
**Commit:** `docs(vrp): scrub stale VRP comment/docstring references across cockpit + shared infra`
---
## Task 10 — Full-suite green gate + removal verification (release gate)
**No file edits.** Final verification against all Global Constraints.
**Commands (all must pass):**
```
# (3) full suite green
uv run pytest -n auto 2>&1 | tail -30 # 0 failed, 0 errors
# (4) no vrp in registry — false STALE alarm gone
uv run python -c "from fxhnt.registry import STRATEGY_REGISTRY; assert not any(k.startswith('vrp') for k in STRATEGY_REGISTRY), list(STRATEGY_REGISTRY); print('no vrp in registry')"
# no orphaned VRP code / imports anywhere in src
grep -rn "import.*vrp_\|VrpStrategy\|deribit_dvol\|dvol_ingest\|black_scholes\|XspOptionBarsRepo\|VolIndexClient\|_backfill_month\|plan_and_record_vrp" src/ # expect: no hits
ls src/fxhnt/application/vrp_*.py 2>&1 # expect: No such file
ls src/fxhnt/application/black_scholes.py src/fxhnt/application/dvol_ingest.py src/fxhnt/adapters/data/deribit_dvol.py src/fxhnt/adapters/persistence/xsp_option_bars.py 2>&1 # expect: No such file (all four)
# (1) OPRA data kept — table model + freeze query still present
grep -n "class XspOptionBarRow" src/fxhnt/adapters/persistence/cockpit_models.py # expect: 1 hit
grep -n "def xsp_freeze_max_date" src/fxhnt/adapters/persistence/forward_nav.py # expect: 1 hit
# (2) Dagster code-location + cockpit app both import clean (no false-execute / no outage)
uv run python -c "import fxhnt.adapters.orchestration.definitions; import fxhnt.adapters.web.app; print('definitions + app import clean')"
# no residual vrp mentions in infra
grep -rln "vrp\|ingest-dvol\|execute-vrp\|backfill-xsp-opra" infra/ # expect: no hits
```
**Constraint 2 spot-check:** confirm `forward_ingest`'s promotion loop and the cockpit gate
default to WAIT for every surviving strategy (the recon-gate never false-PASSes) — covered by
`test_forward_health.py` / `test_dashboard_service.py` in the full run; if either regresses, the
removal touched a shared gate path and must be reverted to the last green task.
**Commit (only after everything above is green):** `chore(vrp): verify full VRP removal — suite green, registry clean, OPRA data intact`
---
## Post-removal note
After merge, update `docs/superpowers/VRP-REMOVAL-TODO.md` and project memory
(`pearl_fxhnt_diversifier_hunt_2026_07_15.md` already says "VRP now fully DELETED (shelved)") to
reflect that the code deletion — not just shelving — is complete, and that the OPRA
`xsp_option_bars` data was retained per Constraint 1.