# Phase E Temporal Encoder + Reasoning Architecture — Design

**Status:** Design doc (not yet implementation plan). Awaiting user approval.
**Date:** 2026-05-15
**Author:** session 9c4e48ad-0f44-4989-8dab-09ec6870540c
**Predecessors:** `pearl_c51_thompson_closed_phase_e3_gap.md`, `pearl_action_pruning_falsified.md`, `project_phase_e3_close.md`
**Production reference stack:** `mamba2_temporal_kernel.cu`, `tlob_kernel.cu`, `attention_kernel.cu`, `grn_kernel.cu`, `vsn_feature_selection_kernel.cu`, `moe_kernels.cu`, `aux_heads_kernel.cu`, `aux_trunk_forward_kernel.cu`, `pearl_1_atom_kernel.cu`

## 1. Goal

Lift the Phase E execution policy from **stateless linear C51 Q** to a **stateful, regime-aware, auxiliary-supervised** Q-network. Close the remaining 10pt Sharpe gap to the Phase 1d.4 baseline at half-tick by adopting the production trainer's temporal-reasoning stack — same components that lifted Phase 1d.2's snapshot-stream AUC from 0.50 → 0.66 at K=6000.

## 2. Why now

The Phase E.3 close + C51 follow-up establish:

- ✅ Alpha signal is real and gets transmitted (rvr = +1.045σ across linear and C51).
- ✅ Calibration was the dominant bottleneck (C51 closed +26pt of Sharpe gap at cost=0 vs linear Q).
- ✅ Action variance was NOT the bottleneck (pruning falsified, -22pt Sharpe).
- ✅ Fill economics was NOT the bottleneck (real spread ≈ fixed for ES — 76% of bars at 1-tick floor).
- ⚠️ The remaining 10pt half-tick gap is **trade-count economics × value-estimation precision** under current stateless architecture.

The production trainer already implements the techniques needed:
- **Temporal memory** (Mamba2, TLOB, attention) — `pearl_state_amplifies_short_horizon_into_long_horizon` proved this works on ES futures.
- **Regime-aware decisions** (MoE) — `pearl_snapshot_alpha_is_regime_conditional` showed spread-Q4 acc=0.747 vs middle quintiles below chance; the alpha lives in specific regimes.
- **Dense auxiliary supervision** (aux heads + separate aux trunk) — `pearl_separate_aux_trunk_when_shared_starves` is the canonical fix for sparse-PnL training.
- **Adaptive atom support** (`pearl_per_branch_c51_atom_span`) — eliminates the hardcoded [-10, +10] choice.

Smart-borrow philosophy: adopt the **techniques** (kernels, controller signals, ISV slots) without importing the **specialization** (4-branch action factorization, magnitude bins, direction-specific reward biases). Same approach that worked for the C51 borrow.

## 2.5. Core architectural pillars (added by user 2026-05-15)

### Pillar A: Full L1-L10 LOB depth input

The DBN MBP-10 files contain real L1-L10 bid/ask data (verified
`dbn_parser.rs:721-728` and `866-873` correctly copy all 10 levels).
The current Phase E env synthesizes L2/L3 at ±tick offsets because
the **fxcache** doesn't carry depth — only L1-derived features
(spread_bps, l1_imbalance) plus the 81-dim Block-S feature vector.

To use real L4-L10, options:
1. **Hybrid loader**: at env construction, peek MBP-10 by timestamp
   for each fxcache bar — adds depth without breaking alpha_cache
   alignment.
2. **Fxcache rebuild**: extend the fxcache schema to store full depth.
3. **MBP-10 direct mode**: skip fxcache entirely; loses alpha_cache.

Pick (1) for the staged rollout. Adds ~120 floats per snapshot
(L1-L10 × bid+ask × {px, sz, ct} = 60 fields × 2 sides = up to 120).
Phase E.4.A.2 task.

### Pillar B: ISV-continual-learning (train AND inference)

Foxhunt's controller pattern already produces and consumes ISV slots
GPU-resident via `pearl_engagement_rate_self_correction` and friends.
Phase E currently freezes ISV at training end. **The proposal: keep
controllers firing during inference / eval / deployment.**

**What stays frozen at inference:** Q-net weights (W, b for the C51
head; Mamba2 SSM parameters; GRN/MoE/VSN weights).

