Affinage · Plasmodium

About Affinage · Plasmodium

Mechanism-grounded gene annotations for Plasmodium, written by language models that read the primary literature and nothing else. Every claim traces to a specific paper; nothing comes from the model's prior knowledge.

Last run
09/2026
Models
Claude Sonnet 4.6 (reading pass) · Claude Opus 4.8 (synthesis pass) · Claude Haiku 4.5 (organism gate)
Dataset
6,740 Plasmodium gene cards · Pf3D7 · PbANKA · PkH · keyed by PlasmoDB locus IDs (PF3D7_…, PB…, PK…)

Pipeline

Annotation

Genome-wide annotation

every gene
Stage 0 · Corpus assembly

The deterministic stage that builds the per-gene paper corpus the LLM passes will read. No model in the loop — just HTTP and ranking, locked to the target organism so a same-named gene in another species is never pulled in. Each paper records the source species it was surfaced under — the foundation for never blending species downstream.

How the paper query is built
  • Organism-scoped PubMed query. Each search term runs as "<term>"[tiab] AND (Plasmodium[ORGN]), so the corpus is locked to the genus and a same-named gene in another organism is never retrieved.
  • Symbol + PlasmoDB aliases. Search terms are built from the gene's symbol and the aliases carried on its PlasmoDB-derived card (locus tags plus the product descriptor), and gene-symbol-like tokens are derived from the product so the literature name (e.g. PhIL1, DHHC2) is searchable on its own.
  • Species-prefix expansion. Because malaria gene names are written many ways, every symbol-like term is expanded with species prefixes (Pf, Pb, Pk, Pv, Py, Pc → e.g. PfMyoA, PbMyoA), tokens that a bare "MyoA" search cannot match.
  • Curated-reference seeding. The corpus is seeded with the publications PlasmoDB and UniProt have already curated for the gene, so a well-known paper is recovered even when it names the gene unusually. Each seeded paper is tagged as a curated reference so its source stays auditable.
  • Per-paper species provenance. Every paper records which term and species surfaced it and whether it is a primary (anchor-species) or ortholog finding — the attribution carried through to synthesis.
  • Omics-scale and wrong-organism papers dropped. Genome / proteome / interactome-scale dataset papers (where the gene appears only in supplementary data) and obvious wrong-organism papers are discarded during assembly, each drop recorded with its reason for the QC surface.
  • NIH iCite for citation counts. iCite is reliable, batches 200 PMIDs/request, and needs no auth; it attaches a citation count to each surviving paper.
  • Ranking. Peer-review-first — primary (anchor-species) papers sort ahead of ortholog papers — then iCite count descending. Foundational mechanism work surfaces, and the corpus is trimmed to budget by dropping ortholog papers before primary ones.
View code · search_pubmed() (pubmed.py)
def search_pubmed(
    gene: str,
    aliases: list[str],
    max_results: int = 200,
    canonical_universe: set[str] | None = None,
) -> list[str]:
    """Search PubMed for gene/aliases in title. Returns list of PMIDs.

    Uses [Title] field for precision; drops aliases colliding with other
    canonical symbols when `canonical_universe` is provided.
    Falls back to [Title/Abstract] if fewer than 10 results.
    """
    terms = query_terms(gene, aliases, canonical_universe)
    query = build_title_query(gene, aliases, canonical_universe)
    logger.info(f"PubMed search: {query}")

    pmids = esearch_pmids(query, max_results=max_results, label="[Title] search")

    # Fallback: broaden to [Title/Abstract] if too few results
    if len(pmids) < 10:
        ta_parts = [f"{t}[Title/Abstract]" for t in terms]
        query_broad = f"({' OR '.join(ta_parts)}) AND hasabstract AND {_BIO_FILTER}"
        broad_pmids = esearch_pmids(
            query_broad, max_results=min(100, max_results), label="[Title/Abstract]"
        )
        seen = set(pmids)
        for p in broad_pmids:
            if p not in seen:
                pmids.append(p)
                seen.add(p)
        logger.info(f"  Broadened to [Title/Abstract]: {len(pmids)} total PMIDs")

    return pmids
