# Cockpit: surface the levered shadow track in Backtest + Replay — Design

**Status:** draft for review
**Date:** 2026-07-05

## Goal

Let the user visually compare the naive `bybit_4edge` book against its levered shadow (`bybit_4edge_levered`) in the two cockpit views that currently show only the naive book: the **Backtest** (`/paper/sim`) and the **Replay** (`/paper/replay`). The overview/gate list already shows both gate rows; these two curve/track views do not. Observe-only — no capital, no new positions.

## Why it is not a trivial toggle (the constraint that shapes the design)

The levered shadow track exists ONLY as a `forward_nav` return series + `forward_summary` gate row + `backtest_summary` reference. It has **no positions** (observe-only) and **no precomputed measured curve**. The two views consume different data:

- **Backtest** reads a precomputed **MEASURED per-coin cost curve** (`compare_measured_cost._bybit_measured_net` → `bybit_liquidity_sweep.per_coin_book_returns`), cached in `compare_measured_cache`, read via `read_cached_single_measured`. The Backtest deliberately shows ONLY measured cost, never flat (a flat/cost-blind curve is the +7097% mirage foot-gun). So the levered Backtest curve must ALSO be measured — it cannot be a cheap flat combine.
- **Replay** reads the venue paper-book `nav_history()` + scrubbable per-day positions (`_venue_repo(venue).nav_history()`). The shadow has no positions, so a levered replay must read its `forward_nav` and render position-less (exactly as carry/xsfunding already does — "return-defined, no scrubbable positions").

## Design

### Component 1 — Backtest: a measured levered curve
- Thread an optional `leverage_shape: dict[str,float] | None` (+ `max_gross`) through `per_coin_book_returns` and `_bybit_measured_net`. When set, the per-sleeve per-coin weights are scaled by `shape[sleeve]/n` and the whole book down-scaled so summed gross ≤ `max_gross` (the SAME transform as `levered_eqwt_daily_returns`, applied at the per-coin weight layer, so the GROSS book and per-coin measured turnover cost stay internally consistent). `leverage_shape=None` → the current naive eq-wt path, byte-identical.
- `precompute_single_book_measured` also computes + caches the levered book under key `bybit_4edge_levered` (reusing `_LEVERED_SLEEVE_SHAPE` / `MAX_BOOK_GROSS` from `bybit_forward_track`).
- Add `bybit_4edge_levered` to `_SIM_BOOKS` in `web/app.py` as a 4th book-switch pill ("Bybit 4-edge levered · shadow"). `_sim_returns` / `read_cached_single_measured` resolve it like the other single books.
- Re-run the `compare-measured-precompute` Job so the levered measured cache is populated (in-cluster, git-synced — like the sleeve-ret Job).

### Component 2 — Replay: naive↔levered track toggle
- `paper_replay` / `paper_replay_at` gain an optional `track` param (default `naive`). `track=naive` → the current venue paper-book `nav_history()` path (unchanged). `track=levered` → read the `bybit_4edge_levered` `forward_nav` series (via `ForwardNavRepo` / the DashboardService `detail`) and render the NAV curve position-less, with the same "return-defined — no scrubbable positions" note carry uses.
- `replay.html` gains a small naive↔levered toggle (like the existing venue toggle), relative-URL, htmx-consistent.

### Objective & honesty guardrails
- The Backtest levered curve MUST be measured-cost (never flat) — the same anti-mirage principle as the naive book. Label it clearly as the levered SHADOW.
- The Replay levered track is the recorded forward_nav (0 days at inception; grows as it accrues) — clearly labelled observe-only, no capital.
- Naive paths stay byte-identical (`leverage_shape=None`, `track=naive`).

## Testing
- Unit: `per_coin_book_returns(leverage_shape=uniform)` == naive; carry-weighted shape scales + gross-caps; `_bybit_measured_net` levered curve differs from naive with the same measured cost model.
- Web: `/paper/sim?book=bybit_4edge_levered` renders (measured curve or graceful pending note); the book-switch shows the 4th pill; `/paper/replay?track=levered` renders the forward_nav curve position-less; `track=naive` unchanged; both leak-clean.
- **LOCAL BROWSER (mandatory, per feedback_verify_cockpit_locally_not_prod):** run the cockpit locally, open both pages in a real browser (playwright), read the actual rendered numbers/curves, screenshot naive vs levered side by side. Never claim "works" off prod/synthetic.

## Non-goals
- No levered Paper view (`/paper`) — the shadow has no positions; Paper stays naive-only.
- No adaptive overlay / killswitch (that is Phase 2 of the leverage spec).
- No capital.

## Risks
- **Measured-cost core is sensitive** — the leverage_shape must not change the GROSS series or the per-coin cost model, only the sleeve weighting; the uniform-shape==naive test is the guard.
- **Precompute Job must re-run** or the levered Backtest shows the graceful pending note until it does — acceptable (never a 500, never a flat curve).
