Skip to content

RM index, items 200–299

One page of the RM index, which is paged by number: every item numbered 200–299, under the status or round heading it had when the index was one file. The rules for adding an entry, and the allocator that claims a number, are on the index page.

⏳ Open, no release decided — ROADMAP.md § Active items

Four items as of 2026-08-21 (RM103's manifest half, RM108 and RM110 here, plus RM117's observability half indexed under its own session below), and the heading was kept while it was empty. Three of the four — RM110, RM103's manifest half and RM108 — shipped on 2026-08-31 in the uncut 0.7.0; RM117 is the one still open, and the rows below carry their own status. The count in this sentence is dated on purpose: it says what the decision round left, not what is open now, and the ✅/⏳ on each row is what answers that. It held six until the 2026-08-21 decision round, whose whole content was that every one of them was a decision nobody had made: RM102 closed outright (→ ROADMAP_HISTORY), RM122 parked on demand (→ the deferral file), RM117 narrowed to its free half, and RM103 split, with the refusal moved to ROADMAP § The 1.0 cleanup. What is left is four minors whose shape is settled and whose release nobody has argued — a different thing from what this heading used to hold, and worth the distinction: two of the six were never design-blocked, one by a test that already pinned the answer and one by a record that held no incident. Items whose release nobody has argued yet belong here rather than in a ROADMAP_0_8/ROADMAP_1_0 file. Nothing is open under this heading as of 2026-09-11 — RM164 was the last, and its section moved to the 0.8 file the day someone asked which 150+ items were open without a release; the heading stays because the allocator writes a new reservation under it. And the section exists because there was nowhere to index one — every other heading names a release or a terminal state, so RM88 and RM89 would have been filed into a document this index could not point at, which is the exact failure this file was written to make impossible. Both have now left it: RM89 the next day, closed by the consumer answer it was waiting on, and RM88 in 0.6.1 once the policy it was really blocked on was decided. Both stay indexed under their release below, because an item that shipped is exactly what this index exists to still be able to find — and the heading stays for the next item filed before its release is argued.

