SeaWolf-AI's picture
Guide states the rubric and size cap from the season, not from prose that went stale
59ee1a0 verified
Raw
History Blame Contribute Delete
8.35 kB
# -*- coding: utf-8 -*-
"""Season registry. Everything that differs between seasons lives here and nowhere else.
Seasons run concurrently: #1 Malaria closes 30 September 2026, #2 Tuberculosis closes 31
October 2026, and for six weeks both take entries. So "the season" stopped being a
constant and became a lookup, and every read of the ledger is scoped by it.
Season 1 keeps the ledger paths it already had. Its 65 scored records stay exactly where
they are - re-homing live data to make the layout tidy is how records get lost, and there
is nothing wrong with the layout that a prefix cannot solve. Season 2 is namespaced under
s2/, and every season after it gets its own prefix the same way.
The scoring rubric is deliberately repeated per season rather than shared. Season 2 carries
corrections for scorer defects measured during Season 1, and none of those corrections may
reach Season 1, where entrants have already been scored under the published rules. The
defects themselves are tracked outside this repository: naming them here would tell an
entrant which way to push a molecule while Season 1 is still taking submissions.
The same applies to each later season. Where a season's admission limits differ from
Season 1's, the limits are here because the code needs them and the page shows them in a
rejection message anyway; the measurements behind the choice are not.
"""
SEASONS = {
1: {
"number": 1,
"name": "Open Discovery Challenge",
"topic": "Malaria",
"topic_ko": "말라리아",
"organism": "Plasmodium falciparum",
"target": "PfDHODH",
"counter_target": "human DHODH",
"closes": "2026-09-30",
"prize_usd": 1000,
"weights": {"activity": 30, "binding": 20, "selectivity": 20,
"admet": 15, "novelty": 10, "synthesis": 5},
# empty prefix: season 1 predates the split and its paths are not moving
"prefix": "",
"anchors": "anchor_scores.json",
"open": True,
},
2: {
"number": 2,
"name": "Open Discovery Challenge",
"topic": "Tuberculosis",
"topic_ko": "결핵",
"organism": "Mycobacterium tuberculosis",
# InhA is the target isoniazid and ethionamide act through, it has direct
# (non-prodrug) inhibitors to calibrate against, 1,460 ChEMBL activities, and a
# 269-residue crystallised construct that docks sanely.
"target": "InhA",
# human fatty acid synthase carries the homologous enoyl-reductase chemistry, so
# selectivity keeps the same meaning it had in season 1: hit the pathogen's
# enzyme, not ours
"counter_target": "human FASN (ER domain)",
"closes": "2026-10-31",
"prize_usd": 2000,
# Not the season 1 split. Each axis is weighted by what this season's evidence can
# support, and the tuberculosis whole-cell model supports less than the malaria one
# did, so activity is paid less and the difference moves to binding and selectivity,
# which are measured rather than predicted. The measurements behind the split stay
# outside this repository while the season is taking entries.
"weights": {"activity": 20, "binding": 25, "selectivity": 25,
"admet": 15, "novelty": 10, "synthesis": 5},
"prefix": "s2/",
"anchors": "anchor_scores_s2.json",
# opened 2026-08-16 after the scorer was measured against its own panel: every
# WHO anti-tubercular scored 20.7-39.2 and every inert control 1.6 or below, and
# triclosan - the reference direct InhA binder - cleared the weak-binding control.
# Both conditions were written down before the panel was run.
"open": True,
},
3: {
"number": 3,
"name": "Open Discovery Challenge",
"topic": "Chagas disease",
"topic_ko": "샤가스병",
"organism": "Trypanosoma cruzi",
# sterol 14a-demethylase. This season can validate its own binding axis because the
# target has established direct inhibitors rather than only prodrugs, which is what a
# reference panel needs in order to mean anything
"target": "T. cruzi CYP51",
# the same enzyme in us. Inhibiting it is where the existing drug class gets its side
# effects, so "hit theirs, not ours" is the actual clinical problem here
"counter_target": "human CYP51A1",
# confirmed 2026-08-19. Six weeks after season 2 closes, so the three seasons finish
# a month apart rather than piling onto one scoring queue.
"closes": "2026-11-30",
"prize_usd": 1000,
# Not season 2's split. Three acceptance tests were written down before the
# whole-cell model was trained; two passed and one failed, and the pre-registered
# consequence of a single failure is to lower activity and move the points to binding
# and selectivity. That is what these weights are. The tests, the numbers and which
# one failed are recorded outside this repository while the season runs.
"weights": {"activity": 10, "binding": 30, "selectivity": 30,
"admet": 15, "novelty": 10, "synthesis": 5},
# Admission limits are per season. Season 3's target turns over a large natural
# substrate and its clinically validated inhibitors are correspondingly large, so a
# cap set for season 1's chemistry would exclude the very compounds this season is
# calibrated against - and a cap that excludes every reference compound is measuring
# drug-likeness in the wrong place. Two PAINS families are likewise not treated as
# rejections here, because they fire on motifs that are ordinary in this season's
# chemistry. The rest of the catalogue is unchanged.
#
# Raising the size cap does not leave size unpoliced: the binding term divides by
# heavy-atom count, so mass bought without affinity is scored down by the ligand
# efficiency term rather than waved through.
#
# Set before the season opened, never during, and checked against live submissions
# from seasons 1 and 2 first - no verdict on an existing entry changed. Which
# compounds motivated each limit is recorded outside this repository.
"gate": {"mw_max": 750.0, "heavy_max": 55,
"pains_allow": ("anil_di_alk", "quinone")},
"prefix": "s3/",
"anchors": "anchor_scores_s3.json",
# opened 2026-08-19, after a reference panel was scored against conditions written
# down before any of it was measured: compounds with nothing to do with the disease
# have to fall below the established drugs, and the potent reference compound has to
# clear the weak one. Both held. The panel and its scores are shown on the page; the
# conditions and the run that judged them are recorded outside this repository.
"open": True,
},
}
DEFAULT = 1
def get(n):
try:
n = int(n)
except (TypeError, ValueError):
n = DEFAULT
return SEASONS.get(n) or SEASONS[DEFAULT]
def public(s):
"""What the page is allowed to see. `prefix` and `anchors` are storage details."""
out = {k: v for k, v in s.items() if k not in ("prefix", "anchors", "gate")}
out["limits"] = limits(s)
return out
def limits(s):
"""The admission numbers the page is allowed to state back to an entrant.
The guide used to write these out in prose and they went stale the moment a season
changed them - the Chagas board told entrants the cap was 550 when it was 750. The page
reads them from here instead."""
g = s.get("gate") or {}
return {"mw_max": g.get("mw_max", 550.0), "heavy_max": g.get("heavy_max", 45)}
def gate(s):
"""Per-season gate overrides, as kwargs for gates.check(). Empty means season 1's."""
return dict(s.get("gate") or {})
def path(s, name):
"""Ledger path for this season, e.g. path(s, "leaderboard.json")."""
return s["prefix"] + name
def listing():
return [public(SEASONS[n]) for n in sorted(SEASONS)]