For each symbol with a fresh live quote:
1. Build feature vector — FeatureExtractor.extract returns 22 elements
2. OOD score — OutlierDetector.oodScore(features). If > 0.6, tier=OOD and pick is dimmed.
3. Ensemble prediction — MultiHorizon.predictEnsemble returns {prob, byHorizon, weights, regime}
4. Calibrate — Calibrator.calibrate(ensemble.prob) if fitted, else raw
5. OOD pull — if oodScore > 0.5, prob = 0.5 + (prob - 0.5) × (1 - oodScore)
6. Conviction check — only keep |prob - 0.5| ≥ 0.10
7. Plan — entry = q.last, stop = entry ± 1.5×ATR, target = entry ± 3×ATR (≥ 2:1 R:R)
8. Feature attribution — top 3 features by |contribution| shown to explain the call
9. Tier — A if prob ≥ 0.70 (or ≤ 0.30), B if ≥ 0.62, C otherwise