Five of the rows below arrived at once, out of a batch of six: RM163–RM168, the 2026-09-01 source-adoption round. RM168 shipped the same day and is indexed under the 0.7 build round above. They answer one question — what else should we adopt as enrichment sources, besides CIViC and PubMind — and they were unusual for this heading in that none of them had been probed when they were filed. Each stated its measured half (a table kind with no provider, a snapshot's actual contents, a number from a probe already run) separately from its candidate half, and none asserted a licence.

All six were probed the same day, and decided with the maintainer that evening — the round is PROPOSAL_0_7_PT2, which is a record rather than a plan and wins over the entries below. Five build inside the uncut 0.7.0 and RM164 parks on a measured negative, having spun off RM171, which shipped two days later. The keeper from the round: five of the six entries said something their own probe contradicted, and four of the six verdicts the proposal drafted were then overturned in the maintainer pass — so an unprobed entry is a question, and a probed one is still only a proposal.

  • ✅ RM299 — SHIPPED 2026-09-27 on main, uncut — a patch, owner format, severity low. Stats.clinvar_count/pathogenic_count/benign_count descriptions now say they count authored rows (one per genotype) of a legacy boolean that folds a tier pair; value unchanged. · from S123 · also in CHANGELOG, CONSUMER_SUGGESTIONS_HISTORY
  • ⏳ RM298 — open, a minor, release undecided, owner format + enricher, severity medium. A per-row source column for pharm_variants.csv, so the ClinPGx currency check can tell a withdrawn annotation from a row that never cited one; lets RM297's withheld finding block again. · from RM297, S122 · also in CONSUMER_SUGGESTIONS_HISTORY
  • ✅ RM297 — SHIPPED 2026-09-28 on main, uncut — a patch (warn, never block; decided 2026-09-27), owner enricher, severity medium. A cited annotation_id the ClinPGx snapshot lacks stops the lookup and is reported with its three readings; a row citing none is reported on a category/triple difference; neither refuses under strict, both count as findings (ClinPgxResult.withheld). The per-row fix is RM298. · from S122 · also in CONSUMER_SUGGESTIONS_HISTORY
  • ⏳ RM296 — open, a minor, release undecided, filed only. Owner format + compiler, severity medium. A PRS has no percentile/Z → conclusion table; pgs.csv restates the PGS Catalog. A MeasureBinRow kind keyed on pgs_id, with the reference distribution and unit as part of the claim, ancestry mismatch withheld, and research_tier constraining the conclusion. · related RM16, RM47
  • ⏳ RM292 — open, a minor, for 0.8, filed only. Owner format + enricher, severity high. Postmortem M3: every check states what it checks and what it checks against; same source reads self-consistent, never verified; a tolerance counts its undecided class. Registry field, roster equality. · related RM267, RM270, RM274
  • ✅ RM295 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner docs/reference_examples, severity low. cyp2d6_structural's CYP2D64 row moved from 22:42127941 (GRCh38 has G) to 22:42128945 (rs3892097), example re-closed; it now joins ClinVar in RM291's test. · related* RM291
  • ✅ RM291 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch (a test only), owner compiler, severity high. Every GRCh38 reference example is compiled and joined on (chrom, pos, ref, alt) against a bcftools-normalized ClinVar slice, expected set by haplotype equality; 614 distinct allele keys join, the SHOX pair (2) is pinned to RM270; the one ref disagreement it found was RM295, fixed. M4. · related RM270, RM295, RM267, RM273
  • ✅ RM290 — SHIPPED 2026-09-29 on main, uncut — a patch, owner schema + compiler, severity low. OverlayTarget.vindication (sole/withheld/none + reason) replaces the one-table constant: concordance sole, resolution.csv withheld, the seven merged tables none; no finding moves. The gene_validity case is a value comparison, filed as RM311. · related S60, RM117, RM311
  • ✅ RM289 — SHIPPED 2026-09-28 on main, uncut — a patch, owner format + enricher, severity low. PgsRow.training_ancestry now says developed and evaluated in (the PGS Catalog's dev and eval stages, which RM163's check compares), and the unknown-terms skip quotes the source's recorded notice and URL and says no declared use changes it. Postmortem P15. · related RM163, S99
  • ⏳ RM288 — open, a minor, release undecided, filed only. Owner enricher, severity low. RM101's exemption block holds the only record: cpic_build, pharmvar_build and pgx_draft make callers enumerate an exception family. One catchable base, or keep the list and record why. Postmortem P14. · related RM101, RM96
  • ⏳ RM287 — open, a minor, release undecided, filed only. Owner enricher, severity low. RM39's explicitly requested ClinGen snapshot, never filed: no lane exists, so an offline deployment never runs the dosage pass. Postmortem P14. · related RM39, RM38
  • ⏳ RM286 — open, a minor, release undecided, filed only. Owner format + enricher, severity low. RM38 handed PharmVar's research-use/personal-key axis to RM27, which closed record-only without it; the restriction is notice prose. A new optional SourceRow column is minor-legal (RM38's 1.0 sizing rested on digest movement). Postmortem P13. · related RM38, RM27
  • ⏳ RM285 — open, a patch, two decisions first, filed only. Owner enricher, severity low. RM171's 'still open' list, never filed: read the legend behind VUS*, decide whether the unrated-miss identities earn rows. The rCRS anchoring of the : deletions shipped as RM293. Postmortem P12. · related RM171, RM273, RM293
  • ⏳ RM284 — open, a minor, release undecided, filed only. Owner format + enricher, severity low. RM72's unopened question: a skip does not displace an earlier answer, so the fact that today's run could not reach a source is dropped; it needs a run-level place. Postmortem P11. · related RM72, RM272
  • ⏳ RM283 — open, a minor, release undecided, filed only. Owner enricher, severity medium. RM175's 'honest remainder', unnumbered: the lane records only CREATED_*.txt, so an archive that stops being rebuilt is invisible. Record S3 Last-Modified in release.json and compare it with the sibling archives. Postmortem P10. · related RM175, RM173
  • ⏳ RM282 — open, a minor, release undecided, parked on a terms-first survey, filed only. Owner enricher, severity low. RM166's 'its own entry': ClinPGx, CPIC and PharmVar are all CC BY-SA no-sale, so a commercial author has no PGx source. Parked on a survey chosen for terms first, satisfiable now. Postmortem P9. · related RM166, RM281
  • ⏳ RM281 — open, a minor, release undecided, filed only. Owner enricher, severity low. RM166's 'its own number': the PGx lane builds from one ClinPGx archive, and clinicalVariants.zip (~5,190 rows, comma-combining type) bears on pharm_variants.csv. Postmortem P9. · related RM166, RM173, RM175, RM282
  • ✅ RM280 — SHIPPED 2026-09-28 on main, uncut — a patch, owner enricher, severity low. grpc's own retry is off on the Atlas channel (it capped at five and would have multiplied under a second layer); AtlasClient._call retries under attempt_floor(5) with upstream's backoff, so JUST_DNA_HTTP_RETRY_ATTEMPTS reaches it, and retries exactly what _translate calls AtlasUnavailable, INTERNAL included. The pacing gate is RM307. Postmortem P8. · related RM192, RM194, RM307
  • ✅ RM279 — SHIPPED 2026-09-28 on main, uncut — a patch, owner compiler, severity low. A variants.csv conclusion that names genotypes at its own locus and never its own is a hint/lint_rows warning; 10 of 10 real over 653,706 rows after three measured exclusions (an rsID's allele description, a haplotype, the row's gene symbol). D14; postmortem P7. · related S68, RM308, RM309
  • ⏳ RM278 — open, a minor, for 0.8, filed only. Owner compiler, severity low. RM218's open question, tracked nowhere: compile exposes neither ensembl_reference nor ba1_threshold, so no CLI-compiled manifest can record its reference. Add both or state why not, and make test_cli_parity.py assert the decided set. Postmortem P6. · related RM218
  • ✅ RM277 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner compiler + enricher, severity low. The literature pass re-fetches a pinned citation whose quote count no longer matches studies.csv (recomputing the count in place was refused: it would attach the old verdict to new quotes), so quote_counter_stale's remedy, re-run the pass online, is now true. P5. · related RM119, S56
  • ⏳ RM294 — open, a minor, release undecided, owner format/enricher, severity low. Whether STRchive's evidence grade travels into the module (authored column at full price against an open upstream vocabulary, a derived sidecar, or provenance). RM276's minor half. · related RM276, RM170
  • ✅ RM276 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity medium. draft-repeats names a drafted locus STRchive grades Refuted/Disputed (DMD, DIP2B, NIPA1, POLG) and counts Provisional apart, reading the grade privately off the catalogue file (a StrchiveLocus field would be minor). P4. · related RM294, RM170, RM165
  • ⏳ RM275 — open, a minor (re-sized 2026-09-27: a new warning code is a closed-vocabulary member a 0.7.2 reader refuses), filed only. Owner compiler, severity medium. RM107's unfiled remainder: frequencies, gene_metrics, literature, gene_validity, clinical_assertions, gwas_effects, expression_effects have no duplicate key; reproduced with a definitive/refuted gene_validity pair that compiles green under --strict. Warn now, derived from the merge key; refuse at 1.0. Postmortem P3. · related RM107, RM109, RM124, RM130
  • ✅ RM274 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity medium. A same-size different-content indel (hosting arm 9) is settled against the GRCh38 reference: the locus event is slid across its repeat and the genotype's payload is looked for among its spellings; kept if found, dropped and named if not, undecided when unreadable. P2. · related RM31, RM272, RM270, RM273
  • ✅ RM293 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity low. The miss lane anchors MITOMAP's 39 : deletions on the vendored rCRS (checked against it) and joins them: unmintable 47 → 8, rated_miss 1 → 2. The three Principle-2 texts corrected. · related RM273, RM171, RM285
  • ✅ RM273 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity high. Three enricher surfaces stop keying an indel on its spelling: the MITOMAP increment joins on events left-aligned against a vendored rCRS (rated misses 6 → 1), CIViC left-aligns a ClinGen-anchored indel, and PubMind's warning states 5,158 of 20,006 indel rows shift left. P1. · related RM270, RM171, RM153, RM134, RM293
  • ⏳ RM272 — open, a minor, for 0.8, owner enricher, severity low. The rsIDs RM268 (anchor base unreadable) and RM271 (non-base alleles) withhold are named only by a log warning on main, since a new EnrichmentResult field is minor-class; add it beside unreachable_rsids/allele_mismatches. · related RM268, RM271
  • ✅ RM271 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity medium. One private predicate at both Ensembl rungs and all four snapshot reads: a non-base ref (dbSNP_novariation, dbSNP_variant, an N-masked chrY ref, <Y>) withholds the locus, a non-base alt (<.>, <R>, empty, an N run) is dropped, no alt left withholds. REST's all-withheld is the answered-empty []; alts narrows for e.g. rs33946775. Found closing RM268. · related RM268, RM272, RM267
  • ⏳ RM270 — open, a minor, release undecided, owner enricher + compiler, severity high. The format names no indel normalization and the compiler cannot apply one (P2), so an indel's variant_key is its source's spelling and a left-aligned VCF misses a respelled row (rs333 CCR5-Δ32 among S120's three). The enricher's vrs_id is identical across the two spellings (probed) and distinct for RM267's wrong event, but never reaches a variant parquet. Build: left-normalize enricher fills, carry vrs_id to the parquet, stamp a checked verdict. S120. · related RM267, RM31
  • ⏳ RM269 — open, 1.0 (a P8 demotion), owner format, severity low. haplotype_b is required, so a hemizygous call (G6PD in a male) has no diplotypes.csv row, while CPIC's own table spells 187 G6PD rows as one haplotype. A sentinel name is accepted today and indistinguishable from an allele; a ploidy column would make old readers read B/B as homozygous. A haplotype-keyed table is the minor-legal fallback if a corpus needs it first. S119. · related RM52 ledger
  • ✅ RM268 — SHIPPED 2026-09-27 on main, cut 2026-09-27 as v0.7.3 — a patch, owner enricher, severity medium. _loci_from_rest anchors a one-sided REST indel on the base at start - 1 via clingen_allele.anchor_indel (probed: insertions -/C with start = end + 1, deletions AGTAAG/-), so rs8176719 resolves to 9:133257521 T>TC; an unreadable base withholds the locus, and an all-withheld answer is (None, source), named by its own warning (a structured list is RM272, minor). The GraphQL rung hands one-sided nodes to REST. Found reproducing S117. · related RM267, RM153
  • ⏳ RM267 — open, a minor, release undecided, owner enricher (+ just-dna-pipelines upstream), severity high. Ensembl's own VCF dump places rs8176719 (ABO O1) at 520 G>GC, a different haplotype from ClinVar/dbSNP/REST's 521 T>TC; across seven checked insertions the dump's POS is REST end − 1. No check here sees it (the anchor base is a real base; RM31 makes indel position differences undecided). A withholding cross-check against ClinVar/REST fits this tier; writing the corrected spelling wants a provenance column, hence minor. S117. S121 (addendum) makes candidate 4 the general rule: ClinVar is loaded in the same run and used only as a fallback, never as a witness, so compare every two-authority placement (by vrs_id where mintable) and withhold on disagreement, recording the witness per row. · related RM31, RM268, RM270
  • ⏳ RM266 — open, a minor, release undecided, owner compiler, severity low. diplotype_phase_ambiguous already computes the phase-confusable pair set (reproduced on hfe_compound_het: C282Y/H63D, C282Y-H63D/wt) but flattens it to a three-example-capped warning string, so a non-caller reader cannot recover it. @dont-discard-computed, not an authored RM28 axis — the set is derived and should be surfaced structurally (a manifest field or small parquet). S116 note 2. · related RM28, ROADMAP § D3/D4
  • ⏳ RM265 — open, a minor, release undecided, owner compiler/format, severity medium. On the replaced=True branch panel_block_deprecated fires whether or not the author needs genes/significance/reference_sha256, and there is no "accepted" key: warn forever, or drop provenance the format says has no home. The design question is whether panel: is deprecated whole or only its reader; a home for the three fields is the P3-clean minor, a conditional warning the patch stopgap that hides the 1.0 loss. S114. · also in ROADMAP § D19, ROADMAP_1_0 § RM4 row
  • ✅ RM264 — SHIPPED 2026-09-25 on main, cut 2026-09-27 as v0.7.3 — a patch, owner format, severity medium. The 0.7.x mitigation half of RM256: quotes_found/quotes_unchecked descriptions send the reader to abstract_only_count and name no new field; a FAQ entry gives the per-row quote_source reading. Nothing added, removed or retyped. S109.
  • ⏳ RM263 — open, a minor, release undecided, owner enricher, severity low. DOI → PMID as an RM50-shaped advisory via Europe PMC search; open question is whether a Crossref/PubMed title disagreement warns. S113.
  • ✅ RM262 — SHIPPED 2026-09-25 on the 0.8 branch, uncut, owner enricher, severity medium. CrossrefClient.work → CrossrefWork: a DOI lookup names the paper off the request exists already made; an HTML 200 now withholds instead of reading as True. S113.
  • 🔵 RM261 — open, deferred by the maintainer as risky, owner enricher, severity low. Stripping comments from the wheel measured −22% zipped; line numbers must be kept, and it reaches the enricher only. Removing the builders from the wheel was refused because cache rebuild from a pip install is a documented deployment.
  • 🕓 RM260 — the split SHIPPED 2026-09-25 on the 0.8 branch, uncut; the shells' removal is 1.0, owner compiler + enricher, severity low. compiler.py (492 KB), the enricher's cli.py (244 KB) and enrich.py (152 KB) are packages under the same import paths; each __init__ re-exports every old name, and those shells go at 1.0.
  • ✅ RM259 — SHIPPED 2026-09-24 on the 0.8 branch, uncut, owner enricher, severity low. gene_spans.genes_covering: a GRCh38 position → every MANE gene within the attribution horizon, a query hint never an attribution (50 at HFE H63D). S112.
  • ⏳ RM258 — open, a minor, release undecided, owner enricher, severity medium. A 5xx reads as "no copy" and the abstract-only row it writes is pinned forever; three candidate repairs, none chosen. Found building RM257 (S110).
  • ✅ RM257 — SHIPPED 2026-09-24 on the 0.8 branch, uncut, owner enricher, severity medium. PmcBiocClient reads an author manuscript Europe PMC calls closed (tables kept, references dropped) on the E-utilities gate; the licence stays Europe PMC's. S110.
  • ✅ RM256 — SHIPPED 2026-09-24 on the 0.8 branch, uncut, owner compiler, severity medium, sizes as a minor. Literature.quotes_checked publishes the quotes a retrieved text settled, from one per-row rule (LiteratureRow.quotes_checked) the enricher's report shares; nulling an abstract miss and redefining quotes_unchecked were both refused. The 0.7.x mitigation split off as RM264 on 2026-09-25 — the field is minor-only, so a patch re-describes the two counters for the released line. S109.
  • ✅ RM255 — SHIPPED 2026-09-24, released in 0.7.2, owner enricher, severity medium. Frequencies are asked per allele over every locus, alts= filters, three silent returns became findings, and a population row carries the allele it describes. S108.
  • ✅ RM254 — SHIPPED 2026-09-21, released in 0.7.2, owner enricher, severity high. ATLAS_IMPORT_FAILURES bound once and named by all three guards; the [atlas] protobuf floor is the gencode stamp; a third absence sentence. S107.
  • RM253 — 🔵 open — a minor, release undecided; filed 2026-09-20. Three seams from one report: a repeat count as a defining allele (<CNV:TR:n> is a length, TA(8) is a count), DEL<bases>/INS<bases> untranslated to <DEL:n>/<INS:n>, and DPYD's HGVS names refused for whitespace. Message halves shipped. S106.
  • ✅ RM252 — SHIPPED 2026-09-20, released in 0.7.1, owner enricher, severity medium. effective_declared_use reads the module's own recorded declaration at every gate with a module; the flag still outranks the file. S105.
  • ✅ RM251 — SHIPPED 2026-09-20, released in 0.7.1, owner enricher, severity medium. An authored pair whose rsID the snapshot knows is recorded from the reference with ref/alts, so a VRS id mints and the compiler's cross-check compares two independent values. S104.
  • ✅ RM250 — SHIPPED 2026-09-20, released in 0.7.1, owner enricher + compiler, severity medium. spec_genome_build looks past the scaffold's stubs and nothing else; append_rows names the template row and its line. S103.
  • ✅ RM249 — SHIPPED 2026-09-20, released in 0.7.1, owner enricher, severity medium. partner_genes on both CPIC clients; the empty-drug explanation gains the pair-keyed arm; the pair count (18 of 103 drugs, six pairs) recorded on RM28. S102.
  • RM248 — 🔵 open — a RESEARCH item, unsized; asked by the maintainer 2026-09-20. Some kind of report schema (Jinja templates or something) where the contents are static and declarative and the CSS lives downstream. Filed as research because the charter speaks first: the Non-goals say presentation belongs to consumers, so the item's own framing — a report declares CONTENTS, not appearance — is the thing to test rather than assume, and that ruling is the first deliverable. P1 decides the other half: OakVar's reporter modules are Turing-complete and Jinja is a spectrum rather than a safe point on it. Not RM7, which is per-sample evaluation output and therefore a consumer contract. Not a fourth library on today's evidence. Pairs with RM28 — ClawBio's pharmgx-reporter reaches its one AVOID across 59 drugs through "special": "warfarin", a hardcoded branch, so the report is where RM28's missing multi-subject predicate surfaces — and with RM188, whose ClawBio and genomi surveys already ran. Cheapest first measurement: what just-dna-lite renders today and which fields a module does not carry. · from the maintainer · also in ROADMAP
  • RM247 — ✅ FIXED 2026-09-20, shipped in just-dna-enricher 0.7.1 (with just-dna-compiler 0.7.1). uv run just-dna-enricher <anything> raises before Typer: [build-system] requires = ["grpcio-tools>=1.68.0"] is a floor with no ceiling resolved in an isolated build env uv.lock does not constrain, so it stamps GRPC_GENERATED_VERSION = '1.84.0' into the generated Atlas bindings while the runtime grpcio is locked at 1.83.1. One number written twice, one pinned and one floating. Blast radius is the whole command surface — cli.py imports alphagenome_check → atlas_client at module scope, so enrich/draft/literature die on an Atlas dep they do not use, and 17 test files error during collection (38 import just_dna_enricher.cli). Reproduced from clean: the generated tree is git-ignored, and uv sync --reinstall-package just-dna-enricher regenerates the same broken stamp — so it arrived with a grpcio-tools release, not a commit here (suite was green at 4658 on 2026-09-13; generated files dated 2026-09-19). Do not bump the runtime floor without re-reading RM192, which measured the Atlas cost at that exact grpcio/protobuf pair. Three candidate repairs argued in the entry: make it one number, import the bindings lazily so a grpcio fault cannot kill draft, and a smoke test that imports the entrypoint the console script does. All three candidate repairs shipped, because the first two are independent defects: the build tool is pinned at the runtime floor (one number, asserted equal, at RM192's measured pair rather than a bump), both module-scope atlas_client guards now catch RuntimeError as well as ImportError, and the console entrypoint is imported by a test. A fourth defect surfaced only by installing the wheel: resolver imports just_dna_compiler.resolution_findings, a module RM244 added after v0.7.0, so the wheel ModuleNotFoundError'd in a clean venv under its own >=0.7.0 floor — the intra-workspace floor guard compares a declaration against the local tree, where every module exists. A new guard reads the dependency's modules off the v<floor> tag; just-dna-compiler is cut to 0.7.1 alongside and just-dna-format stays at 0.7.0. · from a peer session blocked on draft --gene · related RM192, RM196
  • ✅ RM246 — SHIPPED 2026-09-18 in the uncut 0.7 line. A check whose severity is the compile mode said so three ways: (errors if strict else warnings_out) for four codes, an if strict: that also suppressed the symbolic-allele drop, and ResolutionOutcome.strict_errors pairing a warning with a different, longer refusal for three more. The third is the general case: ladder.LadderFinding(warning, refusal=None) plus route, with ResolutionOutcome deriving both warnings and strict_errors from one list of pairs rather than storing two that could drift. What the compile DOES with a refusal stays caller policy — resolution aborts under a strict resolution: prefix, membership accumulates. The @ladder equality widened from 4 codes to 7, and its walk had to become per-construction rather than per-function: the first cut credited nine plain warnings that share resolve_from_table with two real ladder members. · from RM149's first pass, finding 2 · also in CHANGELOG
  • ✅ RM245 — SHIPPED 2026-09-18 in the uncut 0.7 line. Every corpus scenario pointed at <path>:<line>, and 110 of them had no check beyond the line is inside the file. Measured against one ordinary session of code edits (RM244 + RM246): 53 lines ended up outside the function they were written against. # source: now names the file and # anchor: the symbol, and an anchored scenario carries no line at all — the alignment check became the emission site is inside this symbol's range rather than within three lines of this number. 225 of 228 anchored; the three line-only ones are two vocab.py constants for @reserved members and a module docstring. The recovery is the part worth reading: each line was resolved against the revision it belonged to, since deriving from the current tree would have written the drift in permanently. · from RM149's second pass · also in CHANGELOG
  • ✅ RM244 — SHIPPED 2026-09-18 in the uncut 0.7 line. Nine VALID_WARNING_CODES members are emitted by both compiler/resolution.py and enricher/resolver.py, and seven pairs were a different sentence — rsid_unresolved read not found in resolution table, position remains unset in one and not in the injected Ensembl snapshot in the other, so a consumer grepping either found half the emitters. just_dna_compiler.resolution_findings is the nine builders both tiers now speak through; they return str so the literal CodedWarning stays at each emission site, and None omits a clause this caller cannot establish — four withholds, all recorded decisions (S61 twice, S33, and which tables a cross-build skip left unjoined). Placement is the compiler because the enricher already imports resolution.genotype_fits and because the enricher's route dies at 1.0. Three breaks caught by guards rather than by reading: a dedupe that keys on the message, 77 shifted # source: anchors, and a third narrowing of the corpus phrase check. · from the RM149 corpus's second pass · also in CHANGELOG
  • ✅ RM243 — SHIPPED 2026-09-13 in the uncut 0.7 line. ENRICHER.md's which of these attest paragraph opens by refusing to state a total — a number in prose is a registry nothing iterates — and then attributed a count to each of four commands, summing to 17 of the 24 emitting members. enrich() said six and emits 8 (gained published_refutation and evidence_status_currency); check-identifiers said three and emits 5 (gained the two PGS members with RM163); three commands were absent from the sentence entirely. enrich._verification_records' docstring carried the same wrong six. RM218's repair applied a third time: state the rule, not the figure, and assert the property — the attribution moved into the check table, which already carried it per row. Two guards, and the one worth reading is the invariant that was wrong first: the Where cell names the emitting module fails on five correct rows, because that column names the site of the comparison and reference_allele is compared in sequences and attested by enrich. · from the RM149 Gherkin drafting round · also in ENRICHER, CHANGELOG
  • ✅ RM242 — SHIPPED 2026-09-13 in the uncut 0.7 line. alphagenome_check's no-client branch wrote skipped(CHECK, "unchecked"), and "unchecked" is not a member of VALID_VERIFICATION_SKIPS — one of the per-pass spellings that set replaced, surviving in a single call site — so the branch raised ValidationError where it was supposed to record nobody asked. Reachable by the default alphagenome check run against a local AVI snapshot with no ALPHAGENOME_API_KEY, while the --offline branch three lines up attested correctly. Repaired to offline, the member that means needs egress, had none, with client_absence()'s sentence carrying which absence it is in detail. Guarded by an AST walk over every literal skipped() reason in the workspace rather than by pinning the one branch, which would pass the day another pass writes no_snapshot. · from the RM149 Gherkin drafting round · also in CHANGELOG
  • RM241 — 🟡 open, filed 2026-09-13 from RM188's ClawBio half. RM92 built module_spec.weighting because weight is the one magnitude with no unit (@weight-has-no-unit); it is advisory and not reconstructed by reverse_module, with panel/authorship/license. Documented and field-by-field defensible — it is prose, correctly outside content_signature. The survey hit the consequence: translating ClawBio's panel forced an honest weighting block (their weights are importances within a nutrient domain, normalised by the SNPs found, comparable only inside one run), and reverse drops it — so a consumer holding two reversed modules has two weight columns and no way to learn the scales differ, which is what RM92 exists to prevent. Three dispositions, none picked: FAQ it; carry it through from the manifest; or warn on the drop the way the dropped attestation already warns (likeliest, one line). Not by hashing it — a reworded note must not move the digest. · from probes/CLAWBIO_SURVEY · related RM92, RM240, RM188
  • RM240 — 🟡 open, filed 2026-09-13 from RM188's ClawBio half; the translation is run, the landing is not. ClawBio's 28-SNP nutrition panel translated field-for-field: validate green, compile giving 84 weight rows over 28 variants / 24 genes / 12 categories, and compile → reverse → compile reproducing content_signature exactly. Land it as reference_examples/nutrigenomics_panel/ (@probe-becomes-example). Two refusals on the way, both findings: state is required while direction is not, so a translation written against the modern column is refused for omitting the superseded one (the 1.0-cleanup tracker has it, and the run adds that it is the first error a new author meets); and their 28 ref_allele cells carry no coordinate, which the schema correctly refuses. Still needs a resolution.csv for --strict, a sources.csv with read terms (their data_license is blank and MIT covers the code — @a-hosts-terms-are-not-its-contents-terms), a closure, a README and a REFERENCE_EXAMPLES section. · from probes/CLAWBIO_SURVEY · related RM188, RM241
  • RM239 — 🟡 open, filed 2026-09-13 from RM188's ClawBio half. ClawBio's gwas-lookup returns credible sets with a posterior probability and 95%/99% membership per (trait, study). A PIP is the same class of object as an allele frequency or a LOEUF — a number a named dataset publishes — and its key is GwasEffectRow's key plus nothing, so two optional columns (posterior_probability, credible_set) is the shape, minor-legal under P3/P8. Smallest item on the survey's list; do it the next time enricher/gwas.py is open, not on its own. Two things a design owes: whether credible_set is a membership flag or the set's level (95/99 are two answers to one question), and a withhold for a harmonised study carrying none — a nobody-asked third state, never a zero. · from probes/CLAWBIO_SURVEY · related RM90, RM188
  • RM238 — 🟡 open and PARKED on a consumer, filed 2026-09-13 from RM188's ClawBio half. ClawBio's gwas-lookup returns five cis-eQTLs by named tissue (GTEx + EBI eQTL Catalogue). expression_effects.csv is the wrong place for them: AlphaGenome-shaped, one row per (variant, gene) aggregating 371 tracks, and expression.py argues per-track rows are lossless and unreadable. A GTEx row is a measured eQTL in one tissue where the tissue is the fact, so it is eqtl_effects.csv keyed (variant, gene, tissue, dataset). Parked because USE_CASES § 7.2's rule applies — reopen with a consumer, never with an argument — and a competitor rendering the table is an argument; the first step when one appears is the acquisition measurement that parked the frequency snapshot. · from probes/CLAWBIO_SURVEY · related RM194, RM200, RM188
  • RM237 — 🟡 open, filed 2026-09-13 from RM188's ClawBio half. GeneMetricsRow.haploinsufficiency/.triplosensitivity key on a gene symbol; ClinGen publishes four dosage lists and enricher/clingen.py reads one, leaving region curation, recurrent CNVs and ISCA regions — the half a CNV classifier needs — unwritable. ClawBio's dosage map carries an element_type column for exactly that reason (22q11.2 is two of its four rows). A sibling region_metrics.csv keyed (chrom, start, end, name), not an element_type discriminator: a 22q11.2 deletion is not a claim about any one gene in the interval (@gene-map-is-another-sources-attribution), and a shared table would have half its key null per row. Two things first: read ClinGen's terms rather than recalling them, and decide whether region curation is a second surface of the clingen lane (@write-the-sourcerow). · from probes/CLAWBIO_SURVEY · related RM188
  • RM236 — 🟡 open, filed 2026-09-13 from RM188's ClawBio half. consequence (SO term) and impact (HIGH/MODERATE/LOW/MODIFIER) sit in ROADMAP § Reserved namespace as planned axes that get a slot only when a release actually commits; ClawBio's running ACMG engine reads both — PVS1 off consequence=frameshift_variant, PM1 off impact=HIGH, BP7 off both — which is the commitment case. Neither name is in RESERVED_NAMES_0_4, so nothing moves out of it; committing means building the column or adding the slot + a RESERVED_NAME_REASONS entry. The blocker is grain, and it is RM23's blocker restated: MANE-only is lossy, most-severe is an interpretation and therefore out, and a derived consequences.csv keyed (variant_key, transcript) is half cost and the shape RM23 also needs — settle both in one pass. · from probes/CLAWBIO_SURVEY · related RM23, RM188
  • ✅ RM235 — SHIPPED in the uncut 0.7 line (2026-09-13: a verdict module, both gate properties retyped, two CLI branches; no behaviour in the artifact changed, two in the commands did). Filed on a premise the real code refuted: the claim that an unreachable dbSNP or HGNC is counted stale while an unreachable OLS4 reports clean was measured on hand-built IdentifierReport objects carrying states the pipeline does not write — RsidStatus.state is live|merged|absent|withdrawn with no unchecked, and check_identifiers never populates report.rsids at all. Against a dead port the ontology leg raises IdentifierUnavailable and the command exits 1 with an unreachable record for all five checks, so an outage was already a hard refusal carrying its reason (@a-disagreement-with-a-document-may-be-in-the-instrument, applied elsewhere in the very pass that filed this). What survived is S100's shape: clean answered True over ids nobody read when an id-bearing table would not parse, and --strict exited 0 beneath all identifiers current. Both clean properties are now a Verdict — falsy when it carries codes, empty is the pass — so a gate stays binary while the reason rides beside it, which is the one documented exception to the house tri-state. The set holds errors, not non-answers: not_requested and nothing_to_check are deliberately not members, and unreachable could not be. Two behaviour changes: check-identifiers --strict newly exits 1 on an unreadable id-bearing table, and AcmgReport.clean on nothing_to_check goes from None to a pass, superseding that half of RM234 a day later. A prose filter was the defect underneath — unreadable_tables counted the row-taking form's reason as a parse failure, found by the existing tests going red. · from the RM234 investigation · related RM234, RM94, S86, S100
  • ✅ RM234 — shipped 2026-09-12 in the uncut 0.7 line, owner enricher, severity medium. AcmgReport.clean was not self.mismatches, and mismatches selects not_listed/denied — so a run that obtained no SF list gave every row the verdict unchecked, left mismatches empty, and answered True: a comparison that never happened reporting as one where everything agreed. version=None checked=0 clean=True and version=3.3 checked=13 clean=True are the two readings a caller could not tell apart, and @tautology-zero is the rule (a check that cannot fail must not report a pass). The attestation was already right, which is what shaped the repair: verification_record has always returned a skipped on both arms, so the fix is one not_consulted property both read rather than a second condition beside it, with a test asserting the equality across all five arms. None rather than False — negating would claim disagreement with a list nobody read. if report.clean: is unaffected (None is falsy) and the CLI's redundant and report.version guard is gone; --strict gates on mismatches, so no offline run newly refuses. One existing test was asserting the defect and now reads clean is None. · from S100 (just-module-creator) · related RM235, RM72, RM94
  • ✅ RM233 — shipped 2026-09-12, test infrastructure only, owner enricher tests + the suite root, severity medium. main was red at 2001215 on both Python jobs and green on every local run: two tests match a string inside Typer's rich-rendered output, and rich decides colour from the environment, so --use arrives as three ANSI spans (FORCE_COLOR=1 reproduces it) — while the second failure, a phrase wrapped across the error box, was never environment-dependent at all, because CliRunner pins its own width. Repaired in two places because there are two causes: TERM=dumb in a root conftest.py for colour (NO_COLOR fixes only half; COLUMNS is deliberately absent, measured useless against CliRunner), and the already-existing _unwrapped helper promoted out of test_cache_lanes.py into cli_text for wrapping. The transferable half is the private name: the normalizer existed and the second caller could not find it, so it wrote the raw match that went red — and it stripped box drawing but never escapes. 2 of 491 CLI tests were affected; the other 489 pass on the luck of what they match. · from CI run 34703638770 · related RM202
  • ✅ RM232 — landed 2026-09-12, after the 0.7.0 cut (83b1674) and so unreleased; the release class is the maintainer's call and CHANGELOG states both readings, owner compiler + enricher, severity high. RM231 folded each enrichment pass's licence row into its data table's commit and had to name five exemptions to close its roster; two of them are this item. civic_citations.draft_civic_citations and drafting.record_draft_provenance — the scaffold's recorder, reached by five drafters — record the licence only after the compiler's draft.append_* has renamed the drafted rows into place, so a refused merge leaves drafted rows with no licence record and the compile gate nothing to refuse on. A scaffold's <<REPLACE>> placeholder is enough to trigger it, which is S98's own trigger one layer over. RM231's seam does not reach: before_commit binds one callback to one rename, and pgx_draft appends three tables in three separate atomic commits. The fix threads the same optional kwarg through append_rows/append_partial_rows and fires it per file that writes — hoisting ahead of the first append is refuted by covered being unknowable until the append is attempted (differs covers nothing), and binding to first or last alone leaves a table unlicensed either way. Filed at discovery rather than at approval, and that is the transferable half: it had been recorded only as two exemption reasons in a passing test, which no release gate reading no open RMs, all green can see. The guard is now an equality from both ends — nine committing passes, two named callbacks, and every one of the 11 append_* calls carrying a before_commit (all 11 unbound before, all 11 bound after). · from the RM231 handover · related RM231, RM228, RM222, RM142
  • ✅ RM231 — shipped 2026-09-12 in the uncut 0.7.0, owner enricher, severity high. alphagenome expression wrote 12,003 non-commercial rows, then refused its licence row on a scaffold's placeholder and said FAILED — and the compile gate, keyed on the licence table alone, passed the module as unrestricted. Eight passes had the tail. layout.atomic_writer(before_commit=…) runs the merge inside the table's commit; require_sources_file pre-reads the table before the fetch; a guard asserts the eight plus five named exemptions, two of them RM228's same gap in the drafting scaffold. Licence-row-first refused (a row for a pass that contributed nothing). · from S98 (just-module-creator) · related RM128, RM142, RM228
  • ✅ RM230 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity high. EuropePmcClient.lookup leaked httpx.HTTPStatusError, httpx.ConnectError and json.JSONDecodeError into a pass whose try: has only a finally: — hidden because the contract suite's exemption for that class was argued from what one method (fulltext) promises. Removing it also showed covered was keyed on the module and could not express a per-class exemption. check-identifiers gains --use: PGS rows were hardcoded unstated, an academic_research_only score taints at annotation, and the compile's refusal named a flag that did not exist — measured live, 6 of the first 250 Catalog scores are in that class. And RM228's self-recorded debt is disproved: clinvar_draft/pubmind_draft return early before the licence write, so the test kept as a pin on that early return. · from the enricher tail of the 2026-09-11 round · related RM208, RM222, RM228, RM163
  • ✅ RM228 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. Seven *_draft.py providers each carried a copy of the same four decisions and the copies had drifted: two recorded a dataset and never withdrew a stale one, one imported another's private _MATCH_ON across modules, one parsed pydantic's rendered message as an API, and DRAFT_PROJECTIONS was a hand-kept copy of the drafters' match_on. The obvious fix was refuted by measurement: authoring_requirements' any_of grammar cannot express ref/alts require a position, so the one provider that looked correctly derived accepts a partial coordinate the model refuses — constructing the model is the only complete oracle. A drafting.py scaffold splits the derived model rule from a declared source precondition carrying its reason as a field; the import cycle it exposed showed the drafted-value axis had been sitting in provenance.py all along. Registry + AST guards, both failing on all seven pre-migration. · from the long-tail triage of the 2026-09-11 round · related RM222, RM73, RM4
  • 🕓 RM227 — open, owner format, severity medium. RM215 folded allele case into content_signature; derive_variant_key's coordinate fallback still does not, so 1:100:a:g,t and 1:100:A:G,T are two keys for one locus. Fires on a multi-alt row or a non-GRCh38 build, since the VA path normalizes already. Splits joins, not dedup, and moves a stored cell — so RM215's corrected-derivation argument does not reach it. Complicated by ref/alts not being grammar-checked at all. Pinned by a test so the note cannot rot into a silent fix. · from RM215 · related RM215, RM81
  • 🕓 RM226 — open, 1.0, owner format + compiler, severity low. Three decisions the code declares in its own comments and no tracker held: VariantRow.variant_key/authored_ident inside content_signature while every positional model's stamps are outside; likely_pathogenic/likely_benign hardcoded False in weights.parquet with no authored field; and _freeze_identity deriving a key with no build=. Each reversal moves published identities, so each is major — filed so the 1.0 cleanup has a list instead of a grep. · from the 2026-09-11 round's self-declared candidates · related RM15, RM52
  • ✅ RM225 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity medium. Four schema long-tail candidates walked item by item. actionability is closed and three places said otherwise — vocab.py's comment, base.vocabulary's own docstring, and an earlier reference.py incident — plus the _SEED name; renamed VALID_ACTIONABILITY with the old name a working alias. CANONICAL_MT_REFERENCE_SEQUENCES is correctly unenforced but its value was a literal in the refusal beside it. A pgx.py comment named StudyRow.chrom as validated at two sites; it is not. is_multi_valued_number's docstring promised a tri-state its sole caller does not need — the collapse is the contract. The guard measures closedness against the validator and walks the helper's own docstring. · from the long-tail triage of the 2026-09-11 round · related RM217, RM218
  • ✅ RM224 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity medium. SIDECAR_SPELLINGS is keyed on the table key (sources.csv) and the preferred filename was not a key, so sidecar_write_path(dir, "licensing.csv") on a module carrying sources.csv created the second copy the function documents itself as preventing. sidecar_key reads the map backwards, derived; sidecar_spellings normalises through it, so either spelling is a key and every helper is fixed at once. A filename is never refused. · from S96 (just-module-creator) · related RM51, RM49
  • ✅ RM223 — shipped 2026-09-11 in the uncut 0.7.0, owner compiler, severity medium. INTEGRATION_0_7.md stated four registry sizes and all four were wrong when a consumer measured them (ARTIFACT_PARQUETS 22 vs 23, VALID_WARNING_CODES 72 and 71 vs 73, the authoring reference 31 vs 32 models); three moved because the AlphaGenome round landed after the numbers were taken. The document's own § 8 forbids counted prose — nothing walked the file, so the guard, not the four words, is the repair. · from a consumer measurement during the 2026-09-11 round · related RM218, RM217, RM194
  • ✅ RM222 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. Three @write-the-sourcerow findings at one call site. The "contributed nothing writes none" half was a comment above a gate that only checked dry_run, so a --gene filter matching nothing wrote a civic licence row — a claim the module uses a source it does not; both sibling drafters already gate on an outcome. dataset was computed for every row's conclusion and dropped, because record_source_terms had no parameter for one, so the row read dataset='' and a CIViC-drafted module sat outside the currency check --verify-datasets/withdraw_stale_dataset run. And that function's docstring still said "None of these layers can taint", written for the three fact passes and false since this drafter began recording at annotation. · from the 2026-09-11 blind re-derivation round · related RM152, RM85, RM165
  • ✅ RM221 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher + format, severity low. Rich reads a bare [word] as a style tag, so three help texts lost the extra's name — atlas --help printed "Needs the extra" and atlas generate --help "which is in and deliberately not in". Escaped. The extra's size disagreed across five places (22 MB vs the measured 19 MB, two of them written earlier the same day). "Vendored" survived RM196 in the group help and ENRICHER.md while atlas generate --help two lines away said the opposite and the directory holds only a README. And VALID_VERIFICATION_CHECKS' first block said "enrich writes these six" against eight — membership right, sentence drifted; the number is gone and the enricher now walks both sides. · from the 2026-09-11 blind re-derivation round · related RM192, RM196, RM45
  • ✅ RM220 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity high. Two readings of --offline coexisted: pgx/enrich/frequencies make it absolute (RM38's licensing reason, asserted by name in test_pgx_licensing.py), gwas lets an injected client win (documented, and the Catalog is ungated). expression had gwas's shape against pgx's situation — the Atlas is licence-gated, so an injected client fetched under a flag documented as making no egress. @flag-means-same. The axis the two readings differ on is the source's licence, now written down in ENRICHER.md; gwas keeps its behaviour on purpose. The licence gate was masking the hole, so the test declares its use to remove the second gate. · from the 2026-09-11 blind re-derivation round · related RM38, RM194, RM200
  • ✅ RM219 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. download.py documents at length that every fetch stages through .part because HfFileSystem.get creates the local file before discovering the remote is missing; _provision_root_file_snapshot staged its payload and fetched release.json straight to the target two lines later, so a repo publishing no description left a 0-byte one. That turns nobody said into the description is corrupt — _json_parses rejects it and LaneStatus reports release_unreadable, sending an operator to re-pull a lane with nothing to give. The test's fake creates-then-raises, reproducing the documented client behaviour rather than assuming it. · from the 2026-09-11 blind re-derivation round · related RM209, RM187
  • ✅ RM218 — shipped 2026-09-11 in the uncut 0.7.0, owner compiler, severity low. test_counted_prose.py scopes itself to docs/ and the same class was live in compiler.py: "up to twelve in all" against 23 parquets, and _vrs_gap_reason's "six reasons" against 8 arms (RM5 and RM59 each added one without moving the number). Nothing re-counted — both sentences state the rule, and the guard asserts the property each stood in for, for the reasons @answered-is-not-absent's pairwise-distinct arms, which a count never checked. Also: _build_weights' 15-name issubset floor over a 39-column schema promoted to an equality over the walked set, with its two hand-kept halves compared to each other; and validate_spec's docstring, in both copies, corrected from "changes severity only" — strict genuinely adds two aggregate findings. ensembl_reference/ba1_threshold surfaced as CLI-unreachable rather than fixed. · from the 2026-09-11 blind re-derivation round · related RM5, RM59, RM93
  • ✅ RM217 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity low. Eight of vocab's 29 VALID_*/RECOMMENDED_* frozensets were named nowhere in SCHEMAS.md, and RECOMMENDED_ANCESTRY_GROUPS + VALID_EFFECT_DIRECTIONS in no maintained file at all — the other six only in release-scoped ones. The doc described the mechanism (how a field carries its members) and never the registry, which is the recurring shape. Roster added carrying count, openness and purpose but not members (@fieldnames-from-model); the count and the openness flag are both asserted, the latter because actionability once shipped as an open seed against a closed validator. Scoped to vocab's own sets, since a central registry would need vocab to import pgx. · from the 2026-09-11 blind re-derivation round · related RM216, S21
  • ✅ RM216 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. The superset sweep the round owed: every identifier a *_FROM_CODE.md names, grepped against its maintained doc — 341 real surfaces absent across three tiers, most legitimately delegated (@fieldnames-from-model), error types not, because a consumer writes one in an except. ENRICHER.md carried a ten-row table against a tier defining 83 classes, 51 of them named nowhere. Complete roster added, grouped by what raises them (pass / client / builder / snapshot reader / drafting provider) because the groups are the contract, with the narrowing column asserted to be a real subclass ladder — except order is load-bearing. Walked as an equality, builtins dropped rather than the pattern narrowed. · from the 2026-09-11 blind re-derivation round · related RM97, RM101, RM208
  • ✅ RM215 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity medium. ALLELE_PATTERN carries re.IGNORECASE and the cell is stored verbatim, so one heterozygote spelled A/G/a/G/A/g/a/g hashed four ways. content_signature now folds a cell whose grammar is case-insensitive, driven by a CASE_INSENSITIVE_ALLELE marker over the four columns whose validator is that grammar — ref/alts excluded because they are not grammar-checked at all. Filed for 1.0 and the filing was wrong: it cited RM81, a parquet retype, for a change that retypes nothing; this is P3's corrected-derivation case and RM36 is the precedent in the same function. 536 corpus cells measured, none lowercase, so no published signature moves. The variant_key coordinate fallback still splits on case and is surfaced, not fixed. · from the 2026-09-11 blind re-derivation round · related RM214, RM36, RM81
  • ✅ RM214 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity medium. ALLELE_PATTERN carries re.IGNORECASE, so lowercase alleles are legal; the unphased sort beside it was ASCII, which orders every uppercase letter before every lowercase one — so A/g was accepted and a/G refused, the same unordered pair with two answers. Sorted on str.casefold with a stable sort, so every previously-valid value still validates and nothing authored moves: a loosening, minor-legal. It deliberately does not make the pair canonical — A/g and a/G hash differently under content_signature because the cell is stored verbatim (@verbatim-except-order normalizes the order only), and normalizing allele case would move an identity key, which is 1.0 work. · from the 2026-09-11 blind re-derivation round · related RM31, RM5
  • ✅ RM213 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity low (latent). merge_key's docstring says a silent () would merge every row into one and it raised for a model declaring no key while returning () for one declaring an empty key — MeasureBinRow's base-class default. Measured: two rows differing in every column returned equal keys. Latent (authored table, and every subclass overrides), fixed because the next kind to inherit the default would find the collapse in a merge pass. hints.table_key keeps reading the same falsy value as None, which is the right answer to its different question. · from the 2026-09-11 blind re-derivation round · related S51, S48
  • ✅ RM212 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. expression._connect read ALPHAGENOME_API_KEY from os.environ without load_env() — in the one function whose docstring cites @credential-where-read — and nothing else on alphagenome expression's path loads a .env, so a key living only there was invisible and the pass refused with is not set. Measured. cli._atlas_client_or_none had the same gap, failing quietly into the knot interval. Both refusals now carry missing_credential_reason, since export VAR= is strictly stronger than never setting it and "not set" sent an operator to the wrong fix. Same incident as the PharmVar lane's, whose comment already says a pre-check answering differently from what it guards is worse than none. · from the 2026-09-11 blind re-derivation round · related RM191, RM194, RM204
  • ✅ RM211 — shipped 2026-09-11 in the uncut 0.7.0, owner compiler, severity medium. RM93 moved _check_frequency_arithmetic into the pre-flight and left _check_gene_metrics_arithmetic — its exact structural analogue — in a compile-side per-model closure, where a table being loaded in both commands makes a table-by-table audit stop. Four moved: the arithmetic check, _cross_check_gene_metrics and _cross_check_gene_validity (keyed on gene, which is authored and which nothing fills), and _check_declared_license_agrees. Five deliberately did not, recorded rather than left to be re-derived: four are keyed on position or variant_key and would report every unresolved authored row as an orphan, and _source_checks needs a used_sources that is complete only after every sidecar is read. No new dedup — the fact-table extend site already filters on the message. · from the 2026-09-11 blind re-derivation round · related RM93, RM44
  • ✅ RM210 — shipped 2026-09-11 in the uncut 0.7.0, owner compiler, severity medium. _cross_check_literature runs on both sides and every message embeds a count; the pre-flight was handed loaded_kinds and the compile kind_rows (post _apply_symbolic_drops), so a pharm_variants.csv row that is droppable and citing made the two sentences differ by a number and both survived the message dedup — one manifest carrying "1 citation(s) … ['99999999']" beside "2 citation(s) … ['29165669', '99999999']" with warnings_summary: {literature_row_uncited: 2}. Reproduced on reference_examples/pgx_slco1b1_simvastatin. Fixed by passing survivors, the post-drop view the pre-flight already computed for the positional fill; the post-drop sentence is the right one, since the dropped row is not in the artifact. citation_not_in_pubmed and the quote-counter finding share the input and are fixed with it. · from the 2026-09-11 blind re-derivation round · related RM44, RM79
  • ✅ RM209 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity high. upload.py walks locations.SNAPSHOT_ROOT_FILENAMES; download._provision_snapshot iterated a hand-kept (release.json, LICENSE.txt) pair, so RM198's avi_knots.parquet was published and never pulled — and the AVI lane stores no PHRED, so a pulled lane held scores nobody can rank and alphagenome check refuses it. Two docstrings over that code claimed the registry was walked. The test compares the set of root names asked for against the tuple, so a registry that grows by one is covered without anybody remembering. · from the 2026-09-11 blind re-derivation round · related RM191, RM198, RM202
  • ✅ RM208 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity high. One root, two opposite symptoms: CrossrefClient.exists caught httpx.HTTPError, the superclass of both types its own @retry matched, so it made one upstream request where attempt_floor(3) asked for three; GwasCatalogClient._get re-raised the transport leg bare and nothing translated it once the attempts were spent, so associations_for raised raw httpx.ConnectError at a caller told to expect GwasError. Both measured. Repaired with the _request/_get split every other client already had, and guarded by test_retry_is_reachable.py, which walks the package — both clients sat in the contract suite's exempt set, and a roster-walking guard inherits the roster's exemptions (the RM101 blind spot). GWAS's exemption is removed; it joins FOUR_OH_FOUR_IS_AN_ANSWER for its own reason. · from the 2026-09-11 blind re-derivation round · related RM97, RM101, RM187, RM203
  • ✅ RM207 — shipped 2026-09-11 in the uncut 0.7.0, owner compiler, severity high. The withdrawn rsID refusal — fatal in both modes — walked patched and looked the post-expansion ga4gh:VA.… key up in a table keyed by the authored one, so it silently never fired on an expanded row; and it lived only inside resolve_from_table, which only compile_module calls, so where it did fire validate was green in both modes and a plain compile refused. Both reproduced on reference_examples/hfe_hemochromatosis with one column changed. withdrawn_refusals / ambiguous_refusals / ambiguous_warnings are shared predicates both sides call; the sentences are shared (two interpolations, so copying drifts) and only the resolution: / strict resolution: channel prefix is restated, because that text is API. · from the 2026-09-11 blind re-derivation round · related S76, RM93
  • ✅ RM206 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. LookupClients.ensure(name, factory): one lazy path under a lock, name checked against the derived CLIENT_FIELDS, close() walking the same tuple. Six legs built a per-request client and closed it, two assigned back; a host filling six of eight fields had unpaced egress on the one that mattered. A lookup_* call given no bundle now closes the one it built. The CPIC half stays consumer-side (draft_gene(client=)). · from S92 (just-dna-registry) · related RM42, S15
  • ✅ RM205 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity low. VariantHint.checked holds labels only (ensembl, clinvar, ensembl-rest), the unreadable-snapshot finding interpolates the label, and the new VariantHint.snapshots (label → path, every snapshot opened or tried, PubMind and clin_sig legs included) is the one field carrying a path — a host drops it and audits nothing else. Taken as the consumer proposed; _brief(exc) stays upstream's sentence. · from S93 (just-dna-registry) · related RM201
  • ✅ RM204 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity medium. caches.lane_status() → LaneStatus per lane (state ∈ LANE_STATES = present/absent/occupied, looked_in, path, release, release_unreadable), and cache status renders it — the registry's status half beside its provisioning half, so a consumer serving GET /caches stops re-writing the loop. occupied (non-empty, holds no snapshot, the target prepare refuses) used to print as absent; named by the fact rather than the consumer's partial, which guesses a cause. · from S91 (just-dna-registry) · related RM176, RM182, RM184
  • ✅ RM203 — shipped 2026-09-11 in the uncut 0.7.0, owner enricher, severity low. PacingGate.spent: admissions so far, bumped under the slot lock, one per upstream attempt (the clients wait inside their retry loop, measured on gnomad._post and eutils._request). A host metering egress reads it instead of charging by request shape. A waited total was refused: the sleep is outside the lock by design. · from S95 (just-dna-registry) · related RM42
  • ✅ RM202 — shipped 2026-09-11, owner enricher, severity medium. RM198 wired alphagenome_avi's publish_repo and nothing could reach it: cache rebuild --publish walks lanes with a rebuild adapter, which every publishable lane has except this one. The tests passed because they asserted the registry's data and the publish test called plan_reference_snapshot directly, bypassing the CLI — a field can be set correctly and mean nothing if no path acts on it. The guard already existed on the build side (build_command is walked against the real Typer tree) and had no publish equivalent. Ships alphagenome publish, a publish_command field, and a biconditional guard: a publishable lane is reachable by a rebuild adapter or its own command, exactly one. · from RM198 · related RM191, RM198, RM199
  • ✅ RM201 — shipped 2026-09-11 in the uncut 0.7.0, owner format, severity medium. DeclaredChange.requires: the dotted manifest paths a module must carry for a declared change to reach it — a necessary condition, () for every module, None for unstated — with the predicate ours (reaches, three-valued, False the only answer acted on) and RecompileAnswer.declared_for the Kleene filter. RM108's and RM110's corrections carry gene_validity/gene_metrics; RM121's stats.genes pair stays unstated on purpose, and a test asserts that set as an equality. The consumer's None-means-every-module was refused on the algebra. · from S90 (just-dna-registry) · related RM126, RM183
  • ✅ RM200 — shipped 2026-09-11 in the uncut 0.7.0, narrowed to RNA_SEQ and shipped as the tenth derived-fact sidecar rather than as a column or a finding, owner enricher, severity medium. Corrects § 4.7: "no expression direction anywhere in the model" is true of the AVI aggregate (all MAX_ABS_*) and false of the API — eight scorers report is_signed=True. RNA_SEQ is the only scorer with a gene axis (shape varies with the window, 61 genes at one variant and 48 at another), so AlphaGenome attributes it itself — adopt for drafting. CHIP_TF refused on measurement though all 1,617 tracks name a real TF: top-3 of 751 TFs carry 1–3% of the mass, it does not track effect size, and every leader is a singleton track. *_ACTIVE is an activity level, not a variant effect — raw assay units barely moved by the ALT — which makes it a locus annotation rather than a variant one, normalisable by the nonzero_mean every track carries. Assayed 2026-09-11 (probes/ALPHAGENOME_ATLAS § 6.6): consensus fraction is a property of the scorer, not the variant — CAGE/PROCAP are near-unanimous even at PHRED 0.007, so it is no confidence measure and the shape this entry first proposed is dead; RNA_SEQ never exceeds 61% and that is structural, since a variant can raise one gene and lower another. *_ACTIVE does move with the ALT at ~16× control in Z-DNA formers and ~10× in poly-T runs (20% at individual loci) and ~15× in G-quadruplexes — mostly positional, with a real per-variant component wherever geometry is at stake. The G4 row read background until the probe stopped sampling loop bases instead of G-tracts, the third conclusion here overturned by the instrument rather than the data. Positional scorers stay unusable as named claims on two independent tests. All non-commercial; needs the second source name alphagenome_atlas. · from RM193 · related RM191, RM193, RM194