**What adapts at inference via ISV controllers:**
- Slot 543 — stacker threshold (engagement-rate controller continues
  responding to observed trade rate)
- Slot 545 — observed-rate Wiener-α EMA (always updating)
- Slot 546 — Kelly attenuation (tightens after drawdowns)
- Slot atom_headroom (Pearl-1) — adaptive C51 support widens/narrows
  as observed Q-scale shifts
- Slot ~126 — MoE gate entropy EMA (drives MoE λ controller)
- ISV[12] — health composition (if we adopt it) gates ALL downstream
  adaptations

**Effective dynamic weight:** the policy's decision rule
`action = ThompsonSelect(MoE_mix(experts), threshold_gate)` is a
*function* of the ISV slots. As ISV evolves at inference,
the effective policy adapts WITHOUT touching neural-network parameters.
This is "dynamic weight via ISV modulation" — lightweight, safe,
composable with frozen Q-net.

**Optional aggressive variant — LoRA at inference:** add a low-rank
adapter `W' = W + α·U·V^T` where `U ∈ R^{H×r}`, `V ∈ R^{r×H}`,
`r << H`. Update U, V via online SGD on observed reward error during
inference. Adds literal dynamic weights (not just ISV). Out of scope
for Phase E.4 core — possible Phase E.5 extension if ISV-only
adaptation isn't enough.

**Why this composes:** Mamba2 hidden state accumulates within-episode
temporal context (fast adaptation). ISV controllers accumulate
across-episode regime context (slow adaptation). Together they form
a two-timescale online adaptation system on top of a frozen
representational core.

**Failure modes to guard against:**
- ISV runaway in low-data regimes — bound all controller updates by
  Wiener-α floor per `pearl_wiener_alpha_floor_for_nonstationary`.
- Threshold spiraling to no-trade — engagement-rate controller has
  a target floor; verify it activates at inference.
- Adversarial market manipulation against the live ISV — for HFT
  deployment, controllers should have rate limits on update magnitude.

## 3. Architecture (target)

```
┌──────────────────────────────────────────────────────────────────────┐
│ Per-step input: state[10]  +  rolling window buffer[K, 10]           │
│ (current state pushed into a circular buffer of last K snapshots)    │
└────────────────────────────────┬─────────────────────────────────────┘
                                 │
                                 ▼
┌──────────────────────────────────────────────────────────────────────┐
│ Variable Selection Network (VSN)                                     │
│   • Per-state softmax gate over feature groups → vsn_mask[10]        │
│   • Element-wise gated features → x_in[K, 10]                        │
│   • mask EMA → ISV[~120..125]  (interpretability)                    │
└────────────────────────────────┬─────────────────────────────────────┘
                                 │
                                 ▼
┌──────────────────────────────────────────────────────────────────────┐
│ Mamba2 SSM Temporal Encoder                                          │
│   • State-space accumulation over the K-bar window                   │
│   • Output: h_temporal ∈ R^H  (compressed temporal context)          │
│   • SAME kernel as Phase 1d.2 — proven on ES futures                 │
└────────────────────────────────┬─────────────────────────────────────┘
                                 │
                                 ▼
┌──────────────────────────────────────────────────────────────────────┐
│ Gated Residual Network (GRN) Trunk                                   │
│   • h_temporal → h_s2 ∈ R^H'  (shared trunk encoding)                │
│   • Gating + residual; more expressive than linear, cheaper than     │
│     full transformer                                                 │
└──────────────────────────────┬─┴─────────────────────────────────────┐
                               │                                       │
              ┌────────────────┘                                       │
              │  (main path)                                           │
              ▼                                                        ▼
┌──────────────────────────────────┐    ┌──────────────────────────────┐
│ MoE Regime Gate                  │    │ Aux Trunk (SEPARATE)          │
│   • K_e=4 experts, gate by h_s2  │    │   • Linear→ELU→Linear→ELU→    │
│   • Each expert is a C51 head    │    │     Linear MLP                │
│     [9 actions × N_atoms atoms]  │    │   • stop_grad at encoder      │
│   • Output: gate-mixed probs     │    │     boundary                  │
│     p(a, k | s)                  │    │   • Independent Adam          │
│   • gate_entropy_ema → ISV[126]  │    │   • Aux heads:                │
│     drives MoE λ controller      │    │     1) next-bar return MSE    │
│     (existing in production)     │    │     2) 5-class regime CE      │
└────────────────────────┬─────────┘    └──────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────────────────┐
│ C51 categorical output: probs[B, 9, N_atoms]                         │
│   • Adaptive atom support [v_min, v_max] from Pearl-1 controller     │
│   • ISV-driven instead of hardcoded                                  │
└────────────────────────────────┬─────────────────────────────────────┘
                                 │
                                 ▼
┌──────────────────────────────────────────────────────────────────────┐
│ GPU Thompson selector (existing) + alpha_confidence threshold gate    │
│   • Inverse-CDF over each expert's mixed probs                        │
│   • Mapped-pinned action output (current implementation, unchanged)   │
└──────────────────────────────────────────────────────────────────────┘
```

