# VRP pessimistic twin — same-snapshot fix (panel A1) — 2026-08-01

**Status:** instrument fix (measurement only). The twin never touches a trading
decision; no registered parameter value changes; the manage rule, sizing, and
safety gate are untouched byte-for-byte.
**Source:** quant panel 2026-08-01, item A1 (derivatives PM; 3/3 survive).
**Scope:** `execution/vrp_daily.py` close-side twin pricing; the pessimistic
ledger's reader (`execution/fleet_digest.py`); the 4 pre-fix ledger rows.
**Forward-only:** effective for rows appended on or after 2026-08-01. No
historical pessimistic value is recomputed or altered.

---

## 1. The defect

The twin ledger re-prices every paper fill at the worst side of the quoted
spread (paper fills print at NBBO, so the twin is the sleeve's only execution
cost measurement). The OPEN path was correct: decision (selection) and twin
both price off the same chain rows — one snapshot. The CLOSE path fetched
**three times**:

1. decision mid (`_current_spread_value`, run start);
2. the twin's worst-side price (`_twin_close_cost`, its own fetch);
3. the recorded `mid_close_cost` (ANOTHER `_current_spread_value` call after
   the fill-confirm poll — potentially minutes later).

The recorded drag `pessimistic_close_cost − mid_close_cost` therefore mixed
spread cost with market drift between fetches. Evidence, from the committed
ledger: the 2026-07-31 close printed `mid_close_cost 0.18`,
`pessimistic_close_cost 0.15`, `spread_drag_per_share -0.03` — a pessimistic
fill BETTER than the mid, impossible from one quote. The ~0.03/sh of
fetch-timing noise is the same size as the ~0.075/sh round-trip measurand the
sleeve's economics hang on (twin-measured drag 0.035–0.04/sh per side vs
0.18–0.27/sh cycle credit).

## 2. The fix

One `_fetch_leg_quotes` read per managed run produces a single snapshot; the
decision mid (`_spread_mid_from_quotes`), the twin's worst-side price
(`_twin_close_cost_from_quotes`), and the ledger's recorded mid are all
derived from it — mirroring the open path. The profit-take confirmation
re-reads (fidelity amendment 2026-07-25) still take FRESH quotes: a new
observation is their entire point; they do not feed the twin.

**Invariant now enforced by construction and unit-asserted:** from one
snapshot, worst-side ≥ mid for a buy-to-close and worst-side ≤ mid for a
sell-to-open, so `spread_drag_per_share ≥ 0` whenever both numbers exist.
Residual honesty note: "one fetch" is one API response, not one matching
engine instant — each leg's *latest* quote inside the response carries its own
timestamp, so a stale leg can still skew a reading. That residual is exactly
what the kill criterion below watches.

Fail-soft is preserved and now call-site-guarded: a twin computation that
raises records null and the trade proceeds (tested; the twin is observability,
never a gate).

## 3. The 4 pre-fix rows — annotated, not rewritten

One annotation record was APPENDED to `data/state/vrp/pessimistic_ledger.jsonl`
on 2026-08-01 (`type: "annotation"`, `annotates: ["2026-07-13", "2026-07-22",
"2026-07-23", "2026-07-31"]`). No prior line was modified. The close rows
(07-22, 07-31) are basis-contaminated per §1; the open rows are flagged with
them so no downstream constant is ever fit across the basis change (07-13
additionally carries the null-credit occ-key bug). Every ledger reader skips
annotation records (`fleet_digest._gather_option_sleeve` is the only
programmatic reader today; tested for tolerance).

## 4. Pinned forward reading + kill criteria (BINDING — dated 2026-08-01)

Written before any post-fix row exists. Definitions: a "post-fix row" is any
non-annotation row dated ≥ 2026-08-01; a "cohort" is one open + its close;
"negative drag" is `spread_drag_per_share < 0`.

1. **Expectation:** across the next ~5 cohorts (~10 rows), **zero** negative
   drags.
2. **Unstable-feed kill (of the measurement's precision claim):** if ≥ 2
   post-fix rows in the first 5 cohorts print negative drag, the feed is
   declared unstable at the measurand's scale. Consequence: the drag series
   carries an uncertainty band (min/max across the cohort window), and every
   downstream constant derived from it — explicitly including the D1 v2
   spec's amortization drag constant — is taken from the band's
   **conservative (higher-cost) edge**. The fix is not reverted; the band is
   the honest statement of what the instrument can resolve.
3. **Family-level kill (pre-registered here per panel A1):** if measured
   round-trip drag is ≥ 50% of cycle credit **even at wider structures**
   (width 2–3, i.e. the D1 v2 configuration), defined-risk put spreads are
   untradable at retail friction — the family dies, not just the width-1
   variant. Evaluation point: v1 resolution (~2027-01) or the first
   wider-structure cohort set, whichever exists first; the statistic is the
   post-fix twin's median round-trip drag vs median cycle credit.
4. No other criterion may be added after post-fix data is visible; amendments
   to this memo are dated appends.

## 5. Red-team conditions honored (from the panel report)

- **Forward-only:** no historical pessimistic value recomputed or altered —
  the fix changes only how NEW rows are priced.
- **Annotate the 4 existing rows basis-contaminated:** done by appending one
  annotation record (§3); the ledger remains append-only.

## 6. Tests

- `tests/test_execution/test_option_intents.py::test_twin_same_snapshot_invariants`
  — property test of the one-snapshot invariants + an executable negative
  control showing two snapshots CAN print pessimistic < mid (the 07-31 shape).
- `...::test_vrp_close_ledger_same_snapshot_under_quote_drift` — end-to-end:
  under a monotonically rising quote feed the ledger row keeps `drag ≥ 0`,
  records the decision-read mid, and consumes exactly ONE fetch; reverting to
  per-number re-fetching fails it.
- `...::test_vrp_twin_failure_never_blocks_trading` — open and close both
  execute when the twin computation raises.
- `tests/test_execution/test_fleet_digest.py::test_fleet_twin_reader_skips_annotation_records`
  — the digest reports the last TRADE row, not the annotation.
