Skip to main content

Fast fuzzy search over biological sequences (C++ core, Python bindings)

Project description

seqtree

PyPI Python License CI Docs

Fast fuzzy search over biological sequences (amino-acid or nucleotide), as a C++ core with a minimal Python binding. Build an immutable index once, then search single queries or massive batches in parallel.

Two search engines over one trie:

  • seqtm — branch-and-bound enumeration. Exact per-type edit caps (max_subs / max_ins / max_dels) and a fast Hamming-only path. Best for small edit distances (UMI collapse, error correction, CDR3/epitope matching).
  • seqtrie — full-width edit-distance DP carried down the trie. Honours the max_penalty score budget only; it ignores the per-type edit caps. Use it when the budget is the whole specification.

engine="auto" always picks seqtm, because it is the only engine that enforces the caps you asked for. Results are payload-agnostic: (ref_id, score, n_subs, n_ins, n_dels). Downstream libraries map ref_id back to their own payloads (V gene, MHC, counts) and filter.

Beyond search, seqtree ships:

  • Substitution matrices — built-in identity, BLOSUM45, BLOSUM62, BLOSUM80, PAM250, PAM100, and structural — a Miyazawa–Jernigan interaction-strength matrix: each residue's strength q(a)=mean_b e(a,b) is read off the MJ contact potential, so substitutions between residues of like interaction strength are cheap. It separates strong (hydrophobic F W C L Y M I V) from weak (polar/charged S Q D E K) interactors — the strong/weak-interactor axis of TCR-recognition models (Košmrlj et al., PNAS 2008; MJ contact energies from Miyazawa & Jernigan, J Mol Biol 1996) — letting dissimilar-but-chemically-equivalent loops align. Plus custom matrices via SubstitutionMatrix.from_similarity (Gram penalty s(a,a)+s(b,b)−2·s(a,b)).
  • E-values / significance — calibrate hit counts against a background control repertoire (load_control + evalues), the TCRNET approach on a finite-sample footing. See the E-value guide.
  • Calibrated cutoffsthreshold_for_evalue inverts the E-value into the score cutoff that achieves it, per query. A fixed cutoff is not a calibrated one: a control repertoire is dense near germline and sparse among rare junctions, so the same threshold buys a common query far more chance neighbours than a rare one.
  • Gap-block alignmentgapblock restricts alignment to one contiguous indel, which is the right model for a V(D)J junction and, measured against unrestricted affine alignment, is exactly optimal on 98.8% of genuinely related pairs at a calibrated gap_open. A gap prior (central_prior, profile_prior, frame_prior) chooses where the block goes — a sequence score alone cannot. score_matrix scores a whole query set against a whole reference set in one GIL-released C++ call (532 M pairs/s on 16 cores; numpy.asarray wraps the result with no copy), the shape a prototype-distance embedding needs.
  • Pairwise alignment without BioPythonseqtree.pairwise is Needleman–Wunsch (mode="global") and Smith–Waterman (mode="local") with affine or linear gaps, on the raw log-odds scale. It is a drop-in for Bio.Align.PairwiseAligner — verified against it as an oracle across three matrices, ten gap/mode settings and sixty sequence shapes with zero disagreements — and 65–87× faster, since there is no Python in the per-pair loop. dist_matrix gives d = s(a,a) + s(b,b) − 2·s(a,b) directly. BioPython is a test-only dependency; seqtree still needs nothing at runtime.
  • Plain edit distancesseqtree.distance is unweighted hamming and levenshtein (unit costs, no matrix, no alphabet) for when you just need a number, not a scored alignment. hamming_matrix / levenshtein_matrix score a whole set against a whole set in one GIL-released C++ call (numpy.asarray wraps the result with no copy) — no python-Levenshtein or rapidfuzz dependency needed. Hamming requires equal lengths (it raises otherwise); comparison is case-sensitive.
  • Island profilesIslandProfile.fit builds a position weight matrix over a set of frame-aligned junctions (an island) and scores a query column by column against the island consensus, as a non-negative penalty that flows through threshold_for_evalue unchanged. At a repertoire-scale cutoff it recovers 48.5% of held-out members against 37.6% for min-over-members; at a loose cutoff the two are indistinguishable, so it earns its keep only where the cutoff is strict.