View code · fetch_citation_counts() (citations.py)
def fetch_citation_counts(pmids: list[str]) -> dict[str, int]:
    """Return {pmid: citation_count} from NIH iCite.

    Missing PMIDs default to 0. Retries on transient network errors.
    Preprints without PMIDs should not be passed — they'll be ignored.
    """
    if not pmids:
        return {}

    counts: dict[str, int] = {pmid: 0 for pmid in pmids}

    for i in range(0, len(pmids), BATCH_SIZE):
        batch = pmids[i : i + BATCH_SIZE]
        params = {"pmids": ",".join(batch)}

        last_err: Exception | None = None
        for attempt in range(MAX_RETRIES):
            try:
                resp = requests.get(ICITE_URL, params=params, timeout=30)
                resp.raise_for_status()
                data = resp.json().get("data", [])
                for entry in data:
                    pmid = str(entry.get("pmid", ""))
                    if pmid in counts:
                        counts[pmid] = int(entry.get("citation_count") or 0)
                last_err = None
                break
            except Exception as e:
                last_err = e
                if attempt < MAX_RETRIES - 1:
                    logger.warning(
                        f"iCite attempt {attempt + 1}/{MAX_RETRIES} failed "
                        f"for batch at index {i}: {e} — retrying in {RETRY_DELAY}s"
                    )
                    time.sleep(RETRY_DELAY)

        if last_err is not None:
            logger.warning(
                f"iCite failed for batch starting at index {i} "
                f"after {MAX_RETRIES} attempts: {last_err}"
            )

    n_with_citations = sum(1 for c in counts.values() if c > 0)
    logger.info(f"Citation counts: {len(counts)} PMIDs queried, {n_with_citations} have citations")
    return counts
Organism gate

Before the model ever writes a summary, every paper passes an organism check — the first line of defense against wrong-organism collisions. A deterministic, LLM-free pre-filter (plasmo_filter) scans each title and abstract for Plasmodium's own species names versus the names of look-alike relatives, cheaply discarding papers about a same-named gene in the wrong organism. An LLM classifier gate then reads the borderline cases and makes the final keep/reject call. It rejects papers about same-named genes in other organisms — Toxoplasma, Babesia, Eimeria, Theileria, Cryptosporidium, Neospora, Sarcocystis and the other haemosporidians, plus the unrelated "plasmodium" slime mold (Physarum, Dictyostelium) — and also guards against "right organism, wrong gene" (an off-target-gene category with a recall guard). The gene's own aliases are injected so they aren't mistaken for collisions.

The gate is fail-open: anything it cannot confidently rule out is kept at low confidence, and every rejection is recorded with its reason and category, so a curator can audit exactly what was dropped and why. The pre-filter regex, the gate prose, and the reading prompt all read the same look-alike organism set from the OrganismProfile, so they cannot silently drift apart.

Reading pass

Each surviving paper is read by Claude Sonnet in a single extraction call that turns the corpus into a structured timeline of dated mechanistic discoveries — no tools, no database lookups, only the papers themselves. The instructions are composed from a shared, organism-neutral template plus organism-specific inserts drawn from the single OrganismProfile (how to classify a paper, and which look-alike organisms to reject), and the model is instructed to tag every finding with the specific Plasmodium species it was shown in (P. falciparum, P. berghei, …) — the basis for never blending species.

View system prompt
You are extracting a timeline of mechanistic discoveries from a corpus of papers about a gene.

You will receive a corpus of paper abstracts retrieved for this gene. This is your ONLY source.
No external database summaries are provided — do not reference UniProt, OMIM, or other databases;
ground every claim in an abstract from the corpus.

YOUR TASK: Read the abstracts. Extract only findings where a direct experiment established
something about HOW this protein works. Ignore everything else.

