Changes in version 0.99.3 - Docker/docs polish and manuscript-readiness pass performed on top of 0.99.2; no public API change. Aligned documentation wording with analyze_differential_domains() (limma-on-continuous-intensity caveat, NA != zero-signal semantics) and synced regenerated man pages. Changes in version 0.99.2 - Removed inst/CITATION until a manuscript with a DOI is available (README carries the inline citation instead). - codecov.yml: patch coverage gate set to informational so a continuation line (e.g. a string literal) that maps poorly to coverage feedback does not fail commits; README badge switched to the token-free codecov.svg. - Windows notes and error messages clarified. Changes in version 0.99.1 - Made elbow calling orientation-aware so inverse/left-loaded ranked curves produce no_call instead of an implausibly large Super set. - Propagated both NA and the explicit Uncertain class through combined and per-sample transitions. - Fixed two-group limma analysis for grouping factors with unused levels. - Added genome/seqlevel compatibility checks for signal extraction and cross-mark integration; epigenomic cross-mark overlaps are now explicitly strand-agnostic. - Modernized the package citation and strengthened caller input validation. Changes in version 0.99.0 (2026-08-10) Cross-mark integration and per-sample transitions (2026-08-26) - New integrate_cross_mark(se_a, se_b, ...): overlays the per-sample super-domain calls of object B onto the (possibly DIFFERENT) domain universe of object A. Each object A domain is classified from the object B calls of the object B domains that overlap it (any_super or majority aggregation, optional min_overlap_bp). Enables the two-axis design (e.g. enhancer-mark Intensity on the promoter mark's domains, or boundary-rescue of promoter-proximal enhancers). Adds _Call__ + _NOverlaps__ rowData columns, a long-format table in metadata(se_a)$cross_mark_integration, and provenance in metadata(se_a)$cross_mark_provenance. - New transition_matrix_per_sample(se, feature/call_fmt, timepoints, ref): pairwise transitions between per-SAMPLE call columns (mode per_sample, one sample per time point), which compare_superdomains()/compare_superdomain_classes() do not support (they need per-GROUP columns). Adds _SampleTransition___vs_ rowData columns with compare_superdomain_classes()-consistent labels (Persistent_ / to / Uncertain) and per-pair counts tables in metadata(se)$transitions. With ref = NULL all ordered time-point pairs are computed. BEDPE contact-score aggregation in annotate_epi_domains() (2026-08-26) - New bedpe_score_col argument: an optional BEDPE column (integer index = 7 or column name) holding a per-record contact STRENGTH, e.g. the FitHiChIP TMM-normalized contact frequency. Motivated by real datasets (GSE251898) where the published TMM BEDPE loop SET is identical across conditions and only the score varies — count-based contact integration alone is invariant there by construction. - When supplied: metadata(se)$domain_gene_links$contact_score carries the per-evidence-row score; the dedup pair table and the annotation summary gain bedpe_contact_score (summed over UNIQUE supporting records; domain level = sum over all contacted records); rowData(se)$bedpe_contact_score mirrors the domain-level value. bedpe_provenance$score_column records what was used. - Semantics: no BEDPE evidence -> 0; evidence without usable scores (or runs without bedpe_score_col) -> NA, so "no 3D evidence" and "unscored 3D evidence" remain distinguishable. - get_domain_genes() gains a bedpe_contact_score column and a new rank_by = c("tier", "bedpe_score") argument: "bedpe_score" prioritizes candidate genes primarily by descending 3D contact strength (dominant-loop-style target assignment), with the evidence tier and expression as tie-breakers. - Default behaviour (bedpe_score_col = NULL) is unchanged apart from the two new NA-valued columns. Statistical hardening of analyze_differential_domains() (2026-08-23) - analyze_differential_domains() now fits the limma mean-variance trend by default (trend = TRUE): integrated intensity exhibits a strong mean-variance dependence across domains, and without the trend low-signal domains were over-called as significant. The trend is disabled automatically with a warning when fewer than 20 domains pass min_signal filtering. - New robust = FALSE argument exposes limma's robust empirical-Bayes moderation for outlier-resistant inference. - Both settings are recorded in metadata(se)$differential_domains provenance; invalid values are rejected. - Documented the scale-dependence of the log(x + 1) pseudo-count offset (CPM vs RPGC vs spike-in units) and its interaction with min_signal. - eBayes(trend = TRUE) changes P-values slightly relative to previous releases; re-run differential analyses after upgrading. - Bug fix: a two-element character contrast (coefficient-name pair, documented as coef1 - coef2) was silently ignored and the uncontrasted fit was returned. It is now converted to numeric contrast weights, with a clear error when a name does not match a design coefficient. Supplying design without any contrast is now also rejected instead of silently returning an uncontrasted fit. - Bug fix: a user-supplied formula design (e.g. ~ Condition or ~ 0 + Condition) crashed inside limma with an obscure internal error, because the formula object was passed to lmFit() unconverted. Formulas are now materialized with model.matrix() on colData before fitting, so custom paired/batched designs are actually usable. Expert review fixes (2026-08-14) - normalize_portrait(): the completion message no longer uses a sprintf() format string without a placeholder (this produced a runtime warning "argument out of range" and truncated the message to "Normalization complete! Intensity adjusted; SignalDispersion "). The "(bp-scale spatial descriptor) is left unchanged" note is now emitted correctly. - plot_hockey_stick(): when the object was called with mode = "per_group" and group is omitted, the error now states that the calls are per-group and lists the available condition groups, instead of the misleading "Run call_super_domains first" message. - annotate_epi_domains(): the strand-aware signed nearest-TSS distance is now fully vectorized (one match() over the gene model instead of a per-domain O(genes) subsetting loop); output is unchanged. - build_portrait_matrix(): the batch import path accumulates Intensity into a double (numeric()) vector instead of integer() (values were never truncated because R promotes on assignment, but the type was misleading for continuous CPM/RPGC signal). - plot_peak_track(): replaced scale_fill_brewer("Set1") (capped at 9 groups) with the package's own condition palette, consistent with the rest of the visualization suite. - call_super_domains(): documented the intentional asymmetry of min_valid_replicates under support_rule = "fraction" (a low threshold, e.g. 0.5 with n=2, resolves to 1 and can call a "Super + no_call" pair Super because the user explicitly chose how much support suffices). - Added regression tests: fractional Intensity preservation through build_portrait_matrix() (double precision, cache and non-cache paths identical) and the per-group hockey-stick error message. Documentation repositioning (2026-08-11) - Package identity repositioned from "super-domain caller" to "replicate-aware epigenomic domain profiling": DESCRIPTION title and README/vignette narrative now describe the framework as quantitative phenotyping of shared epigenomic domains (Intensity x native peak breadth + within-domain signal architecture), with super-domain calling as one analytical module. ROSE is presented as an optional H3K27ac benchmark; the tangent inflection is documented as a geometric variant, not a bit-exact ROSE reproduction. Breadth top-fraction & stability calling (2026-08-11) - call_super_domains(feature = "Breadth") now supports quantile_cutoff as an explicit top-fraction opt-in, symmetric with Intensity: the cutoff is the quantile_cutoff quantile of each replicate's genome-wide eligible native PeakWidth distribution (top 100*(1-quantile_cutoff)% widest peaks are Broad; e.g. 0.95 = top 5%). It never auto-falls-back to, or from, the data-driven elbow/tangent inflection, so no-call semantics of the default path are unchanged. quantile_cutoff and min_replicate_support are now validated. - n_bootstrap is supported for Breadth (symmetric with Intensity): a per-replicate within-set cutoff stability interval and success rate are stored in get_call_provenance(se, "Breadth")$replicates[[s]]. As with Intensity, this is a resampling-stability diagnostic whose information content shrinks with the size of the ranked set; the dominant uncertainty for Breadth (upstream native-peak set composition) is assessed separately via the peak-set perturbation check in validation/02. Freeze pre-check fixes (deep review 2026-08-10) - Z-score normalization REMOVED from normalize_portrait(): it is a row-wise display/clustering transform that destroys the cross-domain magnitude ranking required by Super calling and must never overwrite the canonical Intensity assay. plot_portrait_pca() and plotting layers already apply their own scaling for display. normalize_portrait() description now states that SignalDispersion is preserved in native bp units. - plot_domain_landscape() now accepts and respects group_var (was hard-coded to "Condition"), matching call_super_domains() / get_replicate_calls() / combine_superdomain_calls() for custom group variables. - filter_promoter_peaks() now enforces domain/TxDb seqlevel compatibility (zero shared -> error, partial -> warning) and validates upstream/downstream parameters, consistent with annotate_epi_domains(). - filter_blacklist() now fails loudly on zero shared seqlevels (chr1-vs-1 mismatch) instead of silently removing 0 peaks, and warns on partial overlap. - validate_epiportrait_object() now verifies the replicate_call_matrix contract (rows = domains, rownames = domain IDs, columns a subset of samples). - stitch_epi_peaks(): min.gapwidth = stitch_distance + 1 so a gap exactly equal to the documented "maximum distance" is merged (off-by-one fix). - get_replicate_calls(group = NULL) preserves the original sample order instead of the alphabetical group order used during column binding. - Removed package-root Rplots.pdf; added ^Rplots[.]pdf$ to .Rbuildignore. - Updated stale comments (annotation resolver, NEWS font wording). Nature-style publication theming (nature-figure skill) - All plots now use a Nature-style publication theme: no background grid lines, thin black axis lines, platform-safe sans-serif, compact base sizes, and frameless legends. Affected: .epi_theme_publication() (hockey-stick, PCA, landscape, transition, replicate support, class composition, feature profile), plot_peak_track() and plot_portrait_correlation() (both switched from theme_minimal to the grid-free classic theme). - Export via save_epiportrait_figure() produces editable-text SVG / PDF (vector fonts, no outlined paths). Intensity replicate-calling transparency (design 2026-08-10) - New get_replicate_calls(): exposes the per-domain x per-replicate super-domain call matrix underlying the group-level replicate-support call (matrix or long format). For mode = "per_group" it reads the stored provenance (replicate_call_matrix is now saved per group); for mode = "per_sample" it reconstructs from the Call_ rowData columns. - call_super_domains(mode = "per_group") now stores the full domain x replicate call matrix in metadata(se)$superdomain_calls[[feature]]$groups[[g]]$ replicate_call_matrix, making 2/3-style support fully auditable. - Documentation clarified (mode descriptions): per_group calls EACH replicate independently on its own ranked feature distribution, then aggregates replicate calls by the support rule; group-mean ranks are stored for visualization only and never determine the group call. - Fixed min_valid_replicates documentation: NULL (default) resolves to the support-rule-required number (majority: floor(n/2)+1; all: n; fraction: ceiling(fraction*n)), not "default 1". Species/genome & annotation audit fixes (deep audit 2026-08-10) - P0-1: filter_blacklist() no longer depends on the TxDb/OrgDb resolver. Blacklist resolution is independent: built-in hg38/hg19/mm10/mm9 blacklists load directly from inst/extdata, so mm9 works and blacklist filtering never requires a TxDb Suggests package. Custom BEDs via blacklist_path. - P0-2: domain-TxDb seqlevel compatibility is now ENFORCED in annotate_epi_domains(): zero shared seqlevels -> error (with domain-only seqlevels reported); partial overlap -> warning. A genome-build / chr-vs-1 naming mismatch is never silently reinterpreted as intergenic domains. Compatibility details (shared, domain_without_txdb, txdb_only) are stored in annotation_provenance. - P1-1: min_expression is now genuinely NULL by default. expressed_first on TPM/CPM uses a documented convenience threshold of 1; on VST/rlog/ normalized_counts it requires an explicit user threshold. high_expression_first needs no threshold and leaves expression_status NA. - P1-2: wide RNA expression matrices with ANY unmatched sample column now error (previously silently dropped); a subset of ChIP samples is allowed. - P1-3: wide RNA validates unique non-empty rownames and numeric values. - P1-4: candidate_priority is re-ranked to a contiguous 1..N ordinal after unique_genes collapse (no gaps from dropped rows). - P1-5: added a real evidence-vs-expression test (BEDPE-supported low-expression gene outranks nearest-only high-expression gene). - P1-6: BEDPE provenance/comment wording unified: records are not modified or re-scored; bedpe_record_id links derived evidence back to the source. - P1-7: gene_symbol is NA when no symbol mapping is available (never a gene_id masquerading as a symbol). - P1-8: a user-provided gene_id_keytype whose mapping fails now warns (not silent); gene_id_keytype is recorded in annotation_provenance. - P1-9: BEDPE seqlevel_style inferred from the anchors (UCSC or custom/unknown), not hard-coded. - P1-10: promoter_upstream / promoter_downstream validated (finite, >= 0). - P1-11: get_domain_genes() validates domains length/NA, group existence, and requires group + expression data for expression_priority != "none". - P1-12/13: documentation clarifies the gene-level representative TSS and the difference between filter_promoter_peaks() (transcript-level promoters) and annotate_epi_domains() (gene-level promoter window). - P1-14: export_epiportrait_results() writes annotation/domain_gene_links.tsv and annotation/provenance.txt when domain annotation is present. - Added 11 audit tests (mm9 blacklist, blacklist/TxDb independence, zero/partial seqlevels, wide unmatched samples, rownames/numeric validation, VST threshold, invalid group, unique rerank, evidence-vs-expression, annotation export). Annotation correctness fixes (deep review 2026-08-10) - P0-1: .gene_model_from_txdb() no longer reduce()s TxDb genes. One TxDb gene is now always one gene-level feature; overlapping genes are never merged into a pseudo-gene ("geneA,geneB"). - P0-2: nearest_tss_distance_bp is now the strand-aware SHORTEST interval-to-TSS distance: 0 when the TSS lies inside the domain (previously the midpoint offset could give several kb for an overlapping TSS). - P0-3: nearest-TSS hits are backfilled by queryHits() so domains on contigs absent from the TxDb stay NA instead of misaligning. - P0-4: primary_genomic_context simplified to Promoter-associated / Gene-body-associated / Intergenic, consistent with the count columns (no more over-produced "Mixed" or unbounded "Downstream"). - P0-5: long-format RNA aggregation now uses stats::aggregate (correct gene x replicate collapse; tapply length mismatch fixed). - P0-6: wide RNA matrix columns are matched to epiPortrait samples BY NAME, not by position; independent RNA sample IDs require the long-format input. - P0-7: candidate_priority is now a true integer rank (order() permutation was being assigned directly). - P0-8: BEDPE evidence score uses pmax() so the strongest 3D evidence is never overwritten by a weaker relation on the same domain-gene pair. - P1-1: gene symbols are resolved once over ALL linked gene ids and backfilled into every relation row (previously only nearest_tss got symbols). - P1-2: gene_id_keytype parameter; custom TxDbs require an explicit keytype instead of hard-coded ENTREZID. - P1-3: unique_genes = TRUE now retains the BEST-SUPPORTED domain-gene association per gene (sorted by priority first). - P1-4: bedpe_support_count counts UNIQUE BEDPE records (a record matching via both directions is no longer double counted). - P1-5: BEDPE seqlevels are actually checked against the domains (zero shared -> error; partial -> warning). - P1-6: BEDPE input validation (non-empty chrom, numeric coordinates, start>=0, end>start). - P1-7: BEDPE provenance notes that records are not modified/re-scored and that bedpe_record_id links derived evidence back to the source (accurate promise). - P1-8: BEDPE promoter-contact linking is range-vectorized (one findOverlaps per direction + join by record id), scaling to 10^4-10^6 interactions. - P1-9: expression provenance records the RNA sample IDs (not the ChIP ones). - P1-10: RNA gene-ID match QC (n_matched / match_fraction in provenance; stop on zero matches, warning on <50%). - P1-11: min_expression = NULL default semantics; expressed_first on non-TPM/CPM types requires an explicit user threshold. - P1-13: ChIPseeker removed from README/vignette install commands and vignette section title (DESCRIPTION no longer imports it). - Genome resolver: custom TxDb seqstyle inferred from seqlevels (no longer hard-coded "UCSC"); filter_blacklist() now uses the shared resolver. - Added 17 edge-case tests (overlapping genes, TSS-inside-domain distance=0, contig mismatch, RNA long/wide alignment, candidate rank, BEDPE validation). Domain-aware annotation & candidate-gene prioritization (integrated design 2026-08-10) - New annotate_epi_domains(): genome-flexible, domain-aware annotation of the final shared domains (not individual peaks). Adds 7 compact rowData columns: primary_genomic_context, nearest_tss_gene_id, nearest_tss_gene_symbol, nearest_tss_distance_bp (strand-aware), promoter_overlap_gene_count, gene_body_overlap_gene_count, fully_contained_gene_count. Stores a long-format domain-gene link table in metadata(se)$domain_gene_links. - New get_domain_genes(): transparent candidate-gene extraction / ordinal prioritization from the stored evidence (evidence first, expression as a secondary tie-breaker; no black-box composite score). - New internal .resolve_genome_resources() / .check_seqlevel_compatibility(): unified genome resource contract (hg38/hg19/mm10 built-in TxDb/OrgDb, mm9 blacklist-only, custom TxDb/OrgDb/blacklist) shared by annotate_epi_domains(), filter_promoter_peaks() and filter_blacklist(). - BEDPE 3D evidence: optional bedpe_promoter_contact (symmetric / bidirectional domain-anchor to gene-promoter contact). BEDPE is read-only: no calling, filtering, merging, or FDR re-scoring; bedpe_record_id links derived evidence back to the source; per-record bedpe_record_id; provenance in metadata(se)$bedpe_provenance. - RNA-seq expression integration: user-declared expression_type (TPM/CPM/VST/ rlog), per-condition median aggregation over replicates, and expression-aware prioritization (none / expressed_first / high_expression_first). Expression alone never creates a domain-gene link (evidence required first). - Removed annotate_epi_peaks(): it was a thin ChIPseeker::annotatePeak() wrapper and epiPortrait's analysis object is the shared domain, not the individual peak. Peak-level annotation remains available via ChIPseeker. - Provenance: metadata(se)$annotation_provenance, $bedpe_provenance, $expression_provenance. - Added 23 tests (genome resolution, linear annotation, BEDPE contacts, RNA-seq integration, candidate prioritization). Changes in version 0.99.0 (2026-08-09) Pre-submission release for Bioconductor. Metric redesign (v1.0 design docs, 2026-08-09): the taxonomy is simplified to the two-axis architecture Intensity x Breadth, and Breadth-Super is moved to a peak-level, consensus-free calling paradigm. Heterochromatin / broad-repressive mark compatibility (plan 2026-08-10) - get_mark_preset() now returns mark_class ("active" / "broad_repressive"), taxonomy_style ("super_domain" / "repressive_remodeling") and class_labels (display aliases). H3K27me3 / H3K9me3 default to stitch_distance = 0: their domains are already spatially clustered by the upstream broad-domain caller (SICER / epic2 / RECOGNICER / MACS2_broad), so epiPortrait no longer applies an extra 5 kb stitching by default (users can pass stitch_distance = 5000 explicitly). - Display-only terminology: with mark = "H3K27me3" (or H3K9me3), plot_domain_ landscape(), plot_class_transition() and plot_domain_class_composition() render Intensity-Extreme / Extended-Domain / Dual-Extreme. The internal canonical classes (Intensity-Super / Breadth-Super / Dual-Super) are never changed, so the API and transition engine stay mark-independent. - New compute_width_transition(): continuous domain-width expansion/contraction descriptor (WidthDelta_bp, log2WidthRatio, WidthDirection) between two condition groups, computed from per-domain median native width. This is a continuous effect descriptor, not a significance test (no new p-value framework at n=2/n=3). - build_portrait_matrix() records domain-source / caller provenance in metadata(se)$domain_provenance when the sample sheet carries optional domain_source / domain_caller / caller_version / caller_mode columns. - Added tests: mark presets, display alias mapping, mark-aware plots, compute_width_transition semantics, domain provenance. Correctness fixes from the deep review (2026-08-09) - Performance: .native_peak_geometry() is now fully vectorized. The previous per-domain R loop (one intersect/reduce per domain) took ~100 s for 3,000 domains and ~17 min for 26,000 domains, making build_portrait_matrix() unusable at mammalian scale. The rewrite clips all peaks to their domains in one pintersect() call and reduces only multi-peak domains (single-peak domains need no reduce), giving an ~10,000x speedup with identical output. Verified on real GBM10 H3K4me3 (26,483 domains): 98.7 s -> 0.01 s for the geometry step; full build_portrait_matrix() incl. a 450 MB BigWig runs in ~6 s. - Breadth-Super: a replicate whose native PeakWidth elbow is NOT reliable (no_call) now contributes NO evidence (its domains become Uncertain) instead of being coerced to "all Typical". Previously no_call was encoded as an all-FALSE logical vector, silently downgrading super support. - Breadth-Super mapping: Unmapped / Ambiguous peaks now never produce Typical evidence. Only uniquely-mapped peaks contribute evidence (broad wins over typical inside a domain). Previously any-overlap domains could be labelled Typical even when their only peak was below the overlap threshold or ambiguous. - build_portrait_matrix(): has_peaks is now always a per-sample logical vector. Previously, when no peak_path column existed, has_peaks was a scalar FALSE and has_peaks[i] for i>1 evaluated to NA, breaking BigWig-only multi-sample mode. has_peaks is also correctly re-subset after fail_action = "drop". - normalize_portrait(): SignalDispersion (a spatial descriptor in bp) is no longer rescaled by library-size factors, quantile or z-score transforms. Only Intensity is normalized; SignalDispersion stays in bp and is scale-invariant by construction. - compare_superdomains(): fixed an inverted condition that forced support_rule = "majority" for reference/pooled transitions even when the stored call used "all" or "fraction". - call_super_domains(feature = "Breadth"): quantile_cutoff is supported as an explicit top-fraction opt-in on the genome-wide native PeakWidth distribution (see "Breadth top-fraction calling" above); n_bootstrap is supported per replicate (within-set cutoff stability, symmetric with Intensity); and min_peak_overlap_fraction is validated to lie in [0, 1]. - Breadth peak-to-domain mapping provenance now records OverlapBp, PeakOverlapFraction, DomainOverlapFraction, the row index AND the actual Domain_ID (epiDomain_xxxxxx). - plot_hockey_stick(feature = "Breadth"): new peak-level branch that plots the replicate-specific native PeakWidth rank curve from metadata(se)$breadth_peak_calls; the replicate is passed via group. - validate_epiportrait_object() now requires Intensity and SignalDispersion (native geometry assays remain optional). - Added unit tests for Breadth no-call propagation, below-threshold Unmapped, ambiguous ties, unique broad/typical mapping, broad-over-typical precedence, and overlap-fraction provenance; consensus A/B robustness benchmark in validation/02_breadth_super_validation.R (Jaccard / PeakBroadCall concordance). Breaking changes (v1.0 metric simplification) - Assays: RobustHeight and EffectiveWidth (alias Spreading / Central80Width) are REMOVED from build_portrait_matrix(). Core assays are now Intensity, SignalDispersion, and (when peak files are provided) NativeMaxPeakWidth, NativeOccupiedWidth, NativePeakCount. The static interval length stays in rowData(se)$IntervalWidth. - signal_contract metadata no longer carries width_baseline_quantile (the central-80% span was removed); SignalSpan80 / .central80_width() are gone. - call_super_domains(): feature = "Breadth" routes to a NEW peak-level Breadth-Super pipeline (see below). RobustHeight / EffectiveWidth / Spreading are no longer valid features; use Intensity, SignalDispersion or Breadth. - combine_superdomain_calls(): combines Intensity x Breadth and produces Intensity-Super / Breadth-Super / Dual-Super / Typical / Uncertain (Width-Super is renamed Breadth-Super). - get_mark_preset(): broad marks (H3K4me3 / H3K27me3 / H3K9me3) now default to primary_feature = "Breadth". New: peak-level Breadth-Super calling - Breadth-Super is called at the NATIVE PEAK level, before and independently of consensus construction: each replicate's genome-wide eligible native PeakWidth distribution is ranked and cut by an elbow/inflection (method / min_quality / tie_policy), producing PeakBroadCall per peak. - Broad peaks are mapped to the shared domain universe by UNIQUE assignment (maximum overlap + min_peak_overlap_fraction, default 0.5); a peak cannot double-count into neighbouring domains (MappingStatus = Unique / Ambiguous / Unmapped). - Replicate-aware aggregation (support_rule / min_replicate_support / min_valid_replicates) yields group-level / global Breadth-Super. - Sample-specific native peak files are OPTIONAL: provide peak_path in the sample_sheet to build_portrait_matrix(). Imported peaks are stored in metadata(se)$native_peaks; peak-level calls and mapping provenance are stored in metadata(se)$breadth_peak_calls / breadth_peak_mapping. - New params on call_super_domains(): min_peak_overlap_fraction, valid_chroms. New: SignalDispersion - Signal-weighted genomic SD within each domain. Secondary within-domain signal architecture descriptor; scale-invariant, spatially sensitive, and requires no background baseline. Replaces the removed EffectiveWidth as the continuous-profile descriptor, but does NOT define Breadth-Super. Visualization - plot_domain_landscape(): y-axis defaults to NativeMaxPeakWidth (falls back to NativeOccupiedWidth / SignalDispersion). - plot_peak_track(): show_effective_width replaced by show_native_occupancy (NativeOccupiedWidth band). - plot_peak_portrait(): features default to Intensity, SignalDispersion, NativeMaxPeakWidth. - Example data (example_se) regenerated with the 5-assay structure and native peaks; validation scripts updated (01_signal_dispersion_validation.R, 02_breadth_super_validation.R). Changes in version 0.99.0 (2026-08-08) Pre-submission release for Bioconductor. Complete refocus of the package from the legacy "4D Shape Shift / MANOVA" framework to a BigWig-first super-domain profiling framework. Algorithm & science - P0-1: negative_policy is now applied once via .sanitize_signal() BEFORE any feature is computed; clip_zero actually clips negatives (Intensity, RobustHeight, EffectiveWidth, custom features all share the sanitized vector). NA positions are treated as 0 to preserve the genomic coordinate axis. The negative fraction is now computed over signal positions (not domain count) and stored in colData(se)$NegativeFraction. - P0-2: bootstrap resampling preserves the user-selected log scale. The effective transform is resolved once; log_transform=FALSE stays FALSE inside the bootstrap (previously it silently re-resolved to TRUE for Intensity). metadata records log_transform_requested and log_transform_used. - P0-3: replicate support uses a configurable rule (support_rule = "majority" | "all" | "fraction") with a min_valid_replicates requirement. no-call replicates are never counted as Super and never inflate support (previously Super + no_call gave 100% support). n=2 majority now requires 2/2. - P0-4: compare_superdomains() gained cutoff_scope = "relative" (default) | "reference" | "pooled". Relative transitions are reported as Relative_Prominence_Up/Down and must not be interpreted as absolute Gain/Loss; only reference/pooled common-cutoff modes report Gain/Loss. - P0-5: Spreading (EffectiveWidth) is sensitive to low-level distributed background; added width_baseline_quantile to build_portrait_matrix() to subtract a per-profile baseline before computing the span. Simulation shows a 100 bp peak in a 1000 bp domain spans ~81 bp for background 0-2 with q10 correction vs 81-700 bp without (validation/01_signal_width_validation.R). - Added min_quality argument to call_super_domains() (previously implicit). - Removed legacy MANOVA and Shape Shift modules: test_global_shape_shift(), test_shape_shift(), test_differential_feature(), classify_shape_shift(), detect_conformational_outliers(), simulate_power(), plot_power_curve(), and their dependent visualization/export/report functions. - Removed the Skewness assay from build_portrait_matrix() (was signal-value skewness, not genomic spatial directionality). Portrait now produces Intensity, RobustHeight, and Spreading. - Added Spreading (per-sample effective signal span = central 80% signal-mass span) as a core assay, aliased as EffectiveWidth / Central80Width. - Moved the static genomic interval length out of the assays into rowData(se)$IntervalWidth (alias "Width"). - Height is now RobustHeight (95th percentile of the signal profile), robust to single-bin spikes. - Added find_hockey_inflection() with two inflection heuristics: - "elbow" (default): maximum perpendicular distance on [0,1]-normalized coordinates; dimensionless and scale-invariant. - "tangent": tangent-optimization cutoff ported from the ROSE algorithm (Whyte et al., 2013, Cell 153:307-319). - Added log_transform argument to call_super_domains(): NULL (auto), TRUE, or FALSE (rank on raw scale for ROSE-style comparison). - Added combine_superdomain_calls() for the Intensity-Super / Width-Super / Dual-Super / Typical / Uncertain taxonomy. Default width feature is now EffectiveWidth (dynamic breadth), not static interval length. - call_super_domains() now stores full call provenance in metadata(se)$superdomain_calls (cutoff, cutoff_CI, quality, status, ...). - Consensus mode is condition-aware: replicate support is stratified by group. per_group mode is replicate-aware (per-replicate calls + group support) rather than a single group-mean ranking. - normalize_portrait() now defaults to method = "None"; TotalSignal and Quantile emit warnings that they may remove genuine global biological shifts. - build_portrait_matrix() gained negative_policy ("error" | "clip_zero" | "allow") and fail_action ("stop" | "drop") arguments. - Added check_signal_compatibility() for pre-analysis BigWig QC. - build_portrait_matrix() now imports BigWig coverage in region batches (memory-bounded for mammalian-scale domains). - Cache keys include full path + size + mtime to avoid collisions and stale reads. - Rewrote vignette and README around the super-domain workflow. - Updated example_se dataset (Spreading assay, RobustHeight, IntervalWidth). Bioconductor packaging - Version bumped to 0.99.0 for first submission. - Removed LazyData; removed unused Suggests; added TxDb and rmarkdown Suggests; unified maintainer metadata via Authors@R. - R CMD check passes with 0 errors / 0 warnings / 0 notes (including --run-donttest). Changes in version 0.1.0 (2026-05-12) Initial Release - Added build_portrait_matrix() core engine for 4D geometric feature extraction (Width, Intensity, Height, Skewness) from BigWig coverage with BiocParallel support, HDF5 on-disk storage option, and per-BigWig caching. - Added get_consensus_peaks() and stitch_epi_peaks() for consensus peak calling and macro-domain stitching. - Added call_super_domains() for ROSE-style single-dimension super-element / broad-domain / steep-peak identification. - Added normalize_portrait() with TotalSignal, Quantile, and TMM methods. (A row-wise Z-score method was prototyped but removed before release: it is a display/clustering transform that would destroy the cross-domain magnitude ranking used by Super calling.) - Added visualization suite: plot_peak_portrait(), plot_peak_track(), plot_hockey_stick(), plot_portrait_pca(), plot_portrait_correlation(). - Added annotate_epi_peaks() for ChIPseeker-based gene mapping with lazy TxDb loading for hg38, hg19, and mm10. - Added filter_promoter_peaks() for promoter-proximal peak exclusion.