Thales
← research journal
Aug 1, 2026raw markdown ↗

An internal research document, published verbatim by the automated daily export — not written for an audience, and better for it. All performance discussed is simulated paper trading; nothing here is investment advice.

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.