# Multi-Sleeve Platform — SPEC (pre-registered 2026-07-05)

**Status update (same day): P1 #10, P2a #11, P3 #12 MERGED — the platform is
built; momentum tenant byte-identical throughout (Δ 0.00e+00 after every
engine touch). Deviations from the plan, per the header rule: (a) all three
phases landed same-day, each still individually branch+PR gated; (b)
`results/meanrev|vrp` formally gitignored (implied by D3, made explicit
after a stray `git add -A` swept a battery log); (c) a latent AFK-guard
bash-3.2 parse bug was found and fixed while extending the guard in P1; (d)
VRP mleg submits MARKET in the scaffold — the net-credit LIMIT sign
convention is a pinned pre-P3-live verification, not assumed. meanrev
battery verdict: RESEARCH.md banner.

POST-BUILD AUDIT (adversarial multi-agent, 2026-07-05 — RESEARCH.md banner):
23 findings confirmed, fixed same day. Deviations it forced: (e) momentum's
five IDENTITY keys (name/contract/api_key_env/results_dir/processed_dir)
made explicit in settings.yaml + keystone-pinned — the refactor made them
behavior-controlling on the live cron but only the sleeves were pinned; (f)
option safety gate strengthened to recompute worst-case loss from leg strikes
(D7's "the strategy never decides what defined-risk means" was only half-true
— it trusted a self-reported field) and to a strict per-kind SHAPE contract
(the per-short pairing check let a net-naked structure pass); (g) the
daily-loss breaker now classifies options by ACTION not side (an OPEN nets
'sell' but is risk-increasing — it was being exempted on crash days); (h) D7's
fleet cross-name WARN report and per-underlying option cap DEFERRED (need
cross-sleeve / broker-option position data; dead fleet key removed, go-live
items pinned in vrp.yaml); (i) meanrev cpcv.purge_days 21→69 (registration
under-purge; verdict robust — under-purge only flatters PBO). Original
Phase-0 text follows.**

**Status: Phase 0 (this document). No code exists yet.** This spec is written
and committed BEFORE implementation, in the same discipline as every other
pre-registration in this repo: the commit timestamp is the registration.
Deviations during build are allowed but must be documented here with a why.

**The reframe:** Thales stops being "a strategy with infrastructure" and
becomes "a platform hosting sleeves," where momentum is the first tenant. The
actual asset is the falsification apparatus (CPCV, pre-registration, keystone
pins, parity harness, fail-closed execution) — all of it strategy-agnostic.

## 0. Verdict — which sleeves, and which not

| Sleeve | Decision | Why |
|---|---|---|
| **meanrev** (2–10d equity reversal) | **BUILD — research first, live only on gate pass** | Near-zero marginal cost (same broker/data/engine/validation); the literal anti-momentum (negatively correlated by construction); the cheapest forcing function for the platform refactor itself. A REJECTED verdict still leaves the platform built — that is most of the point. |
| **vrp** (defined-risk SPY option spreads) | **BUILD — forward-only experiment** | Highest-conviction premium reachable on existing rails (Alpaca options, verified below). CANNOT pass the SHIP gate as constructed — no owned chain history, no options backtest engine — and we will not fake one. Its validation IS a pre-registered forward gate (documented posture, not a gap). Also generates the options fills/TCA exhaust the skew-timed hypothesis will eventually need, without touching that capture's own 12–18mo activation criterion. |
| **futures trend** (micro futures, IBKR) | **DEFER — pre-registered Phase 4, next in line** | Best diversifier on the menu (crisis convexity momentum lacks), but new broker + IBKR gateway automation (headless sessions, 2FA, restarts) + roll logic + short mechanics = a Phase-2-scale project. Do it after the platform is proven on cheap sleeves. |
| **PEAD** (estimate-free SUE from owned XBRL) | **BACKLOG — AFK hypothesis** | An equity *signal*, not an architecture problem. Feed to the AFK loop; promote only if it screens. NB the 3-account cap (below) means promotion requires replacing a killed sleeve or building the deferred sub-book design. |

