Release Notes
- 2026.7.4
Fixed: a
data_frameresource withformat: excel— the format announced in 2026.7.3 — could not be read by a stock install. pandas opens a workbook throughopenpyxl, which was not a dependency ofgain-core, so the read raised anImportErrorasking for the missing package.openpyxl >=3.1is now declared everywheregain-coredeclares its runtime dependencies — the Python distribution, the conda environment and the conda package recipe — so an Exceldata_frameopens out of the box (#423).
- 2026.7.3
Behavior change:
grr_manage --dry-runnow writes nothing at all — it no longer records a.grr/<file>.statefor each file it hashes, so it leaves the repository byte-identical; repeated dry runs re-hash instead of seeding the state cache (#257).Behavior change:
grr_manage repo-initno longer offers--dry-run/--force; both were accepted and ignored, sorepo-init -ninitialised the repository for real (#415).The statistics scan is now bulk-vectorized for float
position_scoreresources over tabix and bigWig — column arrays instead of aRecordper row, and numpy accumulation instead of a call per value — making the histogram and min/max passes ~3–4x faster on tabix and ~9x on bigWig, bit-identical to the per-record path (#385).Every other resource keeps the per-record scan: allele and NP scores, VCF-backed tables, non-float or categorical scores, CNV collections and whole-table (
--region-size 0) runs (#385).GenomicScoreexposes the bulk column-array region read (supports_region_value_arrays/fetch_region_value_arrays, yielding parsedfloat64arrays per score); a backend declares it throughGenomicPositionTable.supports_value_arrays(#398, #409).Turning a raw cell into a score value now lives on
GenomicScoreDef.parse_value/parse_array, instead of being implemented once per record and once per column (#405).Fixed: a literal
nanvalue token — reachable whenna_valuesis configured without the defaultnansentinel — poisoned a score’s recorded min/max and nullified its histogram (#385).The SpliceAI annotator can run under ONNX Runtime:
SPLICEAI_BACKEND=onnxselects it per process, TensorFlow stays the default, and an unrecognised value raises (#297).The five SpliceAI ensemble models now ship as
.onnxartifacts derived from the committed.h5weights and pinned to them by an equivalence test;onnxruntimebecame a runtime dependency ofgain-spliceai-annotator(#296).ONNX is not currently the faster backend: measured ~1.08x slower than TensorFlow at the default window and ~1.26x at the widest (#400).
Fixed: a Dask batch aborted mid-wiring could deliver its error on top of a task’s real result, so a run yielded more results than the graph had tasks; delivery is now exactly-once per task (#381).
Fixed: a string-valued gene score with a
categoricalhistogram was silently recorded as aNullHistogram, because the values were coerced withint()(#352).Fixed: a
data_frameresource read its file relative to the process’s working directory rather than through the resource, so it loaded only by accident; it also now acceptsformat: excelalongsidecsv/tsv, and its info page lists the column description one row per column.draw_score_histogramspointed at a non-score resource now fails with aTypeErrornaming the resource and its type, instead of an emptyAssertionError(#337).CI: the gain-web e2e job reports
NOT_BUILTrather than failing when its branch moves past the commit it was handed (#414), and its per-agent lock is no longer collapsed onto one global resource (#291).CI: the SpliceAI integration tier resolves
GRR_ROOTitself and runs against the node-local real GRR (#321).
- 2026.7.2
Behavior change:
grr_managenow reports every resource it cannot process and exits non-zero, instead of skipping it with a misleadingWARNINGand exiting0; failures are collected per resource and summarised, and a failing statistics task, FTS-index build or stats-hash write now fails the run (#364).grr_managenow reports a configuration error as a singleERRORline (traceback demoted toDEBUG), refuses an unrecognised management command, reports a message-less exception by its class name, and raises a clearValueErrorfor a headerless tabix table on the defaultheader_mode(#364).A
--dry-runexits with the count of resources needing an update — now counting a resource it could not check; other runs exit1on any failure and0otherwise (#364).Fixed:
grr_manage repo-manifest --dry-runreported a settled repository as inconsistent (its exit status was the repository size, not the stale count); it now exits0(#364).Removed: the in-resource aggregation engine — the
fetch_scores_agg/*Query/*AggrAPIs onPositionScore/AlleleScore; aggregate on the annotator instead (#267).Resources may now configure
position_aggregator: count/allele_aggregator: countand an empty-separatorjoin(); the config schema is derived from the aggregator registry (#261).Behavior change: a region is now aggregated per record rather than per base pair, so
meanfloat scores may shift in their last bits on large regions (annotation output unchanged) (#260).Behavior change: a
.dvcsidecar is now the authoritative md5 and size, andgrr_manage --without-dvc(-D) is the verifier that checks it against the bytes on disk; the default mode never hashes a DVC-managed file (#251, #255, #373).Manifest membership is now decided by path, not extension: only the generated
index.htmlandstatistics/index.htmlare excluded, and every other file is manifested (#251, #255, #373).Behavior change:
grr_managenow refuses advc add <dir>output (a.dvcsidecar declaring a.dirmd5 ornfiles), which GAIn cannot verify (#255).Behavior change: the
--with-dvc/--without-dvcoption group is restored on the manifest, stats, repair and info subcommands (removed in 2026.7.1) (#251).A malformed or incomplete
.dvcfile is now reported as a warning and ignored rather than abortinggrr_manage(#251).Fixed: the
DaskExecutorrun loop leaked driver memory by minting an uncancelled asyncio Task per pending future on every 50 ms poll; it now registers oneadd_done_callbackper future (#355).Fixed: the Dask run loop could return zero results for a non-empty graph via a submit-side window where a task was tracked nowhere; a batch now stays queued until its futures are recorded (#365).
Fixed: rewrote Dask run-loop termination around a single
RunStatestate machine, closing a gather-side window that could silently under-deliver results (#367).Fixed: a crashed or OOM-killed Dask worker’s task was yielded as
Noneand cached as a real result, so an all-dead run reported success; failed futures are now gathered as errors and teardown moved into afinallyso a failure no longer leaks worker threads (#367).Fixed: an unguarded exception in a
DaskExecutorworker thread hung the run forever; both workers now deliver the exception as the task result so the run terminates (#372).Behavior change: the SpliceAI annotator now refuses a deletion longer than the model half-window (
ref_len - 1 > distance), whose batch annotation diverged from the sequential path (#320).Behavior change:
build_annotation_pipelinenow defaultswork_dirto an absolute per-process temp dir instead of the cwd-relative./work(whichEPERM’d under a non-root runtime in a root-owned cwd) (#331).Fixed: tabix reads of overlapping-interval tables returned wrong
get_records_in_regionresults when theLineBufferwas warm; ordering is now judged bypos_begin(#250).Fixed: an HTTP GRR download could silently truncate and fail only at the md5 check; it now verifies byte count first and raises a retryable
TruncatedDownloadError(#292).Fixed: a scalar
na_valuessentinel was matched by substring, silently NA-ing real scores (and raising on bigWig); scalars are now matched type-aware by equality (#268).Fixed: a VCF
Number=AINFO field on a record with no ALT allele (ALT=.) now yields a null score instead of leaking the raw pysam tuple (#256).Fixed: a
gene_scorewith a null-histogram config crashed construction and a runtime histogram failure was dropped; the config is accepted and the failure recorded as aNullHistogram(#305).Fixed: the
genes/worst_effect_genescolumns werePYTHONHASHSEED-ordered (deduped viaset()); they now dedupe order-preservingly and are byte-reproducible (#327).Fixed: a tabix table reopened over changed data could answer from a stale buffer, and a failed
close()left a live handle;open()now clears the buffer andclose()closes the handle first (#362).Fixed: the GRR manifest scanner now honors
.gitignorefiles between the GRR root and the resource, not only within it (#369).Fixed: a bigWig query in an unscored gap between buffered intervals could return a bogus score; the buffer search now returns the insertion point (#259).
bigWig region fetch is now sized by record count (adaptive window) rather than fixed base-pair chunks;
direct_fetch_size/buffer_fetch_sizenow mean records per call anduse_buffered_thresholdis accepted by the schema (#259).LineBuffer.prunenow evicts every dead record instead of stopping at the first survivor, bounding buffer growth on dense overlapping tabix scans (#287).build_genomic_position_tablenow warns when a tabix/in-memory table omitszero_based(#379), or whenzero_basedis set on a VCF/bigWig table that ignores it (#378).
- 2026.7.1
Behavior change: a completed anonymous annotation job and its result file now survive the user’s last WebSocket disconnect; stale anonymous jobs are reaped by age via the new
cleanup_anonymous_jobscommand (nothing schedules it) (#216).Closed the GRR credential-leak paths the 2026.7.0 redaction missed —
grr_browse, the definition models’model_dump*and credentials embedded in repository URLs;get_url()/get_public_url()no longer return them and an invalid definition raises a redactedValueError(#202).Behavior change:
GPFWA_EMAIL_USE_TLSis parsed as a string, so only a literaltrueenables STARTTLS.Fixed: the 2026.7.0
.gitignorescan dropped a DVC-managed GRR’s data files; a gitignored file is re-included when a sibling<name>.dvcdeclares it an output (#209/#211).grr_browsecan now filter through the full-text search index (-s), restrict to one type (-t), and print summaries (--summary).Reworked the notifications WebSocket reconnection to retry with exponential backoff and never give up (was dead after five attempts), and to survive navigating to a consumer-less page like About (#204, #215).
Fixed: a pipeline whose build failed is now rebuilt on the next save instead of the cache returning the failed future.
Added
gain.logging, a drop-inloggingproxy guaranteeingTRACE/USER_INFOare installed early; behavior change:-vvvnow selectsTRACE(effect-checker diagnostics moved there too).The single-allele annotation response reports
preserves_domain: truerather thannullfor a non-aggregated attribute.Web UI: fixed three annotation-pipeline editor bugs (stale status bar from a late
pipeline_status, a refresh resurrecting the temporary pipeline, and anNG0956duplicate-key warning).gain.genomic_resources.testingbecame a package with abuildersmodule — a fluent DSL for authoring test GRRs.Documented the
user/passwordbasic-auth keys of anhttprepository.CI:
tests/integrationmoved to a dedicatedgain-core-integrationdownstream job resolving real resources againstgrr-seqpipe(#222).
- 2026.7.0
Hardened HTTP basic-auth credential handling:
user/passwordare no longer logged and are masked in the definition model’srepr()/str(); credentials on a plainhttp://URL to a non-local host now warn.Behavior change: repository definitions are strictly validated — an unknown key in any definition is rejected (guards auth typos; remove stray keys to upgrade).
Untyped genomic resources now resolve to a dedicated
basicresource type that renders an info page and exposes every data file, so caching covers the whole resource (#185).The GRR resource file scan now honors
.gitignorefiles;pathspecis a newgain-coreruntime dependency (#184).Score aggregators now declare
Aggregator.preserves_domain(value_type=…), and the Web UI hides the score histogram for an attribute whose aggregator does not preserve the domain.Fixed: the pipeline editor could still hang on “loading” after a WebSocket reconnect in a case the 2026.6.9 fix missed; a 200 from
GET /api/editor/pipeline_statusis now the authoritativeloadedsignal (#160).Fixed: a flaky
FileExistsErrorcreating the task-graph log directory under concurrency;ensure_log_dirusesmakedirs(exist_ok=True)(#186).Added the
TRACEandUSER_INFOlogging levels and thelogger.trace()/logger.user_info()helpers.Fixed: generated pipeline docs left a resource/histogram link unset for a resource outside the managed GRR; it now falls back to the public URL.
Enlarged the axis and note-label font on generated histogram images.
Web UI: fixed several editor and new-annotator dialog layout issues.
Corrected the “creating an annotator plugin” documentation example (
.strip()vs.lower()).
- 2026.6.10
Fixed: reading a VCF score header no longer logs a spurious htslib
Could not retrieve index fileline; the header open is wrapped inpysam.set_verbosity(0).Added a “creating an annotator plugin” documentation walkthrough.
- 2026.6.9
Fixed: default-attribute selection for score annotators with a
default_annotation(previously none were marked default); gene scores with no histogram config fall back to a default histogram.Fixed: opening a VCF score header no longer forces a needless index lookup over an http GRR.
GRR repository definitions are validated against typed pydantic schemas rejecting unknown keys and checking required fields.
A
public_urlmay now be set on any repository type, not onlyhttp/url.HTTP GRRs now support basic authentication (
user/passwordpassed asaiohttpcredentials).The
annotate_docCLI now builds links from each resource’s public URL.Renamed the stored
Job.annotation_typevalue"columns"→"tabular"(migration 0043, reversible) (#29).Behavior change: saving a user pipeline that references a broken GRR resource now succeeds (HTTP 200) and reports the failure asynchronously, instead of a synchronous HTTP 400 (#150/#152).
A deferred pipeline build failure now carries a reason via a distinct
failedstatus, surfaced live and durably (#155/#156).Fixed: the pipeline editor getting stuck on “loading” after a WebSocket reconnect; the consumer replays load status on connect (#160).
The web API’s read endpoints were converted to async, keeping the ASGI event loop responsive under load (#162–#167).
Web UI: the new-annotator workflow detects duplicate output attribute names.
Web UI: GRR resource and gene-set-collection page images are constrained to a maximum width.
Web UI: upgraded Angular to v21.
Added a fourth Python-interface documentation example.
CI: the anonymous annotate rate-limit is keyed by session under the e2e settings so Playwright tests don’t cross-exhaust one per-IP bucket (#179).
- 2026.6.8
annotate_vcfnow supports CSI-indexed input, lifting tabix’s 512 Mbp limit so long contigs can be region-parallelized.Gene-set collections in
mapformat may now be supplied gzip-compressed.Fixed: the tabix-indexing step parsed the header with a hardcoded tab even for CSV output (#144).
Fixed: duplicate annotation-job names under concurrency; allocation is now a single atomic
UPDATE … RETURNING(#138).Fixed: duplicate quota rows under concurrency;
UserQuota.useris now one-to-one andAnonymousUserQuota.ipunique, with migration 0042 de-duplicating (#139).Fixed: a spurious HTTP 400 “Pipeline … not found” under load; in-use pipelines are pinned by refcount so eviction can’t drop one mid-resolve (#140).
Fixed: running jobs losing their result file on a WebSocket disconnect;
delete_jobsskipsWAITING/IN_PROGRESSjobs (#147).Fixed: deleting a saved pipeline now also evicts it from the web API cache.
Web UI: per-attribute (gene) aggregator selection renders correctly, with finer value-type options driven by the aggregator.
Web UI: pipeline-info loading is driven from reactive signals with de-duplicated status requests.
The GRR browser index table can now be sorted by any column.
Revised the getting-started CLI tutorial and GRR documentation.
CI: the gain-web e2e pipeline tears down its Docker Compose project in
post.cleanupas a backstop.Behavior change:
annotate_tabularnow reads/writes delimited files with quote-aware CSV parsing; a bare"in existing data is now significant, and the separator must be a single character.
- 2026.6.7
Fixed: the VEP effect annotator segfaulting on a bgzipped reference genome; the
.gziindex is now declared and pre-fetched, and anindex_fileoverride is honored for VEP.Fixed: in-page GRR search under a sub-path; the search index is fetched relative to the page URL.
Fixed: the histogram image unreachable from a browser on a directory GRR; the live web help builds it from the public URL.
Fixed: slow pipeline loading under concurrency; the LRU cache no longer closes a pipeline while holding the lock.
Restructured the getting-started GRR documentation.
- 2026.6.6
Fixed:
annotate_tabularcrashing withUnicodeDecodeErroron non-ASCII input; the input is now read as UTF-8.Fixed: default-verbosity runs printing
INFO:distributedmessages; the logger is re-silenced after the dask cluster builds.Fixed: the dask cluster is now torn down gracefully in
DaskExecutor.close(), ending the previous heartbeat-failure log flood.Task-graph executor teardown is now best-effort — a teardown failure no longer crashes a run whose results are written.
Demoted the fsspec “protocol … already exists” message to debug.
Fixed:
grr_managerepo-repair rewriting unchangedindex.htmlpages and bumping their mtime, defeating mtime-based consumers.Web UI: the new-annotator workflow gained a per-attribute (gene) aggregation step.
CI: docs-only master builds now archive a
gain-coreconda package.
- 2026.6.5
annotate_tabular/annotate_vcfnow print a reannotation plan (COPIED/ADDED/COMPUTED/DELETED), with a new--dry-run/-nflag.Reannotation reuse now works through the CLI: an unchanged annotator’s result is copied rather than recomputed.
Fixed:
--full-reannotationleaving stale values; every annotator is forced to recompute.Fixed: a reannotation crash (
TypeError: unhashable type) for annotators with a dict/list-valued parameter.Fixed: gzipped gene-score files read with the wrong separator; the
.gzsuffix is stripped before the.tsvcheck.Fixed: building gene-score histograms rebuilt a
GeneScoresDbper score (O(n²) plus a spurious error).Added a GRR definition-files documentation page.
- 2026.6.4
grr_manageskips rebuilding the full-text search index when the repository contents are unchanged (compares the storedcontents_md5).Revised the getting-started CLI tutorial; removed the obsolete GRR YAML/repository reference pages.
- 2026.6.3
The annotation web API supports a configurable
DEFAULT_PIPELINE(shipping aspipeline/hg38_clinical_annotation), pre-selected in the UI.annotate_tabular/annotate_vcfaccept a GRR resource id as--reannotate, not only a filesystem path.Removed the per-file variant limit (setting, enforcement and UI display).
Web UI: saved pipelines expose a download link to their generated HTML documentation.
Fixed: the single-variant API failing when a pipeline annotator has no GRR resources; the histogram lookup is skipped.
Fixed: annotation-config serialization emitting
internal: null; the field is omitted when unset.Web UI: job notifications arrive in order, number histograms show multiple red markers, and pipelines refetch on login change.
Revised the getting-started CLI tutorial; documented the
gene_columnresource.
- 2026.6.2
When no output file is given,
annotate_tabular/annotate_vcfinsert an.annotatedmarker (was_annotated).annotate_tabular/annotate_vcfnow delete a work directory they created on a clean run (--keep-work-diropts out);annotate_vcfalso closes its pipeline.Added an
annotate_docendpoint serving a saved pipeline’s documentation as a downloadable HTML attachment.Fixed:
allele_scorefilter-grammar edge cases (negative literals, digit-leading identifiers).Web UI: the app version shows on the About page, list-valued attributes render in the single-variant view, and note labels are more prominent.
- 2026.6.1
Reference genomes may now be supplied as bgzipped FASTA (a
.faifaidx and.gziindex required; optionalindex_fileoverride), working local, cached or over HTTP/S3.annotate_columnswas renamed toannotate_tabular(old name kept as a deprecated alias).Reworked the annotator class hierarchy onto a common
AnnotatorBase, fixing output-name and aggregation bugs across the chrom-mapping, liftover, normalize-allele, gene-set and gene-score annotators.The GRR static index embeds a content hash of the full-text search database, so browsers re-fetch it after contents change.
Resource index links in generated GRR pages are now relative.
Pinned
pysamto 0.24.0 and declaredtqdmagain-coreruntime dependency.
- 2026.6.0
grr_cache_reponow shows live progress (atqdmbyte bar on a terminal, milestone lines otherwise) and downloads only missing/stale files;--no-progressdisables it.Raised the GRR caching read-buffer (
CHUNK_SIZE) from 32 KiB to 1 MiB, cutting per-chunk overhead ~32× on large resources.Revised the getting-started CLI and web tutorials.
Backward-incompatible:
grr_cache_reponow takes the pipeline as a positional argument instead of--pipeline/-p.annotate_tabular/annotate_vcfnow treat.bgzas a first-class compression extension for input and output (changing the default--work-dirname derived from a.bgzoutput).Fixed: silent record duplication when an
annotate_tabularinput carried a.csiindex rather than.tbi.
- 2026.5.10
Fixed:
grr_cache_repoaborting a long HTTP download at htslib’s 300 s read cap; the HTTP filesystem now applies only per-read/per-connect limits, with backoff retries and resumable caching.The anonymous-quota refresh commands now reset each quota in a single transaction and also reset
SessionQuota.Added a version API endpoint.
- 2026.5.9
annotate_vcf/annotate_tabularnow run a pre-flight locality check, warning (1001–5000 rows) or aborting (>5000) when the pipeline uses non-local resources;--allow-remote-resourcesdisables it.The GRR index table supports cascading column resize.
Fixed: a GRR summary tooltip truncated on a double quote.
- 2026.5.8
Added a
prepare_tabularCLI that sorts a tabular file by genomic coordinates and writes a bgzip-compressed, tabix-indexed output for region-parallel annotation.annotate_tabulardefaults--input-separatorto a comma for a.csvinput; other inputs still default to a tab.annotate_tabular/annotate_vcfrun sequentially (-j 1) when the input cannot be split into regions.annotate_tabular/annotate_vcfnow run inside theirwork_dirso downloaded.tbiindexes don’t litter the launch directory.Fixed: flicker and column-resize lag in the GRR browser index table.
Expanded the getting-started CLI tutorial with parallelization and resource-caching sections.
- 2026.5.7
Moved the
grr_cache_repoCLI fromgpfintogain.Fixed: the
--versionlabel on thegrr_manage,grr_browse,annotate_columnsandannotate_vcfCLIs.The GRR index table supports sorting by the ID column and drag-resizing columns.
Silenced the spurious htslib “index file is older than the data file” warning for parallel-downloaded GRR resources.
Revised the getting-started CLI tutorial and overview diagram.
- 2026.5.6
Renamed the
annotate_columnsCLI toannotate_tabular(old name kept as a deprecated alias).The web UI runtime-injects the Google Analytics snippet from
GA_MEASUREMENT_ID.Improved the getting-started CLI documentation with installation prerequisites.
The notifications WebSocket now retries on transport-level errors after a 2 s delay.
Fixed: empty-array table header rendering and scrollable grid alignment in the single-annotation report.
- 2026.5.5
Moved the
to_gpf_gene_models_formatCLI fromgpfintogain.
- 2026.5.4
Made
.CONTENTS.json.gzand.CONTENTS.sqlite3.gzbyte-reproducible across platforms.
- 2026.5.3
Refactored the allele score annotator to operate only on VCF alleles by default; deprecated
allele_aggregatorin favor ofaggregator.Fixed: VCF spanning records skipped due to wrong end positions, and allele-score position access.
Standardized canonical annotator names in the docs and fixed new-annotator UI attribute-selection bugs.
Fixed: a race condition when filtering annotators.
URL-encode list/tuple/dict annotation attributes.
Improved GRR browser page styles and table layout.
Fixed: broken annotation infrastructure links.
Update the FTS database when creating the contents file; fixed a statistics-manifest bug.
The single-annotation report now handles array result values.
- 2026.5.2
Added admin views for anonymous users and their quotas; monthly quotas are always displayed.
Anonymous-user quotas are tracked by session ID.
Restyled the GRR about and index pages.
New template infrastructure for resource implementations.
Fixed: BigWig score-definition validation.
- 2026.5.1
Imported the GAIn user documentation into the repository and added Build/Deploy docs CI stages.
Updated the quotas page UI and removed quotas from the about page.