Skip to content

QC Flags

Every flag, reason and class gbcms writes is defined here, once. Other pages include these tables (snippet sections of this file) or link to them, so a definition is written in one place. Three tests keep it that way: one fails when a flag the code emits is missing from this page, one when a flag is defined anywhere else in the docs, and one when the end-of-run summary's table (below) and this page's definitions differ.

Where flags appear. MAF columns are listed first, then the VCF field. In VCF, ; inside a value is written |. The run log ends with a summary of the flags that fired and the rows that need a look: End-of-run summary.

Family MAF column VCF field Mode
Verdict and status reasons gbcms_status, gbcms_status_reason INFO GS, GSR all
Diagnostics gbcms_diagnostic INFO GD all (some RNA, some PairHMM only)
MNP rescue gbcms_rescue INFO GR --rescue-mnp
ASJD splice flags asjd_diagnostic, asjd_*_motif INFO ASJDD, ASJDRM, ASJDAM RNA with --gtf
QC columns rna_editing_site, asjd_flag, mfsd_ks_valid, mfsd_alt_confidence, mfsd_ch_flag INFO RED, ASJD; mFSD INFO RNA; --mfsd
Merged output — (read from the simplex_duplex_* cells) — gbcms merge with combined columns
mFSD report classes — (HTML report) — --mfsd-report
Record shapes in VCF output — ALT <NON_SEQUENCE>, INFO MAF_*, NORM_* MAF input; --show-normalization

Verdict and status reasons

gbcms_status is the verdict: PASS (counted) or FAIL (not counted; zero counts, the row kept). gbcms_status_reason lists |-separated reasons, empty for a clean PASS; reasons stack (WARN_REF_CORRECTED|MULTI_ALLELIC), and the same string is in the VCF GSR INFO. How each is decided: Variant Normalization.

Reason Verdict Set when What to do
(empty) PASS The variant validated against the reference —
WARN_REF_CORRECTED PASS The REF matches the reference at ≥90% of its bases; the reference bases are used downstream (the original REF is kept in original_ref) Check the input's REF; counts are for the corrected REF
WARN_HOMOPOLYMER_DECOMP PASS Never set in 6.7.0 (--rescue-homopolymer is deprecated and ignored; removed in 6.8.0). Before: with the flag, the variant spans a homopolymer, was dual-counted with a corrected allele, and the corrected allele won The row reports that allele's counts, not the given one
MULTI_ALLELIC PASS Another input row is a different ALT at the same locus; sibling-ALT exclusion is active None; each row counts its own ALT
TRACT_CLUSTER PASS The variant shares a repeat-tract scan window with a co-annotated length-changing variant (spans need not touch); sibling exclusion and exclusive ALT assignment are active None; read the rows together
REF_MISMATCH FAIL The REF matches the reference at under 90% of its bases Check the build and coordinates; REF_AT_OFFSET(k) in gbcms_diagnostic says where the REF sits when it is a few bases off
FETCH_FAILED FAIL The reference region could not be read (contig not in the FASTA, past its end) Check contig naming and the FASTA
EMPTY_ALLELE FAIL REF or ALT is empty (a malformed indel; a MAF dash allele is -) Fix the input row
NON_SEQUENCE_ALLELE FAIL An allele is not a base sequence (an IUPAC code, a stray character; - outside MAF input); kept in MAF output, written as <NON_SEQUENCE> in VCF output Fix the input row
ALT_EQUALS_REF FAIL ALT equals REF (any case; - for both in a MAF): no change to count Fix the input row
START_BEFORE_CONTIG FAIL A MAF row at Start_Position 0 that is not a dash insertion (a substitution, a deletion, a delins, or an insertion written with sequence alleles). Position 0 is no base, so nothing can be counted. A dash insertion there is counted (resolved to the base after it); see Input Formats. Kept in MAF output, written as <NON_SEQUENCE> at position 1 in VCF output Fix the input row (MAF positions are 1-based)
ALT_CONTAINS_N FAIL The ALT contains an N base Fix the input row