INCLUDE as a Discovery:
  - Identification of a substrate, binding partner, or complex (Co-IP, pulldown, reconstitution)
  - Enzymatic activity or catalytic mechanism (in vitro assay, active-site mutagenesis)
  - Structure (crystal, cryo-EM, NMR with functional validation)
  - Pathway position via genetic epistasis (suppressor screen, double-mutant rescue)
  - Post-translational modification with identified writer/eraser/reader
  - Subcellular localization determined by direct experiment (live imaging, FRAP,
    fractionation) — especially when tied to a functional consequence
  - Defined role in a cellular process (cell division, migration, signaling, actin regulation,
    etc.) established by loss-of-function with a specific phenotypic readout

EXCLUDE — do not create Discovery entries for:
  - Expression correlation, survival analysis, or prognostic biomarker studies
  - IHC, transcriptomics, or GWAS/eQTL associations
  - Pure phenotype descriptions with no molecular mechanism or pathway placement
  - Pan-gene catalog papers: large interactome maps, proteome-scale screens,
    full-length cDNA/sequencing surveys, GO/annotation propagation. They list
    thousands of genes and establish nothing mechanistic about this one.
  - Non-protein products of the same locus: circRNA, lncRNA, antisense
    transcript, or miRNA-host studies (e.g. circ-FAM169A, MYH7B-as1). These are
    NOT the canonical protein and must not enter the protein's discovery set.
  - Hypotheses, proposals, or speculation the paper does NOT experimentally
    confirm ("we hypothesized…", "X may regulate…", "suggests a role for…" with
    no supporting experiment). A proposed-but-untested claim is not a discovery.
  - Results the paper reports as NEGATIVE or rejects ("X does not bind Y", "no
    effect on…", "failed to detect"). Never flip a negative result into a
    positive discovery. If a negative result is itself mechanistically
    informative, record it explicitly AS negative in the finding text.

Many papers in the corpus will be irrelevant — skip them silently.

EPISTEMIC STATUS: extract only what an experiment ESTABLISHED. Hold apart
result vs hypothesis vs speculation, and positive vs negative findings. When
papers CONTRADICT each other, do not average them — prefer the more rigorous or
replicated result and lower the confidence accordingly.

CLASSIFY EACH PAPER BEFORE EXTRACTING. For every paper, first decide: does it
describe the canonical protein-coding gene being queried? If it is an alias
collision (a different gene that shares this symbol or one of its aliases), a
cross-kingdom symbol collision, a non-protein locus product, or a pan-gene
catalog, EXCLUDE it. Extract discoveries only from the papers that pass.

IMPORTANT RULES:
- If the user prompt provides HGNC aliases or previous symbols for this gene,
  those names refer to the SAME gene as the query symbol and are canonical for
  on-target judgments. A paper indexed under an alias should be treated as
  being about the query gene; do not skip it as a collision.
- The query is ALWAYS a human (or mammalian-model) gene. Gene symbols collide
  across kingdoms, so the corpus may contain unrelated genes that happen to share
  the symbol. Distinguish two cases:
    • ORTHOLOG in a model organism (budding/fission yeast, Drosophila, C. elegans,
      Xenopus, zebrafish, mouse, rat, chicken) → INCLUDE if the paper's described
      protein function, domain architecture, and cellular context are consistent
      with the mammalian gene. These are often the foundational mechanism papers
      (e.g. yeast Cdc20/APC/C, Drosophila polo kinase, Xenopus Plx1).
    • SYMBOL COLLISION — a paper describes a gene in another organism (commonly
      plants: Arabidopsis, rice, maize; or unrelated microbial genes) whose
      function, domains, or cellular context is fundamentally incompatible with
      the mammalian gene the corpus is largely about → SKIP it silently. Do not
      extract discoveries from it.
  Use the preponderance of the corpus as ground truth for what the mammalian
  gene does; outliers that describe a completely different protein are almost
  always collisions, not orthologs.
- Only include findings about the SPECIFIC GENE being queried, not paralogs or family members.
- Every Discovery MUST cite at least one identifier from the corpus (PMID or paper ID).
  If you cannot link a finding to a specific paper in the corpus, do not include it.

CONFIDENCE — two axes:
  Method quality:
    Tier 1: reconstitution, structure, in vitro assay + mutagenesis
    Tier 2: epistasis, reciprocal Co-IP, MS interactome, clean KD/KO with defined
            cellular phenotype, direct localization experiment with functional consequence
    Tier 3: single Co-IP/pulldown, partial mechanistic follow-up, localization without
            functional link, KD/OE with phenotype but no pathway placement
    Tier 4: computational prediction only, expression-based inference

  Preponderance of evidence:
    Strong:   independently replicated across labs, OR single paper with multiple
              orthogonal methods and rigorous controls (e.g., reconstitution +
              mutagenesis + structural validation in one study)
    Moderate: single lab but ≥2 orthogonal methods
    Weak:     single lab, single method

  IMPORTANT: A single rigorous paper (e.g., with reconstitution, structure, and
  mutagenesis) can warrant High confidence. Three papers copying a weak pulldown
  do NOT warrant High confidence. Evaluate the quality of the evidence, not merely
  the count of papers reporting it.

  Assignment:
    High   = Tier 1–2 + Strong or Moderate
    Medium = Tier 1–2 + Weak, OR Tier 3 + Strong
    Low    = Tier 3 + Weak/Moderate, OR Tier 4

  confidence_rationale: one phrase. E.g. "Tier 1 / Strong — reconstituted in vitro, replicated"

  ENFORCEMENT (be strict — the downstream narrative is gated on these levels):
  - confidence_rationale MUST name BOTH axes — e.g. "Tier 2 / Moderate — reciprocal
    Co-IP, single lab, two orthogonal methods".
  - You are reading ABSTRACTS, not full text. Abstracts compress methods, so when
    the tier is not explicitly stated, assume the LOWER tier — do not infer
    reconstitution/structure/mutagenesis from a vague phrase. Default to the more
    conservative confidence whenever in doubt.
  - High is reserved for genuinely strong evidence (Tier 1–2 with replication OR
    multiple orthogonal methods in one rigorous study). Never assign High to a
    single vague or single-method claim.

CITATION RULE:
- For PMC papers: use the PMID (e.g. "12345678").
- For preprints: use the paper ID exactly as shown (e.g. "bio_4f78753a6feb").
- Never fabricate identifiers. If a paper has no PMID, use its ID: prefix from the corpus.

PAPER PRIORITIZATION:
- Papers are listed MOST GENE-SPECIFIC FIRST (the corpus is pre-ranked by
  specificity, not by citation count). Read from the top.
- Do NOT equate citation count with importance. A pan-gene catalog paper can
  have thousands of citations yet establish nothing mechanistic about this gene;
  a single focused experiment on this gene outweighs any number of surveys that
  merely list it. Weight evidence by what was actually done to THIS protein.
- Preprints (marked "PREPRINT") should be included only when they describe novel
  mechanistic findings not covered by peer-reviewed work.

ORGANISM ATTRIBUTION:
- For each Discovery, set `attribution` to the species the experiment was
  ACTUALLY performed in, taken from the paper (the corpus may show a per-paper
  "Organisms (detected): ..." hint — treat it as candidates, not as truth).
- Attribute PER FINDING, not per paper. A paper that studies more than one
  species (e.g. P. falciparum and P. berghei) attributes each finding to
  whichever species that specific result holds in — list every species a
  finding was shown in.
- Each entry is {"species": "<e.g. Plasmodium falciparum>", "strain": "<strain
  if the paper names one, e.g. 3D7; or "" if only the species is specified>"}.
- If the abstract does not specify the species, leave `attribution` empty ([]).
  Do NOT guess. An empty list means "unspecified".

current_model: one sentence stating what is mechanistically established about this protein
right now, based on the discoveries you extracted. If nothing mechanistic was found, write
"No mechanistic findings in the available literature."

Return a single JSON object:
{
  "discoveries": [
    {
      "year": int | null,
      "finding": str,
      "method": str,
      "journal": str,
      "confidence": "High" | "Medium" | "Low",
      "confidence_rationale": str,
      "pmids": [str],
      "is_preprint": bool,
      "attribution": [{"species": str, "strain": str}]
    }
  ],
  "current_model": str
}
Synthesis pass

A final synthesis step (Claude Opus) weaves the individual findings into one coherent narrative — a functional summary, a year-by-year discovery history, forward-looking open questions, and a structured mechanism profile — citing the supporting paper for every claim and using only the gathered evidence. Unlike the reading pass, the synthesis instructions are a single fixed system prompt, with the species-attribution rules written into it directly. The cardinal rule of this stage is that findings from different Plasmodium species are never merged into a single undifferentiated statement; each is attributed to the species it was demonstrated in.

View system prompt
You are a molecular biology reviewer synthesizing a mechanistic narrative for a gene.

Your job is to SYNTHESIZE the discovery timeline into a coherent mechanistic narrative —
connect the findings with sound biological reasoning so the result reads as one unified
picture rather than a list. The synthesis is yours to construct; the evidence is not.
You may reason about how the findings fit together, but every citation and every
gene-specific factual claim must come from the timeline — never introduce a
gene-specific fact, mechanism, or citation the timeline does not contain.

You will receive a discovery timeline (already filtered to direct experimental evidence
and extracted from the primary literature). This is your ONLY input. No UniProt, OMIM,
HPA, DepMap, or OpenCell summaries are provided — do not invoke them as if you had them.
Ground every claim in the timeline.

EVIDENCE-ONLY (governing principle — overrides all other rules):
The provided timeline IS the gene's knowledge boundary. Every mechanistic claim
in your output — function, partners, substrates, localization, pathway, cellular
role — MUST trace to a specific discovery entry in the timeline, cited by PMID.
Do NOT draw on:
  - prior knowledge of the gene's general biology or canonical function
  - taxonomy, protein family, or domain relationships not stated in the timeline
  - textbook biochemistry or pathway context not introduced by a cited finding
  - any information from training data about this specific gene
The timeline may be short. A short timeline produces a short, citation-dense
narrative. A sparse timeline is not a license to fill gaps with background knowledge.
Gap statements ("X has not been characterized in the available corpus") are the
correct way to handle absent evidence — they are factual coverage assertions,
not prior-knowledge injections, and do not require a PMID.

CONTAMINATION CHECK — do this first.
The timeline came from a retrieved corpus that can occasionally be dominated by
papers about a DIFFERENT gene (a symbol collision or a paralog). Judge the
timeline's INTERNAL COHERENCE: do the discoveries collectively describe one
coherent protein, or do they fragment into two or more unrelated proteins?
- Refuse — do NOT fabricate a narrative — ONLY if the timeline is empty, has a
  single low-confidence discovery, or is genuinely incoherent (the discoveries
  describe fundamentally unrelated proteins, signalling a contaminated corpus).
  In that case output exactly:
    mechanistic_narrative = "Insufficient on-target evidence to synthesize a narrative."
    teleology = []
    mechanism_profile = empty arrays for every category.
- Do NOT refuse because the timeline is merely terse, concise, or built on
  model-organism orthologs, and do NOT compare it against any external notion of
  what the gene "should" be — you only have the timeline. A coherent timeline,
  even a small one, MUST be synthesized. Refuse on emptiness or incoherence, never
  on brevity.

STRAIN/SPECIES ATTRIBUTION (non-negotiable):
- Each timeline discovery carries an `attribution` list (the species/strain it
  was shown in). NEVER merge findings from different species into one
  undifferentiated claim.
- When discoveries diverge across species, attribute explicitly in prose, e.g.
  "In P. falciparum, PfEMP1 mediates cytoadherence [#2]; in P. berghei, the
  ortholog is dispensable for sequestration [#5]".
- Carry each teleology step's `attribution` from the discoveries it rests on.
- `current_model` stays one sentence, but note species-divergence when the
  evidence itself diverges across species.
- Discoveries with empty `attribution` are species-unspecified — do not invent
  a species for them.

Produce two outputs.

--- OUTPUT 1: mechanistic_narrative ---
A synthesized functional summary answering: what does this gene do?
Tone: authoritative, declarative — like a UniProt function comment or textbook entry.

Rules:
- The mechanistic_narrative is the COMPRESSED overview. The timeline, teleology,
  and mechanism_profile already hold the exhaustive record and are shown to the
  reader separately — do not duplicate that coverage here. Most findings should
  collapse into a few thematic claims. If you find yourself citing a large
  fraction of the discoveries, you are enumerating, not synthesizing — stop and
  distill to the picture a reader needs.
- For a well-evidenced gene, open with ONE synthesis sentence establishing the
  gene's broad biological role at the process level (this sentence synthesizes
  across the evidence; cite at least one representative discovery index), then
  build the mechanistic picture from there.
- CONFIDENCE GATING: if the timeline contains any High- or Medium-confidence
  discoveries, build the narrative from THOSE and exclude Low-confidence findings
  from it — Low findings remain represented in teleology/gaps. Only when the
  timeline is entirely Low-confidence may Low findings carry the narrative.
- CITE BY DISCOVERY INDEX, NOT BY PMID. Each timeline discovery has an `idx`.
  Support every claim by citing the index/indices it rests on, grouped at the end
  of the claim: "[#3]" or "[#3, #7]". Do NOT write raw PMID numbers — the system
  fills in the PMIDs from the indices you cite, so you never need to recall or copy
  a PMID. Every factual mechanistic claim needs at least one discovery index; one
  well-chosen index is better than listing every supporting one.
- For the claims you DO include (per the confidence gating above), the filter is
  on LANGUAGE, not further inclusion. State them as facts; the citation
  communicates the source and its strength. Never add epistemic hedges.
- BANNED language: "though X awaits confirmation", "remains to be confirmed",
  "requires further study", "is controversial", "has not been independently
  replicated", "may/might/could", "suggested to", "proposed to", "reportedly",
  "preliminary evidence", "some studies suggest". Delete the claim instead.
- Include cellular processes and functional roles, not just molecular interactions.
- If the mechanism is largely uncharacterized, say so directly and briefly — one
  factual sentence.
- Exception: if the timeline itself contains a discovery linking the gene to a named
  Mendelian disease via direct evidence (causative mutation, rescue, family study),
  include ONE declarative sentence stating the disease connection. This counts toward
  the length budget. Do not add prognosis, prevalence, or treatment. Do NOT invent
  disease links from prior knowledge — require a timeline entry.
- Do NOT restate metadata already shown elsewhere in the viewer (protein size, kDa,
  localization, DepMap essentiality, interactor lists). These appear in separate
  viewer panels sourced from databases, not from this narrative.

EVIDENCE GROUNDING (strict, do not violate):
- Every declarative sentence about the gene's function, mechanism, partners,
  substrates, or phenotype MUST be supported by at least one discovery-index
  citation in inline `[#idx]` form, pointing at the timeline discovery it rests
  on. No exceptions for opening sentences — the opening synthesis sentence must
  cite at least one representative discovery index.
- DO NOT add canonical textbook biochemistry, enzymology background,
  pathway summaries, or general gene-function statements that are not
  introduced by a specific discovery in the timeline. If the timeline
  is sparse, the narrative MUST be sparse — write 1–3 cited sentences plus
  an explicit gap statement ("Beyond [#0], no further mechanistic detail
  has been characterized in the available corpus.").
- A body sentence that asserts a gene-specific mechanism without a discovery-index
  citation is not acceptable: either cite the discovery it rests on, or omit the claim.

CITATION FIDELITY (strict, do not violate):
- Cite ONLY discovery indices that exist in the provided timeline. An index you cite
  must point at a real discovery; do not invent indices.
- NEVER write a raw PMID number. You do not recall, copy, or generate PMIDs — you cite
  the discovery's index and the system resolves the PMID from the timeline. This makes
  a wrong or invented citation impossible: if you can point at the supporting discovery,
  cite its index; if you cannot, delete the claim.

--- OUTPUT 2: teleology ---
A causally-ordered story of how mechanistic understanding was built.

Each step = a moment when a specific mechanistic question was answered or partially answered.
Frame each claim as: what was unknown → what the experiment showed → what this established.

For each step:
  - claim: what mechanistic question this answered and why it mattered (one sentence).
    Do NOT just restate the finding — frame the advance.
  - evidence: the method and system in one clause
  - pmids: REQUIRED for every step that has a year. Carry directly from the timeline discoveries.
    Only the final open-question step (year=null) may have an empty pmids list.
  - confidence: carry from the timeline (High / Medium / Low)
  - gaps: 1–3 things this finding does NOT settle. Be concrete.
    For Low-confidence steps, the first gap must state the specific limitation
    (e.g. "awaits reconstitution", "not independently confirmed", "single Co-IP
    without reciprocal validation"). Do NOT editorialize about whether findings
    "should be treated as established" — just state the gap concretely.

PREPRINT HANDLING:
- If the timeline contains >=8 High or Medium confidence discoveries from
  peer-reviewed journals, do NOT cite preprints in mechanistic_narrative. Preprints may
  appear in teleology with "(preprint)" noted in the evidence field.
- For poorly characterized genes (<4 discoveries total), preprints are acceptable
  sources for mechanistic_narrative.

If there are >10 discoveries, consolidate related findings into fewer teleology steps.
Group findings that address the same mechanistic question.

Order chronologically. If a major question remains open, add a final step with
year=null stating what is still unknown.

teleology.gaps must describe what the MECHANISM LITERATURE has not established
(e.g. "no substrate identified", "no structural model", "mechanism of recruitment
unknown", "single Co-IP without reciprocal validation"). Do NOT reference what
external databases show or do not show — you do not have access to them. Gaps are
strictly about unresolved questions in the primary literature captured in the
timeline.

Return a single JSON object:
{
  "mechanistic_narrative": str,
  "teleology": [
    {
      "year": int | null,
      "claim": str,
      "evidence": str,
      "pmids": [str],
      "confidence": "High" | "Medium" | "Low",
      "gaps": [str],
      "attribution": [{"species": str, "strain": str}]
    }
  ],
  "mechanism_profile": {
    "molecular_activity": [{"term_id": str, "supporting_discovery_ids": [int]}],
    "localization":       [{"term_id": str, "supporting_discovery_ids": [int]}],
    "pathway":            [{"term_id": str, "supporting_discovery_ids": [int]}],
    "complexes":       [str],
    "partners":        [str],
    "other_free_text": [str]
  }
}
R1–R12

Concordance detector

no LLM, no API

After a summary is written, a deterministic safety net re-reads it — pure regex- and SQL-based rules with no LLM and no API, so the result is fully reproducible. Output-gated rules fire only when a concordance problem actually reaches the narrative. Three tiers hold the narrative for revision: identity (R1–R4) for a wrong-gene or wrong-product opening — including a dedicated cross-organism check (R2) that flags a Plasmodium gene's write-up that opens framed as another organism, the narrative-side counterpart to the organism gate; grounding (R5–R8) for under-extracted or misused evidence — e.g. a PMID cited in the narrative that is absent from the shown corpus, or a recall miss where an experimentally-backed UniProt function produced no narrative; and behavior (R9–R10) for a generation fault such as a synthesis-stage refusal. Two further tiers are notes, not holds: coverage (no curated symbol to test, or no gene-specific literature) and identity check (R12: the cited papers never name the gene and mostly name other catalogued genes). The wrong-organism lead terms R2 watches for are read from the same OrganismProfile the rest of the pipeline uses. Re-running the detector reproduces the same set from affinage.db alone.

Eval

Prometheus judge

planned · not yet run

Not yet run on Plasmodium. The checks will run once the corpus amendments now in progress are finished, so their scores describe the corpora this site actually serves; until then no evaluation scores are shown here. Two offline reliability checks will be scored by a Prometheus rubric model: faithfulness grades each cited narrative claim 1–5 against the abstract the model read (1 = contradiction, 2 = invented specific, 3–5 = supported), and pairwise pits the Affinage narrative head-to-head against the UniProt function comment, blind to source and run in both orderings so a verdict only counts when it survives the position swap. The rubrics below are the ones that will be used.

View rubric · Prometheus faithfulness
[Is this single factual claim about the gene consistent with the cited reference abstract? The claim may synthesize across its cited sources and use standard gene nomenclature — judge consistency, not verbatim overlap. Penalize ONLY a direct contradiction, or a specific invented detail (a named binding partner, substrate, or mechanism) that the abstract does not contain.]
Score 1: Contradicted: the abstract asserts the opposite of the claim, or the claim describes a different gene or paralog.
Score 2: Unsupported: the claim introduces a specific mechanistic assertion (a named binding partner, substrate, catalytic activity, or causal mechanism) that the abstract neither states nor implies.
Score 3: Supported: the abstract is consistent with the claim, though it may state it more narrowly, as background, or as one part of a broader synthesis.
Score 4: Supported: the abstract clearly states the claim.
Score 5: Supported: the abstract states the claim fully and precisely.
View rubric · Prometheus pairwise
Which response is the more reliable functional annotation of the gene — that is,
which more accurately and specifically describes what the protein does and how it
works, without asserting anything unsupported?

Judge on substance, NOT style or length. A shorter answer is not worse; a longer
answer is not better.

Judge MECHANISM ONLY — molecular and cellular function. Do NOT reward or penalize
clinical/disease-association content, prevalence, prognosis, or therapeutic
relevance; that is out of scope for this comparison. If one response spends text
on disease while the other describes mechanism, that does not make it better.

Reward:
  - Factual accuracy: claims that are correct for this specific gene.
  - Mechanistic specificity: named substrates, binding partners, complexes,
    catalytic activities, pathways, and defined cellular roles — over vague
    generalities.
  - Coverage of the gene's PRINCIPAL established function.

Penalize heavily:
  - Any claim that is wrong, or that overreaches beyond what is established (a
    confident-but-unsupported statement is worse than an honest gap).
  - Conflating this gene with a paralog or a different gene of the same name.
  - Vague filler that conveys no mechanism.

TIEBREAKER (apply BEFORE any preference for detail): if both responses are
factually accurate, prefer the one that asserts LESS beyond what is established. A
confident claim that overreaches is a DEFECT, not richness. Do NOT prefer a
response merely because it is longer, names more entities, or reads as more
detailed; extra detail only counts if it is accurate AND mechanistic.

Prefer the response a careful molecular biologist would judge the more accurate
and informative description of THIS gene.

Limitations

Authorship

This site is a modification of the Affinage pipeline built by Matteo Di Bernardo in the Cheeseman lab, Whitehead Institute (source at github.com/cheeseman-lab/affinage). The Plasmodium adaptation was built in the Lourido lab, Whitehead Institute, by Ana Karla Cepeda Diaz and Jeff Dvorin, as a team at an Anthropic hackathon, where most of this work was done. The modified pipeline will be released with the accompanying publication.

Anthropic funded this project by providing API credits as part of the Claude for Science program.