Install

pip install seqtree       # prebuilt wheels for CPython 3.10–3.13

Prebuilt wheels cover Linux x86-64, macOS arm64 (Apple Silicon), and Windows x86-64. There are no Intel/x86-64 macOS wheels — Intel Macs build from source (see below), which just needs a C++17 compiler and CMake (pulled in automatically by the build).

Build from source

bash setup.sh            # repo-local .venv + editable install
bash setup.sh --tests    # + pytest
bash setup.sh --bench     # + benchmark deps (huggingface_hub, psutil)

Quickstart

import seqtree

idx = seqtree.Index.build(["CASSLAPGATNEKLFF", "CASSLELGATNEKLFF"], alphabet="aa")

p = seqtree.SearchParams(max_subs=2, engine="seqtm")
for hit in idx.search("CASSLAPGATNEKLFF", p):
    print(hit.ref_id, hit.score, hit.n_subs)

# parallel batch (releases the GIL)
results = idx.search_batch(queries, p, threads=0)   # 0 = all cores

# matrix-weighted budget
pm = seqtree.SearchParams(matrix="BLOSUM62", max_penalty=12, engine="seqtrie")
top = idx.search_top("CASSLAPGATNEKLFF", pm, k=5)

# alignment on demand
aln = idx.align(0, "CASSLELGATNEKLFF", p)
print(aln.aligned_query, aln.aligned_ref, aln.ops)

# batch-vs-batch (auto-indexes the larger set)
pairs = seqtree.pairwise_batch(query_set, db_set, p, alphabet="aa")

# E-values against a background control repertoire (TCRNET-style significance)
control = seqtree.load_control("human_trb_aa", size=1_000_000)
target = seqtree.Index.build(vdjdb_cdr3s, alphabet="aa")
for q, r in zip(queries, seqtree.evalues(target, control, queries, p)):
    if r["p_enrichment"] < 1e-3:
        print(q, r["E"], r["n_target"], r["n_control"])

# ...and the cutoff that achieves a target E, per query (-1 = unreachable at this control size)
ceiling = seqtree.SearchParams(max_subs=14, max_penalty=50, matrix="BLOSUM62", engine="seqtm")
thetas = seqtree.threshold_for_evalue(target, control, queries, ceiling, e_target=0.05)

# one contiguous gap block, placed by a prior rather than by the score alone
from seqtree.gapblock import GapBlockIndex, central_prior, embed_in_frame

gbi = GapBlockIndex(cdr3s, "aa", d_max=2)
mat = seqtree.SubstitutionMatrix.blosum62()
for ref_id, score, block_len, block_pos in gbi.search(
        "CASSLGQAYEQYF", 40, mat, gap_open=2 * mat.scale(),
        gap_prior=central_prior(int(1.5 * mat.scale()))):
    ...

# a fixed frame column makes gap placement transitive -- and a column index, hence a PWM, possible
embed_in_frame("CASSGQAYEQYF", width=14, c=4)      # 'CASS--GQAYEQYF'

# a whole query set vs a whole reference set, in one GIL-released C++ call
from seqtree.gapblock import score_matrix, IslandProfile
sm = score_matrix(clonotypes, prototypes, mat, gap_open=2 * mat.scale(), threads=0)
import numpy as np
distances = np.asarray(sm)                          # (len(clonotypes), len(prototypes)) int32, zero-copy

# a position weight matrix over an island, still a non-negative penalty (feeds threshold_for_evalue)
profile = IslandProfile.fit(island_members)
profile.score("CASSLGQAYEQYF")                      # 0 on the consensus, > 0 for deviations