### Components (justification)

| Component | Production kernel | Phase E role | Compat note |
|---|---|---|---|
| Sliding-window state buffer | new (CPU or GPU circular buffer) | Provides K bars of context per step | New buffer mgmt; reset on episode boundary |
| VSN | `vsn_feature_selection_kernel.cu` | Per-state feature-importance gating | Use 10 features instead of 6 groups; mask EMA into ISV |
| Mamba2 SSM | `mamba2_temporal_kernel.cu` | Temporal encoder | Same kernel; D=10 input, configure hidden width |
| GRN | `grn_kernel.cu` | Gated trunk encoding | Direct reuse |
| MoE gate | `moe_kernels.cu` + `moe_lambda_eff_kernel.cu` | Regime-aware Q-head dispatch | K_e=4 (matches spread-quintile regime structure) |
| C51 head | `alpha_c51.cu` (existing) | Per-expert categorical output | Already works |
| Aux trunk | `aux_trunk_forward/backward_kernel.cu` | Separate trunk for aux supervision | Stop-grad at encoder per `pearl_separate_aux_trunk_when_shared_starves` |
| Aux heads | `aux_heads_kernel.cu` + `aux_heads_loss_ema_kernel.cu` | Next-bar MSE + regime CE | Adapt label-builders to Phase E targets |
| Pearl-1 atom span | `pearl_1_atom_kernel.cu` | Adaptive [v_min, v_max] for C51 | Replaces hardcoded support; ISV-driven |
| Thompson selector | `alpha_c51.cu` (existing) | Action selection | Reads gate-mixed probs; no kernel change |

### TFT correspondence

| TFT component | Provided by |
|---|---|
| Variable Selection Network | `vsn_feature_selection_kernel.cu` (direct) |
| Gated Residual Network | `grn_kernel.cu` (direct) |
| Static covariate encoder | absent — Phase E has no static covariates; OK |
| LSTM seq-to-seq encoder | **substituted by Mamba2 SSM** (better; subquadratic) |
| Interpretable multi-head attention | optional Phase E.4.E follow-up via `attention_kernel.cu` |
| Quantile output | **substituted by C51 categorical** (already working) |

The proposed architecture is structurally a TFT, with two strict upgrades vs the original Lim et al. 2021 design:
1. Mamba2 instead of LSTM (linear-time state accumulation, no vanishing-gradient).
2. C51 categorical output instead of quantile loss (proven calibration win).

## 4. State representation changes

Current Phase E state vector (10-dim, single timestep):
```
[alpha_logit, alpha_confidence, spread_bps, l1_imbalance, ofi_sum_5,
 mid_drift_5, position, step_normalized, log_tau, log_event_rate]
```

Proposed: same 10 features but **K-bar history** for all features. Window length K starts at 16 (~16 bars of context); validate empirically against K=32, K=64. Mamba2 handles long-horizon well (Phase 1d.2 used K=6000); the cost is GPU memory not architectural limit.

Per-step input shape: `[B, K, 10]`. The buffer is maintained as a circular array; reset on episode start zeros it (or seeds with the first K observed states once available).

## 5. Training changes

- **Forward**: per step, push current state to buffer, run window → VSN → Mamba2 → GRN → (MoE → C51 head) + (aux trunk → aux heads).
- **Backward**: Q-loss (C51 CE) flows through MoE→GRN→Mamba2→VSN. Aux-loss flows through aux trunk only (stop-grad at encoder boundary, per `pearl_separate_aux_trunk_when_shared_starves`).
- **Loss balance**: per `pearl_loss_balance_controller`, signal-modulated target × Wiener-α. Phase E currently uses Q-loss only; aux-loss weight starts at 1.0 and is controller-driven.
- **Optimizer**: keep plain SGD initially (C51 works with SGD). Switch to Adam in Phase E.4.D if signal plateaus.
- **PER**: NOT in scope for E.4 (current on-policy training works); revisit only if learning is sample-starved.

