How a spectrum becomes a molecule
The plan
How do we actually run this in ninety days with the compute we have?
Kaggle notebook constraints, Explorer and Modal, a validation set that does not lie, lessons from sibling projects, milestones and kill criteria.
The queen's digest
5/5 workers reported · Tue Oct 06 2026 20:00:00 GMT-0400 (Eastern Daylight Time)
Queen digest — compute, pipelines, validation design, submission mechanics, timeline
TL;DR (5 bullets a chief of staff would read)
- The data is now on disk and the competition is machine-readable. A worker downloaded
train.parquet(3,033,286,496 B) toC:\Temp\casmi26\data\. The installed Kaggle CLI 2.2.4 answers authoritatively where the JS-rendered site cannot:is_kernels_submissions_only=True,max_daily_submissions=5, merge deadline 2026-12-07, final 2026-12-14 23:59, 2,672 teams. We went from 403-Forbidden touserHasEntered=Trueduring this tick. - Every timsTOF spectrum in training is Enveda's own. 1,154,969 timsTOF rows = 1,153,785 enveda-180 (synthetic Enamine chemistry, ~0.03 % in COCONUT) + 1,184 enveda-np-examples (250 NP structures, zero of them exclusive — all also appear in GNPS/MassBank/RIKEN). So "timsTOF and natural product and structure-disjoint" has exactly 250 candidate members. There is no clean instrument-matched NP hold-out; we must substitute QTOF.
- The public leaderboard cannot discriminate in the medal zone. Full LB pulled today: 2,673 teams, max
0.480 (not the brief's 0.471), median 0.328. 263 teams score ≥0.42 but only 35 ≥0.43 — a 228-team
pile-up inside one 0.01-wide band. Treat any public-LB delta below ~0.01 as noise. But it is not scored on
the decoy
test.parquet: library search would saturate it, and nobody is near 1.0. - Compute is not the bottleneck; candidate coverage is. A 25 M-param peak-token transformer is ~2 min/epoch on one H200, ~$10 for 50 epochs on Modal. Meanwhile a random ranker's MRR@25 is exactly H₂₅/n = 3.816/n, so pool size is a first-order multiplier on the score. Spend the quarter on the pool, not on the GPU.
- Our own confidence will not rank our own candidates, and the cascade is a trap. Both sibling challenges found within-item confidence ρ ≈ −0.03. Independently, the eyewitness ROC literature overturned "sequential superiority". Both point the same way: fuse simultaneously, gate only for cost, and route with a calibrated absence detector rather than ranker self-confidence.
New concrete facts
- Peak statistics, measured on the real file (
explorer_modal...md, pyarrow 25.0.1): 401,806,233 peaks; mean 158 / median 42 per spectrum; p99 1,347; max 73,318. 85.5 % of peaks are <1 % of base peak; 95.2 % lie in m/z 50–1000. In-RAM 6.45 GB as pyarrow, 25.7 GB as Python float lists (the notebook-OOM case), 0.80 GB as a flattened float16 offset array clipped to top-100. Dense 0.01 Da bins would be 482.5 GB — sparse only. Confidence: high (measured). - Corrupt rows exist:
precursor_mzmax = 2,430,333. Any pipeline that trusts the precursor blindly will ingest garbage. 1 file. High. - RDKit chain of custody is a smaller risk than feared, and I can say why. (
kaggle_code...md+ my own measurements.)Canonicalize()callspickCanonical()on whatever partial set exists when themaxTransforms=1000cap is hit — no status check, no warning — with a lexicographic canonical-SMILES tie-break. The cap IS hit on polyphenols (quercetin 363 tautomers/179 ms, rutin 357 ms, tetracycline 287 ms) versus 0.2–6 ms for caffeine/morphine/erythromycin. But: raising the cap 1000→20000 changed zero of 8 polyphenol InChIKey14s; the bundled InChI has been 1.07.3 since 2024.09.6; no listed change between 2026.03.3 and .6 touches the transform table or scoring; and canonicalisation is a no-op for database-derived SMILES (my 8-molecule canary reproduces the standard keys exactly, and is input-order stable over 12 randomized SMILES each). Residual exposure is concentrated in de-novo-generated SMILES in odd tautomeric forms. 2 files, ~6 sources. High on the measurements, medium on the cross-version claim. - Kaggle environment: image is Colab-based, Python 3.13, numpy 2.1.3, no RDKit — it must be vendored.
rdkit==2026.03.3cp313manylinux_2_28_x86_64wheel = 37,187,145 B, uploaded 2026-06-05,Requires-Dist: numpy, Pillowwith no pins (worker downloaded it). Re-run limit "≤9 h, internet off, external public data and pretrained weights allowed" is from a GitHub mirror of the rules page — medium, not verified on Kaggle itself. - Explorer reality check (my own
sinfo/scontrol/squeue):gyorilab= one node d4079, 4×H200, 773 GB RAM, MaxTime 30 days vs 8 h on the publicgpupartition — butAllocTRESshows all 4 GPUs allocated, three to jobs running 26 d / 11 d / 11 d against 30-day limits. Publicgpuhas 4×(8×H200) and a 104-pending vs 52-running backlog. /scratch is 91 % full. High. - Pool-size evidence is real but non-monotonic. CSI:FingerID top-1 68.5 % → 34.4 % (biodatabase → PubChem, PMC4611636); MetFrag fragmentation-only 22 % → 6 % (PMC4732001). Counter-evidence: CASMI 2016 (PMC5368104), the only study binning by actual candidate count, found performance worst at 200–1,000 candidates and better both above and below — formula size confounds pool size. Also: metadata use moved 34 % → 70 %, beating every model improvement in that contest. Medium-high.
- Fusion: quality-weighted RRF, k=60 (flat over k=10–100: MAP .2134→.2147, Cormack SIGIR 2009, read in full) — but CombMNZ beat RRF in Cormack's own LETOR 3 table (.6107 vs .6051), so a bake-off is mandatory. Borda's PXR failure is mechanistically explained: linear-in-rank weighting lets one engine veto a candidate at rank 400 of 1,000 when only the top 25 are ever scored. High.
- Submission effort profile (my LB pull): median submissions used is 54 for teams ≥0.44 (n=12), 22 for the 0.42–0.43 band (n=228), 3 for teams <0.30. Leaders average ~2.3/day, not the permitted 5. 2,541 of 2,673 teams are solo. High.
Forced analogies — what the eyewitness-line-up lens produced
Paid off.
- Filler fairness → a pool-first discipline. "A line-up is biased when the fillers don't match the witness's description" became a measurable profile (candidates/query, Tanimoto(true, nearest decoy), mass-window width) and the rule fix the pool before fixing the ranker.
- Target-absent line-ups. ~45 % of hidden molecules never reach top-25, i.e. the culprit is not in the line-up. This reframes the biggest single loss as a detection problem and yields a calibrated absence detector that reallocates slots to a second generator.
- CAC curves / "pristine conditions" (Wixted & Wells 2017) → a concrete acceptance gate: monotone CAC, ECE ≤ 0.05, AUROC(absence) ≥ 0.8 before confidence is allowed to drive any decision.
- The mock-witness test — the single cheapest new experiment the lens produced: train on precursor m/z + formula + adduct only, no MS2. If that beats H₂₅/n on our pools, we are harvesting line-up bias, not spectral evidence.
- Chain of custody → the version-canary protocol in fact 3.
Duds, kept honestly.
- Sequential line-ups. I expected this to argue for a cascaded ranker. It argues the opposite: the sequential-superiority effect was overturned once Gronlund/Wixted/Mickes replaced diagnosticity ratios with ROC analysis. Cascade ranking (SIGIR 2011/2017) agrees — gating buys compute, not accuracy. Use the cascade for cost only.
- Double-blind administration. Breaks: we are one human plus agents, and unlike a witness we can resubmit.
Only the pre-registration half survived, as
prereg_template.md. - MRR@25 charges nothing for a false pick, whereas a wrong line-up identification is catastrophic. The cost asymmetry that drives the whole eyewitness literature simply does not exist here.
Contradictions within my subdomain
- "Bigger pools hurt" is supported but incomplete. CSI:FingerID/MetFrag say monotone decay; CASMI 2016 says non-monotonic, worst at 200–1,000, confounded by formula. Any pool-size experiment we run must control for molecular formula or it will measure chemistry instead.
- Consensus strength is unstable. The sibling digest's "+0.038" is, at source, +0.0380 at reference depth 7 with ρ = −0.258. Adding a weaker engine halved it (+0.0380 → +0.0178). And consensus is a catastrophe detector, not a fine-ranker: ρ = −0.763 where 19.2 % of poses were catastrophic vs −0.258 where 0.2 % were. Orthogonality alone must not earn a seat in our fusion — engines need an admission gate.
- enveda-180: drop it or keep it? The filler-selection lens says it is biased chemistry (0.03 % COCONUT). The data says it supplies 99.9 % of all timsTOF spectra — drop it and we lose the instrument entirely. Resolution: re-weight, do not drop; separate the instrument signal from the chemistry signal (runs R0–R6).
- Public LB meaning. My pile-up statistic says it cannot discriminate; the 90-day worker argues it is an unbiased but noisy sample of the private set (SE ≈ 0.02–0.04). Both can be true and both imply the same rule.
Gotchas for the modeler
to_pandas()on the list columns costs 25.7 GB in a 29–32 GB Kaggle session. Use pyarrow or a flattened layout.- A corrupt
precursor_mzof 2,430,333 exists. Filter before trusting mass windows. Canonicalize()silently truncates at the cap and reports nothing. Logenum_statusper candidate.- Tautomer-canonicalising a million-candidate pool is infeasible at 180–360 ms/molecule for flavonoids. Canonicalise unique structures only (train 275,810; COCONUT ≈480 k), cache, and never do PubChem wholesale.
- Holding out the 250 NP timsTOF structures requires deleting their rows from every library, not just one.
- 39 % of "independent" opinions in the sibling project were duplicates. Dedupe before counting consensus.
gyorilab's 30-day queue is fully occupied by 11–26-day jobs; do not plan around it being free.- CRLF line endings break
sbatch;rsyncis broken on Explorer (usescpviaxfer.discovery.neu.edu). - Modal is $2.10/GPU-h for A100-40GB as fetched today, not the brief's $1.40.
Questions for other queens
- q4_challenge_intelligence (posted to
rules_x_execution): what fraction of the hidden set is the public LB computed on? Every kill criterion's threshold depends on that standard error. Also confirm the 9 h re-run limit from a second source — ours is one GitHub mirror. - q6_candidate_space_retrieval: our pool-size experiment must control for molecular formula (CASMI 2016 found the damage non-monotonic and formula-confounded). Does your coverage math do that? And what is the measured recall@25 of a COCONUT-only pool — that is our ceiling, and my workers could only bound it.
- q2_data_forensics: please confirm independently that all 1,154,969 timsTOF rows are enveda-180 + enveda-np-examples, and reverse-engineer the multi-CE merge function from single-vs-merged enveda-180 rows. Our whole hold-out design depends on reproducing that merge exactly.
- q5_methods_lineage: we need ≥4 genuinely orthogonal engines with an admission gate. Which four, and how correlated are their errors? Sibling evidence says shared training data pushes ρ to ≈ +0.45.
Layman sentences
- We are trying to name an unknown molecule from the pattern of fragments it breaks into, and the hardest part is not the guessing — it is making sure the right answer is even on our list of suspects.
- Almost half the hidden molecules will never make our shortlist at all, so the biggest win is widening the shortlist, not polishing the ranking.
- Our practice exam is far easier than the real one, and 228 teams are currently tied within a hair of each other on a scoreboard that cannot tell them apart.
Gaps I could not fill
- Kaggle's official docs are JS shells; GPU types (L4×4, TPU v5e), max submission size, and the 9 h re-run limit rest on third-party mirrors. Medium confidence, flagged in two worker files.
- No public ablation of enveda-180 exists. One datapoint only: a model trained on enveda-180 alone scores 0.138 vs 0.107 random on NPs. The R0–R6 grid is designed but unrun.
- True MFU on H200 is derived, not benchmarked — a 200-step run would settle it.
- Whether
gyorilabmembership (AllowGroups=rc,gyorilab) actually admits our account is unconfirmed; we holdb.gyoriandm.minkaraassociations but have not queued a job. - Fox & Shaw 1994 (CombSUM/CombMNZ original) was not opened — the fusion recommendation leans on Cormack 2009.