# ordinary pairwise alignment -- Needleman-Wunsch / Smith-Waterman, no BioPython
from seqtree.pairwise import align, score, dist_matrix
score("CASSLGQAYEQYF", "CASSPGQAYEQF", mat)                    # global, BLAST defaults (11/1)
score("WWWAAAWWW", "KKKAAAKKK", mat, mode="local")             # Smith-Waterman
score("AAA", "AAAAA", mat, gap_open=5, gap_extend=5)           # linear gaps: open == extend
aln = align("CASSLGQAYEQYF", "CASSPGQAYEQF", mat)              # + aligned strings and ops

d = np.asarray(dist_matrix(v_genes, v_genes, mat, threads=0))  # s(a,a)+s(b,b)-2s(a,b), zero diagonal

# plain edit distances -- unweighted Hamming / Levenshtein, no matrix, no dependency
from seqtree.distance import hamming, levenshtein, hamming_matrix, levenshtein_matrix
hamming("CASSLGQYF", "CASSPGQYF")                             # 1  (equal length only)
levenshtein("kitten", "sitting")                             # 3
h = np.asarray(hamming_matrix(umis, umis, threads=0))        # (len, len) int32, zero-copy

Tests

cmake -S . -B build -G Ninja -DSEQTREE_TESTS=ON
cmake --build build
ctest --test-dir build           # C++ unit tests
pytest tests/python              # Python tests

Benchmarks

python bench/bench_gnuplot.py        # throughput / scaling / matrix / collisions → SVG (needs gnuplot)
python bench/bench.py                # recall vs ground truth (real VDJdb data)
python bench/bench_evalue.py         # true E-value benchmark (target vs background control)
python bench/bench_evalue_matrix.py  # significance across reference/control/query/scope grid
python bench/bench_epitope.py        # epitope detection-complexity (GIL vs NLV)
python bench/bench_gapblock.py       # the gap-freedom ladder: fixed centre → prior → flat → affine
python bench/bench_score_matrix.py   # dense batch gap-block throughput (µs/pair, M pairs/s, RSS)

Figures (throughput, scaling, matrix-scoring overhead, collisions, E-value matrix, epitope detection) and the full methodology are in the benchmarks docs. Set RUN_BENCHMARK=1 for the large tiers.

Development

This repo follows git-flow:

  • master — stable, release-ready; CI + docs deploy run here.
  • dev — integration branch for day-to-day work.
  • feature branches branch off dev and merge back via PR; releases merge devmaster.

Roadmap (affine gaps, position-specific matrices, succinct memory packing) lives in docs/roadmap.rst. Control-set E-values already ship — see the E-value guide.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

seqtree-0.6.0.tar.gz (1.8 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

seqtree-0.6.0-cp313-cp313-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.13Windows x86-64

seqtree-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

seqtree-0.6.0-cp313-cp313-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

seqtree-0.6.0-cp312-cp312-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.12Windows x86-64

seqtree-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

seqtree-0.6.0-cp312-cp312-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

seqtree-0.6.0-cp311-cp311-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.11Windows x86-64

seqtree-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

seqtree-0.6.0-cp311-cp311-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

seqtree-0.6.0-cp310-cp310-win_amd64.whl (1.6 MB view details)

Uploaded CPython 3.10Windows x86-64

seqtree-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

seqtree-0.6.0-cp310-cp310-macosx_11_0_arm64.whl (1.6 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file seqtree-0.6.0.tar.gz.

File metadata

  • Download URL: seqtree-0.6.0.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seqtree-0.6.0.tar.gz
Algorithm Hash digest
SHA256 61debe2628bcdc555fa1502e034f9d922772ba76e79ab8dc38f25f8b9a8095d7
MD5 b16e237d585a6391f07b75f1758e0d3e
BLAKE2b-256 c0e616645e28b4bf89d8bcfe9a4d69dd4830a52a9be86e8e7b63edb4125ede56

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0.tar.gz:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: seqtree-0.6.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seqtree-0.6.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 2ce12d911f4b60f60545867d46a7d71d3b1cf77cd74e1048fe54fafa5de6b0be
MD5 c5ea5ebb0799d222fa80c92400e05ca7
BLAKE2b-256 681c8bf07b2092f069ad2e5c30218ec9be82497b5bcbd2e2a7f56d30923adc21

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp313-cp313-win_amd64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 06331ee3de5bdd89d96aeb72a0a2a0c853ef7f8bfc69b89e9fd723ec18477880
MD5 9a7e2dea9cc1fbb23e29e903e53b8fbf
BLAKE2b-256 a961a4acc7494abade5d69686f92f2b1d497bf62ff203bb8440ccd6e4f200e9d

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1499fb561cd5490dfbebcd93050fb84dbe90025af66d4a268024c7f25031b0c3
MD5 adfd446ebd47ef5cc25587414eaf2a40
BLAKE2b-256 f169db1d5b05805b6bc750854e27e499424b3f3bc2479df74c670be31509cc4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: seqtree-0.6.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seqtree-0.6.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 4f945a83faa241a0bc50de55b0a5ae31b5d34e7c7ca3e97c52110a7085f9694a
MD5 913d420bf959e32ce4d10a8b6cb79096
BLAKE2b-256 74039330eb028a64bf605a1ce30f0b82ef3051e4ca573fe213338954c982be88

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp312-cp312-win_amd64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6cd31859e499df270c55285c2bd05f52167a0b3493d3b762f5975a655a6ccf0c
MD5 5a9aa94f0564939280ceddf2b79e84d5
BLAKE2b-256 059c4e495d52197336606e78aa38ae293253f6087d80fadfb0688171ae031f50

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 72172317e879042f85c020aab844497c8e025f2f5849e1134a016b732d5ee056
MD5 8c14663cb8e215484540f6ffc55c0111
BLAKE2b-256 b527d69b777ff79419c0a3c8a6a420263909723b3c57133a5ab5f12f8c8e4c82

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: seqtree-0.6.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seqtree-0.6.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 771bc6c124304c3a60482c5d9c43baac6060c9ea9f4c6fcddd304391504cde1c
MD5 b627a20f113a7a3b9fe198aabd4c05e7
BLAKE2b-256 4d2761b0af990b0c5ac8cc27835c19aee09d79abdd71037353d5bd858c8d1ab0

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp311-cp311-win_amd64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eec3ba8a47c097f6309ced8ef8e500f69d7192c7c7691f89a9a713e1d4d75bb9
MD5 2317b6aaa4da96b9d18439303e271800
BLAKE2b-256 7937b2b003c4e6ab31c49be75e69107c7c7cf70aceb0106d3cb7eb30fee4b49a

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2615fbe5174c0e39f1b8ccc011c2158cd5d96c6a282ef3df5e399a57195908b4
MD5 471755138253ecad83d2442df76bd223
BLAKE2b-256 2ded9e6552de4b280bf542441163dc663464d6bafff648b7bc941572cb30c8ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: seqtree-0.6.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seqtree-0.6.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 3adc5cf60400b8d67b91421723b9fba45823620da1021f440916edfffc31224a
MD5 6360f14a5bcb5c030ffb1b9ffa4e7665
BLAKE2b-256 8805a19c78b40d3e57855d5a2d6f4395c3e8ca1fbc953b935b4407b69905a2b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp310-cp310-win_amd64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 bc2e078fff952163e7678041fd1d834c56a88a0d413737868603256d3fb8e04b
MD5 38c3ae01b6437bd07ede2d01aaac8764
BLAKE2b-256 b265d50893444160e5c4c87065d577493b74f09c0de735dc10b00a5781416c37

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file seqtree-0.6.0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for seqtree-0.6.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3823ae1e639c0f23d8721783d46e13c5672999537d02e774f9499d65571deda8
MD5 6a156a131d26e9d4c7240b9e9a3b0684
BLAKE2b-256 c82c351faf3e74a2f3c63d22e83068994d42f16df015a071f801843562f96283

See more details on using hashes here.

Provenance

The following attestation bundles were made for seqtree-0.6.0-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: publish.yml on antigenomics/seqtree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page