Release Notes

  • 2026.11.0
    • Distribution: gain-core is published to PyPI and bioconda, the install docs take it from bioconda and keep the iossifovlab channel for the annotators, the sdist and wheel ship the LICENSE, and requires-python is capped at <3.15.

    • binning_tool: the fragment score binner reads and folds fragment_start, fragment_length and int coverage_profile tracks from value arrays, through the new FragmentScore readers get_fragment_arrays_starting_in_region and get_fragment_arrays_overlapping_region, and the array fold of a float score serves median.

    • Statistics: a NumberHistogram stores the same sum and sum_of_squares whatever 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 is None.

    • Annotation and GRR: annotate_variant_effects_vcf writes one INFO value per alternate allele instead of failing on a multi-allelic record, grr_manage repo-info drops the ignored -r/--resource option, GenomicScoreDef repr() and == work before open(), and a forked task graph run accepts a None task_status_dir.

    • gainweb: the single-allele report shows the histogram of an attribute folded by list or most_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_cluster in the dask config, so a user file can add one and keep the bundled ones; the old dae_named_cluster list still works with a warning. setup_client leaves the dask config unchanged, chain_tasks passes the first task its resolved arguments, and the bundled slurm cluster uses number_of_workers.

    • Annotation: the default region_length_cutoff of 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 forward batch_annotate.

    • Scores: GenomicScore.aggregate_region is 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, so repo-repair --force on 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_tool output and tooling: the /tracks table has one layout for every binner kind (tracks_layout 2), the run definition names its genome with reference_genome instead of input_reference_genome, gain.binning.h5_reader reads the tables as data frames, and the new binning_tool_view command 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 a product or an int sum past the float range saturates to a signed inf instead of raising or stalling.

    • Annotation: annotate_vcf writes 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’s promoter_len is 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.grr as grr.

    • Issues closed in this release: all issues, bug issues.

  • 2026.10.0
    • The allele plane: AlleleScore gains the exact-allele and region reads get_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_rows and get_allele_scores_for_allele_agg / get_allele_score_for_allele_agg, beside the existing get_allele_scores_in_region_agg. The region _rows read yields AlleleEntry named tuples (pos, ref, alt, values) (#1750, #1751, #1753, #1754).

    • An allele score declares allele_multiplicity: one | many, a new top-level resource-config key (default one), reported by AlleleScore.multiplicity. The one-row read raises AlleleMultiplicityError (a ValueError) on a many resource (#1750, #1753).

    • The allele statistics build checks allele_multiplicity: a one resource with a repeated allele key warns now and fails from the enforcement release, GAIn 2027.1.0 (ALLELE_MULTIPLICITY_ENFORCEMENT_RELEASE). The one-row read warns once per resource on the same repeat (#1752, #1753, #1757).

    • AlleleScore.fetch_allele_scores and fetch_allele_records are removed; use the get_allele_scores_for_allele* reads. The allele annotator’s exact match reads through the plane: a many resource 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 allele mode the allele annotator routes by the resource’s allele_score_mode: on a substitutions resource an indel, complex or MNV allele gets the region fold over the bases it covers instead of its own line’s value (#1748).

    • binning_tool gains the fragment_score_binner kind: 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 a str score. aggregate.mode is fragment_start (the default, counting fragments), fragment_length or coverage_profile, and aggregate.uncovered_value sets what an uncovered base adds. FragmentScore.get_scores_in_bins is the binned read under it (#1203, #1740, #1741, #1759, #1793, #1794, #1795, #1796, #1742, #1798).

    • Binner entries take a name key that sets the base of their track names, so two entries over the same resource no longer collide (#1792).

    • The sum and product aggregators are added; they keep the input’s numeric type, and binning_tool accepts them on position-score tracks (#1739).

    • gain.grr is 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_LIMIT is stored gzipped as statistics/histogram_<id>.json.gz beside the unchanged truncated sidecar. A rebuild drops the other encoding’s leftover, and the build warns when the gzipped file has no .dvc pointer. 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-size help of the grr_manage statistics, repair and info commands names the one-region-per-contig default and says that 0 does 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).

    • GeneScoresDb and the gene ScoreDesc are removed; gpf now owns them. GeneScore.build_score_help renders one score’s help (#1729, #1730).

    • The deprecated annotate_columns alias is removed; use annotate_tabular (#26).

    • prepare_tabular parses quoted input fields the same way annotate_tabular does (#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 loading status before its outcome, so a fast build no longer leaves the editor on loading (#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 UPDATE per 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 and default_annotation (#317, #318).

    • The docs name aggregator as the resource-level aggregator key and describe the 2026.7.6 cache relocation and its cleanup (#1828, #463).

    • Fixed: the bug issues closed in this release.

  • 2026.9.7
    • The kubernetes named-cluster type is removed; an unknown cluster type fails with an error listing the supported types (#1642).

    • grr_manage repo-fix-histograms is removed; a repository whose statistics predate the truncated-histogram sidecars gets them by rebuilding statistics (#722).

    • grr_manage repo-info and resource-info accept --region-size and default to the same 3 Gb as repo-repair instead 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 GeneScore value accessors included, says it in one sentence naming the resource and the scores it has (#1112, #1701).

    • spliceai-environment.yml is generated from the plugin’s pyproject.toml; vep and demo get no file (#1643).

    • The record-to-annotatable builders raise MalformedRecordError for a record they cannot build, and /api/single_allele/annotate answers 400 instead of 500 or a meaningless annotation to a malformed record, with its own reason for a DAE-style ins/del (#1679, #1680).

    • GET/DELETE /api/pipelines/user address 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).

    • Fixed: the bug issues closed in this release.

  • 2026.9.6
    • The GRR index page’s search module is published as index.js, so a host that serves .mjs as text/plain no longer hangs at “Loading search” (#1709).

    • The GRR index page carries each row’s values once, so a large GRR’s page is a fraction of its former size (#1711).

    • Fixed: the bug issues closed in this release.

  • 2026.9.5
    • The SpliceAI annotator honours mask: with mask: 1 a gain away from the nearest exon boundary and a loss at it score zero, as Illumina’s -M 1 does (#322).

    • gainweb builds every GRR pipeline when the ASGI application loads instead of on its first request; PREWARM_GRR_PIPELINES (env GPFWA_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, and total_pages no longer reports an extra empty page (#791, #1649, #1650, #1660, #1661, #1666).

    • region_size means the same for every resource kind: 0 does not split, a negative value is refused (#1656).

    • DaskExecutor hands dependants a dependency’s Future rather than its gathered value, so repo-repair no longer submits a multi-megabyte graph (#1633).

    • A gene_score without scores:, or a score entry without id, 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.yml and dev-environment.yml are generated from the pyprojects, and each conda recipe’s run list is held equal to its pyproject dependencies (#1639, #1640, #1641).

    • infer_gene_model_parser is removed; infer_gene_models_format is the one entry point (#871).

    • LRUPipelineCache.clean_old_tasks is 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() clears table_loaded before releasing the table (#363).

    • Fixed: the bug issues closed in this release.

  • 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).

    • GenomicScore gains get_chrom_length, get_all_chrom_lengths, get_chrom_length_source and chrom_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.json and fragments.json format version 2) and their info pages show a min/max/mean/median table; a score built before this reads “not computed” there until rebuilt with repo-stats --force (#1541, #1542, #1543, #1544, #1565).

    • repo-repair and --dry-run report statistics files that predate the current schema without rebuilding them (#1586).

    • NumberHistogram accumulates 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_records drops its window parameters (#828, #829).

    • The liftover_chain, gene_models, score-table and gene_score schemas require filename; liftover chains and gene-set collections validate their config; a liftover_annotator with an empty resource id is refused (#1075, #1532, #1534, #1567, #1592).

    • The genome chrom_prefix key is retired: the prefix is derived from the FASTA index, and a config that sets it warns (#1090).

    • LiftoverChain strips del_prefix as a prefix, not a character set (#1530).

    • A mapping-form pipeline config parses without a preamble key (#1535).

    • A VCF row carrying more values than its Number admits reads as null and is reported once per table; a scores: 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_score with type: str and a number histogram is refused at construction (#1308).

    • An input_gene_list must name an attribute marked attribute_type: gene_list (#1490).

    • PositionScore refuses 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_models returns a loaded model and GeneModels.from_transcript_models builds one from transcripts (#1097, #1527).

    • -v raises 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’s TRACE level 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_genome label values (#1079).

    • New GAIn Development docs chapter on annotators and the plugin entry-point mechanism (#1144).

    • Fixed: the bug issues closed in this release.

  • 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_genome parses to None (#1346).

    • Fixed: the bug issues closed in this release.

  • 2026.9.2
    • fetch_region_segments is renamed fetch_region_segments_scores and takes a score_filter; the deprecated fetch_region_segment_scores, fetch_region_values and fetch_position_scores are removed, and get_scores_at_position is the only point read (#844, #1268, #1272, #1383, #1397).

    • validate_records and validate_record_arrays move to statistics.record_validation (#1269).

    • get_genomic_resource_id_version is folded into get_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 bool renders as no in annotation output, distinct from a missing value (#1222).

    • A VCF score reads its values as the header declares them: a Flag reads as bool, a multi-valued field reads its joined text as str, and a stated type: 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_resources answers a resource_type without the full-text index, so grr_manage list -t works 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-budget bundles consecutive regions into one task per track (default 50 Mb), and 0 now means one task per track rather than one per region; an explicit --work-dir is created with its parents; --help no 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.md renders Markdown tables and fenced code, and description tables are styled (#1278, #1279).

    • Ids from a remote .CONTENTS are 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_annotator is split into one module per score kind (#1153, #1154).

    • New GAIn Development docs chapter “Working with resources in Python” and a binning_tool user page; the docs build fails on any warning and renders Google/numpy docstring sections (#1143, #1202, #1219, #1220, #1243, #1254).

    • Fixed: the bug issues closed in this release.

  • 2026.9.1
    • New binning_tool command 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.labels value may be a list, matched and indexed as alternatives (#1225).

    • A bool score reads its cell as text, so False and 0 no longer parse as true; a text bool score built before this needs its statistics rebuilt with repo-stats --force (#1192).

    • The annotation editor templates offer region_length_cutoff (#1184).

    • genomic_scores_impl is split into one module per score kind (#1210).

    • Fixed: the bug issues closed in this release.

  • 2026.9.0
    • Annotators return values keyed by attribute name and the base annotator no longer aggregates; WeightedValues, Aggregator.aggregate_weighted and Attribute.aggregator_instance are removed (#1130, #1133, #1134, #1196).

    • A position_score annotator 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_values is removed (#1131).

    • AlleleScore gains the folding read get_allele_scores_in_region_agg, and the annotator’s region mode streams (#834, #1132, #1163).

    • FragmentScore gains a logical read plane and a folding read; fetch_fragment_scores streams (begin, end, values) (#1119, #1120, #1121, #1122, #1123, #1124, #1126).

    • The fragment_score annotator accepts min_region_overlap_fraction and min_fragment_overlap_fraction (#1125, #1165).

    • none_value_replacement is a position_score attribute parameter (#1135).

    • Attribute parameters count for --reannotate and AttributeConfig.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: genome configurations are validated, and index_file reaches the bgzipped FASTA backend (#1029, #1067).

    • A malformed genome label reads as absent, and an absent input_reference_genome falls through to the genomic context (#1021, #1050, #1053, #1055).

    • render_pipeline_doc takes a PipelineDocAddresses policy (#970).

    • save_as_default_gene_models refuses 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_weight in place of RECORD_WEIGHT_IS_SPAN (#1095).

    • The test-data builders express a public_url and 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).

    • Fixed: the bug issues closed in this release.

  • 2026.8.5
    • The deprecated np_score spellings are removed – the resource type: and the np_score / np_score_annotator annotator names. Write allele_score / allele_score_annotator instead. The resource type: is not a plain rename: np_score read in substitutions mode, so a resource that relied on that default must also declare allele_score_mode: substitutions. The np_score test-data builders are retired with the type (#918, #919, #920).

    • The statistics scan assigns each record to exactly one region – the one its pos_begin falls in – so no statistic varies with --region-size (#816).

    • fetch_region_segments is the unclipped region read on the scores; fetch_region_segment_scores keeps its clipped meaning but is deprecated (#826, #827).

    • The GTF parser reads CDS records 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 nan transcripts (#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 >=, <=, !=, not and grouping, and filtering becomes a capability of the score itself – compile_filter plus score_filter= on the fetch methods (#805, #806, #820).

    • AlleleScore gains 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/ccds tie, and the GTF parser accepts FlyBase-flavour files (#853, #856, #869).

    • The test-data builders gain a_gene_models (#315).

    • /api/pipelines/validate memoises its verdicts, and the annotation worker count is configurable through GPFWA_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).

    • Fixed: the bug issues closed in this release.

  • 2026.8.4
    • An annotation config’s value_transform is compiled by a restricted evaluator instead of a bare eval(); 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’s resource-* commands write only inside the selected resources; the new repo-index command 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_values is renamed fetch_region_segment_scores; the old name is a deprecated forwarder (#729, #734).

    • PositionScore gains a logical get_ read plane, reading the score as a function from position to values (#727).

    • SearchResources reports the group children a search had to skip in an incomplete list (#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).

    • Fixed: the bug issues closed in this release.

  • 2026.8.3
    • A 10x ann_data resource is read whole by default; filtering a multiome down to its genes is opt-in configuration. Deployed 10x resources take a one-time grr_manage -f reprocess (#716).

    • Oversized categorical histograms get truncated sidecars the info pages read; grr_manage repo-fix-histograms migrates a repository built before them (#718, #719, #724).

    • Fixed: the bug issues closed in this release.

  • 2026.8.2
    • GAIn reads both 10x ann_data formats 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_PROXIES accepts only an ASCII decimal string, and the frontend container’s access log writes real log lines (#695).

    • Fixed: the bug issues closed in this release.

  • 2026.8.1
    • The anonymous pipeline-validation endpoint runs on a bounded pool and sheds requests with 503 + Retry-After instead of queueing without limit (#659, #676).

    • The web API derives the client IP in one place, under the new GPFWA_NUM_PROXIES setting (#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).

    • Fixed: the bug issues closed in this release.

  • 2026.8.0
    • Record-ordering validation moved off the score read path and into the statistics scan; a violation refuses the resource with MalformedResourceError naming 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_id can select a top-level repository (#447).

    • build_fsspec_protocol refuses a writable request over http, and a string-valued read_only resolves to a boolean (#528).

    • draw_score_histograms isolates a per-resource failure and skips scoreless resources (#337, #537).

    • New ann_data resource 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_resources takes it, grr_manage list / grr_browse gain -q/--query (plus -s and -t), and /api/resources/search accepts it as query= (#441, #442, #443).

    • The GRR index page gains a hierarchical browse view (#560).

    • The cnv_collection configuration vocabulary is deprecated in favor of fragment_score, warning once per offender until 2027.1.0 (#538).

    • A table: block’s index_filename is honoured everywhere, including the VCF backend and cache prefetch (#595, #596).

    • prepare_tabular publishes 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_manage refuses a dvc add <dir> output up front (#284, #542, #558, #635, #642).

    • Fixed: the bug issues closed in this release.

  • 2026.7.7
    • build_fragment_score_from_resource returns 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_scores returns score-value dicts instead of Fragment objects, and fetch_region is removed in favor of fetch_region_values. No aliases.

    • load_pipeline_from_grr is removed; use load_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).

    • Fixed: the bug issues closed in this release.

  • 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 id must be a single safe path segment, and ids must be unique across the definition tree (#445, #460, #461).

    • The CnvCollection Python surface is renamed FragmentScore, and the fragment_score configuration vocabulary is accepted alongside cnv_collection (#470, #471).

    • The resource test-data builders gain with_meta / with_labels (#319).

    • Fixed: the bug issues closed in this release.

  • 2026.7.5
    • The per-line score objects are gone from the GenomicScore API – values are read straight off records (fetch_records, get_score_from_record); chrom is required in the region reads, and a whole-table read is get_all_records().

    • A resource score declares a single aggregator: key; the per- kind aggregator keys are removed.

    • BigWig fetch buffering is removed (direct_fetch_size becomes fetch_size), and a bigWig score config is validated against what the format can honour.

    • GenomicScore.aggregate_region folds 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.

    • Fixed: the bug issues closed in this release.

  • 2026.7.4
    • Fixed: a data_frame resource with format: excel — the format announced in 2026.7.3 — could not be read by a stock install. pandas opens a workbook through openpyxl, which was not a dependency of gain-core, so the read raised an ImportError asking for the missing package. openpyxl >=3.1 is now declared everywhere gain-core declares its runtime dependencies — the Python distribution, the conda environment and the conda package recipe — so an Excel data_frame opens out of the box (#423).

  • 2026.7.3
    • Behavior change: grr_manage --dry-run now writes nothing at all — it no longer records a .grr/<file>.state for 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-init no longer offers --dry-run / --force; both were accepted and ignored, so repo-init -n initialised the repository for real (#415).

    • The statistics scan is now bulk-vectorized for float position_score resources over tabix and bigWig — column arrays instead of a Record per 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).

    • GenomicScore exposes the bulk column-array region read (supports_region_value_arrays / fetch_region_value_arrays, yielding parsed float64 arrays per score); a backend declares it through GenomicPositionTable.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 nan value token — reachable when na_values is configured without the default nan sentinel — poisoned a score’s recorded min/max and nullified its histogram (#385).

    • The SpliceAI annotator can run under ONNX Runtime: SPLICEAI_BACKEND=onnx selects it per process, TensorFlow stays the default, and an unrecognised value raises (#297).

    • The five SpliceAI ensemble models now ship as .onnx artifacts derived from the committed .h5 weights and pinned to them by an equivalence test; onnxruntime became a runtime dependency of gain-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 categorical histogram was silently recorded as a NullHistogram, because the values were coerced with int() (#352).

    • Fixed: a data_frame resource read its file relative to the process’s working directory rather than through the resource, so it loaded only by accident; it also now accepts format: excel alongside csv/tsv, and its info page lists the column description one row per column.

    • draw_score_histograms pointed at a non-score resource now fails with a TypeError naming the resource and its type, instead of an empty AssertionError (#337).

    • CI: the gain-web e2e job reports NOT_BUILT rather 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_ROOT itself and runs against the node-local real GRR (#321).

  • 2026.7.2
    • Behavior change: grr_manage now reports every resource it cannot process and exits non-zero, instead of skipping it with a misleading WARNING and exiting 0; 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_manage now reports a configuration error as a single ERROR line (traceback demoted to DEBUG), refuses an unrecognised management command, reports a message-less exception by its class name, and raises a clear ValueError for a headerless tabix table on the default header_mode (#364).

    • A --dry-run exits with the count of resources needing an update — now counting a resource it could not check; other runs exit 1 on any failure and 0 otherwise (#364).

    • Fixed: grr_manage repo-manifest --dry-run reported a settled repository as inconsistent (its exit status was the repository size, not the stale count); it now exits 0 (#364).

    • Removed: the in-resource aggregation engine — the fetch_scores_agg / *Query / *Aggr APIs on PositionScore / AlleleScore; aggregate on the annotator instead (#267).

    • Resources may now configure position_aggregator: count / allele_aggregator: count and an empty-separator join(); 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 mean float scores may shift in their last bits on large regions (annotation output unchanged) (#260).

    • Behavior change: a .dvc sidecar is now the authoritative md5 and size, and grr_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.html and statistics/index.html are excluded, and every other file is manifested (#251, #255, #373).

    • Behavior change: grr_manage now refuses a dvc add <dir> output (a .dvc sidecar declaring a .dir md5 or nfiles), which GAIn cannot verify (#255).

    • Behavior change: the --with-dvc / --without-dvc option group is restored on the manifest, stats, repair and info subcommands (removed in 2026.7.1) (#251).

    • A malformed or incomplete .dvc file is now reported as a warning and ignored rather than aborting grr_manage (#251).

    • Fixed: the DaskExecutor run loop leaked driver memory by minting an uncancelled asyncio Task per pending future on every 50 ms poll; it now registers one add_done_callback per 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 RunState state 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 None and cached as a real result, so an all-dead run reported success; failed futures are now gathered as errors and teardown moved into a finally so a failure no longer leaks worker threads (#367).

    • Fixed: an unguarded exception in a DaskExecutor worker 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_pipeline now defaults work_dir to an absolute per-process temp dir instead of the cwd-relative ./work (which EPERM’d under a non-root runtime in a root-owned cwd) (#331).

    • Fixed: tabix reads of overlapping-interval tables returned wrong get_records_in_region results when the LineBuffer was warm; ordering is now judged by pos_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_values sentinel 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=A INFO 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_score with a null-histogram config crashed construction and a runtime histogram failure was dropped; the config is accepted and the failure recorded as a NullHistogram (#305).

    • Fixed: the genes / worst_effect_genes columns were PYTHONHASHSEED-ordered (deduped via set()); 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 and close() closes the handle first (#362).

    • Fixed: the GRR manifest scanner now honors .gitignore files 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_size now mean records per call and use_buffered_threshold is accepted by the schema (#259).

    • LineBuffer.prune now evicts every dead record instead of stopping at the first survivor, bounding buffer growth on dense overlapping tabix scans (#287).

    • build_genomic_position_table now warns when a tabix/in-memory table omits zero_based (#379), or when zero_based is 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_jobs command (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 redacted ValueError (#202).

    • Behavior change: GPFWA_EMAIL_USE_TLS is parsed as a string, so only a literal true enables STARTTLS.

    • Fixed: the 2026.7.0 .gitignore scan dropped a DVC-managed GRR’s data files; a gitignored file is re-included when a sibling <name>.dvc declares it an output (#209/#211).

    • grr_browse can 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-in logging proxy guaranteeing TRACE / USER_INFO are installed early; behavior change: -vvv now selects TRACE (effect-checker diagnostics moved there too).

    • The single-allele annotation response reports preserves_domain: true rather than null for 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 an NG0956 duplicate-key warning).

    • gain.genomic_resources.testing became a package with a builders module — a fluent DSL for authoring test GRRs.

    • Documented the user / password basic-auth keys of an http repository.

    • CI: tests/integration moved to a dedicated gain-core-integration downstream job resolving real resources against grr-seqpipe (#222).

  • 2026.7.0
    • Hardened HTTP basic-auth credential handling: user / password are no longer logged and are masked in the definition model’s repr() / str(); credentials on a plain http:// 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 basic resource 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 .gitignore files; pathspec is a new gain-core runtime 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_status is now the authoritative loaded signal (#160).

    • Fixed: a flaky FileExistsError creating the task-graph log directory under concurrency; ensure_log_dir uses makedirs(exist_ok=True) (#186).

    • Added the TRACE and USER_INFO logging levels and the logger.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 file line; the header open is wrapped in pysam.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_url may now be set on any repository type, not only http/url.

    • HTTP GRRs now support basic authentication (user / password passed as aiohttp credentials).

    • The annotate_doc CLI now builds links from each resource’s public URL.

    • Renamed the stored Job.annotation_type value "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 failed status, 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_vcf now supports CSI-indexed input, lifting tabix’s 512 Mbp limit so long contigs can be region-parallelized.

    • Gene-set collections in map format 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.user is now one-to-one and AnonymousUserQuota.ip unique, 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_jobs skips WAITING / IN_PROGRESS jobs (#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.cleanup as a backstop.

    • Behavior change: annotate_tabular now 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 .gzi index is now declared and pre-fetched, and an index_file override 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_tabular crashing with UnicodeDecodeError on non-ASCII input; the input is now read as UTF-8.

    • Fixed: default-verbosity runs printing INFO:distributed messages; 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_manage repo-repair rewriting unchanged index.html pages 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-core conda package.

  • 2026.6.5
    • annotate_tabular / annotate_vcf now print a reannotation plan (COPIED / ADDED / COMPUTED / DELETED), with a new --dry-run/-n flag.

    • Reannotation reuse now works through the CLI: an unchanged annotator’s result is copied rather than recomputed.

    • Fixed: --full-reannotation leaving 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 .gz suffix is stripped before the .tsv check.

    • Fixed: building gene-score histograms rebuilt a GeneScoresDb per score (O(n²) plus a spurious error).

    • Added a GRR definition-files documentation page.

  • 2026.6.4
    • grr_manage skips rebuilding the full-text search index when the repository contents are unchanged (compares the stored contents_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 as pipeline/hg38_clinical_annotation), pre-selected in the UI.

    • annotate_tabular / annotate_vcf accept 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_column resource.

  • 2026.6.2
    • When no output file is given, annotate_tabular / annotate_vcf insert an .annotated marker (was _annotated).

    • annotate_tabular / annotate_vcf now delete a work directory they created on a clean run (--keep-work-dir opts out); annotate_vcf also closes its pipeline.

    • Added an annotate_doc endpoint serving a saved pipeline’s documentation as a downloadable HTML attachment.

    • Fixed: allele_score filter-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 .fai faidx and .gzi index required; optional index_file override), working local, cached or over HTTP/S3.

    • annotate_columns was renamed to annotate_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 pysam to 0.24.0 and declared tqdm a gain-core runtime dependency.

  • 2026.6.0
    • grr_cache_repo now shows live progress (a tqdm byte bar on a terminal, milestone lines otherwise) and downloads only missing/stale files; --no-progress disables 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_repo now takes the pipeline as a positional argument instead of --pipeline/-p.

    • annotate_tabular / annotate_vcf now treat .bgz as a first-class compression extension for input and output (changing the default --work-dir name derived from a .bgz output).

    • Fixed: silent record duplication when an annotate_tabular input carried a .csi index rather than .tbi.

  • 2026.5.10
    • Fixed: grr_cache_repo aborting 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_tabular now run a pre-flight locality check, warning (1001–5000 rows) or aborting (>5000) when the pipeline uses non-local resources; --allow-remote-resources disables 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_tabular CLI that sorts a tabular file by genomic coordinates and writes a bgzip-compressed, tabix-indexed output for region-parallel annotation.

    • annotate_tabular defaults --input-separator to a comma for a .csv input; other inputs still default to a tab.

    • annotate_tabular / annotate_vcf run sequentially (-j 1) when the input cannot be split into regions.

    • annotate_tabular / annotate_vcf now run inside their work_dir so downloaded .tbi indexes 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_repo CLI from gpf into gain.

    • Fixed: the --version label on the grr_manage, grr_browse, annotate_columns and annotate_vcf CLIs.

    • 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_columns CLI to annotate_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_format CLI from gpf into gain.

  • 2026.5.4
    • Made .CONTENTS.json.gz and .CONTENTS.sqlite3.gz byte-reproducible across platforms.

  • 2026.5.3
    • Refactored the allele score annotator to operate only on VCF alleles by default; deprecated allele_aggregator in favor of aggregator.

    • 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.