Conversation
nrminor
force-pushed
the
v3.3.0-rc
branch
17 times, most recently
from
July 14, 2026 22:12
ffef836 to
964587d
Compare
nrminor
force-pushed
the
v3.3.0-rc
branch
4 times, most recently
from
July 19, 2026 14:36
ef95a63 to
5bbfbe1
Compare
Collaborator
|
More LIMS side refactor commits coming tomorrow. I am having to reorder some of the steps towards the end of the BLAST step like Stacking blast results after ADD_READ_COUNTS_TO_BLAST which is necessary row level info for blast uploads. On the LIMS side it looks like we only need to update the schema in one place: The fasta reports for each query on the LIMS side will be limited to only contigs (both short and long) to prevent blowing up prod lists. I am also attempting to build a just e2e-labkey test but if LK permissions are too much of a pain I may have to ditch this idea. |
nrminor
force-pushed
the
v3.3.0-rc
branch
2 times, most recently
from
August 3, 2026 19:33
4f9db6c to
edfa1ea
Compare
When BLAST tasks disagree for one contig, select rows with the highest bitscore and then the lowest e-value before checking taxonomic consistency. Continue to fail on equally strong conflicting assignments instead of selecting one by input order.
Assign DEACON_UNION_INDEXES and ANNOTATE_LEAST_COMMON_ANCESTORS to the existing medium process profile. These operations can exceed the low profile's memory allocation on larger indexes and BLAST result sets, so request the resource class that matches their observed requirements.
Configure Clumpify to perform exact sequence deduplication instead of treating dedupe=2 as a disabled boolean. Disable optical-name matching, substitutions, N-containing matches, and optional pair reordering so duplicate decisions depend on sequence content while interleaved mates remain adjacent.
Force BBDuk to interpret known interleaved batches as paired input and remove the complete pair when either mate is rejected. Mark single-read batches explicitly as unpaired so SRA-style spot suffixes do not control pairing heuristics.
Construct the final LabKey log collection only when LabKey integration is enabled. Avoid eagerly creating the LabKey upload log directory for runs that cannot produce LabKey artifacts. Preserve the existing final-log collection and storage behavior for LabKey-enabled runs.
Replace separate BLAST and Big Table stackers, and the inline experiment concatenation, with one Polars-backed utility. Sort inputs deterministically, validate matching headers and known numeric fields, and stream concatenated output with bounded memory. Rename the per-sample and experiment processes around their result scope, update publication selectors and reporting wiring, and remove the obsolete pre-enrichment stack process. Test focused ordering, empty-input, schema, path, and numeric-validation contracts. Exercise final BLAST equivalence through the importable main API with production-equivalent arguments, and verify in the end-to-end suite that aggregate result tables contain their ordered per-sample rows.
…d machinery Skip re-inserting a (sample, query_class) batch into the LabKey hits list when it is already present there, using the list itself as the completion ledger instead of a separate experiment-ID guard list. Removes the guard check/register processes and script, uploads each batch in a single atomic insert, and reconciles the per-batch LIMS wiring left over from the earlier per-read-type enrichment split.
… on insert error Re-include both WebDAV upload-done signals in the LabKey upload-completion gate so Slack cannot fire before those uploads finish, quote the --csv argument for consistency with sibling flags, and make a failed row insert exit non-zero (after retries) instead of logging an error while still reporting success.
Adds LABKEY_WEBDAV_UPLOAD_QUERY_FASTA to upload each per-read-type query FASTA (contig, merged, single) that was actually BLASTed, both to WebDAV and under the results dir, threading the batch FASTAs from PREPARE_BLAST_QUERIES through REPORTING into LIMS_INTEGRATION.
…PLE_BLAST_RESULTS Route the LIMS_INTEGRATION per-sample BLAST feed through the consolidated per-sample concatenation output via a dedicated multiMap branch.
Both upload scripts duplicated the destination-list presence check (with the QueryFilter -> filter-string fallback) and the single atomic insert. Move them to py_nvd.labkey_io so the two scripts delegate to one implementation.
Gate a real-LabKey run on an nvd preset (LabKey coordinates) plus the LABKEY_API_KEY Nextflow secret; skip when the preset is absent and fail with a clear message when it exists but a coordinate or the secret is missing. Use a random experiment_id, assert the first run inserts per-batch hits carrying query_class, and assert a rerun adds no rows (dedup on the hits and FASTA lists). Keep the run's rows and WebDAV files by default so they can be inspected (NVD_TEST_LABKEY_KEEP=0 removes them and the experiment's WebDAV directory on exit). Run it with 'just e2e-labkey' (streams progress, and prompts securely for LABKEY_API_KEY when the secret is unset), mirroring the other e2e targets. Parameterize the shared LabKey run helper so the mock and real tests reuse it.
Without --experimental only short_assembly_contig is produced, so the LIMS e2e never exercised the per-query-class split it exists to verify. Turn on experimental (with --merge_pairs and the sourmash fixtures) so the run also emits overlap_merged_pair and single_read, and assert both a contig class and a read-derived class reach the destination list in the mock and real tests.
…IMS e2e NVD_TEST_LABKEY_EXPERIMENT_ID pins the experiment id (default random) and skips the pre-clean, so a rerun against an id that already has rows verifies the check-ahead skips duplicates across invocations. NVD_TEST_LABKEY_EXPERIMENTAL=0 runs contig-only (faster, short_assembly_contig only); the read-class assertion is gated on experimental so it holds either way.
The urllib WebDAV test relied on the SSL_CERT_FILE env var to trust the mock's self-signed cert, but that is only honored if set before the process's first SSL context is created -- unreliable in a shared pytest process (passed on macOS, failed on Linux CI with CERTIFICATE_VERIFY_FAILED). Pass an explicit ssl context built from the mock cert to urlopen instead, so trust is deterministic and no process-global env state is touched.
CI has no LabKey credentials or secret store, so both LIMS end-to-end tests
(the mock and the real) are marked 'labkey' and run only via 'just e2e-labkey'.
The 'just e2e'/'e2e-test-ci' selection ('slow and network and not labkey') is
thus the SRA test only, as it was before the LIMS work; 'just e2e-labkey' uses
'... and labkey'. The self-contained mock-server unit tests still run in the
fast suite.
This was referenced Aug 5, 2026
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.
This is a big one. TL;DR: v3.3.0 refactors the entire pipeline around a paradigm henceforth referred to as "query classes," where each query class can be come its own parallelized shard within the nvd workflows.
The idea behind query classes
Before v3.3.0,
nvdcollapsed all reads into whatever contigs SPAdes gave us. These contigs were then QC'd and then sent into big BLAST searches against Core NT.This system works well in that the relatively small number of contigs that fall out of each sample's reads put a low bound on the query search space that BLAST has to contend with. Its downside is that it introduces yet another significant risk of sensitivity loss/false negative introduction. If the assembler can't resolve contigs for a given read, it will simply be lost as a potential fragment of interest and will never be searched against Core NT.
If you're working with a clinical sample where most taxa are expected to have good whole-genome representation, this is unlikely to pose a problem. Most reads will come from those well-represented genomes, giving the assembler plenty of grist to collapse down into representative contigs.
But if your library is highly fragmented, many reads will come from sheared genomes that simply don't have the read representation they'd need to resolve into contigs. These genomes, and the taxa they stem from, will thus be lost in the old
nvdparadigm. Despite its claims to be tuned for use on sheared environmental samples, this was a major weakness fornvd, and in many cases it led to visible under-sensitivity compared to other pipelines, e.g.,nao-mgs.Version 3.3.0 introduces an elegant solution to this problem and refactors the entirety of the pipeline around that solution. Rather than all queries being contigs,
nvdnow tracks whether a read resolved into a contig or not, and also whether a read pair was merged into a consensus read. Each of these kinds of queries (hence, "query classes") then becomes its own BLAST input. For a given sample, contigs will be searched in their own BLAST process. But merged reads that didn't resolve into a contig will also get searched in their own BLAST instance, as will single reads. Retaining reads that were not captured in any of the contigs almost entirely restores sensitivity that was lost in the previousnvdparadigm.Query classes are still experimental and have a downside
This feature remains experimental (gated behind
params.experimental == true); running in the old paradigm still works and remains exercised in our end-to-end testing. That said, this new paradigm is transformative enough that we expect to make it the only run mode supported bynvd.The major downside to searching many more query sequences in BLAST is that you're now searching many more query sequences in BLAST, and thus
nvdas a whole has potential to take 1.5 to 2 times longer. To maintain the fastest possible reporting turnaround, we've thus adjusted our LabKey LIMS integration to upload BLAST results as they become available rather than waiting until all query class searches have finished. With this adjustment, contig-based results still upload more or less as quickly as they did pre-v3.3.0. High-sensitivity read results will become available later as their respective searches complete.Enabling future feature releases
Query classes also come with a variety of sidecar artifacts that give observability into how query sequences are routed into each of the query classes, with summaries provided at various stages of the pipeline where query classes for each sample are handled in parallel. This helps build toward upcoming changes in v3.4 that enhance the information
nvdreports to users.In addition, v3.3.0 brings a significant semantic reorganization of the results directory in hopes of empowering more intuitive exploration of results by users.
Overall, if cv3.2.0 was the "CRUMBS release", v3.3.0 is the "query classes" release. This all builds toward producing a reimagined results reporting system in #46, which will be up next!