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:
- decision mid (
_current_spread_value, run start); - the twin's worst-side price (
_twin_close_cost, its own fetch); - the recorded
mid_close_cost(ANOTHER_current_spread_valuecall 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.
- Expectation: across the next ~5 cohorts (~10 rows), zero negative drags.
- 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.
- 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.
- 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 keepsdrag ≥ 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.