Skip to content

fix(delta): decoy displacement must exceed the event; add the missing BND decoy - #508

Merged
joshfactorial merged 1 commit into
developfrom
fix/decoy-scales-and-covers-bnd
Aug 4, 2026
Merged

fix(delta): decoy displacement must exceed the event; add the missing BND decoy#508
joshfactorial merged 1 commit into
developfrom
fix/decoy-scales-and-covers-bnd

Conversation

@joshfactorial

Copy link
Copy Markdown
Collaborator

Two defects in the negative control, found while cross-checking job 20824321. Neither changes a caller result; both change whether the caller results are believable.

1. The decoy did not displace large events

It shifted every record a flat 2 Mb. Truvari matches sized variants on reciprocal overlap, so a 19.6 Mb deletion moved 2 Mb still overlaps ~90% — and matching it is correct behaviour.

Measured: decoy_scoreable recall=0.202, TP=17, and all 17 were larger than the shift:

n=17   min=2,048,336   median=4,255,928   max=19,619,570      (shift was 2,000,000)

Not one match was smaller than the displacement. The control was reporting "the shift is too small" while its warning text claimed "the scorer is matching far more loosely than intended"it misdiagnosed its own failure, which is worse than staying silent, because it points the reader at the wrong subsystem.

Displacement is now max(2 Mb, 2 × |SVLEN|), so it always exceeds the event and overlap is zero by construction. END moves with POS, or the record would describe a span it no longer occupies.

Verified on hand-computed cases — shift exceeds span in every one, so no shifted interval overlaps its original:

event shift POS span
500 kb DEL 2 Mb (floor) 1,000,000 → 3,000,000 preserved
19.6 Mb DEL 39.24 Mb 5,000,000 → 44,239,140 preserved
2.05 Mb DUP 4.10 Mb 3,000,000 → 7,096,672 preserved
BND (no SVLEN) 2 Mb 9,000,000 → 11,000,000 END == POS

2. decoy_truvari was never called for BND

It ran once, for scoreable. So the headline manta_BND = 0.935 had:

positive control selftest_BND = 1.000, all 62 records
negative control absent

That missing half is what distinguishes detection from coincidence. --bnddist sets a proximity window, and nothing measured how often a displaced breakend still lands inside it.

BND is also where the decoy works best: a breakend is a point (END == POS), so any shift displaces it completely — no size-scaling needed.

… BND decoy

Two defects in the negative control, found while cross-checking job 20824321.

1. THE DECOY SHIFT DID NOT DISPLACE LARGE EVENTS. It moved every record a flat
   2 Mb. Truvari matches sized variants on reciprocal overlap, so a 19.6 Mb
   deletion shifted 2 Mb still overlaps 90% — and matching it is CORRECT
   behaviour. Measured: decoy_scoreable recall=0.202, TP=17, and ALL 17 were
   larger than the shift (min 2,048,336 bp against a 2,000,000 bp shift, median
   4.3 Mb, max 19.6 Mb). Not one match was smaller than the displacement.

   So the control was reporting 'the shift is too small' while its warning text
   claimed 'the scorer is matching far more loosely than intended' — it
   misdiagnosed its own failure, which is worse than being silent.

   Displacement is now max(2 Mb, 2 x |SVLEN|), so it always exceeds the event and
   overlap is zero by construction. END moves with POS, or the record would
   describe a span it no longer occupies. Warning text corrected to say what a
   match would now mean.

   Verified on hand-computed cases:
     500 kb DEL   -> shift 2 Mb (floor)    POS 1000000 -> 3000000,  span kept
     19.6 Mb DEL  -> shift 39.24 Mb        POS 5000000 -> 44239140, span kept
     2.05 Mb DUP  -> shift 4.10 Mb         POS 3000000 -> 7096672,  span kept
     BND (no SVLEN) -> shift 2 Mb          POS 9000000 -> 11000000, END==POS
   Shift exceeds span in every case, so no shifted interval overlaps its original.

2. decoy_truvari WAS NEVER CALLED FOR BND. It ran once, for 'scoreable'. So the
   headline manta_BND=0.935 had a positive control (selftest_BND=1.000 across all
   62 records) and NO negative control — the half that distinguishes detection
   from coincidence. --bnddist sets a proximity window and nothing measured how
   often a displaced breakend still lands inside it.

   BND is where the decoy works best: a breakend is a point (END==POS), so any
   shift displaces it completely.

Neither changes a caller result. Both change whether the caller results are
believable.

Co-Authored-By: Claude <noreply@anthropic.com>
@joshfactorial
joshfactorial merged commit 5358a37 into develop Aug 4, 2026
4 checks passed
@joshfactorial
joshfactorial deleted the fix/decoy-scales-and-covers-bnd branch August 6, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant