# The MEME-outcome gate, and how it relates to AxoMEME

**Purpose of this doc:** explain what the gate model *is*, why it is a **separate, deliberately tiny
model** rather than the AxoMEME neural network, and how the two fit together in the DM3 pre-screen.
The short version: they answer two different questions, at two different granularities, and coupling
them would make both worse.

---

## Two models, two questions

| | **The gate** (this deliverable) | **AxoMEME** (the neural network) |
|---|---|---|
| Question | *Is this alignment worth running MEME on at all?* | *Which sites are under selection, and how strongly?* |
| Granularity | one number **per alignment** | one prediction **per codon site** |
| Input | 3 scalars: `num_seqs`, `num_sites`, `median branch length` | the **full codon MSA + tree** (the whole matrix) |
| Output | P(MEME reports ≥1 site at p ≤ 0.1) | per-site log-LRT (the MEME statistic itself) |
| Model class | XGBoost (XGBClassifier, native monotone_constraints; ships as its own JSON, no converter) | Phylogenetic Axial Transformer (~12 MB, ~0.9 M params) |
| Cost | microseconds, CPU, no GPU | seconds, GPU-friendly |
| Trained on | 3,000 production MEME jobs, label = MEME-found-a-site | HyPhy MEME LRT labels on codon alignments |

They are **complementary**, not redundant. The gate is a **triage front-end**; AxoMEME is the
**per-site predictor** that runs only once triage says it's worthwhile.

---

## The pipeline (two stages)

```
  submission (alignment + tree)
        │
        ▼
   ┌──────────────┐   3 scalar features (num_seqs, num_sites, median BL)
   │   GATE        │   -> P(MEME finds anything)
   │  (this model) │
   └──────┬───────┘
          │  RED (score < 0.30)  ─────►  abstain: "MEME often finds little here" — don't spend the
          │                              per-site model or a full MEME run unless the user insists.
          │  GREEN / UNCERTAIN
          ▼
   ┌──────────────┐   full MSA + tree
   │  AxoMEME NN   │   -> per-site predicted LRT + which sites are selected (detect + rank top-k)
   └──────────────┘
```

The gate decides **whether to bother**; AxoMEME decides **what's there**. On a shallow, low-power
alignment the gate says "skip," and the expensive per-site model never runs — which is exactly where
running it would be least informative anyway.

---

## Why the gate is a separate model (and not AxoMEME with an extra head)

This is the design decision most likely to be questioned, so it's worth stating plainly. We considered
using AxoMEME's own outputs (it has a per-site selection-probability head) as the triage signal, and
rejected it, for three concrete reasons:

1. **Different label, and AxoMEME's head is calibrated to the wrong one.** AxoMEME's selection head is
   trained against the *LRT magnitude*, not "does MEME report anything." On shallow trees — the exact
   regime where triage matters — that head reads confidently high even when MEME will report nothing.
   Using it as the gate reproduces the original miscalibration.

2. **The triage signal is knowable *before* the expensive model runs.** Whether an alignment has enough
   power for MEME to detect anything is largely a property of its *size and divergence* — num taxa, tree
   depth, branch lengths. Those are three cheap scalars. Spending a 12 MB transformer + GPU inference to
   answer a question that three numbers answer at 0.87 AUC is backwards. The cheap model *is* the right
   tool; it lets DM3 abstain in microseconds without loading AxoMEME at all.

3. **Decoupling keeps each honest and maintainable.** The gate is a calibrated, monotone, auditable
   3-feature tree — a reviewer can read exactly why it fired. Baking triage into the transformer would
   entangle "is there signal" with "where is it," and every retrain of one would risk the other. Two
   small models with clear contracts beat one model doing two jobs.

The empirical backing: on the DM3 validation, the gate's *tree-geometry* features reach AUC 0.87 for
"will MEME find anything," while AxoMEME's own strength is *detection AUC ~0.97 for which sites* once
you've decided to look. Each is strong at its own job; neither is good at the other's.

---

## What the gate shares with the AxoMEME research

Although it's a separate model, the gate is not disconnected from the AxoMEME work — it came directly
out of it:

- **The features are the AxoMEME "power" intuition, distilled.** The AxoMEME research established that
  MEME's own statistical power scales with tree depth/diversity, and that on shallow trees the LRT label
  itself is near-noise (a perfect surrogate ceilings at ~0.25–0.35 Spearman there). The gate operationalizes
  exactly that finding: `median branch length` and `num_seqs` are the tree-depth signal, and the gate's
  whole reason to exist is to abstain in the low-power regime AxoMEME identified.
- **The label comes from the same ground truth.** Both are supervised by HyPhy MEME output — AxoMEME on
  the per-site LRT, the gate on the derived per-alignment "did it report a site." Same source of truth,
  two projections of it.
- **Same honesty discipline.** The AxoMEME work reframed the product from "predict the LRT precisely" to
  "detect + rank + **abstain** where the data can't support a claim." The gate is the *abstain* half of
  that reframe made concrete: it is the component that tells the user "this alignment can't support a
  confident MEME call," which is the scientifically honest thing to say on shallow trees.

So: **the gate is a spin-off, not a competitor.** AxoMEME is the surrogate for the MEME *statistic*; the
gate is the surrogate for the MEME *decision* ("is this worth running"). They were built from the same
data and the same finding, and in DM3 they run as one two-stage pipeline.

---

## Practical notes for DM3

- The gate ships as `meme_gate.json` — XGBoost's own native format, 3-feature input `[num_seqs, num_sites, median_pos_dist]`. It is monotone in all three features (adding sequences,
  codons, or depth can only *raise* the score) and calibrated so the score reads as P(MEME reports a
  site at p ≤ 0.1).
- It does **not** need AxoMEME to run. DM3 can show the badge from the gate alone (microseconds, CPU);
  AxoMEME's per-site predictions are the *next* stage, invoked only when the gate/UX decides it's worth
  it.
- If AxoMEME's per-site predictor is later wired into DM3 for the GREEN/UNCERTAIN path, no change to the
  gate is required — the contract between them is just "gate score → run-or-abstain," which is already
  what the pipeline (`prescreen.py`) implements.
