Skip to content

fix(chrombpnet): drop the 33 mouse (mm10) models — chorus is hg38-only - #121

Merged
lucapinello merged 2 commits into
mainfrom
fix/2026-08-01-drop-mouse-chrombpnet-models
Aug 1, 2026
Merged

fix(chrombpnet): drop the 33 mouse (mm10) models — chorus is hg38-only#121
lucapinello merged 2 commits into
mainfrom
fix/2026-08-01-drop-mouse-chrombpnet-models

Conversation

@lucapinello

Copy link
Copy Markdown
Contributor

The defect

ENCODE publishes a mouse developmental atlas of ChromBPNet models (embryonic forebrain / midbrain / hindbrain / limb / liver / heart / neural tube / facial prominence, stages E11.5–E14.5). 33 of the registry's 42 ATAC/DNASE entries were those mouse models, and every code path around them assumes hg38:

  • scripts/build_backgrounds_chrombpnet.py opens genomes/hg38.fa and draws its DHS-anchored positions from the hg38 DHS vocabulary. So the per-track CDFs shipped for those 33 rows were built by pushing human sequence through mouse models.
  • The registry recorded no organism, so there was no field to filter or assert on. That is what let the mismatch ship.

Why 9 is the right surviving set

The 9 human models kept here are exactly the set scripts/generate_catv1_defaults.py already listed as CHROMBPNET_HUMAN_ANNOTATIONS, with the comment "CATv1 is GRCh38-only, so those have no counterpart and are omitted." The filter already existed in one place and had simply never propagated to the registry or the builder — so this is an independent corroboration, not a fresh judgement call.

The background

chrombpnet_pertrack.npz goes 786 → 753 rows (9 human ATAC/DNASE + 744 human CHIP) by pure row subsetting — no model was run and no CDF value recomputed.

Validated (validate_753.py, all checks passed):

