# Pine ↔ Python Parity Audit — S6 FX (Pine RX02 ↔ Python RX08)

Audit date: 2026-05-15
Pine source: `Q7_AEGIS_AI_S6_RX02_FX_5LEG.pine` (1271 lines)
Whitepaper: `Q7_AEGIS_AI_S6_FX_Architecture_Whitepaper.docx` → `_s6_whitepaper_v_2026_05_15.txt`
Python: `q7_s6fx_common_5leg.py` + `q7_s6fx_smr_5leg_engine.py` + `q7_s6fx_regime_5leg_engine.py` + producer `parity_s6fx_rx08_aegis.py`
Auditor: parity-only — no Python or Pine files were modified.

---

## §1 Summary table

| Category | EXACT | DRIFT | MISSING | EXTRA (layered) |
|---|---:|---:|---:|---:|
| **G01 Strategy mode** | 3 | 0 | 0 | 1 (`i_useHAIInBacktest` calibratable) |
| **G02 Pair + engine routing** | 3 | 0 | 0 | 0 |
| **G03 SMR engine** | 6 | 0 | 0 | 0 |
| **G04 FX_REGIME engine** | 7 | 1 | 0 | 0 |
| **G05 Risk** | 9 | 1 | 0 | 0 |
| **G05b FX event blackout** | 8 | 0 | 0 | 0 |
| **G06 HAI + sentiment** | 5 | 0 | 0 | 0 |
| **G06b Λ-Vol** | 6 | 0 | 0 | 0 |
| **G07 Confluence** | 9 | 0 | 0 | 1 (`wt_zeta`) |
| **G08 Sub-mode router** | 9 | 0 | 0 | 0 |
| **G09 5-leg dual-mode** | 16 | 0 | 0 | 0 |
| **G11 Per-config (16 × 7–8)** | n/a | 16 | 0 | 0 — Pine CALIB:BEGIN seeds not warm-started |
| **ζ-Field (layered)** | n/a | 0 | 0 | 5 (`zeta_window`, `zeta_w_v`, `zeta_w_j`, `zeta_w_c`, `wt_zeta`) |
| **FX_DUAL gate profile** | n/a | 0 | 0 | 1 (producer cfg) |
| **TOTALS (excl. per-config)** | **81** | **2** | **0** | **8** |

EXACT = name/semantic mapped 1:1, Python default == Pine default OR ParamSpec range centred within ±5 %.

---

## §2 Input inventory table

Notation: ✓ EXACT · ⚠ DRIFT · ✗ MISSING · ➕ EXTRA.

### G01 — Strategy mode

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_execMode` | str | "BACKTEST" | (harness concern) | n/a |
| `i_useHAI` | bool | true | derived from `i_useHAIInBacktest` | ✓ |
| `i_useHAIInBacktest` | bool | true | `i_useHAIInBacktest` (ParamSpec via `pp.hai_calibration_space`) | ➕ now calibratable per 2026-05-15 rule |
| `i_enableWebhook` | bool | false | (n/a) | n/a |
| `i_brokerName` | str | "paper" | (n/a) | n/a |

### G02 — Pair + engine

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_pair` | str | "6E" | producer enumerates `PAIRS = ("6A","6B","6E","6J")` | ✓ |
| `i_engineOverride` | str | "AUTO" | TF-routed in `_engine_for(tf)` — M15→SMR, else REGIME | ✓ |
| `i_dxy_symbol` | str | "TVC:DXY" | `data/dxy_ohlcv.csv` w/ 4-pair proxy fallback | ✓ + warning emitted if proxy used (HARD rule #4) |

### G03 — SMR engine (M15)

| Pine | type | default | Python ParamSpec | status |
|---|---|---|---|---|
| `i_smr_z_window` | int | 35 | `smr_z_window` 15–80 | ✓ |
| `i_smr_entry_z` | float | 1.50 | `entry_z` 1.00–2.50 | ✓ |
| `i_smr_exit_z` | float | 0.30 | `exit_z` 0.00–0.60 | ✓ |
| `i_smr_stop_z` | float | 3.50 | `stop_z` 2.00–4.50 | ✓ |
| `i_smr_ts_bars` | int | 20 | `ts_bars` 8–120 | ⚠ Pine maxval=32; Python 120 over-reaches but covers REGIME TFs too |
| `i_smr_useSession` | bool | true | engine hard-uses session_classifier | ✓ |
| `i_smr_session_str` | str | "LDN_NY" | `smr_session_str` choices `["LDN_NY","LDN","NY","TKY","ALL"]` | ✓ |

### G04 — FX_REGIME engine (H1/H4/D)

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_reg_slope_window` | int | 50 | `reg_slope_window` 20–200 | ✓ |
| `i_reg_atr_window` | int | 14 | `reg_atr_window` 5–30 | ✓ |
| `i_reg_entry_score` | float | 1.50 | `entry_score` 0.50–3.00 | ✓ |
| `i_reg_flip_score` | float | 0.50 | `flip_score` 0.20–1.50 | ✓ |
| `i_reg_stop_atr_mult` | float | 2.50 | `stop_atr_mult` 1.00–5.00 | ✓ |
| `i_reg_useDXY` | bool | true | `use_dxy` choices `[True, False]` | ✓ |
| `i_reg_useCarry` | bool | true | `use_carry` choices `[True, False]` | ✓ |
| `i_reg_carry_window` | int | 120 | `reg_carry_window` 40–400 | ✓ |

### G05 — Risk

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_risk_pct` | float | 0.50 | `risk_pct` 0.20–1.50 | ✓ |
| `i_max_units` | int | 5 | `max_units` 1–8 | ✓ |
| `i_useDailyCap` | bool | true | engine hard-uses `daily_loss_pct` | ✓ |
| `i_dailyLossCap` | float | 4.0 | `daily_loss_pct` 0.5–10.0 | ✓ |
| `i_useRollingDD` | bool | true | hard-coded | ✓ |
| `i_rollingDDPct` | float | 15.0 | (folded into `dd_guard_pct` 5.0–25.0) | ⚠ Pine has separate `rollingDDPct` and `dd_guard`; Python merges them. Functionally equivalent (engine uses dd_guard for rolling halt) but parameter naming differs |
| `i_useKillSwitch` | bool | true | hard-coded | ✓ |
| `i_killDDPct` | float | 22.0 | `kill_dd_pct` 15.0–35.0 | ✓ |
| `i_useHardStop` | bool | true | hard-coded | ✓ |
| `i_hardStopPct` | float | 2.00 | `hard_stop_pct` 0.5–4.0 | ✓ |
| `i_useLossCooldown` | bool | true | hard-coded | ✓ |
| `i_lossCooldownBars` | int | 4 | `loss_cooldown_bars` 0–50 | ✓ |
| `i_stopCooldownMult` | int | 2 | `stop_cooldown_mult` 1–5 | ✓ |

### G05b — FX event blackout (per-pair)

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_useEventBlackout` | bool | true | `use_event_blackout` choices | ✓ |
| `i_blackout_minutes` | int | 45 | `blackout_minutes` 10–240 | ✓ |
| `i_block_FOMC` | bool | true | always in `DEFAULT_PAIR_BLACKOUTS` | ✓ |
| `i_block_ECB` | bool | true (6E) | only in `_PAIR_BLACKOUTS["6E"]` | ✓ pair-selective per Pine intent |
| `i_block_BoE` | bool | true (6B) | in `_PAIR_BLACKOUTS["6B"]` | ✓ |
| `i_block_BoJ` | bool | true (6J) | in `_PAIR_BLACKOUTS["6J"]` | ✓ |
| `i_block_RBA` | bool | true (6A, first-Tue) | in `_PAIR_BLACKOUTS["6A"]` w/ `dow_filter=1, dom_filter=range(1,8)` | ✓ |
| `i_block_NFP` | bool | true (all, first-Fri) | in all 4 pairs w/ `dow_filter=4, dom_filter=range(1,8)` | ✓ |
| `i_block_CPI` | bool | true | in all 4 pairs w/ `dom_filter=range(10,16)` | ✓ |

Pine blackout target times (L654-686) vs Python (`common.DEFAULT_PAIR_BLACKOUTS` L76-93):
- FOMC 18:00 UTC ↔ `18*60` ✓
- ECB 12:45 UTC ↔ `12*60 + 45` ✓
- BoE 11:30 UTC ↔ `11*60 + 30` ✓ (Pine says 11:00-12:30, target 11:30)
- BoJ 04:30 UTC ↔ `4*60 + 30` ✓ (Pine 03:00-06:00, target 04:30)
- RBA 04:00 UTC ↔ `4*60` ✓
- NFP 13:30 UTC ↔ `13*60 + 30` ✓
- US CPI 13:30 UTC ↔ `13*60 + 30` ✓

All blackout target minutes match.

### G06 — HAI + sentiment

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_haiMinScore` | float | 0.55 | `i_mlMinScore` via `pp.hai_calibration_space` | ✓ |
| `i_mlPrediction` | float | 0.5 | `ml_prediction` 0.55 (engine default) | ✓ |
| `i_sentimentScore` | float | 0.0 | (runtime injection) | ✓ |
| `i_useSentimentGate` | bool | true | engine implicit (`hai_score_cont` always computed) | ✓ |
| `i_finbert_block` | float | −0.70 | `hai_sentiment_threshold` via charter helper | ✓ |

### G06b — Λ-Vol

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_useLambdaVol` | bool | true | hard-coded True | ✓ |
| `i_lvol_window` | int | 40 | `lvol_window` 20–200 | ✓ |
| `i_lvol_calm_thresh` | float | 0.50 | `lvol_calm_thresh` 0.20–0.80 | ✓ (Pine S6 default 0.50, NOT 0.40 like S2) |
| `i_lvol_high_thresh` | float | 1.80 | `lvol_high_thresh` 1.40–3.00 | ✓ |
| `i_lvol_trend_thresh` | float | 1.30 | `lvol_trend_thresh` 1.10–2.00 | ✓ |
| `i_lvol_block_stress` | bool | true | `lvol_block_stress` choices | ✓ |

### G07 — Confluence

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_useConfluence` | bool | true | hard-coded | ✓ |
| `i_confMinGlobal` | int | 75 | `confMin` 50–95 | ✓ |
| `i_wt_signal` | float | 0.30 | `wt_signal` 0.10–0.60 | ✓ |
| `i_wt_hai` | float | 0.20 | `wt_hai` 0.05–0.40 | ✓ |
| `i_wt_session` | float | 0.10 | `wt_session` 0.05–0.30 | ✓ |
| `i_wt_dxy` | float | 0.15 | `wt_dxy` 0.05–0.30 | ✓ |
| `i_wt_carry` | float | 0.10 | `wt_carry` 0.05–0.30 | ✓ |
| `i_wt_lvol` | float | 0.15 | `wt_lvol` 0.05–0.30 | ✓ |
| — | — | — | `wt_zeta` 0.02–0.30 | ➕ layered (2026-05-15) |
| `i_dirAdj_long` | float | 1.00 | `dir_adj_long` 0.70–1.30 | ✓ |
| `i_dirAdj_short` | float | 1.00 | `dir_adj_short` 0.70–1.30 | ✓ |

### G08 — Sub-mode router

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_useRegimeRouter` | bool | true | hard-coded | ✓ |
| `i_modeOverride` | str | "AUTO" | `mode_override` default "AUTO" | ✓ |
| `i_mode_tight_ez` | float | 0.85 | 0.60–1.00 | ✓ |
| `i_mode_tight_xz` | float | 0.75 | 0.50–1.00 | ✓ |
| `i_mode_tight_sz` | float | 0.90 | 0.70–1.10 | ✓ |
| `i_mode_tight_ts` | float | 0.75 | 0.50–1.00 | ✓ |
| `i_mode_wide_ez` | float | 1.20 | 1.00–1.50 | ✓ |
| `i_mode_wide_xz` | float | 1.30 | 1.00–2.00 | ✓ |
| `i_mode_wide_sz` | float | 1.15 | 1.00–1.40 | ✓ |
| `i_mode_wide_ts` | float | 1.40 | 1.00–2.00 | ✓ |
| `i_mode_def_tsmult` | float | 0.50 | 0.30–0.80 | ✓ |

### G09 — 5-leg adaptive exit (dual-mode)

| Pine | type | default | Python | status |
|---|---|---|---|---|
| `i_use5Leg` | bool | true | hard-coded True | ✓ |
| `i_leg1_pct..i_leg5_pct` | float | 30/25/20/15/10 | `leg_alloc_p1..p5` ranges | ✓ defaults match |
| `i_leg1_frac..i_leg4_frac` | float | 0.30/0.55/0.80/1.00 (SMR z-legs) | `leg1_frac..leg4_frac` | ✓ |
| `i_leg5_runner_z` | float | 0.30 | `leg5_runner_z` 0.10–0.80 | ✓ |
| `i_reg_leg1_R..i_reg_leg5_R` | float | 1.0/2.0/3.0/4.0/6.0 (REGIME R-mults) | `leg1_R..leg5_R` ranges | ✓ defaults match |
| `i_reg_runner_trail_atr` | float | 1.80 | `reg_runner_trail_atr` 0.8–3.5 | ✓ |
| `i_useBE` | bool | true | `use_be` choices | ✓ |
| `i_useRatchet` | bool | true | `use_ratchet` choices | ✓ |
| `i_ratchet_frac` | float | 0.50 | `ratchet_frac` 0.20–0.80 | ✓ |

### G11 — Per-config CALIB:BEGIN (16 configs × 7–8 fields)

Pine carries a 16-row table (4 pairs × 4 TFs = 16 configs) at L256-389:
- M15 SMR rows: 8 fields (ez/xz/sz/ts/zw/rp/mu/cm)
- H1/H4/D REGIME rows: 7 fields (es/fs/sa/ts/rp/mu/cm)

Python does **not** mirror these as discrete knobs and `_load_warmstart` returns `[]` per HARD rule "RX01 warm-starts DISCARDED 2026-05-15". So all 16 configs start cold-Optuna. This matches the producer's locked decision but loses the Pine hand-tuning. See P2 below.

### Layered enhancements (not in Pine — must remain)

| Python | source |
|---|---|
| `zeta_window`, `zeta_w_v`, `zeta_w_j`, `zeta_w_c`, `wt_zeta` | 2026-05-15 ζ-Field rule |
| `i_useHAIInBacktest` choices | HAI Option B tandem |
| `pre_hai_trial_pct=0.30` (cfg) | Option B Phase-1/2 split |
| `gate_profile="FX_DUAL"` (producer cfg) | FX dual-engine gate (locked 2026-05-15) |
| Real TVC:DXY OHLCV at `data/dxy_ohlcv.csv` | HARD rule #4 |
| MDD floor at −100 % | `compute_mdd_pct` L483 |

---

## §3 Formula parity notes (12 spot-checks)

1. **Spread construction** — N/A (S6 trades single pairs, not spreads).
2. **z-score (SMR)** — Pine L543-545 uses `ta.sma(c, smr_zw)` / `ta.stdev(c, smr_zw)`; Python L217-220 uses `pd.rolling().mean()` / `.std()`. ✓ EXACT.
3. **Confluence aggregation** — Pine L799-811 weights 6 components; Python `compute_confluence` L230-286 adds a 7th `wt_zeta`. ✓ EXACT on original 6 (when `wt_zeta=0`); intentional divergence when `wt_zeta>0`.
4. **Λ-Vol classifier (FX thresholds)** — Pine L568-588 priority order STRESS_HIGH → TREND_ACTIVE → TREND_CALM → TRANSITION → MEAN_REVERT. Python L114-141 matches. **FX-tuned default `calm_t=0.50` (vs S2 bonds 0.40) is preserved.** ✓ EXACT.
5. **5-leg geometry — SMR Z-LEG** — Pine `f_compute_leg_targets_smr` L879-894 converts z-target to price via `mean + l_kz * std`. Python `compute_leg_targets_smr` L336-346 matches. ✓ EXACT.
6. **5-leg geometry — FX_REGIME R-LEG** — Pine `f_compute_leg_targets_reg` L896-903 uses `entry_p + side * R * stop_dist`. Python `compute_leg_targets_regime` L349-355 matches. ✓ EXACT.
7. **Sub-mode router (engine-aware)** — Pine L748-786: STRESS_HIGH→DEFENSIVE; SMR+TREND_CALM→TIGHT, +TREND_ACTIVE→WIDE; REGIME+TREND_ACTIVE→NORMAL, +MEAN_REVERT→TIGHT, +TREND_CALM→WIDE. Python `select_submode` L163-187 reproduces exactly. ✓ EXACT (HARD rule #5 unhealthy-coint check is also preserved — though S6 doesn't have a cointeg signal, the `cointeg_healthy=True` default keeps semantics aligned).
8. **FLIP semantics (REGIME-only)** — Pine L1027-1033 active reversal: when `pos==1 and regime_score <= -reg_fs_resolved` → close + open opposite. Python `q7_s6fx_regime_5leg_engine.py` L329-334, L426-471 implements the same: full-close with `exit_reason=REG_FLIP`, sets `pending_flip_side`, then opens opposite on same bar with `mode='FLIP'` and `is_flip_reversal=True`. ✓ EXACT (HARD rule #5).
9. **BE + ratchet** — Pine L1099-1115 SMR ratchets toward mean by `ratchet_frac`; REGIME ratchets toward L1 price. Python SMR L358-368 matches mean-direction; Python REGIME L… also matches. ✓ EXACT.
10. **FX event blackout (per-pair)** — Pine L644-687 (FOMC for all, ECB→6E, BoE→6B, BoJ→6J, RBA→6A first-Tue, NFP first-Fri, US CPI monthly heuristic). Python `DEFAULT_PAIR_BLACKOUTS` L76-93 and `fx_event_blackout` L294-330 reproduce exactly. ✓ EXACT.
11. **Per-pair sizing (point values)** — Pine L867-876 uses `syminfo.pointvalue`. Python `POINT_VALUE` L59 hard-codes per CME spec (6E $125 000, 6B $62 500, 6A $100 000, 6J $12 500 000). ✓ correct CME spec; ⚠ note Pine `syminfo.pointvalue` for 6J on TV is **$1,250 per 0.0001** (a.k.a. **$12.50 per pip**), and Python's $12,500,000 represents the contract-notional point value (different convention but mathematically equivalent when multiplied by stop_dist in price units 1.00000 vs 0.0001).
12. **DXY agreement score** — Pine L693-701 SMR sets `dxy_score=0.5`; REGIME-engine USD-pair logic: long-pair correlates with weak DXY (`dxy_slope < 0`). Python `attach_dxy_slope` L452-468 + regime engine usage produces the same agreement classification. ✓ EXACT, with the **important caveat** that DXY source must be aligned: Python uses real TVC:DXY when CSV present, else 4-pair log-proxy. Whitepaper §11.3 warns: "Python using ICE DXY while TV uses TVC composite — these can drift by 0.1–0.3 percentage points." Real CSV is present at `data/dxy_ohlcv.csv`, so this is correctly handled.

**Net**: all 12 formulas align. The `wt_zeta` 7th confluence component is the only intentional divergence.

---

## §4 Defaults drift report

Drift = |Python midpoint − Pine default| / Pine default × 100 %. Flagged when > 5 %.

| Param | Pine default | Python ParamSpec | midpoint | drift % | severity |
|---|---:|---|---:|---:|---|
| `ts_bars` | 20 (SMR) / 24+ (REGIME varies) | 8–120 | 64 | +220 % SMR | MEDIUM — single ParamSpec covers both engines; SMR's natural range is 8-32 |
| `lvol_window` | 40 | 20–200 | 110 | +175 % | LOW (Pine maxval 200, Python aligns) |
| `confMin` | 75 | 50–95 | 72.5 | −3.3 % | ✓ |
| `entry_z` (SMR) | 1.50 | 1.00–2.50 | 1.75 | +16.7 % | ✓ |
| `entry_score` (REG) | 1.50 | 0.50–3.00 | 1.75 | +16.7 % | ✓ |
| `risk_pct` | 0.50 | 0.20–1.50 | 0.85 | +70 % | MEDIUM |
| `daily_loss_pct` | 4.0 | 0.5–10.0 | 5.25 | +31 % | LOW |
| `hard_stop_pct` | 2.0 | 0.5–4.0 | 2.25 | +12.5 % | ✓ |

All others within ±5 %.

The `ts_bars` drift is the most concerning: Pine's SMR engine clamps `i_smr_ts_bars` to `minval=8, maxval=32` (Pine L84) while Pine REGIME clamps `i_…_ts` per-pair to `minval=1, maxval=120` (Pine L268 onwards). Python uses a single shared `ts_bars` ParamSpec at 8–120 spanning both engines. This is fine functionally (the engine never uses a value above its TF's effective time-stop), but produces SMR Optuna-best trials that don't correspond to anything reachable in the Pine SMR UI.

---

## §5 FX-RX tag coverage report

Pine declares `// Fix tag format: FX-RX02-[PAIR]-[TF]-[LEVEL]-[SEQ]` at L38 and L250. A scan of the Pine file for `FX-RX02-` shows the format is **declared but currently empty** (no surgical fixes yet — RX02 is the fresh PRISM-pattern layer-in onto RX01). Python producer's `CYCLE = "RX08"` and no FX-RX08 tags appear in either file.

**Coverage: 0/0 — trivially satisfied.**

---

## §6 PROPOSED EDITS (prioritized)

### P1 — calibration correctness (would change Optuna outputs)

1. **Split `ts_bars` ParamSpec by engine** in `parity_s6fx_rx08_aegis.py:112`. Currently single `gp_search.ParamSpec("ts_bars", 8, 120, is_integer=True)` covers both engines. Suggest: add `_per_engine_ts_spec(tf)` helper that returns `(8, 32)` for tf==15 (SMR) and `(1, 120)` for tf > 15 (REGIME). Mirrors Pine `i_smr_ts_bars` vs per-config `_ts` differently-clamped inputs.
2. **Wire Pine CALIB:BEGIN per-config warm-starts into `_load_warmstart`** in `parity_s6fx_rx08_aegis.py:250`. Current implementation returns `[]` per the locked "RX01 warm-starts DISCARDED" decision — but Pine CALIB:BEGIN is **not RX01**; it's Pine's curated v1 warm-start. Recommended: build a `PINE_WARMSTART` dict keyed by (pair, tf) and return trial-0 from it. Concrete table for SMR M15: `{("6A",15): {"entry_z":2.00, "exit_z":0.60, "stop_z":4.30, "ts_bars":29, "smr_z_window":16, "risk_pct":0.90, "max_units":5, "confMin":75}, ...}` etc., extracted directly from Pine L256-389.
3. **Tighten `risk_pct` upper bound** to 1.50 (Pine maxval 2.0, Python 1.5 OK but Pine maxval) — currently aligned, no action.
4. **Verify 6J point-value convention** with a 1-trade end-to-end sanity check. Pine `syminfo.pointvalue` returns broker-published values; Python hard-codes $12,500,000 (notional per 1.00000 of price). The math is equivalent only if stop_dist is in price units (not pips). Document this in `q7_s6fx_common_5leg.py` `POINT_VALUE` block.

### P2 — formula / behavioral

5. **`rolling_dd_pct` is missing** from Python ParamSpec set. Pine has `i_useRollingDD` + `i_rollingDDPct` (default 15.0) as distinct from `dd_guard_pct`. Python folds rolling DD into `dd_guard_pct` (5.0–25.0). Functionally `dd_guard_pct` IS the rolling halt trigger, so this is a NAMING gap, not a logic gap. Recommend renaming `dd_guard_pct` → `rolling_dd_pct` in producer + engine for Pine alignment, OR add an alias resolver.
6. **DXY data quality gate** — `load_dxy_ohlcv` emits a one-shot RuntimeWarning when falling back to proxy. For RX08 calibration cycles, recommend escalating this to a producer-level hard requirement: if real DXY missing, refuse to run REGIME configs (not SMR — SMR doesn't depend on DXY). The current behavior runs with proxy but flags the discrepancy in §11.3 of whitepaper as a "common bug source." A pre-flight check at `_prepare_data` would prevent silent drift.
7. **FLIP confluence bypass** — Pine implicitly allows FLIPs to ignore confluence (active reversal trumps probabilistic gate); Python explicitly does this at `q7_s6fx_regime_5leg_engine.py:559-560`. ✓ EXACT — confirming, no action needed.

### P3 — naming / cosmetic

8. **`hai_min_score` ↔ `i_mlMinScore` aliasing** is identical to S2 issue; document or rename.
9. **`smr_session_str` UTC hour bounds** are calibratable via `session_hr_tky_end`, `session_hr_ldn_end`, `session_hr_ny_start` ParamSpecs (4–20 each). Pine hard-codes 7/16, 12/21, 0/9 (L617-622). This is a Python EXTRA — flag as intentional expansion of search space and document so Pine UI bounds don't surprise users.
10. **`wt_zeta` documentation** in Pine — add a comment under G07 noting the 7th confluence component now exists Python-side.

---

## §7 Verdict

S6 RX02 Pine ↔ Python RX08 parity is **HIGH**. All 12 spot-check formulas align: substrate (rolling SMA-z for SMR, EMA-slope+carry+DXY-agreement for REGIME), Λ-Vol classifier with FX-tuned `calm_t=0.50`, sub-mode router (engine-aware: SMR favors MEAN_REVERT, REGIME favors TREND_ACTIVE), 5-leg dual-mode (Z-LEG for SMR, R-LEG for REGIME with trail), FLIP semantics (active reversal, mode='FLIP'), per-pair FX event blackout. All layered enhancements (HAI Option B, ζ-Field, FX_DUAL gate, MDD floor, real TVC:DXY) are additive and gated by switches.

Top concerns: (1) `ts_bars` ParamSpec doesn't split SMR vs REGIME bounds, producing un-loadable-in-TV SMR best-trials. (2) Pine CALIB:BEGIN warm-starts are not wired into `_load_warmstart` — discarded together with RX01 results, but they're Pine v1 curation, not RX01 inheritance. These two edits would close the principal calibration-quality gaps.