Diagnostics

gbcms_diagnostic (VCF GD) says what the reads, or the reference, show about a row. Semicolon-separated in MAF, | in VCF; empty when none. Set after counting on a PASS row; on a FAIL row only REF_AT_OFFSET. Parametric flags count under their base name in the run log. Examples: ZERO_ALT, PARTIAL_DOMINANT;MNP_DISC_RATIO(2/5);MNP_RESCUE_ELIGIBLE.

Flag Mode Set when What to do
ZERO_ALT all No read carries the ALT (no confirmed ALT reads) None, or check the input allele (see OBSERVED_ALLELE)
PARTIAL_DOMINANT all partial_alt exceeds alt_count. For a pure indel, partial_alt includes reads whose CIGAR shows an indel of a different length in the same tract, so this usually means a coexisting allele the annotation does not describe Inspect (--trace shows per-read lengths)
MNP_DISC_RATIO(n/m) all Every MNP row: n positions where REF and ALT differ, of its m bases Describes the MNP's shape
MNP_RESCUE_ELIGIBLE all n/m is at most --rescue-mnp-threshold: the MNP is a rescue candidate With --rescue-mnp, rescue runs on it
HIGH_N_FRACTION(f) all More than 5% of the depth (f) has N at the locus A masking hotspot (duplex); counts are thinner
CLIP_CANDIDATES(n) all An insertion with no confirmed ALT where n (≥ 2) reads carry a soft clip ≥ 8 bp whose boundary lies within the insert's duplication reach (anchor ± insert length + 10): carriers the aligner may have written as clips rather than insertions Inspect in IGV
OBSERVED_ALLELE(chrom:pos:REF>ALT:n/0) all No read carries the given allele exactly, and n reads carry this allele (canonical VCF form, 1-based POS) The input is likely mis-described; the counts stay the given allele's
COEXISTING_ALLELE(chrom:pos:REF>ALT:n/m) all The given allele is present (m reads carry it exactly), but more reads (n) carry another allele in the same stretch, e.g. a germline indel or stutter in a repeat A caveat for reading the VAF
POSSIBLE_MINORITY_HAPLOTYPE(chrom:pos:REF>ALT:c/n) all At an indel or delins the exact-carrier rule judges, a change within 25 bases of the event whose base is the one the ALT's reads written without their gap show there (1-based POS), carried by c of the n reads placed apart from the event (two or more, over 1%): too few for a haplotype's (under three or 3%) or too one-sided in pair orientation (an oxoG or FFPE artifact sits in one), so it was left unmasked A minority haplotype carrying it (a germline SNP after a tumour's loss, a subclone) would count ALT where its reads read as the ALT; weigh low alt_count here with that in mind. The counts are unchanged
MNV_SHARED(chrom:pos:REF>ALT:n/m) --read-judge sequence, and an SNV row routed to the judge under the rules At a substitution (an SNV) with a co-listed MNV that holds its change (the same length over its bases, reading its ALT where it changes them): n of the row's m ALT reads spell that MNV whole (the MNV's 1-based POS). The judge counts the MNV's carriers as the SNV's ALT reads (RJ-28), so the two rows share them. One flag per such MNV The SNV's alt_count includes the MNV's carriers: one molecule can sit in both rows' counts and mFSD size distributions (two KS tests on one event in the BH family). The counts are unchanged
INDEL_SHARED(chrom:pos:REF>ALT:n/m) --read-judge sequence, and an SNV row routed to the judge under the rules At a row with a listed row that is its ALT with listed neighbours (an indel or delins holding the row's whole change, such as a delins that is two listed deletions together): n of the row's m ALT reads spell that row whole (its 1-based POS). The judge counts that row's carriers as this row's ALT (RJ-28's indel twin), so the rows share them. One flag per such row The row's alt_count includes that row's carriers: one molecule can sit in several rows' counts and mFSD size distributions. The counts are unchanged
UNEXPLAINED_READS(n/m) --read-judge sequence, and an SNV row routed to the judge under the rules n of the row's m depth reads fit none of its candidate sequences (REF, the ALT, the other alleles at its site, each with every context the judge weighs) within ten confident mismatches. The fit rule makes such a read depth only where its aligner places it elsewhere at least as well (XS ≥ AS, or MAPQ 0 with no XS); a read the aligner places here alone is judged by its bases at the row, as any other Weigh the row's counts with that in mind where n is a large share of m: foreign reads the aligner places uniquely (a paralog's, reads at a homozygous deletion in a repeat) can count. The counts are unchanged
UNIT_COUNT_UNSPANNED(change:bases/longest) all At a deletion of 50 bp or more, the nearest other unit count at its breakpoint on either side (one more unit of a tandem run beside it deleted, or one fewer; change is its length change, deleted bases negative) reads like the given deletion past what a read can spell: a read must hold bases bases from the junction windows' first base (the first difference and 24 more) to spell the count in full, and the longest read is longest. A listed other count is held wherever it first differs, and also when its REF runs past the reference held (its bases cannot be read, so no read can be shown to tell it from the given deletion): the reads that do not reach the difference are partial evidence instead of ALT (RJ-24, rule X; alt_count is 0 until a read can tell). A count nobody listed that no read can spell is held for nothing For a count nobody listed, the row's alt_count may include that allele's carriers: no read can tell them apart. A listed one's reads are already partial evidence. The flag changes no count
NO_TELLING_BASE --read-judge sequence At a pure insertion of 50 bp or more, no base within the haplotypes the judge reads tells REF's equal window from the ALT's once the guard's masks are read (RJ-23): the run the insert slides over reaches past the reads, or masks take every base that would tell. Every read is depth only Explains a zero REF and ALT at a covered long insertion; no read could tell the alleles apart
SW_FALLBACK(n) PairHMM backend n depth reads could not be evaluated by the haplotype matrix (the reference context is missing or does not contain them): scored by the Smith-Waterman fallback where it can run, else left NEITHER (one WARN per variant names why) The row's counts came partly from another scorer, or miss reads
SPLICE_SKIP_DOMINANT(n) RNA A deletion-type locus where more reads splice over the deleted span (CIGAR N, no observation) than confirm ALT; RNA aligners write large deletions as splices (STAR: ≥ alignIntronMin, default 21 bp) alt_count 0 may hide carriers written as junction reads
NON_DISCRIMINATING_LOCUS PairHMM backend A nearby germline sibling combination reconstructs the reference haplotype (e.g. a homopolymer deletion cancelled by an adjacent insertion of the same base), so REF and ALT are the same sequence and reads tie to NEITHER Explains zero REF and ALT at a covered locus
RESCUED_COMPONENT(chrom:pos:REF>ALT) --rescue-mnp The row's counts are that component SNV's, not the annotated MNP's Read gbcms_rescue
REF_AT_OFFSET(k) all (FAIL rows) A REF_MISMATCH row's REF (3+ bases) matches the reference exactly k bases from its position (every such offset within 3, nearest first, /-separated) Correct the input's coordinates; the row is not moved or counted

OBSERVED_ALLELE and COEXISTING_ALLELE both need n ≥ 3, n > m, n ≥ 5% of the scanned reads, and an allele that is not already an input row. One exception: at a deletion of 50 bp or more beside a run of its unit, another unit count present at its breakpoint (listed in the input, always; or, unlisted, spelled in full on 3 or more fragments the aligner places here) holds the row's ALT calls (RJ-24, rule X); where it takes one, it is named in the same form at the deletion's anchor, listed or not, with n the fragments fitting the ALT's windows whose ALT call it takes and m those that tell the given count from it (OBSERVED_ALLELE where m is 0). n and m are taken over the reads the counts read (first-class reads the mapping rule admits: in RNA a unique mapper, NH:i:1, below --min-mapq; under strandedness enforcement, sense reads only), so they compare with alt_count and ref_count.

Before 6.6.0 the scan used its own filter (not secondary, not supplementary, mapq >= min_mapq): it had no strand filter, so antisense reads that enforcement keeps out of the counts still entered n and m, and it did not keep the loop's NH:i:1 rescue. A review measured COEXISTING_ALLELE(...:16/12) with antisense reads present against 8/6 without them, both enforced. The diagnostic now shares the counting loop's admission rule (O8 #186, built in #217). Measured on FORTE: counts unchanged everywhere; the diagnostic changes on 1 exon-edge probe row (100/0 → 98/0) and 5 of 7,224 splice-probe rows. Other tools tally other alleles over the same filtered reads as their primary counts (bam-readcount, ASEReadCounter otherBases, VarDict).

MNP rescue

gbcms_rescue (VCF GR), with --rescue-mnp only, is an audit trail: method=decomposed;outcome=<outcome>;original_ref=R;original_alt=A;original_partial=P;original_confirmed=C[;adopted=chr:pos(R>A)][;positions=…]. See Architecture → MNP Rescue Pass.

Outcome Meaning Counts written
rescued The best component beats the MNP's ad; gbcms_diagnostic gains RESCUED_COMPONENT(chrom:pos:REF>ALT) and a warning is logged The adopted component's
skipped_grouped The MNP is in a co-annotated group (its reads are assigned against the siblings) The MNP's
haplotype_confirmed At least one read shows the whole haplotype (mnp_confirmed_alt > 0): the BAM shows the annotated allele The MNP's
no_improvement No component beats the MNP's ad: the partial evidence was not component carriers (e.g. reads with an indel inside the block, which the complex path counts as REF with nearby-indel evidence). Rescue correctly declines The MNP's
ref_validation_failed No component SNV survived preparation (an anomaly: the MNP itself passed REF validation); logged as a warning The MNP's

ASJD splice flags

RNA with --gtf. asjd_diagnostic lists QC flags, semicolon-separated; counts are per fragment (a molecule's R1 and R2 are one vote). Motifs (asjd_ref_motif, asjd_alt_motif) are GT-AG, GC-AG, AT-AC, OTHER or UNKNOWN. The ASJD columns: Output Formats.

Flag Condition Meaning
LOW_ALT_JUNC asjd_n_alt_total < 5 Insufficient ALT junction evidence
LOW_REF_JUNC asjd_n_ref_total < 10 Insufficient REF baseline
NOVEL_ALT_JUNC ALT dominant junction differs from REF and is unannotated ALT uses an unannotated junction
NON_CANONICAL_MOTIF ALT junction differs from REF and its motif is not GT-AG/GC-AG/AT-AC Likely mapping artifact
STRAND_DISCORDANT ALT junction differs from REF, asjd_n_alt_junc ≥ 5, and minority transcript-strand fraction ≥ 0.30 Mixed transcript-strand support → alignment artifact. A --no-strandedness diagnostic: under enforcement (the default) antisense reads never reach the junction tally wherever the gene strand is resolved, intronic loci included. Where both strands' genes cover the locus (no strand), the tally reads every read; a junction belongs to one gene's intron, so a mixed-strand junction stays suspicious there. Disabled for --strandedness unstranded.
MULTI_JUNCTION ALT fragments use > 2 distinct junctions Complex splicing event
RETENTION_DOMINANT(n) Variant's REF span reaches within 2bp of an annotated intron boundary (a donor/acceptor site of a transcript on the variant's gene strand — transcript termini and antisense genes excluded); n ≥ 10 fragments splice over the locus (CIGAR N spans it — excluded as no-observation) and outnumber the allele-classified fragments, which are mostly junction-free The reads that genotype this locus are the intron-retaining minority: vaf is the VAF within that population, not allelic balance. An allele-specific retention shows a very high vaf here; a neutral splice-site variant shows roughly the allelic fraction of the unspliced reads. Explains LOW_REF_JUNC;LOW_ALT_JUNC at such loci — the junction evidence exists but is on the excluded reads.
NOVEL_JUNC_AT_SPLICE_LOSS(n@start-end) Same splice-site gate; the top unannotated junction on the spliced-over fragments is anchored (±5bp) to an annotated intron boundary on the gene strand, is not the deletion itself written as a splice (same length, at the locus), and is carried by n ≥ 5 fragments — more than confirm ALT The mutant allele's splicing outcome (an exon skip or alternative-site junction) is visible while alt_count is not — typically a splice-destroying variant whose carriers splice around the locus. start-end is a 0-based, half-open intron interval (the asjd_*_junction convention).

The floors are ASJD's own junction-evidence minimums (LOW_REF_JUNC / LOW_ALT_JUNC). When RETENTION_DOMINANT is present, any junction flags alongside it (NOVEL_ALT_JUNC, MULTI_JUNCTION, …) describe the allele-classified reads — by the marker's own condition the junction-bearing minority of an intron-retaining population — not the spliced majority, which only the ASJD-2 markers report.

QC columns

Columns whose value is itself a flag. Each column's place in the output is in Output Formats; this is its definition.

Column Mode Value What to do
rna_editing_site (VCF RED) RNA, --rna-editing-db True when the locus overlaps a known A-to-I editing site An A>G / T>C call there is likely editing, not a somatic mutation
asjd_flag RNA, --gtf True when REF and ALT junction usage differ (Fisher p < 0.05; asjd_qval is BH-corrected across variants) Candidate allele-specific splicing; read asjd_diagnostic
mfsd_ks_valid --mfsd True when both ALT and REF have ≥ 5 fragments in the size window (50–1000 bp), so the KS test ran; when False the KS statistics are NA Do not read the KS columns when False
mfsd_alt_confidence --mfsd How much ALT data there is: TESTABLE with ≥ 5 ALT fragments in the size window (the KS minimum), SPARSE with 1–4, NONE with none Not a reliability grade: at 5 fragments a real size shift is detected only about 8% of the time
mfsd_ch_flag --mfsd True when the variant falls in a clonal-hematopoiesis (CH) gene (from Hugo_Symbol) A prior, not fragment evidence; matched-normal data decide CH

Merged output

gbcms merge writes a combined simplex_duplex_* cell as NA where it cannot add the two inputs' counts. The flag below is not a column: the end-of-run summary derives it from a merged MAF.

Flag Set when What to do
COMBINED_NA A combined count, total or VAF cell (simplex_duplex_*, the strand-bias statistics left out) is NA on the row: an input's count was missing or not a number, or the duplex and simplex MNP rescues adopted different alleles (the merge log names each) Do not use the combined counts or VAF there; read each input's own columns

mFSD report classes

The --mfsd-report HTML grades each variant's fragment-size evidence (see mFSD Report): the ALT fragments against the REF fragments at the same locus in the same plasma sample. It is graded evidence, never an origin call; the KS threshold is on the BH-FDR q-value across the sample's variants (mfsd_qval_alt_ref), not the raw p-value. Nothing leans toward CH: at the fragment counts a targeted cfDNA panel produces, a tumor variant usually looks like REF too (on labeled ACCESS plasma, about 30% of tumor variants below 50 ALT fragments did), so similar sizes are no evidence for clonal hematopoiesis. Matched-normal (buffy coat) data decide CH; a CH-associated gene is shown as a note and changes nothing.

flowchart TD
    Start(["Variant"]) --> AltCheck{"ALT fragments ≥
--mfsd-report-min-alt?"} AltCheck -->|"No"| Insufficient(["INSUFFICIENT"]):::grey AltCheck -->|"Yes"| KSValid{"KS test ran?
(mfsd_ks_valid)"} KSValid -->|"No"| Insufficient KSValid -->|"Yes"| Shorter{"KS q < 0.05, ALT shorter
where the size distributions
differ most?"} Shorter -->|"Yes"| Somatic(["LEANS-SOMATIC"]):::green Shorter -->|"No"| None(["NO-SIZE-EVIDENCE"]):::blue classDef green fill:#27ae60,color:#fff,stroke:#1e8449,stroke-width:2px; classDef blue fill:#7f8c8d,color:#fff,stroke:#616a6b,stroke-width:2px; classDef grey fill:#95a5a6,color:#fff,stroke:#7f8c8d,stroke-width:2px;
Use mouse to pan and zoom
Class Rule What it means
LEANS-SOMATIC KS q < 0.05 and the ALT fragments shorter where the two size distributions differ most (the ALT ECDF above the REF ECDF at the KS statistic) ALT fragments significantly shorter than REF: increased confidence the variant is tumor-derived (on labeled ACCESS plasma, duplex fragments: 22 of 97 tumor variants, 0 of 39 white-cell variants)
NO-SIZE-EVIDENCE The KS test ran and the ALT fragments are not significantly shorter (including a significantly longer ALT) The sizes do not separate ALT from REF; not evidence for clonal hematopoiesis
INSUFFICIENT The KS test did not run (mfsd_ks_valid False: a class has fewer than 5 fragments) Too few fragments for the size test

Variants with fewer ALT fragments than --mfsd-report-min-alt are left out of the report.

In VCF, the mFSD summary is in INFO: MFSD_REF_COUNT, MFSD_ALT_COUNT, MFSD_REF_LLR, MFSD_ALT_LLR, MFSD_DELTA_ALT_REF, MFSD_KS_ALT_REF, MFSD_PVAL_ALT_REF, MFSD_QVAL_ALT_REF, MFSD_SUB_NUC_REF_FRAC, MFSD_SUB_NUC_ALT_FRAC, MFSD_SUB_NUC_ENRICHMENT, MFSD_MONO_NUC_REF_FRAC and MFSD_MONO_NUC_ALT_FRAC (Output Formats → INFO).

Record shapes in VCF output

Field Set when Meaning
ALT <NON_SEQUENCE> MAF input, a row with no VCF allele: an allele that is not a base sequence (or empty), a deletion spanning its whole contig, or a row at Start_Position 0 that is not an insertion The row is FAIL (reason in GSR); REF is the reference base at POS
INFO MAF_START, MAF_REF, MAF_ALT MAF input The MAF row the record came from, as written: look a result up by its input
INFO NORM_POS, NORM_REF, NORM_ALT --show-normalization The left-aligned record gbcms counted

End-of-run summary

At the end of every gbcms dna and gbcms rna run the log carries a QC summary: which flags fired, on how many rows, which rows need a look, and what to do about each. Most users read the counts and the VAF and never open the flag columns; the summary points to the few rows where that is not enough.

It reads the output the run has written, MAF or VCF, after writing it. It changes no count, column or row, writes no file and does not change the exit code. If a sample's output cannot be read, the run logs a warning and carries on; the sample is named in the block under "Not checked", with a sample that failed to count, and the closing line is a WARNING that says "k of n samples not checked", so an incomplete check never reads as a clean one.

Each flag is in one of three tiers. The first two are the rows that need a look.

Tier The row What to do
Fix the input Rejected (FAIL), or its input is wrong Correct the input row and run again
Check the call Counted, but its count or VAF may not mean what it looks like Look at the row before you use the number
Informational A caveat or a description Nothing; read it when a number looks odd

For each tier the block gives the number of rows (a row with flags in two tiers is in both) and each flag that fired, most rows first. The first two tiers show a zero as none, so a clean run reads as one. It then names the first rows that need a look (input problems first) and the output fields to filter on for the rest. With several samples in one run the block combines them: each flag with the number of samples it fired in, and the samples with the most rows to look at. A flag the reading build does not know, written by another build, is listed apart and is not counted as needing a look, except on a FAIL row.

The run's last line is a WARNING when any row needs a look and an INFO line when none does; the exit code is unchanged, so flagged rows never fail a pipeline.

gbcms summarize makes the same summary from outputs already written (older runs, many samples, a merged MAF), as text, JSON, a cohort table or MultiQC content.

The mFSD report classes are not in the output rows, so the summary leaves them out.

An example, from 2,000 synthetic rows:

QC summary for sample S: 40 of 2,000 rows need a look (2.0%)
  Rows with only informational flags: 107; with no flag: 1,853
  Fix the input: 2 rows
    REF_MISMATCH: 2 rows
      The REF does not match the reference: check the build and coordinates;
      REF_AT_OFFSET says where it does match
    REF_AT_OFFSET: 1 row
      The REF matches the reference a few bases away: correct the input's coordinates
      (the row is not moved or counted)
  Check the call: 38 rows
    PARTIAL_DOMINANT: 30 rows
      More reads partly match the ALT than carry it, often a coexisting allele the
      annotation misses: inspect the locus (--trace shows per-read lengths)
    OBSERVED_ALLELE: 7 rows
      No read carries the given allele but others carry another one: the input is likely
      mis-described; the counts stay the given allele's
    CLIP_CANDIDATES: 1 row
      An insertion with no ALT reads, but soft-clipped reads may hold its carriers:
      inspect in IGV
  Informational: 113 rows
    ZERO_ALT: 55 rows (no read carries the ALT)
    MULTI_ALLELIC: 40 rows (another row has a different ALT here)
    COEXISTING_ALLELE: 18 rows (another allele is more frequent: a VAF caveat)
  Rows to look at (first 5 of 40, input problems first):
    chr1:1000 A>T (GENE1): REF_MISMATCH, REF_AT_OFFSET(2)
    chr1:1001 A>T (GENE2): REF_MISMATCH
    chr1:1002 A>T (GENE3): PARTIAL_DOMINANT
    chr1:1003 A>T (GENE4): PARTIAL_DOMINANT
    chr1:1004 A>T (GENE5): PARTIAL_DOMINANT
  Find them in the output (MAF columns): gbcms_diagnostic, gbcms_status, gbcms_status_reason
  What each flag means and what to do: https://msk-access.github.io/gbcms/reference/qc-flags/

The tables list every flag by tier with the line the summary prints for it (a short gloss for an informational flag). The definitions are above; the tests keep the two in step.

Fix the input

Flag The summary says
REF_MISMATCH The REF does not match the reference: check the build and coordinates; REF_AT_OFFSET says where it does match
REF_AT_OFFSET The REF matches the reference a few bases away: correct the input's coordinates (the row is not moved or counted)
FETCH_FAILED The reference region could not be read: check contig naming and the FASTA
EMPTY_ALLELE REF or ALT is empty: fix the input row
NON_SEQUENCE_ALLELE An allele is not a base sequence: fix the input row
ALT_EQUALS_REF ALT equals REF, so there is no change to count: fix the input row
START_BEFORE_CONTIG The row starts before the contig's first base (Start_Position 0): fix the input row; MAF positions are 1-based
ALT_CONTAINS_N The ALT contains an N base: fix the input row

Check the call

Flag The summary says
WARN_REF_CORRECTED The input's REF was corrected to the reference: check the REF; the counts are for the corrected REF
WARN_HOMOPOLYMER_DECOMP The row reports a corrected allele's counts, not the given one: check which you want
OBSERVED_ALLELE No read carries the given allele but others carry another one: the input is likely mis-described; the counts stay the given allele's
PARTIAL_DOMINANT More reads partly match the ALT than carry it, often a coexisting allele the annotation misses: inspect the locus (--trace shows per-read lengths)
CLIP_CANDIDATES An insertion with no ALT reads, but soft-clipped reads may hold its carriers: inspect in IGV
POSSIBLE_MINORITY_HAPLOTYPE A change on a minority of nearby reads may be counted as ALT: weigh a low alt_count with that in mind (the counts are unchanged)
MNV_SHARED Under the sequence judge the SNV's ALT reads include a co-listed MNV's carriers, so one molecule counts in both rows: read the two rows together (the counts are unchanged)
INDEL_SHARED Under the sequence judge the ALT reads include a listed indel's carriers holding this change, so one molecule counts at several rows: read them together (counts unchanged)
UNIT_COUNT_UNSPANNED Another unit count of a run beside this long deletion reads like it past every read here: an unlisted one's carriers may count as ALT (the counts are unchanged)
UNEXPLAINED_READS Under the sequence judge some depth reads fit none of the row's candidate sequences: where they are a large share, foreign reads may count (the counts are unchanged)
NO_TELLING_BASE Under the sequence judge no base within reach tells a long insertion's REF window from its ALT's, so every read is depth only: a zero REF and ALT here is not an absence
SW_FALLBACK Some reads were scored by a fallback aligner or left uncounted: the row's counts came partly from another scorer
SPLICE_SKIP_DOMINANT More reads splice over the deleted span than confirm ALT: an alt_count of 0 may hide carriers written as junction reads
NON_DISCRIMINATING_LOCUS A nearby germline combination makes REF and ALT the same sequence: a zero REF and ALT here is not an absence
RESCUED_COMPONENT With --rescue-mnp the row reports a component SNV's counts, not the MNP's: read gbcms_rescue
rescued The best component SNV beat the MNP, so its counts are written: read gbcms_rescue
ref_validation_failed No component SNV survived preparation (an anomaly): the MNP's own counts stand; read the logged warning
NON_CANONICAL_MOTIF The ALT junction's splice motif is not canonical: likely a mapping artifact
STRAND_DISCORDANT The ALT junction has mixed transcript-strand support: likely an alignment artifact
RETENTION_DOMINANT Most reads splice over the locus, so the counted reads are the intron-retaining minority: read vaf as the VAF within them, not as allelic balance
NOVEL_JUNC_AT_SPLICE_LOSS Carriers of a splice-destroying variant may splice around the locus while alt_count is low: read asjd_diagnostic for the junction
rna_editing_site The locus overlaps a known A-to-I editing site: an A>G or T>C call there is likely editing, not a somatic mutation
COMBINED_NA A combined simplex_duplex count is NA (a count missing in one flavour, or mixed MNP rescue): the combined VAF is unusable, so read each flavour's own columns

Informational

Flag The summary says
MULTI_ALLELIC another row has a different ALT here
TRACT_CLUSTER shares a repeat window with another indel
ZERO_ALT no read carries the ALT
COEXISTING_ALLELE another allele is more frequent: a VAF caveat
MNP_DISC_RATIO the MNP's shape; nothing to do
MNP_RESCUE_ELIGIBLE a rescue candidate (--rescue-mnp)
HIGH_N_FRACTION over 5% of depth is N: counts are thinner
LOW_ALT_JUNC fewer than 5 ALT junction fragments
LOW_REF_JUNC fewer than 10 REF junction fragments
NOVEL_ALT_JUNC the ALT uses an unannotated junction
MULTI_JUNCTION ALT fragments use over two junctions
asjd_flag ALT and REF junction usage differ
skipped_grouped in a co-annotated group; rescue left it
haplotype_confirmed a read shows the whole MNP haplotype
no_improvement no component beat the MNP; its counts stand
mfsd_ks_valid the KS test did not run
mfsd_alt_confidence few or no ALT fragments in the size window
mfsd_ch_flag in a clonal-hematopoiesis gene: a prior