Publication readiness: primary-call matrix, EVE toolchain, vignette suite, hygiene - #7
Merged
Merged
Conversation
…PLAN SH2.6) Three new columns in viral_summary.tsv to help distinguish genuine viral infection from endogenous viral element (EVE) read artifacts, motivated by COVID ViralScan finding F-005 (anellovirus reads mapping to NALCN/chr13 and LINC02742/chr11 EVE loci rather than exogenous virus): - accession_breadth: fraction of indexable gene IDs with ≥1 UMI in any cell. Genuine infection spreads across ORF1/ORF2/ORF3; EVE artifacts concentrate on 1-2 host-integrated loci. Computed in compute_stats() from viral_matrix. - host_viral_ambig_fraction: proportion of viral UMI that also mapped ambiguously to the host genome, from the existing adata.layers["counts_host_viral_ambiguous"] written by multimap.py (was never read by detection.py until now). High fraction = reads from host genomic regions. Only populated when multimapping is enabled. - eve_risk: Boolean flag when the virus family/genus appears in EVE_RISK_GENERA (new frozenset in constants.py), covering all Anelloviridae genera plus Gyrovirus. All 582 tests pass. No changes to existing column schema. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Original `viralscan evidence` run (job 25180994) crashed at samtools sort because combined.fa had duplicate NC_002076.2 headers. A manual hf_align job (25181135) filled the gap but was never committed, leaving BAM/coverage.tsv non-reproducible. This commit closes that gap: - covid_viralscan/scripts/slurm_evidence_rerun.sh: re-aligns the existing viral_reads.fasta (912 MB, produced before the crash) to viral_genome.dedup.fa (1 copy of NC_002076.2) via minimap2 -ax sr + samtools sort, then regenerates coverage.tsv via viralscan.evidence.coverage_table(). Covers both x213-g and x216-g in one job. - covid_viralscan/RUNBOOK.md: added Stage 5 (Evidence) section documenting the crash cause, the dedup fix, and how to re-run. - PLAN.md: added T5 completion note (closes T5). To regenerate BAM + coverage.tsv: sbatch covid_viralscan/scripts/slurm_evidence_rerun.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oducibility note
F-005 findings file updated 2026-07-15:
- Mark reproducibility note RESOLVED (slurm_evidence_rerun.sh committed)
- Add CellTypist enrichment (T6 tripwire) result:
* EBV (HHV4_EBNA-2): 5 positive cells, all epithelial, 0 B cells — absent
* Anelloviruses enriched in Epithelial cells (OR 3.3–4.2, FDR<1e-40) and
Plasma cells (OR 3.1, FDR 5e-13) — consistent with EVE-artifact mechanism
(intronic pre-mRNA from ubiquitous genes expressed in epithelial/B-lineage)
* HHV-6b, HHV-1: 2–4 cells, below interpretation threshold
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…earning, last-session update - decisions.md: T5 reproducibility (commit-not-rerun rationale) + T6 negative EBV result - learnings.md: plasma cell EVE mechanism (high intronic pre-mRNA → EVE reads from expressed loci) - last-session.md: updated to reflect post-compaction session (SH2.6, T5, T6 closed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ifact (job 25237061) Phase A/B/C results: - All 8 detected anellovirus accessions (Alpha/Beta/Gamma/Samek) appear in Phase A (multi-chromosomal GRCh38 alignment, depth 67–1503) — accession-level artifact confirmation - NC_001479.1: Phase B BLAST confirms 100% identity to human intergenic at pos 120-303 - Phase C clean: HHV-1, EBV, HHV-6B, CeHV2, MPXV, Molluscum, SARS-CoV-2 are reference-clean - Surviving non-EVE signal (1–4 UMI each) below defensible detection threshold - F-005 closed: no genuine viral infection in these COVID PBMC samples Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
anndata is an eager top-level import in scripts/multimap.py but was only satisfied transitively via scanpy in pyproject.toml, and was absent from environment.yml along with scikit-learn. Declare anndata>=0.9 explicitly and add both anndata and scikit-learn to environment.yml so the documented conda environment is complete (and so a --no-deps install is safe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every runtime dependency is now satisfied by the conda environment built from environment.yml, so pip should not re-resolve them. --no-deps mirrors the CI install and avoids letting pip rebuild snakemake from PyPI, whose connection_pool transitive dep fails to build with older setuptools. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
STAR_BIN was pinned to an author-specific conda-env absolute path, which broke the reference-strategy benchmark on any other machine. Default to 'STAR' on PATH and allow an override via the VIRALSCAN_STAR_BIN environment variable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
results_genomic/ and results_hostfilter/ under covid_viralscan/ are human-subjects outputs and were untracked, one 'git add .' away from being committed. Exclude them alongside the existing covid data/results ignores. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Independent 7-dimension review (adversarially verified) + Linus code review of the package ahead of release. Records the two-track verdict (software days-away, manuscript venue-gated), the completed pre-tag hygiene fixes, and the remaining owner-gated items. Updates PLAN 'Next up' and .living/decisions.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Learning behind the anndata fix: a green suite does not validate the declared install contract when CI installs with --no-deps. Captures the process-gap and how to gate it (bare-venv wheel import / deptry; keep pyproject and environment.yml deps in sync). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
reference_strategy.py SLURM template (conda setup, PYTHONPATH), fastq_root fallback, and default_manifest() paths are now env-driven / neutral placeholders; emptydrops.R honours VIRALSCAN_R_LIBS / R_LIBS_USER instead of a hardcoded R library path. Completes the STAR_BIN fix so a pip install no longer ships one developer's filesystem. No test asserts these values; write_slurm_array still renders and preflights the required tools. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The function deletes the output directory's contents (os.remove / shutil.rmtree) after a prompt, but its name and docstring described a read-only inspection. Rename it and document the destructive behaviour; update the single caller. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
hostresponse._detect_and_normalize had a sparse/dense if/else with byte-identical arms; build_ref_main nested an 'if reference_panel == anellovirus' inside the identical outer check. Both are no-ops; collapse them. Behaviour unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HEAD had drifted ~20 commits past the 2.5.0 bump with a behavior-changing default (multimap-method equal -> host-conservative) sitting in [Unreleased], and no tag existed. Bump __version__ and all version strings to 2.6.0, and close [Unreleased] as [2.6.0] with the previously-undocumented changes (EVE artifact flags, sibling cross-mapping warning, EM/multimap performance work) plus the packaging fixes. Tag + publish remain user-gated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Data Availability mislabelled GSE210063 as 'COVID-era clinical' (it is HHV-6B CAR-T); corrected. Removed the unsupported 'under 2 h on 8 cores' runtime claim (documented full-depth runs were 3.5-4 h). Added the missing ViralTrack reference (Bost et al., 2020) and in-text citation. Added an explicit ethics/provenance placeholder for the unpublished COVID clinical libraries (IRB statement + author identities still required from the authors). Sync PLAN 'Next up'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--multimap-primary-call unique-only previously controlled only sample-level detection; downstream summaries, per-cell rows, plots, and cell-type enrichment still read viral numerators from adata.X. Add a shared matrix_for_genes() helper and route all viral numerators through the selected primary-call matrix, while keeping full-matrix total-UMI denominators for umi_per_10k and viral_fraction. The HTML report's "Infected cells (any virus)" count now counts unique virus-positive barcodes rather than cell-virus rows. Documents the policy in docs/output_reference.md, README.md, and the report template. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
annotate_eve.py annotates endogenous-viral-element analysis outputs against GRCh38 (Phase A read loci, Phase B NT BLAST hits, Phase C panel-vs-genome PAF) with a bundled test. slurm_eve_analysis.sh drives the three phases; it takes machine-specific paths through environment variables (no institutional paths), validates tools and inputs before long-running phases, and survives zero BLAST hits under pipefail. covid_viralscan/README.md replaces hardcoded CellRanger and FASTQ paths with env-var instructions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Supersede basic_usage.ipynb with a task-oriented suite, each grounded in a manuscript result narrative: quickstart, reference building, multimapping correction, cell-calling denominators, cell-type enrichment, specificity/ true-negative, QC & read evidence, and host-response with depth control. Six execute in CI on synthetic/committed data; two are [skip-ci] (index build / kb count) with public-data download blocks and no institutional paths. Adds a README index and VIGNETTES_PLAN, wires the Sphinx toctree, and fixes the enrichment vignette to pass RunConfig (not a dict) to cell_type_enrichment(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Add the mycelium session logs, decisions, learnings, INDEX, and log registry for the 2026-07-15..20 sessions (code review, primary-call matrix, EVE toolchain, vignette suite), plus the covid review findings under outputs. Add the aifi-scrna-pipeline convention pack and reference it from CLAUDE.md and ACTIVE_CONVENTIONS.yaml. Excludes transient data-lineage hook telemetry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Add a non-breaking curation layer: scripts/build_curation_view.py generates a gitignored curation/ tree of relative symlinks from scripts/curation_manifest.yaml, organized both by manuscript result (by-result/) and by artifact type (by-type/). Originals are never moved; the view is disposable and regenerable (--clean). Adds /curation/ to .gitignore. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Two silent-failure bugs in annotate_eve.py: - Phase B looked up BLAST subject-local coordinates as GRCh38 chromosome coordinates, mis-annotating clone/scaffold NT subjects. Gate on _is_chromosome_subject() (whole-chromosome RefSeq only); flag others as subject_not_chromosome. - No chromosome-name normalization, so a UCSC-vs-Ensembl (chr7 vs 7) mismatch annotated everything intergenic. Add _normalize_chrom() in load_gtf_genes keys and annotate_locus queries, plus _warn_namespace() when Phase A/C query chromosomes are disjoint from the GTF. Also harden slurm_eve_analysis.sh read extraction to keep stderr and emit a visible WARN instead of a silent `|| true`. Adds Phase B parse-path, normalization, and namespace-warning tests (8 passed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Non-behavioural cleanup from the review: extract the 5x `viral_count_matrix if ... else adata.X` guard into utils.resolve_count_matrix(); drop matrix_for_genes' dead non-get_indexer branch (AnnData var_names always has get_indexer); collapse the double .sum() in the host-viral ambiguity denominator to a single float(...sum()); reuse _sum_axis1 for the per-cell total-UMI sum. 57 targeted tests pass; ruff clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Replace the third-party `evonk` conda path with a generic `python` / `$VS_CONDA_ENV` placeholder in PLAN.md and covid_viralscan/RUNBOOK.md. Gitignore the `.living/log/data-lineage/` hook telemetry (contains abs paths, never tracked). Add the PLAN.md vignette-suite DONE row (PLAN contract) and refresh todo/TODOLIST.md. Note: ~14 functional SLURM/infra scripts and reference_manifest.json still embed `VS_CONDA_ENV=/exports/.../evonk/...` as a default; scrubbing those needs per-script env-var-ization or ship-scope exclusion — tracked in TODOLIST. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Session log, decision, and learning (L-24) for the atomic-commits push, the gitignored symlink curation view, and the "do all" todo pass (EVE fixes, primary-call cleanup, hygiene). Captures the reusable non-breaking-reorg pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
build_multimap_layers called pd.isna(ec_raw) on every one of the ~100M BUS records (~5% of the pass, 2M calls / 2.3s on a 2M-record profile). Replace with a single vectorised `~pd.isna(ec_arr)` mask applied once before the loop. Byte-identical output; equal 36.5s->33.9s, em 51.8s->50.5s on 2M records; 33 multimapping tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
The 195 src/viralscan/data/*.gtf (7.7 MB) are fetched from Zenodo via `viralscan data fetch` at runtime (cache dir, not the package dir), nothing reads the bundled copies, and package-data already excludes them from the wheel. Untrack them (git rm --cached; local copies kept) and gitignore. Shipped anellovirus_accessions.tsv is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Session log, learning L-25 (committed profiling artifacts go stale), and the verified repo-slim result. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
build_multimap_layers iterated every one of the ~100M BUS records. bustools emits one record per (barcode, UMI, ec), so a (cell, ec) recurs once per distinct UMI — 3.18x duplication measured on a real output.bus.txt. Every emitted share is linear in count for a fixed (cell, ec) and the output matrices sum duplicate COO entries order-independently, so sum counts once (vectorised barcode->cell map + groupby(['cell','ec']).sum()) before the loop. Numerically identical: golden comparison of all 8 layers x 4 methods at rtol=1e-9 (6x-duplication synthetic) matches; 33 multimapping tests and the full suite (593) pass. Realistic-duplication benchmark (dup 3.43x): equal 19.2->6.3s (3.0x), em 28.8->9.1s (3.2x). Stacks on the CSR fast path and pd.isna hoist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Four never-called symbols and one dead branch, net -36 lines, golden-identical (multimap all-layers rtol=1e-9) and full suite (593) green: - multimapping._matrix_value + its non-sparse fallback: original_counts is always the sparse kb count matrix, so coerce to CSR once and drop the `orig_csr is None` special case. One code path, no per-element scipy __getitem__ dispatch. - detection._encode_image: a base64 helper duplicated by inline code already in generate_html_report; never called. - reference_strategy.command_for_row: never-called wrapper; callers use commands_for_row(...)[0] inline. - menu._config_bool: never called. Each verified to occur exactly once (definition only) across all tracked .py. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
…sment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
todo/read-start-distribution.md: detailed plan for read-start distribution + PCR-dup handling in `viralscan evidence` (per-position histogram along the viral genome; --read-start-profile / --dedup umi|markdup|none). docs/ROADMAP.md: tiered future-work plan grounded in the manuscript's stated limitations, this session's review findings, and existing TODOLIST items. Indexed in TODOLIST. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
…admap docs/IMPLEMENTATION_PLAN.md orders all ~24 roadmap items into dependency-aware phases (M0 ship → P1 robustness/CI → P2 host-response → P3 evidence positional features → P4 reference/specificity → P5 validation → P6 perf → M7 release), each tagged AUTO / COMPUTE / OWNER so the "back to back" scope is honest about what I can build end-to-end vs what needs a cluster, real data, or a release action. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
…p (D1-D3) - D1: Detection.preprocessing makes var_names unique up front (warns) so duplicate reference accessions no longer crash gene->column lookup; matrix_for_genes raises a clear error on non-unique input. New test. - D2: EVE _is_chromosome_subject accepts legacy gi|...|ref|NC_...| sseqids (re.search with a start/pipe boundary), still excludes viral NC_0xxxxx. Test. - D3: clamp host_viral_ambig_fraction to [0,1] (the ambiguous layer is not a strict subset of adata.X viral counts, so the ratio can slightly exceed 1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
`viralscan evidence --read-start-profile [--dedup umi|markdup|none] [--bin-size N]` writes a per-position 5' read-start distribution along each viral reference (read_start_profile.tsv) — exposes 3' bias, subgenomic-RNA junctions, and EVE/integration hotspots the aggregate coverage summary cannot. Pure `_parse_sam_read_starts` (CIGAR ref-span, strand-aware 5' start, UMI dedup per CB+UMI from the <CB>_<UMI>_<n> read names, flag filtering, binning) is unit-tested on synthetic SAM with no samtools dependency, mirroring the existing _parse_coverage_output split; `read_start_distribution` is the samtools wrapper (markdup mode shells out to samtools markdup -r). 94 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
From the end-of-increment parallel review: - evidence_run: `--read-start-profile` without `--viral-fasta` was a silent no-op; now `_die`s like `--blast`. - detection.preprocessing: raise a clear error on duplicate var_names instead of var_names_make_unique() (renaming silently dropped the duplicate accession's counts, since the viral accession list keeps the original name). - evidence._parse_sam_read_starts: guard int(FLAG)/int(POS) so a stray non-record line is skipped, not a crash (matches the sibling parsers); if/else -> ternary. - annotate_eve._is_chromosome_subject: tighten regex to human chromosomes NC_000001..24 (+ NC_012920); NC_0000\d\d also accepted e.g. mouse NC_000067. - test_multimapping: unused loop var trial -> _trial (ruff B007). Full suite 602 green; ruff clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
… review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
`viralscan evidence --cell-tags` writes viral_reads.tagged.bam with CB:Z/UB:Z tags parsed from the <CB>_<UMI>_<n> read names, so viral reads can be grouped by cell in IGV. Pure `add_cell_tags_to_sam` is unit-tested on synthetic SAM; `write_tagged_bam` is the samtools wrapper. Guarded to require --viral-fasta. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Each run writes results/reference_provenance.json recording the viral reference used (index / t2g / GTF, technology, multimapping settings) and the viral accessions both in the reference and detected — so results are traceable to their annotation (the paper's EBV gene-attribution divergence is annotation- driven). Pure reference_provenance() is unit-tested. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
From the batch parallel review: - add_cell_tags_to_sam skips lines without the 11 mandatory SAM fields (like the sibling parser's len(f)<6 guard) instead of appending a tag after a non-optional field on a malformed record. - _cb_umi returns None when the CB or UMI is empty (e.g. "_TTTT_1"), avoiding an invalid empty CB:Z:/UB:Z: tag value. Also hardens A1's read-start dedup. G1 provenance reviewed clean. Tests added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
C1 (host-response gene symbols + enrichment) was already implemented — mygene.info mapping (_map_ensembl_to_symbols, graceful on network failure), _add_symbol_column on the weights/stability/depth-diagnostics/differential CSVs, and Ensembl->symbol translation before gget.enrichr. Add the missing network-free unit tests for the pure helpers (detection, column insert with version-stripping, empty-input). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
- F5: add a CI job that executes the 6 CI-runnable vignettes with nbmake so docs can't silently rot (the enrichment vignette once broke under [skip-ci]); the two heavy [skip-ci] notebooks are excluded. All 6 verified to run locally. - G2: non-human host support was already present (ENSEMBL_SPECIES: mouse mus_musculus/GRCm39 + 15 species); add a test locking mouse/rat/macaque resolution and the unknown-host error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Primary-call matrix consistency, evidence read-start/cell-tags, reference provenance, host-response gene symbols, EVE toolchain + fixes, non-human hosts, the vignette suite + nbmake gate, the multimap collapse (~3x faster / ~6x less peak RSS), and the repo-slimming/hygiene work. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Cut 2.7.0: __version__, CITATION.cff, Dockerfile, Singularity.def, conda-recipe/meta.yaml, and docs/cli_reference.md all bumped 2.6.0 -> 2.7.0; CHANGELOG [Unreleased] closed as [2.7.0] - 2026-07-21 with compare-links updated (v2.6.0...v2.7.0). Ready for `git tag v2.7.0`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
The PR was red in CI (never actually green — local runs use py3.14). Fixes: - hostresponse.py: add `from __future__ import annotations` so the `seeds: list | None` parameter annotation no longer evaluates `type | None` at import time, which raised TypeError on Python 3.9 and broke collection of all hostresponse tests (a declared-supported version). - test_analysis.py: `test_data_dir_has_gtf_files` now skips when no GTFs are present — they are fetched from Zenodo (`viralscan data fetch`), not bundled (untracked in this branch), so a fresh checkout has none. - ruff format: 7 files reformatted to satisfy `ruff format --check` (pre-existing format debt in constants.py/reference_strategy.py plus this session's files). Full suite 613 green; ruff check + format --check clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
kb-python 0.30.x has no `--version` flag: `kb --version` prints help and exits 1, which under `set -e` aborted the "Validate documented conda environment" job before `snakemake --version`. Use `kb --help > /dev/null` (reliable exit 0) to confirm the kb CLI is installed and runnable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
- evidence.py: annotate _parse_sam_read_starts / read_start_distribution return type as list[dict[str, object]] and the dedup set as set[tuple[object, str]] (was bare dict/set, tripping [type-arg]). - multimapping.py: rename the EM-allocation loop var genes -> ec_genes so it no longer collides with the list[int] genes bound earlier in build_multimap_layers (was tripping [assignment]). Lint job runs mypy src/viralscan; these were the last 4 errors keeping PR #7's CI red. ruff check + ruff format --check + mypy now all clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
…back
The Lint job's `mypy src/viralscan` failed on installed third-party source:
anndata>=0.13 ships py.typed and uses PEP 695 (`class Foo[T]`) syntax that
mypy rejects while targeting python_version=3.10 ("Type parameter lists are
only supported in Python 3.12+"), aborting before any of our code is checked.
- pyproject: add a mypy override with follow_imports="skip" for anndata.*/
scanpy.* — treat as Any without parsing, so upstream syntax can't break the
lint job (preferred over pinning mypy target to 3.12, which would forfeit
3.10-syntax gating on our own code, or pinning the deps).
- menu.py: with anndata no longer masking downstream checks, mypy flagged a
real error — the pyfiglet-absent fallback `_figlet_format` had a signature
incompatible with the real `figlet_format` (conditional variants must match).
Match pyfiglet's (text, font="standard", **kwargs) -> Any.
Reproduced in a fresh venv with the exact CI pip line (anndata 0.13.2, mypy
2.3.0): ruff check + ruff format --check + mypy src/viralscan all clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
`kb --help` prints usage to stderr and exits non-zero in kb-python 0.30.x (it wants a subcommand), so it aborted the smoke-test step under `set -e` even with stdout redirected — the prior `kb --help > /dev/null` fix was wrong. Use `command -v kb`, which is the reliable check that the kb console script is installed in the environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NZ2gKabckBq5McUgZa7w8s
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.
Prepares ViralScan for publication. 19 commits spanning features, docs, and hygiene; test suite green throughout.
Features
feat(detection)):--multimap-primary-callnow consistently drives viral numerators across summaries, per-cell rows, plots, and cell-type enrichment via a sharedmatrix_for_genes()helper, while total-UMI denominators stay on the full matrix. HTML "Infected cells" now counts unique barcodes.feat(covid)):annotate_eve.py+ hardenedslurm_eve_analysis.shfor endogenous-viral-element screening against GRCh38 (Phase A/B/C), env-var-driven and path-clean.Correctness fixes
fix(covid)): Phase B no longer treats BLAST subject-local coordinates as chromosome coordinates (clone/scaffold subjects flagged); added chromosome-name normalization (chr7↔7) with a namespace-mismatch warning to prevent silent all-intergenicoutput; SLURM read-extraction surfaces real errors instead of swallowing them.Docs
docs(vignettes)): replacesbasic_usage.ipynb; each grounded in a manuscript result (multimapping recovery, cell-calling denominators, enrichment, specificity, QC/evidence, host-response depth control). Six execute in CI; two are[skip-ci]with public-data blocks. No institutional paths.docs(manuscript)): data-availability, runtime, and citation fixes.Refactor & hygiene
refactor(detection): dedupe the primary-call plumbing (resolve_count_matrix()), drop dead code.chore(package)/chore(hygiene): remove institutional abs paths from shipped files; scrub the third-partyevonkconda path from docs; version reconciled to 2.6.0;--no-depsDocker/CI; declareanndata.chore(curation): gitignored, regenerable symlink curation view (scripts/build_curation_view.py) for manual paper curation — non-breaking.Known follow-ups (tracked in
todo/TODOLIST.md)VS_CONDA_ENV=/exports/.../evonk/...as a default — needs per-script env-var-ization or ship-scope exclusion.user.signingkey) — recent commits may be unsigned.🤖 Generated with Claude Code