                       Changes in version 0.99.0                        

Corrections made before submission

  - compareSFS() suppressed every warning from chisq.test(), so a
    p-value resting on expected counts below 5 looked as trustworthy as
    any other. It now returns the smallest expected count and
    chisq_approx_ok, which is FALSE in that case, and silences only that
    one warning; the statistic and p-value are unchanged.
  - flagTemporalInconsistency() classified each site with the last host
    processed and flagged transient sites in every sample. Sites are now
    classified within each host and flagged only in the samples of hosts
    where they are transient.
  - exactBottleneck(method = "exact_bb") matched donor variants to rows
    by position alone, which is wrong for segmented genomes, and paired
    donor frequencies with recipient read counts by index when some
    sites did not match. Sites are now matched by chromosome, position
    and allele. An estimate that reaches maxNb triggers a warning.
  - The documentation of exactBottleneck() states how exact_bb departs
    from Sobel Leonard et al. (2017) and that wright_fisher is a
    heuristic score.
  - flagISNV(), calcDiversity() and calcNeutralityTests() stop on
    arguments they do not use.
  - adaptiveFilter("ont") uses minDepth = 60, the depth above which Bull
    et al. (2020) found over 99% sensitivity and precision for
    single-nucleotide variants; it was 30.
  - correctSFSBias(), compareSFS(), the WithinHostSFS bins and depth
    slot, consensusISNV(), flagReplicateDiscordance() and
    validateDiversity() are documented as implemented: truncation
    rescales the whole spectrum, bins are right-closed, the stored depth
    is a median, the consensus object holds only allele frequencies, and
    the diversity ranges are heuristic plausibility bounds rather than
    literature values.
  - ISNVFilter() documents minBaseQual, minMapQual and replicateConc as
    recorded but not applied, and flagISNV() warns when they are set,
    instead of ignoring them silently. WithinHostExperiment() requires
    an altFreq assay, as documented.
  - trackFrequency() builds its table in one vectorised step, which is
    much faster on genome-wide data and gives the same rows.
  - plotFrequencySpectrum(), plotPairScatter() and plotQCDashboard()
    clip the view with coordinate limits instead of removing data
    outside the axis range, which dropped jittered points with a
    warning; plotFrequencyTrajectory() uses the Okabe-Ito palette, as
    described, and plotSFS() recycles it for more than eight samples.

New features

  - WithinHostExperiment S4 class extending RangedSummarizedExperiment
    for within-host pathogen iSNV data, with setValidity enforcing
    structural invariants.
  - Multi-caller import: readWithinHost() reads VCFs in the LoFreq,
    Freebayes, generic and iVar-style field layouts with auto-detection
    (ivar variants writes a TSV, so an iVar-style VCF comes from a
    converter). readWithinHostTable() handles the iVar TSV directly, and
    generic CSV.
  - Replicate-aware QC: flagISNV() applies configurable quality filters
    without removing data. flagReplicateDiscordance() identifies
    discordant technical replicates with full provenance logging.
    flagPrimerSites() masks amplicon primer regions.
  - Diversity indices: shannonISNV(), piISNV() (with optional
    finite-sample correction per Nei 1987), wattersonISNV(),
    simpsonISNV(), chao1ISNV(), and calcDiversity() for per-sample
    within-host diversity.
  - Neutrality tests: tajimaD(), fusFs(), and calcNeutralityTests() for
    site-frequency-spectrum-based neutrality testing with
    deep-sequencing-aware sample size capping.
  - Site frequency spectrum as a first-class object: WithinHostSFS S4
    class stores the within-host SFS with metadata (sample, genome
    length, depth, detection threshold). buildSFS() / buildSFSList()
    construct from a WHE; correctSFSBias() applies ascertainment bias
    correction for the detection threshold (truncation or binomial
    method); neutralityFromSFS() computes Tajima's D, Fu's Fs, and Fay
    and Wu's H (new) from a single SFS object; compareSFS() tests SFS
    homogeneity between samples; plotSFS() provides publication-quality
    SFS visualisation.
  - Temporal QC for longitudinal data: flagTemporalInconsistency()
    identifies transient iSNVs that appear at only one timepoint (likely
    artefacts) versus persistent ones detected across multiple
    consecutive timepoints. Supports configurable minTimepoints and
    minConsecutive thresholds.
  - Cross-contamination detection: detectCrossContamination() identifies
    index-hopping signatures where a high-frequency variant in one
    sample appears at suspiciously low frequency in a co-sequenced
    sample, consistent with adapter exchange during pooled sequencing.
    Returns a structured DataFrame of suspect events with source/sink
    frequencies and run metadata.
  - GFF3 annotation: annotateFromGFF() overlaps variant sites with gene
    models from a GFF3 file, adding GFF_FEATURE to mcols(rowRanges) for
    use with dndsWithinHost(). annotateCodonChange() extends this with
    CDS-aware codon translation: given a GFF3 and reference FASTA, it
    determines the affected codon, translates both reference and
    alternative alleles using the standard genetic code, and classifies
    each SNV as Synonymous, Nonsynonymous, or Nonsense -- all in pure R
    with no external annotation tools required.
  - Selection analysis: dndsWithinHost() estimates within-host dN/dS
    with the Nei-Gojobori counting method, normalising by the synonymous
    and nonsynonymous sites of the CDS features in a GFF3 and reference
    FASTA, with Jukes-Cantor correction; estimateSelectionCoefficient()
    for time-series selection coefficient inference.
  - Multi-caller consensus: consensusISNV() for deriving consensus
    variant calls across callers, calcCallerConcordance() for
    inter-caller agreement metrics, benchmarkCallers() for caller
    performance comparison.
  - Longitudinal analysis: trackFrequency() for tracking variant allele
    frequencies over time, detectEmergingVariants() for identifying
    newly arising variants, plotFrequencyTrajectory() for
    publication-quality trajectory plots.
  - Transmission analysis: transmissionPairs(), exportPairFrequencies(),
    calcSharedVariants(), and quickBottleneck() (approximate
    beta-binomial MLE, Sobel Leonard et al. 2017) for bottleneck
    estimation.
  - Exact bottleneck estimation: exactBottleneck() implements the exact
    beta-binomial, Wright-Fisher, and presence-absence methods (Sobel
    Leonard et al. 2017).
  - Strand bias detection: sciStrandBias() and flagStrandBiasSCI() for
    strand bias filtering that accounts for unequal strand coverage.
  - Adaptive filtering: adaptiveFilter() for technology-specific QC
    presets (Illumina, ONT, PacBio HiFi).
  - Diversity modelling: fitDiversityModel() for regression modelling of
    diversity measures, multitestCorrection() for multiple testing
    correction, permutationTest() for non-parametric hypothesis testing.
  - Validation: validateDiversity() for cross-checking diversity
    estimates against literature-reported ranges.
  - ViralBottleneck bridge: asViralBottleneckInput() exports
    standardised data for the ViralBottleneck package (Zheng et
    al. 2025).
  - Interoperability: as(whe, "VRanges"), as(vr,
    "WithinHostExperiment"), and as(whe, "data.frame") for seamless
    integration.
  - Batch operations: methods for the S4Vectors combineRows() and
    combineCols() generics merge experiments together with their QC logs
    and filters.
  - Publication-quality visualisation: plotFrequencySpectrum(),
    plotPairScatter(), plotQCDashboard(), and plotFrequencyTrajectory()
    with a colour-blind-safe palette (Wong 2011).
  - SARS-CoV-2 case study in the vignette, with the same workflow run on
    synthetic examples for influenza A, HIV-1 and M. tuberculosis.