## 6. Phasing

Each phase produces a runnable smoke + backtest. Each phase ships as a discrete experiment we can A/B against the prior best.

**Phase E.4.A — Foundation (1 week)**
- Phase E.4.A.1: Sliding-window state buffer (GPU-resident, circular)
- Phase E.4.A.2: Hybrid MBP-10 depth loader — extend
  `load_snapshots_from_fxcache` to peek MBP-10 by timestamp and
  populate real L4-L10 bid/ask in `SnapshotRow.bid_l[3..10]` /
  `ask_l[3..10]`. Preserves alpha_cache alignment.
- Phase E.4.A.3: Extend state vector to include depth features
  (L1-L10 cumulative size, spread-curve slope, etc.)
- Phase E.4.A.4: Mamba2 forward + backward (already exists; wire into Phase E)
- Phase E.4.A.5: GRN trunk (already exists; wire)
- Phase E.4.A.6: C51 head reads h_s2 instead of state directly
- Phase E.4.A.7: **ISV-continual-learning toggle** — controllers fire
  at eval time too (already in smoke at training; lift to backtest eval).
- Smoke + backtest vs C51-flat-baseline (target: maintain +10.4 at cost=0, lift half-tick)
- **Falsification: if Sharpe at cost=0 drops, the temporal architecture isn't lifting — pause and diagnose before adding more.**

**Phase E.4.B — Regime gating (1 week)**
- Add VSN feature selection
- Add MoE 4-expert gating + λ controller (existing kernel)
- Validate expert utilization (should specialize across spread quintiles)
- A/B vs E.4.A

**Phase E.4.C — Aux supervision (3-4 days)**
- Add aux trunk + heads (next-bar return MSE, 5-class regime CE)
- Validate aux losses converge (`pearl_separate_aux_trunk_when_shared_starves` gate: CE < 0.1 AND dir_acc > 0.95)
- Validate Q-learning isn't destabilized
- A/B vs E.4.B

**Phase E.4.D — Adaptive atoms + polish (3-4 days)**
- Pearl-1 atom span controller (replaces hardcoded [-10, +10])
- Add health composition (ISV[12]) feeding controller / atom span
- Trade-rate target sweep at high-cost regime (closes the trade-count economics)
- Final 2D sweep, write close-out memo

**Phase E.4.E — Optional follow-ups (defer)**
- TFT interpretable multi-head attention
- IQN quantile head composed with C51
- Pearl-4 Adam adaptive hyperparams

## 7. Falsification criteria

For the architecture upgrade to be worth the engineering cost:

**Smoke must show (vs C51-flat-baseline R_mean = -1.1):**
- R_mean improvement ≥ 50% (i.e., R_mean ≥ -0.5)
- rvr maintained (≥ +1.04σ)
- Action entropy NOT collapsed to Wait-only (>0.5 × ln(9))

