Release Notes
- 2026.11.0
Distribution:
gain-coreis published to PyPI and bioconda, the install docs take it from bioconda and keep theiossifovlabchannel for the annotators, the sdist and wheel ship the LICENSE, andrequires-pythonis capped at<3.15.binning_tool: the fragment score binner reads and foldsfragment_start,fragment_lengthand intcoverage_profiletracks from value arrays, through the newFragmentScorereadersget_fragment_arrays_starting_in_regionandget_fragment_arrays_overlapping_region, and the array fold of a float score servesmedian.Statistics: a
NumberHistogramstores the samesumandsum_of_squareswhatever the order of the additions, and the statistics PNG images no longer embed the matplotlib version, so a rebuild on another host leaves both unchanged. A missing gene set collection histogram isNone.Annotation and GRR:
annotate_variant_effects_vcfwrites one INFO value per alternate allele instead of failing on a multi-allelic record,grr_manage repo-infodrops the ignored-r/--resourceoption,GenomicScoreDefrepr()and==work beforeopen(), and a forked task graph run accepts aNonetask_status_dir.gainweb: the single-allele report shows the histogram of an attribute folded by
listormost_common. Registration and pipeline saves refuse an email or a pipeline name that would leave the user’s storage folder, the email check runs in linear time and accepts long TLDs, an empty genome field means no genome instead of a 500, and a failed pipeline build sends the client a sanitized error. Python, Angular and Playwright dependencies are updated to close the open Dependabot alerts.Docs: revised Python interface and Genomic resources pages.
Issues closed in this release: all issues, bug issues.
- 2026.10.2
Task graph: named clusters are a dict under
gain_named_clusterin the dask config, so a user file can add one and keep the bundled ones; the olddae_named_clusterlist still works with a warning.setup_clientleaves the dask config unchanged,chain_taskspasses the first task its resolved arguments, and the bundled slurm cluster usesnumber_of_workers.Annotation: the default
region_length_cutoffof the position and allele score annotators is 15 Mbp, the effect annotator’s value, and a region over the cutoff logs a warning. The annotator decorators forwardbatch_annotate.Scores:
GenomicScore.aggregate_regionis removed in favour of the per-kind aggregating reads,get_score_histogram()and its sibling accessors read the only score when no id is given, and the position score binner folds from value arrays with numpy. Log-scale histogram bin edges are rounded to 10 significant digits, sorepo-repair --forceon another host no longer rewrites the statistics.gainweb: a logged exception or a Django 500 posts to a Zulip stream when the four
GPFWA_ZULIP_*variables are set, at most 10 posts per 10 minutes and with URL credentials stripped; handled request errors log at WARNING. The web UI keeps the pipeline list and status right when the reload after a save, save-as or delete fails.Docs: a Task graph chapter and a “Running in parallel” page, a revised Annotators chapter with “Testing an annotator”, a Binning infrastructure page with the command-line tools grouped, and resource pages that open with how to create the resource in place of the Factories page.
Issues closed in this release: all issues, bug issues.
- 2026.10.1
binning_tooloutput and tooling: the/trackstable has one layout for every binner kind (tracks_layout2), the run definition names its genome withreference_genomeinstead ofinput_reference_genome,gain.binning.h5_readerreads the tables as data frames, and the newbinning_tool_viewcommand prints them as text. A pooled fragment entry over hundreds of resources starts in seconds instead of a minute.Aggregation: the
most_common(k)aggregator is added, and aproductor an intsumpast the float range saturates to a signedinfinstead of raising or stalling.Annotation:
annotate_vcfwrites the missing value for an INFO value that does not fit the declared type instead of stopping, the promoter check treats the+strand as it does the-strand, and the effect annotator’spromoter_lenis documented and offered in the pipeline editor.GRR: the tabix bulk read parses each batch with the pandas C parser, and a search index that left a resource out is rebuilt by the next
repo-repair.gainweb: the web UI refetches jobs and pipelines only once a reconnected socket has opened.
Docs: a Command line tools section with a page per tool, the Python interface and Genomic resources chapters reorganised with new resource pages and a guide to reading histograms, and an API section on every resource page, with the examples importing
gain.grrasgrr.Issues closed in this release: all issues, bug issues.
- 2026.10.0
The allele plane:
AlleleScoregains the exact-allele and region readsget_allele_scores_for_allele/get_allele_score_for_allele,get_allele_scores_for_allele_rows/get_allele_score_for_allele_rows,get_allele_scores_in_region_rows/get_allele_score_in_region_rowsandget_allele_scores_for_allele_agg/get_allele_score_for_allele_agg, beside the existingget_allele_scores_in_region_agg. The region_rowsread yieldsAlleleEntrynamed tuples (pos,ref,alt,values) (#1750, #1751, #1753, #1754).An allele score declares
allele_multiplicity: one | many, a new top-level resource-config key (defaultone), reported byAlleleScore.multiplicity. The one-row read raisesAlleleMultiplicityError(aValueError) on amanyresource (#1750, #1753).The allele statistics build checks
allele_multiplicity: aoneresource with a repeated allele key warns now and fails from the enforcement release, GAIn2027.1.0(ALLELE_MULTIPLICITY_ENFORCEMENT_RELEASE). The one-row read warns once per resource on the same repeat (#1752, #1753, #1757).AlleleScore.fetch_allele_scoresandfetch_allele_recordsare removed; use theget_allele_scores_for_allele*reads. The allele annotator’s exact match reads through the plane: amanyresource folds an allele’s rows by each attribute’s aggregator, and an exact match requires the row’s own position, so a row that starts earlier and spans the position no longer matches (#1755).In its default
allelemode the allele annotator routes by the resource’sallele_score_mode: on asubstitutionsresource an indel, complex or MNV allele gets the region fold over the bases it covers instead of its own line’s value (#1748).binning_toolgains thefragment_score_binnerkind: tracks of fragment resources (single-cell ATAC samples and other interval collections), pooled or per resource, grouped by a constant, by a cell-metadata table or by the raw value of astrscore.aggregate.modeisfragment_start(the default, counting fragments),fragment_lengthorcoverage_profile, andaggregate.uncovered_valuesets what an uncovered base adds.FragmentScore.get_scores_in_binsis the binned read under it (#1203, #1740, #1741, #1759, #1793, #1794, #1795, #1796, #1742, #1798).Binner entries take a
namekey that sets the base of their track names, so two entries over the same resource no longer collide (#1792).The
sumandproductaggregators are added; they keep the input’s numeric type, andbinning_toolaccepts them on position-score tracks (#1739).gain.grris the public import path for the GRR constructors, the resource builders (*_from_resource/*_from_resource_id) and their signature types, for scripts and notebooks (#1765).A full categorical histogram past
UNIQUE_VALUES_LIMITis stored gzipped asstatistics/histogram_<id>.json.gzbeside the unchanged truncated sidecar. A rebuild drops the other encoding’s leftover, and the build warns when the gzipped file has no.dvcpointer. Existing plain files stay valid until the next rebuild (#1733, #1734, #1735).A statistics rebuild reports a stale DVC-tracked histogram whose blob is not pulled instead of skipping it silently (#1732).
Genome statistics pack whole contigs into batch tasks, so a GRR of many-scaffold genomes builds a fraction of the tasks, and a contig split across regions no longer loses the base pair at each region boundary (#1788).
The
--region-sizehelp of thegrr_managestatistics, repair and info commands names the one-region-per-contig default and says that0does not split (#357).A categorical gene score over an int column with empty cells gets its categorical histogram again instead of a null one, a regression since 2026.7.3 (#1744).
GeneScoresDband the geneScoreDescare removed; gpf now owns them.GeneScore.build_score_helprenders one score’s help (#1729, #1730).The deprecated
annotate_columnsalias is removed; useannotate_tabular(#26).prepare_tabularparses quoted input fields the same wayannotate_tabulardoes (#145).A forward tabix region query that starts in a gap before the buffer is answered from the buffer instead of a fresh fetch (#340).
gainweb sends a pipeline’s
loadingstatus before its outcome, so a fast build no longer leaves the editor onloading(#176).The web UI’s pipeline editor validates a pipeline cleared before the editor has loaded, keeps validating after a failed pipeline-list refetch, and marks the config dirty on a keystroke during a reload (#693, #1779, #1777).
The daily and monthly quota refreshes run one
UPDATEper quota table (#807).The password-reset form no longer truncates the request path in its template context (#784).
The test-data builders gain
an_annotation_pipeline, and the table-score builders gain explicit position-column mappings anddefault_annotation(#317, #318).The docs name
aggregatoras the resource-level aggregator key and describe the 2026.7.6 cache relocation and its cleanup (#1828, #463).
- 2026.9.7
The
kubernetesnamed-cluster type is removed; an unknown clustertypefails with an error listing the supported types (#1642).grr_manage repo-fix-histogramsis removed; a repository whose statistics predate the truncated-histogram sidecars gets them by rebuilding statistics (#722).grr_manage repo-infoandresource-infoaccept--region-sizeand default to the same 3 Gb asrepo-repairinstead of a 3 Mb fallback, and the command functions take their options as keyword-only parameters (#1657).A forced statistics rebuild that fails names the failed resource and leaves it to be rebuilt by the next repair, and a failed task’s traceback is written to its task log (#1719).
Bulk statistics reads are bounded by cells rather than rows, so a hundreds-of-columns score no longer exhausts a worker’s memory (#1717).
A repeat repair, verify or cache sync stats each current file once instead of twice (#1659).
Every surface that refuses an undefined score id, the
GeneScorevalue accessors included, says it in one sentence naming the resource and the scores it has (#1112, #1701).spliceai-environment.ymlis generated from the plugin’spyproject.toml;vepanddemoget no file (#1643).The record-to-annotatable builders raise
MalformedRecordErrorfor a record they cannot build, and/api/single_allele/annotateanswers 400 instead of 500 or a meaningless annotation to a malformed record, with its own reason for a DAE-styleins/del(#1679, #1680).GET/DELETE /api/pipelines/useraddress only the caller’s own saved pipelines and answer 400/204 instead of 500 to any other id (#1674).gainweb’s validation pool no longer wedges into 503s after abandoned validations, a pipeline build dropped from the cache mid-flight is closed and reported
unloaded, and a build the loader pool cancelled is rebuilt instead of spun on (#1699, #1677, #1673).The web UI’s notifications reconnect picks its backoff delay when subscribed, not when requested (#206).
The test-data builders gain
a_gene_set_collection(#316).
- 2026.9.5
The SpliceAI annotator honours
mask: withmask: 1a gain away from the nearest exon boundary and a loss at it score zero, as Illumina’s-M 1does (#322).gainweb builds every GRR pipeline when the ASGI application loads instead of on its first request;
PREWARM_GRR_PIPELINES(envGPFWA_PREWARM_GRR_PIPELINES) controls it (#657).The anonymous endpoints answer 400 instead of 500 to a wrongly shaped body, a bad
page, a non-object annotatable, a multipart body without its file or a numeric pipeline id, andtotal_pagesno longer reports an extra empty page (#791, #1649, #1650, #1660, #1661, #1666).region_sizemeans the same for every resource kind:0does not split, a negative value is refused (#1656).DaskExecutorhands dependants a dependency’s Future rather than its gathered value, sorepo-repairno longer submits a multi-megabyte graph (#1633).A
gene_scorewithoutscores:, or a score entry withoutid, is refused by the schema instead of after the table is read (#1613, #1614, #1628).A histogram file survives no rebuild in which its score stopped producing one, and a histogram annulled by its definition shows the configured reason on the info page (#1309, #1604).
environment.ymlanddev-environment.ymlare generated from the pyprojects, and each conda recipe’s run list is held equal to its pyproject dependencies (#1639, #1640, #1641).infer_gene_model_parseris removed;infer_gene_models_formatis the one entry point (#871).LRUPipelineCache.clean_old_tasksis removed; a started pipeline build is never timed out (#1662).The resource-file state is read with fewer stats and opens, decoded as UTF-8, and an s3 timestamp is read with a HEAD (#1082, #1083, #1084, #1631, #1664).
The reference-genome page’s nucleotide shares use the shared percentage rule (#1086).
GenomicScore.close()clearstable_loadedbefore releasing the table (#363).
- 2026.9.4
Genomic scores store their chromosome lengths at repair as
statistics/chrom_lengths.json, one block per source, under a freshness key of their own; a resource repaired before this has no file until its next repair, and a DVC checkout without payloads skips it with a warning (#1574, #1576, #1580).GenomicScoregainsget_chrom_length,get_all_chrom_lengths,get_chrom_length_sourceandchrom_length_sources, answered from the stored file when current and live through the table otherwise; coverage fractions read the stored lengths first (#1577, #1578).A labelled score whose contigs are only partly listed by its genome is repaired with a warning; one with no contig in common fails the resource (#1575).
Position and fragment scores store segment and fragment lengths exactly (
coverage.jsonandfragments.jsonformat version 2) and their info pages show a min/max/mean/median table; a score built before this reads “not computed” there until rebuilt withrepo-stats --force(#1541, #1542, #1543, #1544, #1565).repo-repairand--dry-runreport statistics files that predate the current schema without rebuilding them (#1586).NumberHistogramaccumulates count, mean and standard deviation, shown in a Summary column on the score info pages (#1589, #1617).A nullified histogram is persisted with its reason, no page addresses its image, and an image from an earlier build is removed (#1025, #1533, #1555, #1556).
values_from_recordsdrops its window parameters (#828, #829).The
liftover_chain,gene_models, score-table andgene_scoreschemas requirefilename; liftover chains and gene-set collections validate their config; aliftover_annotatorwith an empty resource id is refused (#1075, #1532, #1534, #1567, #1592).The genome
chrom_prefixkey is retired: the prefix is derived from the FASTA index, and a config that sets it warns (#1090).LiftoverChainstripsdel_prefixas a prefix, not a character set (#1530).A mapping-form pipeline config parses without a
preamblekey (#1535).A VCF row carrying more values than its
Numberadmits reads as null and is reported once per table; ascores:entry naming an INFO field the header does not declare, or a tabular column not in the header, is a configuration error naming the resource and score (#1257, #1258, #1489, #1498, #1500, #1521).A
gene_scorewithtype: strand a number histogram is refused at construction (#1308).An
input_gene_listmust name an attribute markedattribute_type: gene_list(#1490).PositionScorerefuses an inverted span and the overlap it can hide, on both validation paths (#668, #1526).The gene-models serializers refuse a model that was never loaded;
join_gene_modelsreturns a loaded model andGeneModels.from_transcript_modelsbuilds one from transcripts (#1097, #1527).-vraises the root logger’s level even when it already has a handler (#1583, #1607).The gain-core conda recipe depends on
dask-core, so an install pulls no bokeh, and gain’sTRACElevel survives bokeh being loaded (#1569).GRR pages render language-tagged fenced code consistently, and the resource description no longer lives in a shadow root (#1289, #1321).
The editor’s suggested liftover config narrows the
source_genome/target_genomelabel values (#1079).New GAIn Development docs chapter on annotators and the plugin entry-point mechanism (#1144).
- 2026.9.3
A score’s chromosome lengths resolve on
GenomicScoreImplementation.get_chrom_lengths, and the statistics region split reads them there (#1413, #1414, #1418, #1419, #1448).A presigned s3 url lives seven days, so a pysam handle on an s3 GRR no longer dies 100 s after open (#1398, #1434).
The GRR index page ships sqlite-wasm, Roboto and the Material Symbols subset inside the GRR’s
.static/and uses no jQuery, so it renders offline; it gains a clear-search button, code blocks render monospace, and the initial table order matches its sorter (#1335, #1351, #1399, #1400, #1452, #1454).The resource info page links each breadcrumb segment into the hierarchical view, offers a copy button for the resource id, and lists labels by key (#1477, #1482).
A scan skips a malformed resource id with a warning instead of failing the enumeration, and a
.segment is refused (#1385, #1386).A closed position table releases its header and fetch windows, and
TabixGenomicPositionTable.open()no longer leaks its handle on failure (#360, #361, #627).A non-scalar cell nullifies one score’s statistics instead of aborting the build (#1337, #1358).
Opening a bigWig on an uncached remote GRR with a pyBigWig build that lacks remote support refuses with a message naming both (#1425).
Error messages redact a presigned url’s signature as well as its userinfo (#1363, #1370).
An absent preamble
input_reference_genomeparses toNone(#1346).
- 2026.9.2
fetch_region_segmentsis renamedfetch_region_segments_scoresand takes ascore_filter; the deprecatedfetch_region_segment_scores,fetch_region_valuesandfetch_position_scoresare removed, andget_scores_at_positionis the only point read (#844, #1268, #1272, #1383, #1397).validate_recordsandvalidate_record_arraysmove tostatistics.record_validation(#1269).get_genomic_resource_id_versionis folded intoget_full_id(#1382).A substitution on a contig the score never mentions yields no value instead of raising, and an absent contig is one uncovered run for the aggregating reads (#1211, #1253).
A false
boolrenders asnoin annotation output, distinct from a missing value (#1222).A VCF score reads its values as the header declares them: a
Flagreads as bool, a multi-valued field reads its joined text asstr, and a statedtype:the header contradicts, or a number histogram over a non-numeric score, is a configuration error (#1221, #1233, #1259, #1284, #1285, #1307, #1336, #1338).A refused value nullifies one score’s min/max instead of aborting the statistics build (#1312, #1313).
search_resourcesanswers aresource_typewithout the full-text index, sogrr_manage list -tworks on a GRR with no index (#1212).Task-graph cache reconciliation resolves missing inputs through a producer index and invalidates descendants in one walk (#1213, #1236).
Tabix contig lists are memoised, contig membership is a set test, and a plane read resolves its request once (#1173, #1282, #1303, #1304).
The SpliceAI TensorFlow backend sizes
predict()chunks from a position budget, about 2x faster per window (#427).binning_tool:--task-budgetbundles consecutive regions into one task per track (default 50 Mb), and0now means one task per track rather than one per region; an explicit--work-diris created with its parents;--helpno longer lists the annotation provider’s options (#1214, #1215, #1230, #1234, #1240, #1301).The GRR index page keeps the browse view, folder, search term and type filter in the URL hash, and in the hierarchical view the search prunes the tree under the current folder and follows the breadcrumb (#578, #579, #581, #582, #583, #1331).
A GRR
about.mdrenders Markdown tables and fenced code, and description tables are styled (#1278, #1279).Ids from a remote
.CONTENTSare URL-encoded and escaped on the index page (#1352).The credential-bearing fetch url is redacted on every failed open, including libBigWig’s and pysam’s stderr and a presigned url’s signature (#1106, #1314, #1318, #1333, #1339).
score_annotatoris split into one module per score kind (#1153, #1154).New GAIn Development docs chapter “Working with resources in Python” and a
binning_tooluser page; the docs build fails on any warning and renders Google/numpy docstring sections (#1143, #1202, #1219, #1220, #1243, #1254).
- 2026.9.1
New
binning_toolcommand bins position scores into a fixed genome grid and writes one HDF5 column per track; the run definition names the reference genome and is validated before any task runs (#1198, #1200, #1201, #1202).A
meta.labelsvalue may be a list, matched and indexed as alternatives (#1225).A bool score reads its cell as text, so
Falseand0no longer parse as true; a text bool score built before this needs its statistics rebuilt withrepo-stats --force(#1192).The annotation editor templates offer
region_length_cutoff(#1184).genomic_scores_implis split into one module per score kind (#1210).
- 2026.9.0
Annotators return values keyed by attribute name and the base annotator no longer aggregates;
WeightedValues,Aggregator.aggregate_weightedandAttribute.aggregator_instanceare removed (#1130, #1133, #1134, #1196).A
position_scoreannotator answers an empty region per aggregator, refuses an attribute without an aggregator at pipeline load, and refuses a region starting below position 1;PositionScore.fetch_region_weighted_valuesis removed (#1131).AlleleScoregains the folding readget_allele_scores_in_region_agg, and the annotator’s region mode streams (#834, #1132, #1163).FragmentScoregains a logical read plane and a folding read;fetch_fragment_scoresstreams(begin, end, values)(#1119, #1120, #1121, #1122, #1123, #1124, #1126).The
fragment_scoreannotator acceptsmin_region_overlap_fractionandmin_fragment_overlap_fraction(#1125, #1165).none_value_replacementis aposition_scoreattribute parameter (#1135).Attribute parameters count for
--reannotateandAttributeConfig.as_dict()(#1155).Numeric annotator parameters are validated at pipeline load (#1166).
Aggregating reads are 15-39% faster per annotatable (#1157, #1161).
The info page’s Alleles section is redesigned and renders only on an allele score; an allele score built before this reports its indel groups as not computed until rebuilt with
repo-stats --force(#982, #1105, #1118).Fragment scores publish fragment statistics instead of covered positions; a fragment resource built before this needs a rebuild (#926, #1127).
The coverage fraction measures the whole reference genome, and the Coverage and Alleles tables share one percentage format (#990, #1041, #1057).
RegionCoverage’s segment accessors raise on a region without segments (#1043).The credential-bearing fetch url is redacted on every failed read (#1017, #1052, #1058, #1078).
type: genomeconfigurations are validated, andindex_filereaches the bgzipped FASTA backend (#1029, #1067).A malformed genome label reads as absent, and an absent
input_reference_genomefalls through to the genomic context (#1021, #1050, #1053, #1055).render_pipeline_doctakes aPipelineDocAddressespolicy (#970).save_as_default_gene_modelsrefuses an unwritable model before opening the output (#978).Score construction, the statistics scan and s3 downloads make fewer round trips (#1038, #1039, #1042, #1059).
A score kind implements
record_weightin place ofRECORD_WEIGHT_IS_SPAN(#1095).The test-data builders express a
public_urland a group repository (#953).The annotation editor highlights every invalid string field (#1164).
New GAIn Development docs section, docstrings for the declared API, and docs built on every CI build (#1033, #1139, #1140, #1141, #1142, #1147, #1188).
- 2026.8.5
The deprecated
np_scorespellings are removed – the resourcetype:and thenp_score/np_score_annotatorannotator names. Writeallele_score/allele_score_annotatorinstead. The resourcetype:is not a plain rename:np_scoreread in substitutions mode, so a resource that relied on that default must also declareallele_score_mode: substitutions. Thenp_scoretest-data builders are retired with the type (#918, #919, #920).The statistics scan assigns each record to exactly one region – the one its
pos_beginfalls in – so no statistic varies with--region-size(#816).fetch_region_segmentsis the unclipped region read on the scores;fetch_region_segment_scoreskeeps its clipped meaning but is deprecated (#826, #827).The GTF parser reads
CDSrecords into the coding interval, repairing transcripts GENCODE flags incomplete; picked up when a resource is rebuilt (#909).The gene-models parsers read tables as text and refuse malformed records by name instead of producing
nantranscripts (#907, #929, #931, #963, #973).Filename suffixes are matched case-insensitively wherever behaviour hangs on one (#348, #975).
The single-allele annotation response links each resource on its child repository’s declared
public_url(#838).Anonymous-quota rows store what a user has consumed, so a raised limit applies immediately (#750).
The score filter language gains
>=,<=,!=,notand grouping, and filtering becomes a capability of the score itself –compile_filterplusscore_filter=on the fetch methods (#805, #806, #820).AlleleScoregains a bulk ref/alt column-array read (#780).The resource info pages document coverage, allele and fragment statistics: covered positions, segment and fragment counts, length histograms, allele classes, the substitution matrix with ts/tv, and indel/complex grids – in sortable tables, in natural chromosome order (#772, #777, #779, #794, #988, #997).
Repository publishes go through a write-temp-verify-move seam, a file’s recorded state carries the store’s change token (the S3 ETag), and downloads reuse the streamed md5 – a steady-state sweep of an unchanged s3 repository takes 5x fewer round trips (#865, #880, #881, #933, #936, #948).
Gene-models format inference reports a per-format rejection ledger and breaks the headerless
refseq/ccdstie, and the GTF parser accepts FlyBase-flavour files (#853, #856, #869).The test-data builders gain
a_gene_models(#315)./api/pipelines/validatememoises its verdicts, and the annotation worker count is configurable throughGPFWA_ANNOTATION_MAX_WORKERS(#833, #837).Secrets stay out of logs: the backend’s daphne access log is discarded and the GRR download path redacts url credentials (#620, #795).
- 2026.8.4
An annotation config’s
value_transformis compiled by a restricted evaluator instead of a bareeval(); an expression outside the allowlist is refused when the pipeline is built (#764, #767).The web API’s authentication endpoints are rate-limited, per client IP and per submitted address (#694).
grr_manage’sresource-*commands write only inside the selected resources; the newrepo-indexcommand publishes the repository globals from the manifests on disk (#760).The repository index is published gzipped only; readers still fall back to an uncompressed copy (#758).
fetch_region_valuesis renamedfetch_region_segment_scores; the old name is a deprecated forwarder (#729, #734).PositionScoregains a logicalget_read plane, reading the score as a function from position to values (#727).SearchResourcesreports the group children a search had to skip in anincompletelist (#686).Live single-use codes and url credentials are kept out of the logs, and anonymous config text cannot forge log records (#629, #655, #701, #754).
- 2026.8.3
A 10x
ann_dataresource is read whole by default; filtering a multiome down to its genes is opt-in configuration. Deployed 10x resources take a one-timegrr_manage -freprocess (#716).Oversized categorical histograms get truncated sidecars the info pages read;
grr_manage repo-fix-histogramsmigrates a repository built before them (#718, #719, #724).
- 2026.8.2
GAIn reads both 10x
ann_dataformats itself – the matrix-market triple and the CellRanger.h5– and scanpy is retired as a dependency. The statistics build no longer opens the count matrix, so repairing a large 10x resource completes in seconds (#708, #712).GPFWA_NUM_PROXIESaccepts only an ASCII decimal string, and the frontend container’s access log writes real log lines (#695).
- 2026.8.1
The anonymous pipeline-validation endpoint runs on a bounded pool and sheds requests with
503+Retry-Afterinstead of queueing without limit (#659, #676).The web API derives the client IP in one place, under the new
GPFWA_NUM_PROXIESsetting (#667).A search over a group repository skips a child that cannot answer it instead of dying on it (#680).
Each score kind states its record-ordering rule on both statistics scan paths (#591, #592).
- 2026.8.0
Record-ordering validation moved off the score read path and into the statistics scan; a violation refuses the resource with
MalformedResourceErrornaming the locus and the rule (#587, #588, #589, #590).A tabix table whose index and configuration name different columns is refused at open (#553).
An unknown score id is refused up front, whatever the region holds.
A caching repository carries the id of the repository it wraps, and
repository_idcan select a top-level repository (#447).build_fsspec_protocolrefuses a writable request over http, and a string-valuedread_onlyresolves to a boolean (#528).draw_score_histogramsisolates a per-resource failure and skips scoreless resources (#337, #537).New
ann_dataresource type: an AnnData single-cell matrix served from the GRR, with statistics and an info page (#608).The resource query language moved into the GRR itself:
search_resourcestakes it,grr_manage list/grr_browsegain-q/--query(plus-sand-t), and/api/resources/searchaccepts it asquery=(#441, #442, #443).The GRR index page gains a hierarchical browse view (#560).
The
cnv_collectionconfiguration vocabulary is deprecated in favor offragment_score, warning once per offender until 2027.1.0 (#538).A
table:block’sindex_filenameis honoured everywhere, including the VCF backend and cache prefetch (#595, #596).prepare_tabularpublishes its output and index atomically (#618).Hardening against untrusted GRR content and anonymous requests: control characters in names are refused, browse pages autoescape, the query parser bounds its input, and
grr_managerefuses advc add <dir>output up front (#284, #542, #558, #635, #642).
- 2026.7.7
build_fragment_score_from_resourcereturns a fresh score per call instead of a process-wide shared instance.The per-kind score reads are renamed after their kind (
fetch_position_scores,fetch_allele_scores,fetch_fragment_scores),fetch_fragment_scoresreturns score-value dicts instead ofFragmentobjects, andfetch_regionis removed in favor offetch_region_values. No aliases.load_pipeline_from_grris removed; useload_pipeline_from_file_or_resource(#508).The bulk statistics scan covers allele, fragment, int- and str-valued scores, bit-identical to the per-record path and several times faster (#406, #421).
- 2026.7.6
A GRR cache must live on a local filesystem; off one, the per-file download lock silently degraded to a no-op (#473).
A repository
idmust be a single safe path segment, and ids must be unique across the definition tree (#445, #460, #461).The
CnvCollectionPython surface is renamedFragmentScore, and thefragment_scoreconfiguration vocabulary is accepted alongsidecnv_collection(#470, #471).The resource test-data builders gain
with_meta/with_labels(#319).
- 2026.7.5
The per-line score objects are gone from the
GenomicScoreAPI – values are read straight off records (fetch_records,get_score_from_record);chromis required in the region reads, and a whole-table read isget_all_records().A resource score declares a single
aggregator:key; the per- kind aggregator keys are removed.BigWig fetch buffering is removed (
direct_fetch_sizebecomesfetch_size), and a bigWig score config is validated against what the format can honour.GenomicScore.aggregate_regionfolds a region into one value per requested score, and the typed score factories return concrete types (#438).The per-record score read path is 17-34% faster, per backend.
- 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.