Scoring, thresholds, and honest reporting
This page explains LipidOracle's scoring and tresholding system. It differs in many ways from classical lipidomics tools that stop at a positive match. LipidOracle attempts to quantify specificity: is there enough information to claim that the top hit is better than the others? Or is there a group of equally likely candidates? These questions are addressed quantitatively by analyzing all possible isomers, their fragments, and obtain a honest estimate of the underlying ambiguity in annotation.
The short version
Every scoring step in LipidOracle is built around one rule: never report more structural detail than the spectrum can actually support, and always make it possible to check that claim yourself. Where the evidence is decisive, the name says so. Where it isn't, the name says that too, instead of quietly picking whichever candidate happened to score highest.
Two questions, kept structurally separate
LipidOracle's annotation pipeline answers two different questions about a lipid, and it never lets an answer to one leak into the other: which chains are present (stage 2), and where exactly, within those chains, does a double bond or oxidation sit (stage 3). Each stage produces its own score (s2_score, s3_score), its own selection logic, and its own honesty check, described below. Neither one is used to prop up the other.
Why a single confidence score is not enough
Both stage-2 and stage-3 scores are normalised per spectrum, so the best-scoring candidate for a given feature always reads close to its own scale's maximum. That's a deliberate, standard choice — it's what makes a score comparable across spectra of wildly different intensity — but it has a consequence worth stating plainly, because most tools that report a "confidence score" don't: a high top score, on its own, cannot tell you whether the runner-up scored almost as well.
A feature where the second-best candidate trails far behind is a confident, well-determined call. A feature where five or ten candidates all cluster near the same top score is not, even though both features report an identical-looking best score. Reading the score column alone, you cannot tell these two situations apart — and a workflow that reports only the single best-scoring name per feature is, structurally, throwing that distinction away.
This is exactly why LipidOracle does not stop at "report the best-scoring candidate." Everything described below — the selection method, the assertion gate, and the resolvability audit — exists specifically to recover the information a bare top score cannot express: how many isomers is the spectrum actually unable to tell apart, and is the reported name honest about that.
How this differs from a typical lipidomics workflow
Most MS/MS lipid annotation tools score every candidate against the spectrum, keep the single best-scoring hit per feature, and report its name and score as the answer. That's not wrong as far as it goes — but it silently assumes that "best-scoring" means "determined", which, as above, is often not true. LipidOracle starts from the opposite assumption: ambiguity is the normal case, and the pipeline's job is to detect it and say so, not paper over it.
Typical workflow
- Reports the single best-scoring candidate per feature, whether or not any rival came close.
- A fixed score-ratio cutoff (e.g. "within 1% of the top hit") decides what's kept, regardless of how many candidates cluster there.
- A confident-looking name is produced even when the deciding peaks were never actually observed in that spectrum.
- Thresholds are often unstated, unpublished, or buried in source code rather than in the documentation a user reads.
LipidOracle
- Reports every candidate within a statistically meaningful, spectrum-specific credible set — one candidate when the evidence is decisive, many when it isn't.
- Checks, per feature, whether the winning candidate actually has peaks distinguishing it from its best rival — not just a higher score.
- Falls back to a coarser, honest name (e.g. species-level) rather than asserting a position the spectrum cannot back up.
- Tests its own thresholds against chemically impossible structures, on the record, and publishes every default and every parameter (see Parameters).
Stage 2: which chains are present
Once a sum composition is fixed (say PC 34:1), there is usually more than one way to split those carbons and double bonds across two acyl chains — 16:0_18:1 or 16:1_18:0 weigh exactly the same, so a precursor mass alone can never tell them apart. Stage 2 uses the MS2 fragment spectrum to decide, scoring each candidate arrangement as a blend of two questions: did the fragments this structure predicts actually show up, and how much of what was actually measured does this structure explain.
s2_score = 0.75 × (matched_weight − 2 × exclusion_penalty) / total_weight
+ 0.25 × (matched_intensity / total_intensity)
Fragments a structure predicts should be absent count too: finding one anyway is evidence against that structure, and is subtracted at twice its weight — ruling a candidate out is worth more than merely supporting one.
Passing the score thresholds (s2_lo_score_cutoff, then a relative cutoff against the best candidate in that scan) only means a candidate out-scored its rivals. It does not mean the spectrum could tell them apart. So every contested composition is separately audited: the winning arrangement is compared against its best-scoring disagreeing rival, and the pipeline counts, peak by peak, which of the fragments unique to one or the other were actually observed. Only when the winner's own distinguishing peaks were seen more often than the rival's is the call marked resolvable. That verdict — yes, no, or uncontested — is published in every export as s2_resolvability (the same three-state column for stage 3's C=C/oxygen-position audit is s3_resolvability), not buried in an internal log.
Stage 3: exactly where, within a chain
Stage 3 takes an already-identified chain and asks where, specifically, a double bond or an oxygen sits — using MS2 evidence that breaks the chain itself, not just the fragment that detaches it from the glycerol backbone. This needs a dissociation method built for the purpose: LipidOracle supports five, each implementing a published, peer-reviewed fragmentation chemistry (see references below) rather than a proprietary in-house scheme.
| Method | What it measures |
|---|---|
ead1 / ead2 | Electron-activated dissociation: a near-continuous fragment ladder along the whole chain, whose spacing shifts at a double bond. ead2 additionally localises hydroxyl and ketone groups. |
uvpd | UV photodissociation: a sharp pair of diagnostic ions flanking a double bond, ~24 Da apart. |
oad | Oxygen attachment dissociation: two required anchor ions per double bond (OAD02, OAD15), currently scoped to unoxidised diacyl PC [M+H]+. |
ozid | Ozone-induced dissociation: a matched aldehyde/Criegee ion pair per double bond, validated for specific class/adduct combinations. |
By default, every candidate's score is converted into a probability, not rescaled to a fixed 1.0. A top score alone still cannot say whether it was a decisive win or a coin toss among ten near-ties, which is exactly what selection exists to answer instead. Three further checks recover that information, and none of them can be read off the score column alone:
- Selection of credible candidates. By default, candidates are converted into a probability distribution (a calibrated softmax over the scores), and the pipeline keeps the smallest set of candidates whose combined probability reaches a target (95%). The size of that set is itself the confidence statement: A decisive spectrum keeps one candidate, an ambiguous one keeps many. A position is written into the final name only when a single placement holds a majority of that probability; otherwise the name stays at the level the evidence actually supports.
- The assertion gate. Even a clear score leader isn't enough on its own — a lead built on a single matched peak isn't real evidence. Before naming a position, most engines additionally require a minimum score margin over the runner-up and a minimum number of actually matched peaks, together; the exact combination varies slightly by engine (see Stage 3).
- Resolvability. The same rival-comparison audit used at stage 2, applied here to the positional call: was there a peak in this specific spectrum capable of telling the winning position apart from its closest rival? Published per feature, per aspect, in
diag/s3_resolvability.csv. - Sanity check against impossible structures. One further check is unusual enough to be worth calling out on its own. LipidOracle can construct double-bond placements that are chemically impossible, e.g. double bonds crammed onto consecutive carbons, which real fatty-acid biosynthesis never produces. It scores them through the exact same pipeline as real candidates. If an impossible structure scores nearly as well as the real winner, that's a warning that there is a problem with the current threshold, the scoring, or the query spectrum.
Honest reporting
- Ambiguity is reported, not resolved by fiat. When multiple structures are equally consistent with the spectrum, the annotation says so — as multiple idlevel-3 candidates, and as explicit uncertainty markers inside the exported CXSMILES structure itself — rather than arbitrarily picking one and presenting it as settled.
- The pipeline is allowed to say "I don't know". Every fallback described above (species-level names, unlocalised positions, the assertion gate) exists to let an annotation stop short of a claim the data doesn't support, instead of forcing a confident-looking answer out of thin evidence.
- What's calibrated is distinguished from what isn't. Where a confidence number has actually been fitted against known, confirmed positions, that's stated. Where a number is exported only as a diagnostic because no ground-truth dataset exists yet to calibrate it against (for example, stage 2's chain-arrangement posterior), that's stated too, instead of presenting every number as equally trustworthy.
- The method is checked against its own worst case. The null-decoy test above exists purely to catch LipidOracle being overconfident about its own output — a self-audit most tools do not publish, if they run it at all.
References
- OADUchino H, Tsugawa H, Takahashi H, et al. Computational mass spectrometry accelerates C=C position-resolved untargeted lipidomics using oxygen attachment dissociation. Communications Chemistry. 2022;5:162. https://doi.org/10.1038/s42004-022-00778-1 — LipidOracle's
oadengine implements the pinned MS-DIALPCOadSpectrumGeneratorspectrum-generation rules from this work. - OzIDRoss DH, Lee J-Y, Bilbao A, et al. LipidOz enables automated elucidation of lipid carbon–carbon double bond positions from ozone-induced dissociation mass spectrometry data. Communications Chemistry. 2023;6:74. https://doi.org/10.1038/s42004-023-00867-9 — LipidOracle's
ozidengine reproduces LipidOz's precursor-formula aldehyde/Criegee product rules at the spectrum level; it is not a replacement for LipidOz's own chromatographic workflow. - EADWu et al. Analyst. 2025. https://doi.org/10.1039/d5an00567a — the published method LipidOracle's
ead1engine implements. - UVPDWilliams PE, Klein DR, Greer SM, Brodbelt JS. Pinpointing Double Bond and sn-Positions in Glycerophospholipids via Hybrid 193 nm Ultraviolet Photodissociation Mass Spectrometry. Journal of the American Chemical Society. 2017;139:15681–15690. https://doi.org/10.1021/jacs.7b06416 — the diagnostic-ion chemistry LipidOracle's
uvpdengine models.
Where to go next
- Stage 3: acyl-chain analysis — the full technical reference for every engine, parameter, and formula summarised above.
- Parameters — every threshold in this page, with its default value and what changing it does.
- Nomenclature and CXSMILES — how a reported name and structure encode exactly how much is known and how much isn't.
- The built-in MS2 library — what stage 2 matches against before stage 3 ever runs.