**Backtest must show (vs C51-flat-baseline Sharpe_ann at half-tick = -13.8):**
- Half-tick Sharpe_ann ≥ -8 (closes 5pt+ of the remaining 10pt gap to Phase 1d.4 baseline at -4.0)
- Trade rate ≤ 70/ep at best τ (moving toward Phase 1d.4's 20-50/ep regime)
- Cost=0 Sharpe_ann ≥ +8 (not regressed below the C51-flat result)

If these don't hit by Phase E.4.B end: rollback to C51-flat and reconsider. The temporal architecture is a STRATEGIC bet — if it doesn't deliver, we have a known-good fallback (the C51-flat policy already shipped in this session).

## 8. Risks

- **State-buffer memory**: K=64 × 10 features × float = 2.5KB per env-instance. For batch backtest with 500 episodes the working set is fine. K=600 (full smoke horizon) is 24KB/instance — also fine.
- **Mamba2 init**: Phase 1d.2 used random init + trainable end-to-end (`pearl_tlob_no_pretraining`). Should work for Phase E too.
- **Aux head label leak**: `pearl_trend_scanning_purged_cv_doesnt_sterilize_forward_features` warns that forward-window labels leak into forward-horizon targets. Mitigation: aux supervision uses NEXT BAR (single-step) target, not multi-bar trend-scanning label.
- **MoE expert collapse**: if all 4 experts learn the same C51 distribution, MoE adds parameters without benefit. Mitigation: `moe_lambda_eff_kernel.cu` λ controller penalizes gate entropy collapse; existing kernel does this.
- **Loss balance instability**: with Q-loss + 2 aux losses, the encoder receives 3 gradient streams. `pearl_loss_balance_controller` is the production answer; adopt at Phase E.4.C.

## 9. Open questions

- **Window length K**: start at 16, sweep 16/32/64. Mamba2 doesn't impose a ceiling.
- **MoE expert count K_e**: start at 4 (matches spread-quintile structure from Phase 1c). Validate by checking expert utilization per regime.
- **Aux head regime classes**: 5 classes for spread quintiles, OR 5 classes for volatility quintiles? Pick spread (alpha-conditional dimension from Phase 1c).
- **Should we keep the threshold gate?** The current `--train-threshold` is a CPU-side gate. Once the Q-net is temporal + regime-aware, the gate may be redundant. Test with `--train-threshold 0.0` in E.4.B.

## 10. Out of scope / future research

**Out of scope (Phase E.4 core):**
- Different markets (validated as not the bottleneck for ES futures spread economics)
- Action-space changes (pruning falsified; full 9 stays)
- PER / off-policy replay (current on-policy training has no observable sample-starvation)
- LoRA dynamic weights at inference (aggressive ISV-continual-learning variant — Phase E.5 if needed)

**Future research (Phase E.5+ or production-tier):**
- **TGGN graph reasoning over L1-L10 depth**
  (`ml-supervised/src/tgnn/`): foxhunt has an existing CPU-based
  Temporal Graph Gated Network for HFT (Performance targets <500ns
  graph build, <1μs GNN inference). The trainable adapter is
  GPU-native (`crates/ml/src/tgnn/trainable_adapter.rs` using cuBLAS
  GpuLinear + GpuAdamW) but the message-passing layer is CPU.
  Honest assessment for Phase E.4: marginal benefit over the
  TFT-Mamba2 stack — the 81-dim Block-S features already encode
  LOB structure and Mamba2 captures temporal context. TGGN's
  strongest value is in (a) multi-instrument cross-asset graphs,
  (b) full MBP-10 depth utilization, (c) production HFT
  sub-1μs latency. With Pillar A (L4-L10 input wired), the depth
  case becomes stronger — revisit as Phase E.5 candidate.
- **TFT interpretable multi-head attention** —
  `attention_kernel.cu` + `attention_backward_kernel.cu`.
  Adds variable-importance via attention weights. Already deferred
  in section 6 as Phase E.4.E.
- **IQN dual head composed with C51** — joint sampling
  (`pearl_thompson_for_distributional_action_selection`). Trade-off:
  +2-3× training overhead for marginal exploration gain.
- **Pearl-4 Adam adaptive hyperparams** — replace plain SGD.
- **xLSTM / KAN / Liquid alternative encoders** — adapters exist
  in `crates/ml/src/hyperopt/adapters/`. Test only if Mamba2
  plateaus.
- **Multi-instrument extension** (ES + NQ + RTY graph for
  cross-asset signals) — opens up TGGN's strongest use case.

## 11. Approval gate

**This is a design proposal, not yet an implementation plan.** Before invoking `superpowers:writing-plans` to produce a step-by-step implementation:

- [x] User approved the TFT-Mamba2 architecture ("the idea is great
      we use that", 2026-05-15)
- [x] TGGN clarified — foxhunt-specific Temporal Graph Gated
      Networks (`ml-supervised/src/tgnn/`). Existing CPU
      implementation + GPU adapter. Deferred to Phase E.5+ research
      per Section 10.
- [x] L4-L10 depth source verified — DBN MBP-10 files contain real
      L1-L10. Pillar A (Section 2.5) integrates them via hybrid
      MBP-10 peek alongside fxcache.
- [x] ISV-continual-learning concept adopted as Pillar B
      (Section 2.5) — core architectural feature, not optional.
- [ ] User confirms phasing (4 phases × ~3 weeks total)
- [ ] User confirms scope: stop after E.4.D? Or extend with E.4.E?
- [ ] User approves the falsification criteria (smoke + backtest thresholds)

After approval, the writing-plans skill produces task-by-task TDD implementation steps for Phase E.4.A first.
