Skip to content

Make species and assembly reference data real, validated, and load-bearing - #3

Merged
sr320 merged 1 commit into
mainfrom
reference-data-cleanup
Aug 28, 2026
Merged

sr320 merged 1 commit into
mainfrom
reference-data-cleanup

Conversation

@sr320

@sr320 sr320 commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Three cleanups flagged in the codebase review. They turned out to be one coherent problem: AREE's reference context was decorative — nothing read it, nothing validated it, and the fact that most needed surfacing was invisible.

The substantive find: an invisible annotation crossing

HESSER2024_VCOR declares the Roslin assembly (GCA_902806645.1). AREE standardizes its identifiers against a different one: the current NCBI reference xbMagGiga1.1 / GCF_963853765.1, annotation release RS_2024_06 — a different assembly from a different sequencing centre, because that is what the crosswalk is built from.

This is correct behaviour. NCBI Gene IDs persist across assemblies and re-annotations, which is precisely why the identifier hierarchy prefers them. But nothing recorded that the crossing happened — a reader of the evidence table saw only the study's own assembly and would reasonably assume the identifiers came from it.

Every evidence record now carries identifier_annotation_release alongside genome_assembly:

column value for HESSER2024_VCOR
genome_assembly GCA_902806645.1 (cgigas_uk_roslin_v1) — what the study used
identifier_annotation_release GCF_963853765.1 (xbMagGiga1.1), annotation release GCF_963853765.1-RS_2024_06 — what the identifiers refer to

For demo studies it is empty, not invented: the demo crosswalk is synthetic and has no annotation provenance to report.

Both accessions were verified against the NCBI Datasets API rather than trusted from the strings already in the repo. The verification date is recorded in the file.

A latent bug: species was not in the meta-analysis grouping key

Not merely unvalidated — absent from GROUP_KEYS entirely. Harmless while everything is one species, but it meant two failure modes, neither of which would have raised anything:

  • a second species would have pooled into the same estimate as the oyster;
  • a curator writing "Magallana gigas" instead of "Crassostrea gigas" would have silently split one animal in two, producing two half-powered meta-analyses.

That second case is live, not hypothetical: the Pacific oyster was reassigned from Crassostrea to Magallana, both names are in current use, and AREE's own crosswalk is built under Magallana while every registered study says Crassostrea.

Adds registry/controlled_vocabularies/species.yaml mapping accepted names and synonyms onto NCBI taxids, and a species_taxid evidence column. Grouping is now on the canonical taxid. The reported name is preserved in species — validation warns on a synonym rather than rewriting it, consistent with how the repo treats identifiers.

Genome assemblies: dead code made load-bearing

data/reference/genome_assemblies.yaml was read by no code and shipped PLACEHOLDER_CONFIRM_BEFORE_REAL_USE as an accession. It now carries both oyster assemblies with verified accessions, and aree validate-study rejects a genome_assembly that does not resolve to an entry, cross-checking its taxid against the species. Resolution accepts the assembly_id, either accession, or the combined form publications actually use.

A test asserts no placeholder accession can return.

Stale status field

HESSER2024_VCOR sat at analysis_status: not_started through several harmonization runs. Rather than only fixing the value, aree harmonize now warns when it harmonizes a study still registered as not_started — the field is curator-maintained, so it will drift again otherwise. It does not rewrite the curator's YAML.

Correction to the review: I had also flagged annotation_version: null as stale. That was wrong — the source states no annotation version, and the null is documented honest curation. Left as is.

Also

The four assay harmonizers each duplicated the species/assembly/annotation block. Folded into one study_reference_fields() helper so they cannot drift apart on this again.

Verification

Lint clean · 132 tests pass (was 96) · demo pipeline · real-study path · Streamlit serves HTTP 200 · full CI sequence run locally against a fresh venv.

scripts/check_real_study_evidence.py now also guards the annotation crossing and the taxid, so CI catches a regression:

OK: HESSER2024_VCOR — 351 evidence records, 87.2% identifiers resolved,
no imputed statistics, annotation crossing recorded (xbMagGiga1.1 / RS_2024_06)

Meta-analysis output is unchanged at 34 pooled rows, all simulated — the real study still contributes none, as expected.

Docs

  • handling_genome_versions.md rewritten around the two real assemblies and the crossing.
  • adding_a_species.md gains the synonym guidance and corrects a claim that is now false — it said meta-analysis "does not reference species directly, so nothing there needs to change."
  • roadmap.md drops the resolved placeholder item.

Still open

The real study continues to contribute no pooled estimate, and random-effects pooling remains exercised only on simulated inputs. That needs a second real study with full statistics, not more reference-data work.

🤖 Generated with Claude Code

…aring

Three cleanups from the codebase review, which turned out to be one coherent
problem: AREE's reference context was decorative. Nothing read it, nothing
validated it, and the one fact that most needed surfacing was invisible.

Species identity. `species` was free text compared by exact string. The Pacific
oyster was reassigned from Crassostrea to Magallana; both names are in current
use; every study registered here says Crassostrea while the identifier
crosswalk is built under Magallana. Adds
registry/controlled_vocabularies/species.yaml mapping accepted names and
synonyms onto NCBI taxids, and a `species_taxid` evidence column carrying the
canonical identity alongside the reported name, which is preserved.
`aree validate-study` now rejects an unknown species and warns on a synonym.

Meta-analysis groups on `species_taxid`, not the reported name. Previously
species was absent from the grouping key entirely — harmless while everything
is one species, but it meant a second species would have pooled into the same
estimate, and a curator writing "Magallana gigas" would have silently split the
oyster in two. Neither failure mode would have raised anything.

Genome assemblies. data/reference/genome_assemblies.yaml was read by no code
and shipped `PLACEHOLDER_CONFIRM_BEFORE_REAL_USE` as an accession. It now
carries both oyster assemblies with accessions verified against the NCBI
Datasets API (recorded in the file), and `aree validate-study` rejects a
`genome_assembly` that does not resolve to an entry, cross-checking its taxid
against the species. Resolution accepts the assembly_id, either accession, or
the combined form publications use ("GCA_902806645.1 (cgigas_uk_roslin_v1)").

The annotation crossing, which is the substantive find. HESSER2024_VCOR
declares the Roslin assembly, but AREE standardizes its identifiers against the
current NCBI reference — xbMagGiga1.1, release GCF_963853765.1-RS_2024_06, a
different assembly from a different centre. That is correct behaviour, since
NCBI Gene IDs persist across assemblies, but nothing recorded that it happened.
Every evidence record now carries `identifier_annotation_release` next to
`genome_assembly`. It is empty, not invented, for the synthetic demo crosswalk.

Stale status. HESSER2024_VCOR sat at `analysis_status: not_started` through
several harmonization runs, so `aree harmonize` now warns when it harmonizes a
study still registered as not_started rather than only fixing the one value.
(Its `annotation_version: null` is not stale — the source states no annotation,
and that is documented honest curation.)

Also folds the four assay harmonizers' duplicated reference-field blocks into
one `study_reference_fields()` helper, so they cannot drift apart on this again.

Tests: 96 -> 132. scripts/check_real_study_evidence.py additionally asserts the
annotation crossing and taxid, so CI guards them. Docs updated:
handling_genome_versions.md rewritten around the real assemblies and the
crossing, adding_a_species.md gains the synonym guidance and corrects its claim
that meta-analysis ignores species, roadmap.md drops the resolved placeholder
item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sr320
sr320 merged commit d141e38 into main Aug 28, 2026
4 checks passed
@sr320
sr320 deleted the reference-data-cleanup branch August 28, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant