AlignAIR v3.0.0 — PyTorch rewrite, CLI, self-contained models, docs site, release automation - #10
Merged
Merged
Conversation
…rner floor mixture)
…rd, LCB promotion); training-side gates -> 5b
…er B3, consistency target, Kendall strategy
…ladder sequenced)
…r-vs-coords diagnostic
…essons Replaces the MkDocs theme with a Vite + React + TypeScript site that is both the reference and a teaching surface, deployed to GitHub Pages from website.yml (base /AlignAIR/, refresh-safe routing). Reference: all 15 pages authored as typed TSX rather than markdown, carrying the corrected content -- the AIRR field contract (orientation, derived productive, reserved is_contaminant), the model contract, benchmarks with the 24 metric definitions, and measured per-device throughput stated with its hardware, backend and timing boundary. Lessons: a typed step model with immediate-feedback checks and progress kept in the browser, across five tracks -- foundations, predicting, training, benchmarking, integrating -- with interactive widgets for V(D)J assembly, reverse-complement, the CLI, AIRR fields, record filtering, donor genotypes, the benchmark sandbox, and the training curriculum. The curriculum widget's ramps mirror Curriculum().params(), including SHM dropping to zero for a TCR locus.
….0.0 The image installed from source without setup.py, so the optional Cython germline-CIGAR kernel was never built and the container silently ran the pure-Python fallback -- slower than a local install, while the published throughput figures assumed the compiled path. The Dockerfile is now multi-stage: a builder with a C toolchain compiles the wheel, the slim runtime installs it, and `alignair doctor` in the image reports derive_backend=cython. The image does not grow; the toolchain stays behind. doctor also reports parasail and derive_backend, so the active backend is visible rather than assumed -- the docs claimed doctor reported parasail before it did. Models cache under a declared volume; the docs show mounting it so a `--model <id>` run does not re-download on every invocation. Version is 3.0.0 across pyproject, the conda recipe and the Galaxy wrapper. The MkDocs CI job and the [docs] extra are removed with the MkDocs source; package metadata and the conda summary drop the "dynamic reference" wording that contradicted the fixed-reference contract.
An external review of the site found claims that were wrong against the code. Each was verified against the implementation before editing. - *_call_set was documented as an exhaustive equivalence class. It is not: threshold.py applies an absolute p>=0.5 cut, caps at 3, and falls back to top-1 when nothing clears. So it is the model's candidate set, it can be truncated, a one-member set is not necessarily confident, and its members need not share a gene or family. Reworded site-wide and documented the real rule; the benchmark truth-side "equivalence set" wording is correct and kept. - --columns core was labelled "no gapped alignment". needs_assembly() returns True for core (it emits the junction, an assembly product), so core buys a smaller file, not a skipped stage. minimal is the only preset that skips assembly, and therefore the only one without coordinates. Fixed in nine places. - The junction field showed an amino-acid string; junction is nucleotides. Split into junction / junction_aa. - alignair models info / reference export do not resolve catalog ids (unlike predict). Examples now resolve via `alignair models path`. - validate-airr was described as the official AIRR-C schema validator. It imports only csv; it is a structural check. Documented as such, with airr.validate_rearrangement() named for formal validation. - The 10x example kept a column name that does not exist in the raw input (umis, not umi_count), and the Change-O hand-off did not filter to complete records. - The reserved *_resolved_call / *_call_level / *_set_confidence fields read as conditionally usable. They are always blank; say so. Also corrects a latent error in the calibration section: temperature scaling is monotonic, so it cannot change the top call, but pipeline.py applies it to the same probabilities the absolute-threshold selector consumes, so it *can* change call_set membership. Website builds clean; 740 tests pass.
The two interactive widgets presented numbers that were never measured. Both are now backed by artifacts, and one of them was not merely imprecise but directionally wrong. BenchSandboxWidget interpolated linearly between two hand-set endpoints across a continuous 40-312nt slider, so almost every number it displayed was invented. Worse, it showed AlignAIR ahead of IgBLAST for every gene at every slider position, captioned "drag to see AlignAIR's edge grow on short fragments". The frozen benchmark says the opposite for V: IgBLAST wins V on the full-length strata (high_shm .990 vs .895, hard_full .990 vs .980, clean_full a 1.000 tie) and wins it decisively on 5'-anchored fragments (amplicon_fr2 .995 vs .820). Its "full-length" V figures (.776/.745) matched no stratum at all - clean_full is 1.000/1.000 - and appear to be aggregates from an older run. Rebuilt on six discrete measured strata (200 cases each) from the 2,600-case human-IGH benchmark, showing both tools honestly, including where AlignAIR loses. Each gene now carries the benchmark's own verdict from the Bonferroni-corrected paired bootstrap, so the two panels whose visible gap is not significant say so - which is what the preceding lesson step already told the reader to look for. The real story is more specific than the old one: the gains are in D, J, junction-anchored reads and orientation, not everywhere. CliWidget invented its entire output: a device banner, a fingerprint line, a "2.4s" timing and a "982 complete / 14 partial / 4 failed" tally, none of which the CLI prints. Replaced with output captured verbatim from a real run against alignair-igh-human on 400 simulated full-length IGH reads, matching the format string in cli/predict.py. The captured run's 68 partial assemblies are now a teaching point rather than something to hide. Hero: the network runs once, but coordinates, CIGARs and the junction come from deterministic post-processing after it, so "in a single forward pass" overstated the claim; it now says what is true. Added an above-the-fold evidence strip with the NAR paper DOI, the benchmark page and the failure-modes page. TRB card: alpha/gamma/delta are absent from the pretrained registry, not unsupported by the architecture - you can train them. Website builds clean; 740 tests pass.
Semantic controls, keyboard/focus handling, contrast, motion and responsive fixes across the site. Treated as engineering, not a palette tidy-up. Semantic controls - Every toggle group (model chooser, all seven widget toggles, MCQ options) now carries role="group" with a label and aria-pressed per option, so state is announced instead of conveyed by fill colour alone. - The curriculum range gained a real <label>, aria-valuetext (position + stage) and aria-describedby to its note. - Lesson and track progress bars are role="progressbar" with value/valuetext; the model-finder panel and every value readout that changes on interaction are aria-live regions. - MCQ options are no longer hard-disabled after answering: they stay focusable and reviewable by assistive tech, with the correct/your-answer status in sr-only text and the result panel as role="status". Full reference fingerprints are exposed via sr-only, not title-only. Keyboard and focus - Skip-to-content link; a single global :focus-visible ring (many controls were inline-styled with none). - After Continue/Previous/Try again/completion, focus moves to the new step heading; the smooth scroll respects reduced motion. Contrast (all verified numerically against WCAG AA) - Replaced every muted grey carrying readable text with a 5:1 floor (#6f6d85 on light, #9d9bb0 on dark). #8b899d (3.4:1), #b9b7c7 (2.0:1), #9b99ac (2.8:1), #a09eb2 and slate-400 headers all failed. Selected/ dropped/correct states no longer rely on colour, opacity or strikethrough alone. Motion and responsive - prefers-reduced-motion neutralizes transitions, animation and smooth scroll site-wide. The aa-rise keyframe was referenced everywhere but never defined (a no-op); it is now defined AND reduced-motion-gated. - Grids use minmax(min(px,100%),1fr) and the V/D/J builder reflows, so nothing overflows at 320px. Decorative graphics (hero strand and ruler, segment bars, window chrome, icon glyphs) are aria-hidden; the hero illustration is a single labelled role="img". Website builds clean (tsc + vite).
Migration guide - examples/igblast-migration/README.md: a runnable, CI-validated guide (its alignair commands parse against the real CLI via the docs-cli-sync test). Maps invocation, reference selection and output fields; explains the semantic differences (call sets, coordinates, junction assembly, confidence, partial predictions); gives CPU/GPU guidance with no unsupported performance claims; ends with a migration checklist. - The field-by-field side-by-side is genuine output from BOTH tools on the same 348 nt IGH read: IgBLAST -outfmt 19 and a real `alignair predict --model alignair-igh-human@1.0.0` run (1-based AIRR TSV, not the benchmark's internal 0-based artifact). It shows honest agreement (V, J, junction nt, productivity), a real D disagreement, the call_set / assembly-status extensions, and the documented 1-2 nt J boundary jitter (CAKGVILAVT. vs CAKGVILAVTG). - website: pages-migrate.tsx renders the same content as a docs page. IA restructure (primary journey unmistakable, everyday use separated from training and benchmarking) - New section order: Get started, Using AlignAIR, Reference, Training, Evaluation, Design, Maintainer. "Guides" is renamed "Using AlignAIR" and training is pulled into its own Training section; benchmarking already lived in Evaluation. - DOCS is recomposed in section-grouped order so the sidebar and the Previous/Next flow agree. - Get started now reads getting-started -> migrating-from-igblast -> concepts. Getting started states the five-step journey up front (install -> demo -> model -> align -> read output) and notes you do not need Learn or Training to reach a first prediction; it links the migration guide at the top and a Next block at the end. - Contextual link added from Known failure modes' "when to prefer IgBLAST" section. Website builds clean; docs-cli-sync passes.
- website: new Community section with a Citation & support page - the NAR citation and DOI, a note about the CITATION.cff "Cite this repository" button, copyable BibTeX, a routing table (bug / feature / model request / usage question / scientific question / security), and a checklist of what a useful bug report contains (alignair --version, pinned model, alignair doctor, exact command, minimal reproducer). Linked from the footer. - bug_report.md was still the default GitHub template (asking for Browser and iPhone model). Replaced with an AlignAIR-specific one that asks for version, model, `alignair doctor`, the command, and a minimal reproducer - matching the checklist on the page. - SECURITY.md's scope described `torch.load` on "bundles", which predates the .alignair format. Corrected: inference sections (config, safetensors weights, reference_json) load with no pickle execution and are fingerprint-verified; only resumable-checkpoint sections (dataconfig, train_state) use pickle, so trust still matters for those. - Consistency: retired the last "equivalence set" wording in the examples READMEs (candidate set). Website builds clean; docs-cli-sync passes.
A complete run on a real, public human IGH repertoire, from raw reads to a validated AIRR table. Every number is captured from an actual run; nothing is illustrative. Dataset: Briney et al. 2019 (Nature), ENA/SRA run SRR8283604, BioProject PRJNA406949 - a baseline healthy-donor human antibody heavy-chain repertoire, Illumina 2x250, INSDC free reuse. Pinned to alignair-igh-human@1.0.0. Reproducible and self-contained: the first 2000 read pairs are streamed (no 1.2 GB download), with published md5s for both subsets; a bundled zero-dependency Python merger (merge_pairs.py) overlaps the mates into full VDJ amplicons deterministically (stable md5), so the example runs with nothing but curl and Python. The captured result is the centerpiece: 1945 reads, 0 dropped, 0 failed, 97.8% complete assemblies, validate-airr clean, and 99.6% auto-reverse- complemented by the orientation head (this library's reads are antisense) - with real CDR3s out the other end (CAKNRVAAAGTMFATW, ...). It is honest about the rough edges too: 43 partial (nonproductive_indel), and only 687/1902 complete records productive, attributed correctly to raw reads without UMI consensus plus a demo-grade merge, not to the model - which is the point of the honesty flags. - examples/end-to-end/README.md: validated (alignair commands parse in CI), structured download -> merge -> predict -> inspect -> validate -> summarise. - examples/end-to-end/merge_pairs.py: the bundled merger. - website: pages-tutorial.tsx renders it as the "Worked example" page in Get started (getting-started -> migrating-from-igblast -> worked-example -> concepts); linked from Getting started's Next block. Website builds clean; docs-cli-sync passes (18).
… example Three precision fixes, no new content: - Checksum semantics: state explicitly that the R1/R2 md5s are of the extracted 2000-read subset computed locally, not ENA/SRA's published hashes, which validate the complete ~1.2 GB source files. - Bundled merger: describe merge_pairs.py as deterministic demonstration preprocessing, not a production pipeline - record its parameters (largest overlap >=20 nt, <=10% mismatch, concatenate on overlap), that it drops unmerged pairs (55 of 2000), and that it does no quality-aware consensus or UMI correction. - Call INSDC availability a data-access policy (free reuse), not a software-style license. - Also drop the "398-444 nt" merged-length claim; that was only the upper tail of the histogram, so state the longest reach (~444 nt). Website builds clean; docs-cli-sync passes (18).
Root cause of the unreadable docs: index.html force-added class="dark" to <html> whenever the OS preferred dark mode, but the site is only half dark-mode-aware. The docs pages and shared components carry Tailwind dark: variants (dark:text-slate-300, light text), while the body background is hardcoded light (#fbfbfd) and never flips, and there is no theme toggle to turn it off. Under OS dark mode that produced light-grey text on a light background - the "almost impossible to read" docs. The light palette is the real, contrast-verified design, so the fix is to render light-only: removed the dark-activation script from index.html. The class is now never added, all 68 dark: variants stay dormant, and every page renders in the intended light palette regardless of OS theme. (color-scheme: light already pins UA rendering.) Also fixed the homepage signature-card overlap: the field labels were width:68px, so "junction_aa" overflowed its column into the value. Widened to 92px with flex-shrink:0.
Removed the BrandMark component and its use in the navbar and footer; the brand is now just the "AlignAIR" wordmark.
Add a docs badge and a centered call-to-action under the header linking to the documentation, guides, and interactive lessons at mutejester.github.io/AlignAIR, so new users land on the site to learn.
Align the README with the terminology corrected across the site and examples: *_call_set is a capped, threshold-based candidate set, not an exhaustive equivalence class.
These files become the public PyPI description and citation/package metadata, so they are corrected to match the reviewed website: README: - "in one pass, with no multi-stage heuristic pipeline" overstated the pipeline; the network runs once, then deterministic post-processing produces coordinates, the junction, and the AIRR record. - "largest improvements on short fragments" contradicted the measured results: gains concentrate in D/J and orientation, and V accuracy is comparable to IgBLAST (not better) on short fragments and heavy-SHM full-length reads. Now stated honestly, linked to known failure modes. - alignair validate-airr described/shown as an AIRR-C schema validator; it is a structural check (columns, coordinate/CIGAR bounds, productivity), not the official airr validator. CHANGELOG: - 3.0.0 dated (2026-07-17; update to the actual tag date if it slips). - equivalence set -> candidate set; retired the stale "Material for MkDocs" line (docs are the React/TypeScript site). CITATION.cff: add version 3.0.0 and date-released. conda/meta.yaml: Python floor >=3.10 to match pyproject requires-python (was >=3.9).
…istry Rewrite release.yml so a tag builds one authoritative artifact set, tests it, and publishes those exact artifacts without partial-release risk: - build-wheels (cross-platform matrix) + build-sdist run once; publishing jobs only download those artifacts, never rebuild. - smoke tests one built wheel before any publication. - TestPyPI publish (OIDC, environment testpypi, skip-existing) -> install smoke that pulls AlignAIR from TestPyPI and deps from PyPI. - Draft GitHub Release (contents: write) with all wheels, the sdist, and SHA256SUMS, created before any irreversible publish. - PyPI publish (OIDC, protected environment pypi) and GHCR push run only after the draft exists; the Release is flipped to published only after both succeed. No PYPI_API_TOKEN anywhere. - Container: GHCR, hardcoded lowercase ghcr.io/mutejester/alignair, tag strips the leading v (v3.0.0 -> :3.0.0), built once, smoke-tested in the container, then pushed as :<version> and :latest (packages: write). - wheels.yml stays as the PR/main build gate. website.yml: add a build-only PR check; deployment stays restricted to main. (Requires Pages source = GitHub Actions.) Docs: migrate every Docker reference (README badge + commands, examples, website pages) from Docker Hub thomask90/alignair to ghcr.io/mutejester/alignair.
…/main gate release.yml owns the authoritative release build + publish, so wheels.yml no longer needs to run on release:published (it would rebuild the matrix redundantly). It remains the continuously-green cross-platform build gate for PRs and main.
Release workflow (release.yml): - guard job: refuse to publish unless the tag matches pyproject's version AND the tagged commit is contained in origin/main; a test job reruns the Linux suite on the tagged commit. Nothing builds until both pass. - TestPyPI provenance: instead of installing with a competing --extra-index-url (dependency-confusion surface), download the wheel TestPyPI serves and require it to be byte-identical (SHA-256 + filename) to the authoritative build, then install it with deps from normal PyPI. - Ordering: draft-release -> GHCR (reversible) -> protected PyPI (immutable, last) -> flip the Release to published. The irreversible step runs last. - draft-release is rerun-safe: create if absent, re-upload with --clobber if a draft exists, refuse to touch an already-published release. website.yml: deployment gated to refs/heads/main (a manual dispatch on a feature branch can no longer publish it); PRs still get the build check. Benchmark reconciliation: the eval page, the design-page summary, the training lesson, and the README all cited the older run's aggregate (V 0.745/0.776, "23 of 24", 4,400/22-strata) that the widget correction had already retired. Reconciled to the frozen 2,600-case / 13-stratum dataset used by the widget, verified from the artifact: AlignAIR better on 18 of 24 metrics, gains in D/J and orientation, and V an honest aggregate loss (IgBLAST 0.856 vs 0.828), driven by short fragments and heavy-SHM full-length. Short-fragment V weakness is now visible everywhere. Dates: revert CHANGELOG to "unreleased" and drop CITATION date-released until the tag date is known at finalization (version 3.0.0 kept).
…ding Three evidence corrections + a supply-chain pin. 1. Evidence bundle (benchmarks/bench_v2/): the numbers were embedded only in TSX; now there is an auditable bundle - the full model-comparison report (24 metrics, per-stratum + overall, CIs, verdicts), the case manifest (13 strata, 2600 cases, seed 123, germline reference SHAs, software versions), the generated cases, and SHA256SUMS. A new CI job (benchmark-artifact.yml) validates the report and manifest against the alignair_benchmark artifact contracts and checks the checksums. The bundle README documents the reproduction flow and flags the provenance still missing (evaluated model id/fingerprint/commit; IgBLAST version; cases generated with alignair 2.0.2) - to be supplied or regenerated before it is a complete v3.0.0 record. 2. Point estimates vs statistical decisions: the eval page said "better on 18" while its callout called the counts point-estimate tallies. Reconciled from the artifact: AlignAIR is point-estimate-higher on 18 (IgBLAST on 6); under the Bonferroni-corrected paired bootstrap that is 18 statistically better / 4 / 2 inconclusive, and all 18 AlignAIR-higher metrics are significant. "better" now means a supported verdict, in the eval page, its callout, the README, and the design summary. 3. Reproduction command: the widget said reproduce with `alignair benchmark` (the AlignAIR-only 4-stratum self-check). It now points to the alignair_benchmark harness (build -> evaluate each tool -> compare) and the frozen bundle, and keeps the self-check explicitly separate. Supply chain: pin pypa/gh-action-pypi-publish to commit 76f52bc (v1.12.4) instead of the mutable release/v1 tag.
The source igh_airr_input.tsv used CRLF, which git normalized to LF on commit, so the recorded SHA256SUMS (computed on CRLF) no longer matched the stored blob and the artifact CI checksum check would have failed. Normalize the case files to LF, pin LF via .gitattributes, and recompute SHA256SUMS on the LF bytes. Records are unchanged; results reproduce.
The bench_v2 comparison does not pin which AlignAIR model produced the predictions or the IgBLAST version, so its results cannot be attributed to the v3.0.0 product. Per the decision to re-run before launch, remove all quantitative head-to-head claims and the comparison widget from launch-facing surfaces until the verified rerun exists; keep only qualitative / model-validation statements. - README, Benchmarks page, and the design summary: the "18 of 24", aggregate V/D/J values, and tool-comparison verdicts are replaced with a qualitative "validated on a frozen ground-truth benchmark" statement and a note that a verified v3 head-to-head with full provenance is in preparation. - Benchmarking lesson: the per-stratum comparison widget is removed and the step reworked to teach how to read a benchmark (per-stratum, point-estimate + interval) without publishing comparative scores. The self-check example JSON is labelled illustrative. - BenchSandboxWidget is dropped from the widget barrel and carries a do-not-republish header; the file is retained for the verified rerun. - benchmarks/bench_v2/ is relabelled ARCHIVAL / pre-v3.0.0 with a status banner; its cases remain canonical, its comparison is not v3-attributable. Added comparisons/RERUN.md: the target layout, exact AlignAIR + IgBLAST commands, the provenance to capture, and the rule that published numbers are regenerated from comparison_report.json. Website builds clean; docs-command gate passes; bundle checksums verify.
1. Python 3.10: test_conda_recipe imported tomllib (3.11+). Fall back to tomli, and add `tomli; python_version < "3.11"` as a dev/test dep. 2. WFA fallback: get_aligner() returned WFAAligner without checking that pywfa is importable (the native import is lazy, so it failed only at align() time). It now probes wfa_available() / parasail_available() before selecting each backend. 3. Apple Silicon: parasail ships no arm64-macOS wheel, so `AlignAIR[cli]` tried to compile it and failed. Add a pure-Biopython fallback aligner (biopython is already a core dep) as the final link in the chain WFA -> parasail -> Biopython, and exclude parasail from [cli]/[reader] on Darwin/arm64 via an environment marker so the default Apple Silicon install succeeds and uses the fallback. parasail stays wherever a binary wheel exists (Linux, Windows amd64, macOS x86_64). 4. Windows 32-bit: cibuildwheel was producing win32, which PyTorch does not support. Add *-win32 to the skip list; win_amd64 stays. 5. Conda: `conda render` was removed from modern conda. Use `conda-build conda/ --output` (renders without building). Tests: new test_bio_fallback.py covers the clean-environment path (no pywfa, no parasail -> Biopython) and the AlignResult contract. Full suite 746 passed; env markers verified (parasail excluded only on Darwin/arm64).
…ass)
The dual-mode recipe used a top-level Jinja set-preamble plus environ to
switch between local (path) and PyPI (url+sha) source. Modern
conda-build's second rendering pass drops those preamble variables, so
`local_build` went undefined -> the PyPI branch ran -> `version` was
undefined -> `conda-build --output` failed.
Simplify conda/meta.yaml to a literal, local-source recipe: no top-level
Jinja variables, no environ, inline version, `source: path: ..`. It now
renders identically on both passes (there is nothing context-dependent
to lose). The eventual Bioconda recipe (published sdist url+sha, and
GenAIRR on a conda channel) is separate future work, noted in the recipe.
Also removed a `{% set %}` sequence that was sitting inside a YAML
comment - jinja2/conda-build parse the whole file, so that literal
delimiter was itself a render error.
Dropped the now-vestigial ALIGNAIR_LOCAL_BUILD env from the CI step;
updated test_conda_recipe to assert the literal/stable render.
registry/sources.py imported tomllib directly to parse config.toml. The import is lazy (only when a config file exists), so smoke tests never hit it, but on Python 3.10 (no stdlib tomllib) reading a registry config raised ModuleNotFoundError at runtime. Move a module-scope `try: import tomllib except ModuleNotFoundError: import tomli as tomllib` to the top of sources.py, and add `tomli; python_version < "3.11"` to the CORE dependencies (not just dev) - reading the registry config is runtime functionality. This was the only remaining direct tomllib import under src/. The redundant [dev] entry is dropped (core is inherited there).
_excl_lock() only caught FileExistsError. On Windows, opening the lockfile with O_EXCL while another holder has it open raises PermissionError (a sharing violation: WinError 32/5 -> errno 13), not FileExistsError, so a waiting thread crashed instead of polling. This surfaced under real contention (test_excl_lock_serializes_concurrent_holders). Catch PermissionError too and route it through the existing poll/stale-reclaim/timeout path, but ONLY when the lockfile actually exists - a genuine permission failure (the path cannot be created) still propagates immediately rather than spinning to timeout. Regression tests simulate both: a Windows-style PermissionError while the lockfile exists (must be treated as contention, not a crash) and a PermissionError with no lockfile (must surface as PermissionError, not TimeoutError).
MuteJester
marked this pull request as ready for review
July 18, 2026 12:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release candidate for v3.0.0 — a complete PyTorch rewrite of AlignAIR (the
alignairpackage), replacing the legacy TensorFlow lineage.Highlights
alignairCLI (predict / train / demo / models / reference / convert / validate-airr / compare / genotype / doctor / benchmark)..alignairmodel format with an embedded, fingerprinted germline reference; pretrained human IGH, IGK+IGL, TRB.Status: draft — not merge-ready yet
Opened to start remote CI. Outstanding before merge/tag:
pypi/testpypienvironments configured.