Conversation
Scaffold the VEP annotation crate (Phase 1) with: - allele.rs: VCF↔VEP allele conversion (vcf_to_vep_allele, allele_matches) and match_allele/vep_allele scalar UDFs - coordinate.rs: CoordinateNormalizer for 0-based/1-based coordinate system detection via schema metadata, with FilterOp selection - schema_contract.rs: variation cache schema validation, default column definitions, and column list parsing - lookup_provider.rs: LookupProvider that generates interval join SQL against a variation cache table with allele matching post-filter - table_function.rs: lookup_variants() UDTF with argument parsing (vcf_table, cache_table, optional columns, optional prune_nulls) - lib.rs: register_vep_functions() and create_vep_session() building on bio-function-ranges' BioQueryPlanner with IntervalJoinExec Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oin filter The IntervalJoinPhysicalOptimizationRule failed to recognize interval joins when the join filter contained additional predicates beyond the two range conditions (e.g. match_allele UDF in lookup_variants). The parser expected exactly two BinaryExpr children under a top-level AND, but filters like `a.end >= b.start AND a.start <= b.end AND match_allele(...)` produce a nested AND tree with three leaves. Changes: - Add flatten_and() to recursively collect leaf predicates from AND trees - Rewrite try_parse() to iterate leaves and skip non-range predicates - Change IntervalBuilder methods from panic to Result for graceful handling of duplicate bounds and missing fields - Add integration test confirming lookup_variants produces IntervalJoinExec - Add unit tests for extra-predicate and no-range-predicate cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…for VEP lookup VCF (small) is now the build side and cache (large) is the probe side. LEFT JOIN ensures all VCF variants appear in output with NULLs for unmatched cache annotations. Cache rows with all-NULL annotation columns are pre-filtered via subquery before probing. Changes: - IntervalJoinExec: matched_build_rows bitmap, EmitUnmatchedBuild state, single-partition probe for LEFT joins - lookup_provider: FROM vcf LEFT JOIN cache ON ..., NULL pre-filter subquery - Tests for LEFT JOIN semantics and NOT NULL pushdown verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts the DF 52.1.0 upgrade (Cargo.toml, Cargo.lock, pileup dep pin, CLAUDE.md). Fixes create_hashes signature (&mut Vec<u64> in DF 50). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DataFusion 50+ reads parquet strings as Utf8View by default. Treat Utf8, Utf8View, and LargeUtf8 as interchangeable in schema validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensembl VEP cache uses bare chromosome names (1, 22) while VCF files may use chr-prefixed names (chr1, chr22). Detect the mismatch at scan time and wrap the VCF side in a subquery that strips the prefix, keeping the equi-join as plain column equality so IntervalJoinExec is preserved. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no columns argument is passed, return all cache columns except coordinate columns (chrom, start, end) and source_* bookkeeping columns, instead of a hardcoded 3-column default. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
IntervalJoinExec stored the JoinFilter but never evaluated it, causing row explosion when joining VCF against VEP cache — overlapping cache entries at the same position passed the interval check but should have been rejected by allele matching. Add apply_join_filter() and filter_result_batch() helpers that evaluate the filter expression on matched row pairs and update the LEFT JOIN bitmap only for surviving matches. The filter is applied at all four batch-emission sites (streaming, low-memory continuation, low-memory complete, and full-batch paths). For CoitreesNearest and CoitreesCountOverlaps the filter is skipped via effective_filter(), since these algorithms have semantics that conflict with the range overlap predicates typically present in the JoinFilter. When no filter is present (the common case), the overhead is negligible: one function call plus two None-branch checks, with the batch returned as-is without copying or allocation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…missing REF check Two issues caused ~7% extra rows (4,345,025 vs VEP's 4,048,342): 1. Coordinate system mismatch: VCF uses half-open intervals [start, end) while VEP cache uses 1-based closed [start, end]. The symmetric weak overlap (>=, <=) caused VCF [100, 101) to match cache entries at both position 100 AND 101. Fixed by using asymmetric overlap (>, <=) which correctly handles half-open vs closed intervals. 2. Missing REF allele verification: match_allele() only checked the ALT allele, allowing false positives where a cache entry had the same ALT but different REF (e.g. "C/G" matching a VCF A->G variant). Added REF allele check supporting both VEP-format and VCF-format allele strings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The JoinFilter application added in a609a2c evaluated ALL filter predicates on every output batch, including the range overlap conditions (a.end >= b.start AND a.start <= b.end) that the interval tree already enforces. This caused ~50% performance regression for range table providers (overlap, merge, etc.) where the filter contains only range predicates. Now effective_filter() walks the filter's AND-tree and returns None when every leaf is a BinaryExpr (comparison already handled by the tree). The filter is only applied when non-range predicates are present — e.g. UDF calls like match_allele() in VEP lookups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VEP caches contain duplicate rows on (chrom, start, end, allele_string) with different variation_name values (e.g. dbSNP + COSMIC IDs at the same position). This caused ~1,133 extra output rows vs VEP's output. The cache subquery now GROUP BYs on the join key columns: - variation_name: STRING_AGG(DISTINCT ..., ',') to comma-concatenate all co-located variant IDs, matching VEP's Existing_variation format - Other annotation columns: MAX() (values are identical across dupes) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GROUP BY was inside the cache subquery (before the join), which only collapsed duplicates with the same allele_string. A VCF variant matching multiple cache entries with different allele_strings would still produce multiple output rows. Restructured to GROUP BY all VCF columns AFTER the LEFT JOIN, matching VEP's one-row-per-variant semantics. Added plan assertion verifying AggregateExec sits above IntervalJoinExec. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The post-join GROUP BY turned the streaming IntervalJoinExec pipeline into a blocking operation with high memory usage (had to accumulate all join results before aggregating). Removed the GROUP BY entirely. Cache duplicates (~0.03% extra rows from entries with identical position+allele but different variation_name) pass through as separate rows. This is a conscious trade-off: streaming performance over exact VEP row-count parity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add new `bio-function-vep-cache` crate providing a window-based KV cache backend using fjall LSM-tree storage. This replaces full Parquet scans (~1B entries) with targeted window lookups, reducing cache loads from ~6M per-variant to ~3K per-window per sample. Key components: - key_encoding: canonical chromosome ordering with (chrom, window_id) keys - kv_store: fjall wrapper with Arrow IPC serialization (LZ4 compressed) - loader: parallel Parquet-to-fjall ingestion (per-chromosome parallelism) - cache_exec: KvLookupExec streaming ExecutionPlan with LEFT JOIN semantics - cache_provider: KvCacheTableProvider with auto-detection via downcast - allele_index: per-window position index with injected matcher functions Integration with bio-function-vep via optional `kv-cache` feature flag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split monolithic Arrow IPC windows into compact binary position index (for probing) + per-column Arrow IPC entries (loaded on-demand), reducing deserialization waste from 256x amplification to near-zero. New APIs: - VepKvStore::open_with_cache_size(path, bytes) — custom fjall block cache - VepKvStore::create_with_options(path, schema, ...) — full fjall tuning - KvCacheTableProvider::open_with_cache_size(path, bytes) - PositionIndex: compact binary position index (from_batch/to_bytes/from_bytes) - Format v1: EntryType-based key encoding (position index + per-column entries) Benchmark (chr1, 319K variants, 88M cache rows): - v0 baseline: 29.7K variants/s (12T, 32MB cache) - v1 default: 149K variants/s (4T, 32MB cache) — 5x faster - v1 tuned: 227K variants/s (6T, 4GB cache) — 7.6x faster Default fjall block cache raised from 32MB to 256MB. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-chromosome SQL queries with partition-level parallelism. Instead of discovering chromosomes and issuing 25+ separate queries, create a single physical plan and execute each DataFusion partition concurrently with per-window locking for safe concurrent writes. - Add WindowLocks for per-window tokio::sync::Mutex coordination - Add split_batch_into_windows() using arrow::compute::take() - Add flush_with_lock() for lock-guarded window writes - Replace load_chromosome() with load_partition() - Change parallelism from fixed 25 to optional cap (None = no limit) - Add target_partitions CLI arg to load_cache example - Add tests for multi-partition loading and concurrent cross-window indels Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-partition flush (read-modify-write amplification causing indefinite hangs on real data) with two-phase approach: - Phase 1: parallel partition reads into SharedWindowBuffers (in-memory) - Phase 2: sequential single-pass flush of each window to fjall Removes WindowLocks, flush_with_lock, load_partition, FLUSH_THRESHOLD. Adds SharedWindowBuffers, read_partition. Net -60 lines. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move IPC serialization to parallel spawn_blocking tasks and use fjall's Batch API to reduce L0 compaction pressure. Three-phase approach: 1. Parallel read: partition streams → shared window buffers 2. Parallel serialize: spawn_blocking per window (IPC + LZ4) 3. Batched write: 100-window batch commits to fjall chr22 benchmark (15.1M variants, 78 cols): Before: ~31s (21s flush with L0 stalls from 309K individual inserts) After: ~19s (6s serialize+write phase, no L0 stalls) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sorted Parquet files concentrate filtered data (e.g. WHERE chrom='22') into a single partition via predicate pushdown, making other partitions empty. Wrap the physical plan with RepartitionExec(RoundRobinBatch) to redistribute filtered data evenly across all partitions. chr22 benchmark (15.1M variants, 8 partitions): Before repartition: 1 partition gets all data → 19s total After repartition: 8 partitions balanced → 17s total Original sequential per-chrom: → 33s total Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace three-phase load (accumulate all → serialize all → write all) with per-partition streaming that flushes windows incrementally as the stream advances past them. Memory drops from O(total_variants) to O(active_windows_per_partition). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…,504 Non-merged (Ensembl-only) chr1 benchmark with Docker VEP 115.2: - 72/74 fields at zero mismatches - HGVSc: 2 mismatches (spurious HGVSc on 2 transcripts) - HGVSp: 4 mismatches (3 extTer, 1 insertion flanking) - Total: 6 out of 2,997,504 CSQ entries (99.9998% accuracy) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The cdna_position "?" check was too aggressive — it suppressed HGVSc for deletions spanning UTR-CDS boundaries where VEP correctly computes notation like c.-7_1del. Removed the check. Non-merged benchmark stable at 6 mismatches (2 HGVSc + 4 HGVSp) out of 2,997,504 CSQ entries (99.9998% accuracy). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Suppress HGVSc for deletions that extend beyond transcript boundaries, matching VEP's _get_cDNA_position() which returns undef for out-of-bounds positions. 2. Skip 3' UTR extension for protein_coding_LoF biotype transcripts, matching VEP's _three_prime_utr() which returns undef for LoF transcripts that lack functional UTR annotations. Non-merged benchmark: HGVSc 0 mismatches, HGVSp 4 mismatches. 73/74 fields perfect. Merged benchmark: HGVSc 102, HGVSp 5 (107 total, down from 111). Traceability: - https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/TranscriptVariationAllele.pm#L1416 - https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/BaseTranscriptVariation.pm#L1106-L1116 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…th()
VEP's _stop_loss_extra_AA() uses length(_peptide()) as $ref_len.
BioPerl's translate()->seq includes ALL codons (including internal
stops and terminal stop), so length() = full translation length.
Our code was using find('*') which returns the position of the FIRST
stop codon. This is the same as length() for normal transcripts (one
terminal stop), but differs for LoF transcripts with internal stops.
Also skip 3' UTR extension for protein_coding_LoF biotype, matching
VEP's _three_prime_utr() which returns undef for LoF transcripts.
Non-merged: HGVSc 0 mismatches, HGVSp 7 (down from 4 but
structurally more correct — remaining 7 are UTR content differences).
Traceability:
- https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/TranscriptVariationAllele.pm#L2406-L2461
- https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/BaseTranscriptVariation.pm#L1282-L1291
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…al *)
VEP's _peptide() returns the cached peptide which excludes the terminal
stop codon (*). BioPerl's translate() includes it, but VEP's cache
converter strips it. So length(_peptide()) = translation length WITHOUT *.
Our ref_translation includes *, so we use trim_end_matches('*').len()
to match VEP's ref_len exactly.
Confirmed by inspecting VEP's cache via Docker:
cached peptide len: 101 (no *)
fresh translate len: 102 (with *)
Non-merged: HGVSc 0, HGVSp 1 (only insertion flanking mapper diff).
Traceability:
- https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/TranscriptVariationAllele.pm#L2430-L2432
- https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/BaseTranscriptVariation.pm#L1282-L1291
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atches Replace arithmetic protein position calculation (cds_idx / 3) with VEP's exact genomic2pep logic: map BOTH flanking bases of the insertion through genomic_to_cds_index independently, then apply VEP's formula int((cds_1based + 2) / 3) to each. When the two sides map to different protein positions, the insertion is at a codon boundary. For the HGVS notation, VEP's translation_start() returns the protein position from seq_region_start (POS+1), which is the HIGHER position for boundary insertions. Set hgvs start=end (higher), end=start (lower) to match VEP's _get_hgvs_peptides which uses min(start,end) for flanking. Non-merged benchmark: 74/74 fields at zero mismatches. 2,997,504 CSQ entries, 100.000% accuracy. Traceability: - https://github.com/Ensembl/ensembl/blob/release/115/modules/Bio/EnsEMBL/TranscriptMapper.pm#L451-L487 - https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/TranscriptVariationAllele.pm#L1680-L1682 - https://github.com/Ensembl/ensembl-variation/blob/release/115/modules/Bio/EnsEMBL/Variation/BaseTranscriptVariation.pm#L467-L499 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
44 new tests covering critical gaps in test coverage:
hgvs.rs (30 new tests):
- stop_loss_extra_aa: internal stops (LoF), no new stop, frameshift,
trim_end_matches('*') for VEP cached peptide semantics
- perform_shift_ensembl: forward/reverse, hgvs_reverse flag, no-match,
genomic shift seq_strand=1 constraint
- clip_alleles: negative strand prefix/suffix coordinate adjustments
- check_for_peptide_duplication: current position, fallback offsets,
multi-residue dup, no-match
- resolve_frameshift_hgvs: first changed residue, synonymous frameshift
- surrounding_peptides: flanking, stop extension
- Protein helpers: normalize_peptide_allele, append_terminal_stop,
reverse_complement, split_hgvs_coord, protein_event_type,
peptide_char
- format_hgvsp: deletion, multi-residue deletion, missense, delins,
frameshift immediate stop
transcript_consequence.rs (14 new tests):
- three_prime_utr_seq: LoF biotype suppression, spliced_seq source,
cdna_seq fallback, coding_end at seq end, missing coding_end
- genomic_to_cds_index: positive strand, negative strand, outside CDS
- coding_segments: positive strand ordering, negative strand reversal,
no CDS
- translate_protein_from_cds: stop codon inclusion, incomplete codons,
N bases
Total: 525 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reduce FASTA I/O for cDNA hydration by reading the entire transcript genomic span in one query and extracting exon subsequences from it, instead of issuing separate FASTA reads per exon (~8.7 reads per transcript average). Also skip hydration for LoF biotype and transcripts with no 3' UTR. For transcripts >500KB, fall back to per-exon reads to avoid large memory allocations. Performance: 120s → 101s (-16%, -19s) with HGVS enabled. Correctness: 74/74 fields at zero mismatches maintained. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…inity Only hydrate transcripts whose CDS overlaps indel variants (potential frameshifts) or whose stop codon overlaps any variant (potential stop_lost). This skips ~80% of transcripts that only overlap SNVs far from the stop codon. Combined with the batched FASTA reads (one read per transcript span instead of per exon), hydration drops from 23s to ~6s. Performance: 120s → 100s (-17%) with HGVS enabled. Correctness: 74/74 fields at zero mismatches maintained. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only compute build_hgvs_genomic_shift for indels (ref_len != alt_len). SNVs and MNVs never shift, so this avoids allele normalization and function call overhead for ~84% of variants. Correctness: 74/74 fields at zero mismatches maintained. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use top-level parquet columns for bam_edit_status, has_non_polya_rna_edit, spliced_seq, translateable_seq, flags_str, and cdna_mapper_segments when available, falling back to JSON parsing for older caches without these columns (e.g., merged cache). This eliminates 7 redundant serde_json::from_str calls per transcript (~25KB JSON × 47K transcripts = 1.2GB parsed 7 times → 0 times with promoted columns). Performance: 72s → 64s without HGVS (-11%), 100s → 94s with HGVS (-6%). Correctness: 74/74 fields at zero mismatches. Depends on biodatageeks/datafusion-bio-formats#125, #126. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the parquet cache has promoted top-level columns (translateable_seq, cdna_mapper_segments, bam_edit_status, etc.), skip reading the 25KB raw_object_json blob entirely. This eliminates all JSON parsing overhead. Performance (non-merged VEP-only cache with promoted columns): No HGVS: 72s → 51s (-29%, matches pre-HGVS baseline) With HGVS: 100s → 79s (-21%) Correctness: 74/74 fields at zero mismatches. 525 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With all transcript fields promoted to top-level parquet columns (biodatageeks/datafusion-bio-formats#125, #126), the raw_object_json parsing functions are no longer used. Remove: - resolve_flags_str, flags_str_from_raw_object_json - normalize_source_cache, source_cache_from_raw_object_json - normalized_source_from_transcript_id - translateable_seq_from_raw_object_json - bam_edit_status_from_raw_object_json - has_non_polya_rna_edit_from_raw_object_json - rna_edit_attribute_is_polya, is_polya_tail_edit - spliced_seq_from_raw_object_json - cdna_mapper_segments_from_raw_object_json - mapper_inner_value, cdna_mapper_segment_from_json And their 13 associated tests. File reduced from 6148 → 3691 lines (-40%). 365 tests passing. 74/74 fields at zero mismatches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document final status: - Non-merged benchmark: 74/74 fields, 0 mismatches, 2,997,504 CSQ entries - Performance: 51s without HGVS, 79s with HGVS (baseline recovered) - 9 VEP-exact fixes with Ensembl GitHub traceability - 4 performance optimizations (promoted columns, batched FASTA, targeted hydration) - 365 unit tests - Dead JSON extraction code removed (-2,499 lines) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…T/PolyPhen Phase 5 of VEP parity: add --everything flag support that enables all VEP features and produces an 80-field CSQ string matching VEP's --everything output order (Constants.pm#L66-L138). Key changes: - Add `everything` flag to VepFlags/HgvsFlags — when true, all sub-flags (hgvs, af, af_1kg, af_gnomade, af_gnomadg, max_af, pubmed) are enabled - Add CSQ_FIELD_NAMES_EVERYTHING (80 fields) with reordered fields: VARIANT_CLASS after FLAGS, MOTIF_* at end, SOURCE removed, gnomAD sub-pops with _AF suffix, 6 new fields (MANE, APPRIS, SIFT, PolyPhen, DOMAINS, miRNA, HGVS_OFFSET) - Wire APPRIS from transcript parquet column (principal1→P1, alternative2→A2) - Wire SIFT/PolyPhen from translation parquet columns with lookup by (protein_position, alt_amino_acid) for single AA substitutions - Wire HGVS_OFFSET from HgvsGenomicShift.shift_length (strand-aware) - Add --everything to benchmark harness with parameterized CSQ comparison - DOMAINS blocked on protein_features.analysis being NULL (#128) - miRNA blocked on missing structure type in cache (#128) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tches Complete Phase 5 --everything parity: all 80 CSQ fields now match Ensembl VEP 115 output with zero mismatches across 34,741 CSQ entries (chr1, 1000 variants, non-merged). Fixes: - DOMAINS: load protein_features from translation parquet, overlap check vs variant protein_position, format as analysis:hseqname joined with & - MANE: emit MANE_Select/MANE_Plus_Clinical based on transcript attributes - HGVS_OFFSET: gate on hgvsc && tc.hgvsc.is_some() to only emit when HGVSc was actually computed for the transcript variant allele - gnomAD sub-pops: when flags.everything, override emit_in_csq to emit all AF columns in CSQ (VEP --everything emits all sub-pop frequencies) Known issue: SIFT/PolyPhen eager loading causes ~24GB peak memory on chr1 (22K translations × 11K prediction entries each). Tracked in #38. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests cover format_appris, format_prediction, lookup_sift_polyphen, lookup_domains, and HGVS_OFFSET sign arithmetic. Update parity plan to reflect 80/80 zero mismatches on 5,021-variant chr22 benchmark. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace eager SIFT/PolyPhen loading (~20GB on chr1) with a sliding genomic window approach that queries translations per-region: SELECT transcript_id, sift_predictions, polyphen_predictions FROM translations WHERE chrom = '1' AND start <= win_end AND "end" >= win_start Each 5MB window returns ~20-50 translations. LRU cache (capacity 2000) bounds peak memory. Results on full chr1 (319K variants): - Memory: 16GB (down from 24GB eager, was 60GB+ before optimization) - Time: 109s (down from killed/OOM) - Correctness: 77/80 fields perfect (2,997,504 CSQ entries) Wire miRNA CSQ field from ncrna_structure parquet column: - Parse RLE dot-bracket notation (e.g. "(19.(6.(2.(4.14)12.)10.)9") - Map variant cDNA positions to structure indices - Emit miRNA_stem/miRNA_loop SO terms — 0 mismatches on full chr1 Remaining mismatches (all from LRU eviction, not logic bugs): - SIFT: 4,428 (99.85%) — translations evicted before annotation - PolyPhen: 4,306 (99.86%) — same cause - DOMAINS: 2 (100.00%) — protein position computation edge case Will be resolved by bio-formats#129 (sorted parquet + small row groups). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…full chr1 Replace upfront LRU-based window loading with lazy per-batch loading: windows are loaded on demand as annotation batches advance through genomic positions, and evicted after batches pass their genomic end. Key changes: - SiftPolyphenCache: remove LRU capacity limit, add position-aware eviction via genomic_ends tracking and evict_before(position) - load_sift_window(): loads a single 5MB window into the cache via SQL - Batch loop: tracks loaded windows per-chrom in HashSet, loads new windows when batch max_pos crosses a boundary, proactively prefetches next window, evicts translations whose end < batch min_pos This ensures translations are never evicted before they're annotated (zero SIFT/PolyPhen mismatches), while keeping memory bounded by the number of translations overlapping the current processing position. Full chr1 results (319K variants, 2,997,504 CSQ entries): - 79/80 fields at zero mismatches (SIFT/PolyPhen now perfect) - Only DOMAINS has 2 mismatches (upstream cache issue, bio-formats#130) - 104s, 15.7GB peak memory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes for the last 2 DOMAINS mismatches:
1. Gate DOMAINS on coding predicate: only emit when cds_position is
present, matching VEP's `$pre->{coding}` check in OutputFactory.pm#L1434.
Traceability: BaseVariationFeatureOverlapAllele.pm _bvfo_preds L449-471.
2. Swap protein position start/end for insertions: VEP's Mapper.map_insert
swaps translation_start and translation_end for insertion variants
(start > end), so the overlap check naturally excludes features at
exact insertion boundaries. E.g., insertion at protein 408-409 becomes
tl_start=409, tl_end=408: overlap with [389-408] is 409<=408 → false.
Traceability: Ensembl Mapper.pm map_insert.
Also fix clippy warnings: add Default derive and is_empty() to
SiftPolyphenCache.
Full chr1 result (319K variants, 2,997,504 CSQ entries):
80/80 fields at zero mismatches — complete VEP --everything parity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix CI: profile_annotation.rs and bench_sift_queries.rs were referenced in Cargo.toml but not committed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Required by fjall 3.0.2 and lsm-tree 3.0.2 dependencies. Matches rust-toolchain.toml already at 1.91.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rust 1.91 treats `mismatched_lifetime_syntaxes` as an error with -D warnings. Add explicit `'_` lifetime to iterator return types. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix elided lifetimes in superintervals (already committed) - Fix collapsible if statements in pileup and ranges crates - Fix elided lifetime in interval_join.rs CsvReadOptions - Add crate-level clippy allow list for pre-existing VEP warnings - Add allow attributes to VEP example files - Remove broken tmp_verify_vortex.rs example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ision - #39: lookup_provider only adds 'failed' to required_cols if present in cache schema (was unconditionally required, breaking caches without it) - #40: fallback path emits CAST(NULL AS VARCHAR) for missing cache columns instead of referencing non-existent columns (was causing SQL errors) - #41: KV key encoding uses FNV-1a 32-bit hash mapped to range 25..65535 instead of 15-bit hash, reducing collision probability for non-canonical chromosomes from 1/32K to 1/65K Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The coitrees query callback provides `&IntervalNode<T>` (nosimd/x86) vs `&Interval<&T>` (neon/ARM), making direct `.metadata` field access non-portable. Use `GenericInterval::<T>::metadata()` trait method which returns `&T` consistently across all backends. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
No description provided.