check result
rows 753 = 744 CHIP + 9 ATAC/DNASE
the 9 are exactly the human allow-list pass
rows removed exactly 33, zero of them CHIP
9 surviving accessibility rows bit-identical `max
sample counts unchanged 18,672 / 34,004 / 1,088,128
CHIP counts 37,344 / 68,008 / 2,176,256
CDF health all finite, all monotone, no all-zero rows

The name-collision trap

The mouse tissue names collide with human ENCODE CHIP biosamples — liver, heart, brain and forebrain are all human CHIP contexts in chrombpnet_JASPAR_metadata.tsv. A name-only filter would silently delete human CHIP rows.

So the removal keys on (assay, cell_type), never on the bare tissue name; the validator asserts no CHIP row is dropped, and 16 human CHIP rows with colliding names were correctly kept. The registry header now carries this warning for the next person.

Scope: what is not changed

Enformer (1,643 mouse tracks) and Borzoi (2,608) stay unexposed. Both are human-only today only because a *_human_targets.txt was chosen — nothing asserts that choice against the FASTA the builders open, and nothing would catch a future *_mouse_targets.txt. Also unfixed here: AlphaGenomeOracle(organism="mouse") is accepted, stored, and never read. Those get a per-row genome field and a hard assert in follow-up work.

Re-adding mouse properly needs an mm10 FASTA and an mm10 region set for background construction (the cCRE Registry has an mm10 build; the DHS vocabulary does not), so it is tracked separately rather than as a registry edit.

Blast radius

No consumer breaks — chrombpnet.py, discovery.py, mcp/server.py, _setup_prefetch.py and the builder all read the registry dynamically, and no test pins its contents. Setup now prefetches 9 model tars instead of 42.

Two stale comments updated (discovery.py's alias-dedup note, generate_catv1_defaults.py's "also ships mouse models") and one misleading test docstring.

507 passed, 4 skipped, 0 failed

🤖 Generated with Claude Code

ENCODE publishes a mouse developmental atlas of ChromBPNet models
(embryonic forebrain/midbrain/hindbrain/limb/liver/heart/neural tube/
facial prominence, E11.5-E14.5). 33 of the registry's 42 ATAC/DNASE
entries were those mouse models, and every code path around them
assumes hg38:

  - scripts/build_backgrounds_chrombpnet.py opens genomes/hg38.fa and
    draws its DHS-anchored positions from the hg38 DHS vocabulary, so
    the per-track CDFs shipped for those rows were built by pushing
    *human* sequence through *mouse* models.
  - The registry recorded no organism, so there was no field to filter
    or assert on. That is what let the mismatch ship.

The 9 surviving human models are exactly the set that
scripts/generate_catv1_defaults.py already listed as
CHROMBPNET_HUMAN_ANNOTATIONS ("CATv1 is GRCh38-only, so those have no
counterpart and are omitted") — so the filter already existed in one
place and had simply never propagated to the registry or the builder.

chrombpnet_pertrack.npz goes 786 -> 753 rows (9 human ATAC/DNASE + 744
human CHIP) by pure row subsetting; no model was run and no CDF value
recomputed. Validated: the 9 surviving accessibility rows are
bit-identical, sample counts unchanged (18,672/34,004/1,088,128), all
744 CHIP rows preserved, every CDF finite/monotone/non-zero.

Re-adding mouse needs an mm10 FASTA *and* an mm10 region set for
background construction (the cCRE Registry has an mm10 build; the DHS
vocabulary does not), so it is tracked separately rather than as a
registry edit. The mouse heads of Enformer (1,643 tracks) and Borzoi
(2,608) stay unexposed; both are human-only today only because a
*_human_targets.txt was chosen, with nothing asserting that against the
FASTA the builders open.

CAUTION for any future species filter: the mouse tissue names collided
with *human* ENCODE CHIP biosamples — "liver", "heart", "brain" and
"forebrain" are all human CHIP contexts in
chrombpnet_JASPAR_metadata.tsv. The removal keys on (assay, cell_type),
never on the bare tissue name; the validator asserts no CHIP row is
dropped, and 16 human CHIP rows with colliding names were correctly
kept.

No consumer breaks: chrombpnet.py, discovery.py, mcp/server.py,
_setup_prefetch.py and the builder all read the registry dynamically,
and no test pins its contents. Setup now prefetches 9 model tars
instead of 42.

507 passed, 4 skipped, 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The registry goes 42 -> 9 ATAC/DNASE models and the shipped NPZ goes
786 -> 753 rows, so every doc stating the old numbers now contradicts
the code.

audits/AUDIT_CHECKLIST.md:205 is the one that matters most: it is the
canonical-numbers list, and it ends "No doc may disagree. P1". Merging
the removal without this change would make the checklist contradict the
thing it exists to check. Its entry now also records *why* the number
moved, so the next reader does not have to reconstruct it.

Nine locations, all live docs:
  audits/AUDIT_CHECKLIST.md:93,205
  docs/NORMALIZATION_GUIDE.md:135,174,466,551,789,1094
  README.md:374,1228

Two judgement calls:

  - README.md:361 keeps "786 h5's". That column is "Mirror size" and
    describes what is hosted on chorus-chrombpnet-slim, which is a
    different 786 from the CDF row count — the 33 mm10 h5s are still on
    the mirror. Added the fetch behaviour instead, matching how the
    Cherimoya row already distinguishes hosted from fetched.
  - CHANGELOG.md is untouched. Its 786 references (:17,:198,:208,:210,
    :343) are historical release records and correctly describe what
    shipped at the time; rewriting them would falsify the history.

docs/plans/chrombpnet-hf-slim-mirror.md:91 also keeps its "42 ChromBPNet
ATAC/DNase x 25.6 MB" — that is mirror sizing arithmetic in a planning
doc, not a live count.

507 passed, 4 skipped, 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lucapinello
lucapinello merged commit a7aa472 into main Aug 1, 2026
1 check passed
@lucapinello
lucapinello deleted the fix/2026-08-01-drop-mouse-chrombpnet-models branch August 1, 2026 14:26
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