**Attention is the binding constraint, not compute or capital.** Hard cap:
**3 live sleeves** for a solo operator. One digest email, ever.

## 1. Verified pre-flight facts (2026-07-05)

- **Alpaca allows up to 3 simultaneous paper accounts per user profile**,
  each with its own API keys, positions, and equity — confirmed current as of
  late 2025 sources. One-account-per-sleeve fits exactly, with zero headroom.
- **Multi-leg (Level 3) options are supported in PAPER** via Trading API
  (`order_class: "mleg"`, legs array with per-leg symbol/side/ratio/intent)
  and alpaca-py (our pinned 0.43.x era supports options). Defined-risk
  spreads are executable as single atomic orders.
- Alpaca **paper options fills are simulated** (same class of caveat as
  equities: paper measures rule-fidelity, never execution quality). Document,
  don't fight.
- To confirm at Phase-3 setup (low risk): options approval level defaults on
  paper accounts; per-account options buying-power mechanics.

## 2. Architecture decisions (D1–D14)

**D1 — A sleeve is a 6-tuple.** `(config file, state dir, results dir,
broker account, workflow, keystone set)`. The platform owns everything
downstream of the strategy contract: sizing guardrails, execution, state,
validation harnesses, monitoring, ops.

**D2 — One paper account per sleeve.** Attribution solved at the broker:
physically separate equity curves, fills, positions; safety gates evaluate
per-account equity; reconcile runs per sleeve; no netting logic anywhere.
*Rejected:* virtual sub-books in one account (sleeve-tagged client IDs +
fill-attribution ledger + virtual cash + netting when two sleeves disagree
on the same name) — complexity only real money in a single account should
ever force. The 3-account cap is accepted and pinned (see D14).

**D3 — Momentum is grandfathered in place.** Momentum keeps
`config/settings.yaml`, `data/processed/`, `results/` exactly as today. New
sleeves get `config/{sleeve}.yaml`, `data/state/{sleeve}/`,
`results/{sleeve}/`. *Rejected:* uniform migration of momentum into the new
namespace — moving files that CI commits daily breaks committed-history
continuity, the workflow persist list, heartbeat paths, the captures
registry, backup includes, and docs-consistency tests, all for aesthetics.
The platform treats paths as per-sleeve config values; momentum's happen to
be the legacy ones. Deliberate, documented, not debt.

**D4 — Two strategy contracts, both funneling into the one chokepoint.**
- *Weight-based* (exists): `compute_signals(panel) → generate_weights(date)`
  → `build_target_weights` → orders. Momentum already implements it;
  meanrev slots in as a second `Strategy` subclass + registry entry.
- *Order-intent* (new, VRP): `intents(date, positions, state) →
  [OptionStructure]` — legs, expiries, rolls don't live in weight space;
  forcing them there corrupts both interfaces.
- **Fleet law (unchanged):** every order from every contract passes through
  `pipeline.execute_orders` and the fail-closed safety gate. No sleeve gets
  a bypass path, ever.

**D5 — CLI: one global `--sleeve` option** (app-level callback; default
`momentum`) resolving config/state/results/broker-keys. Every existing
command, document, and test is unchanged by default. *Rejected:* per-command
`--config` flags (leaky; trivially cross-wires a backtest against the wrong
state dir).

**D6 — Keystones per sleeve.** `config_guard` grows a per-sleeve registry
(momentum's `KEYSTONES` unchanged); `verify-config`/`selfcheck` check every
sleeve; `test_keystones_match_real_settings` iterates all sleeve configs.
Each sleeve's clean-start date, cadence, purge window, and safety limits are
pinned in ITS keystone set.

**D7 — Safety gate: per-sleeve limits + new structural option REJECTs.**
Existing HALT/REJECT taxonomy transfers per account (limits scale to sleeve
equity). New, enforced in the GATE (not the strategy, so a sleeve bug cannot
create undefined risk): every short option leg must be paired within the
same submitted structure; structure max loss (width − credit) ≤ pinned % of
sleeve equity; no naked short options, period; per-underlying position cap.
Plus one fleet-level WARN-only report: combined per-name exposure across
sleeve accounts (momentum and meanrev both long AAPL is invisible
per-account).

**D8 — Halt semantics.** `data/processed/TRADING_HALT` stays the **fleet
halt** (every sleeve checks it — one file stops everything, commit+push
semantics unchanged). New per-sleeve halt: `data/state/{sleeve}/HALT`, written
by **`thales --sleeve X halt`** (--sleeve is the app-level global, so it
precedes the subcommand — the D8-draft `thales halt --sleeve X` does NOT parse;
corrected per the 2026-07-05 audit). Kill-switches are per-sleeve (own equity
curve, own state file, own re-entry).

**D9 — One workflow per sleeve.** Own cron, own concurrency group, own
timeout, own secrets (`ALPACA_API_KEY_{SLEEVE}` / `ALPACA_SECRET_KEY_{SLEEVE}`);
failure emails arrive pre-labeled by sleeve; disjoint state paths make the
push races content-free (the rebase-retry covers the rest);
`heartbeat-monitor.yml` extends to check every sleeve's equity file. Each
sleeve pins its own cadence (meanrev selects daily; VRP checks rolls daily,
trades ~weekly).

**D10 — One digest email, per-sleeve sections, fleet header.** Three emails **[BUILT 2026-07-13, PR #30: `thales fleet digest` + fleet-digest.yml; momentum's in-workflow digest retired]**
a day is how alert fatigue kills monitoring. Each sleeve gets its own
oos-monitor with its own pinned forward criteria and verdict history. New
`thales fleet status [--json]` (the audit routine's one-stop read) and, once
two sleeves accrue, `thales fleet correlation` — **forward realized
cross-sleeve correlation is data nobody sells**, and it is exactly what the
allocation rule (D12) will eventually consume. The per-sleeve equity JSONLs
are already the capture; the correlation is derived, so it is a report, not
a new capture stream.

**D11 — Validation parameterized per sleeve.**
- CPCV purge = f(sleeve max lookback): momentum 252d (unchanged); meanrev
  ≈ 21d — purging a 5-day signal by 252d is massive over-purging that
  throws away most paths. Pinned per sleeve.
- Per-sleeve `baseline_metrics.json` (byte-identical guard), pinned OOS
  reference, clean-start date, walk-forward windows.
- VRP has NO backtest by posture: its keystone file documents the forward
  gate as the validation instrument (absence of a backtest is a documented
  decision, not a hole).
- The engine gains a `stock_selection: "daily"` cadence for meanrev —
  **additive only**; momentum's byte-identical guard must show Δ 0.00e+00
  after the change, like any engine-adjacent edit.

**D12 — Capital allocation rule, PRE-REGISTERED NOW** (this commit is the
registration): if/when real money ever spans sleeves, allocation is
**equal-risk** — inverse trailing-126-trading-day realized vol of each
sleeve's live equity curve — rebalanced **quarterly**, never
performance-chasing, never overridden by whichever sleeve had the best
recent quarter. Becomes a pinned fleet keystone when `config/fleet.yaml`
lands in Phase 1. (Boring and right; the alternative is the exact
gate-shopping the go_live section exists to prevent.)

**D13 — Ops surface extensions.** AFK `pretool_guard.sh` deny list gains
`data/state/`; `backup_data.sh` include gains `data/state` and
`results/{sleeve}` evaluation dirs; CAPTURES.md ↔ `captures.py` gain
per-sleeve stream entries (the lockstep test enforces it); RUNBOOK
what-runs-where table goes per-sleeve; AUDIT.md daily/weekly checks read
`thales fleet status --json` so the weekly routine's cost stays flat as
sleeves are added.

**D14 — Attention budget, pinned.** Max 3 live sleeves. A 4th strategy
(e.g., promoted PEAD, futures trend) replaces a killed sleeve or waits.
Single digest. One new live sleeve at a time, phases fully gated.

## 3. Sleeve specs

### S1 — meanrev (Phase 2)
- **Hypothesis family** (exact params pre-registered via
  `thales research draft-hypothesis --slug meanrev_v1` at Phase-2a start,
  BEFORE any run): short-horizon reversal — buy the most oversold decile by
  2–10d z-scored return within the liquid top of the existing Russell-1000
  panel; hold ~3–5d; equal or inverse-vol weights (likely NO Kelly — the
  pooled-cohort semantics don't transfer to daily cadence; per-sleeve config
  decides); per-day turnover cap at face value (cap × 1).
- **Gates = standard SHIP apparatus at meanrev parameters, PLUS two
  sleeve-specific re-validations:**
  1. **Cost-model re-check at meanrev turnover.** Flat-10bps ≡ Almgren-Chriss
     was validated at MOMENTUM turnover only; meanrev turns over ~10×. The
     strategy lives or dies on costs — run the equivalence diagnostic at its
     turnover before believing any Sharpe.
  2. **Timing bound re-run under meanrev config.** The next_open-vs-next_close
     wash was measured on momentum; a 10× turnover strategy is 10× more
     clock-sensitive.
  3. CPCV with purge ≈ 21d, standard + survivorship-free on golden.
- **Live (2b) ONLY on gate pass** — paper account #2, own workflow, digest
  section, 30+ day shakedown before anyone reads its equity curve as signal.
  Honest prior: published raw reversal edge has decayed badly since the
  2000s; expected outcome is REJECTED — and the platform survives that.

### S2 — vrp (Phase 3, forward-only)
- **Mechanical rule (pinned in `config/vrp.yaml` keystones before the first
  order; current draft, finalize at Phase-3 start):** sell a ~30-delta SPY
  put credit spread, ~30 DTE, defined width (e.g., $5); manage at 21 DTE or
  50% of max profit, whichever first; re-enter next cycle; one structure
  cohort at a time; risk per structure (width − credit) ≤ pinned % of sleeve
  equity; **defined-risk only, no naked short options ever** (also enforced
  structurally in the safety gate — D7 — so a bug can't do it either).
- **Forward gate (its entire validation):** own oos-monitor-style criteria
  pinned before first trade — e.g., ≥126 live td, Sharpe bootstrap lower
  bound and max-DD limits, plus the left-tail honesty line: this premium
  pays BECAUSE it hurts sometimes; a drawdown inside the pinned envelope is
  the strategy working, not failing.
- **Relation to the skew capture:** untimed vanilla VRP is a SEPARATE
  hypothesis from the skew-timed version (12–18mo accrual, pre-registered
  activation) — running it does not touch, and must not be used to shop,
  that criterion.

### S3 — deferred (pre-registered so they don't drift)
- **futures trend** — Phase 4, next in line after the platform is proven:
  micro futures (MES/MGC/FX/rates) time-series trend on IBKR; the known
  costs are gateway automation, roll logic, short mechanics, new data.
- **PEAD** — AFK hypothesis backlog: estimate-free SUE from the owned
  PiT-correct XBRL store (seasonal random-walk earnings model, no analyst
  feed). Equity signal on the weight contract if it ever screens.

## 4. Phase plan (each phase = its own branch + PR, gated by the existing guards)

| Phase | Content | Exit gate |
|---|---|---|
| **P0** | This spec | Committed (done) |
| **P1** | Platform extraction, ZERO behavior change: `--sleeve` resolution, sleeve/keystone registries, `config/fleet.yaml` (incl. D12 allocation keystone), fleet status command skeleton. Momentum = sole tenant, grandfathered paths | Byte-identical baseline **Δ 0.00e+00**; full parity harness green; entire suite green; docs-consistency green; momentum CI workflow diff ≈ zero |
| **P2a** | meanrev research on the platform: strategy class, engine daily cadence (additive), pre-registration, evaluate + CPCV(purge 21) + survfree-golden + cost/timing re-validations | Verdict recorded either way; baseline guard still Δ 0 after the cadence addition |
| **P2b** | meanrev LIVE paper (account #2, secrets, workflow, digest section, captures entries) — **only on 2a pass** | 30-day shakedown clean; per-sleeve reconcile/heartbeat/backfill proven |
| **P3** | VRP: order-intent contract, options safety REJECTs, account #3, pinned rule + forward gate; live paper day one | Safety gate proven on synthetic bad structures (naked leg, oversized loss → REJECT); first cycle executes + rolls cleanly |
| **P4** | futures trend (IBKR) — not scheduled; pre-registered next | — |

## 5. Risk register
- **Refactor touches engine behavior** → the byte-identical guard is the
  tripwire; any Δ ≠ 0 stops the phase.
- **CI blast radius on the live momentum cron** → grandfathering (D3);
  Phase-1 aims for a near-zero diff to `paper-trading.yml`.
- **Alert fatigue** → one digest (D10); per-sleeve failure emails are
  pre-labeled; fleet status is one command.
- **Cross-sleeve concentration invisible per-account** → D7 fleet exposure
  warn.
- **3-account ceiling** → accepted + pinned (D14), but keep the framing honest
  (review 2026-07-05): ATTENTION being the real constraint is the design
  principle; the NUMBER 3 is an Alpaca paper-account artifact, not a design
  choice. Futures-trend (deferred) likely needs a 4th account on IBKR — treat
  3 as a wall to move then, not "full by design". Revisit with real money
  (which forces the sub-book design anyway) OR at the 4th-broker step.
- **Paper can't measure execution (equities OR options)** → documented; all
  paper verdicts are rule-fidelity verdicts.

### Pre-registered walls for the NEXT contract (audit 2026-07-11)

Mapped by the new-contract stress rehearsal (futures/IBKR) so nobody
discovers them by crashing into them. None block today's sleeves; ALL must
be cut before a futures/short-capable/non-Alpaca sleeve:

- **safety.py encodes long-only-equity semantics**: `side=="sell"` ≡
  de-risking (a SHORT entry would be uncapped and a short cover mis-read),
  the over-sell guard would reject legitimate short opens, and the
  daily-loss breaker's all-sells exemption inverts for shorts. The gate
  needs position-aware direction logic for a shortable contract.
- **Notional is multiplier-blind**: order `notional` assumes qty×price =
  exposure; futures contract multipliers break every notional-based limit.
- **`execution.broker` now fails loudly for non-"alpaca"** (was a dead key
  silently trading Alpaca) — a real Broker subclass must be implemented and
  wired in `cli._make_broker`.
- **NYSE calendar hardcoded** (utils/calendar.py) — futures sessions differ.
- **Weights-vs-order_intent seam**: a futures TREND sleeve is weights-shaped
  but needs short weights + margin sizing; decide extend-vs-third-contract
  deliberately, don't shoehorn.
- **Solo-operator attention** → phase discipline: one live sleeve added at a
  time, each fully shaken down before the next starts.

## 6. Open items for Dan (decide before the relevant phase)
1. **Seed capital per paper account** — proposal: $10k each (comparability
   with momentum's track); VRP fine at $10k for $5-wide spreads.
2. **Approve/adjust the meanrev hypothesis family** (S1) before Phase-2a
   pre-registration locks the exact params.
3. **Approve/adjust the VRP rule + forward-gate numbers** (S2) before
   Phase 3 pins them.
4. Phase-1 go signal.
