57f2a4a958e5a6432829e33deaaf7b0475971188 braney Thu Sep 17 09:52:34 2026 -0700 quickLift: keep the target strand a reverse complemented protein just got quickLiftPslBackToProtein turns the alignment over when pslTransMap hands back strand[0] == '-', because a protein psl is only ever "++" or "+-". pslRc does that and makes the target strand explicit as it goes, so the psl comes out "+-". The assignment at the end of the function then set strand[1] to '+' regardless and undid it, leaving "++" over blocks that are in minus strand target coordinates. pslIsProtein wants strand[1] plus the three to one relation between the last block and the target end, so it answered no. pslTrack.c then passed a size multiplier of one to lfFromPslx and every block was drawn at a third of its length at a mirrored position, which is the symptom the reverse complement was added to prevent. The assignment is now the else branch of the same test. hg/lib/tests/quickLiftTester.c covers this. It goes through the public quickLiftPsl rather than the static function, builds its chains in memory in the shape quickLiftSourceRanges leaves them, and needs no database. Six cases: a protein over a same strand chain and over an opposite strand chain, a chain that gaps only the reference, a chain that drops a source base and so splits a codon, an mRNA over both chains, and an alignment with no chain under it. Each one runs pslCheck2, which is what notices a strand that disagrees with the blocks. With this fix backed out, only the opposite strand case changes and it reports three errors placing the blocks outside the target range. Found in the v504 code review, refs #38349. refs #38249 diff --git src/hg/lib/tests/expected/quickLiftTest src/hg/lib/tests/expected/quickLiftTest new file mode 100644 index 00000000000..317c5d94a18 --- /dev/null +++ src/hg/lib/tests/expected/quickLiftTest @@ -0,0 +1,49 @@ +== protein, chain on the same strand +chain: t=chrSrc:100-400 q=chrRef:100-400 qStrand=+ blocks 100-400/100-400 +before 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrSrc 1000 100 400 1 100, 0, 100, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 +lifted 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrRef 1000 100 400 1 100, 0, 100, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 + +== protein, chain on the opposite strand +chain: t=chrSrc:600-900 q=chrRef:600-900 qStrand=- blocks 600-900/600-900 +before 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrSrc 1000 600 900 1 100, 0, 600, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 +lifted 100 0 0 0 0 0 0 0 +- prot 100 0 100 chrRef 1000 100 400 1 100, 0, 600, + strand='+-' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 + +== protein, chain gaps the reference +chain: t=chrSrc:100-400 q=chrRef:100-401 qStrand=+ blocks 100-250/100-250 250-400/251-401 +before 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrSrc 1000 100 400 1 100, 0, 100, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 +lifted 100 0 0 0 0 0 1 1 ++ prot 100 0 100 chrRef 1000 100 401 2 50,50, 0,50, 100,251, + strand='++' isProtein=1 qSize=100 blockSizes[0]=50 pslCheck errors=0 + +== protein, lift splits a codon +chain: t=chrSrc:100-401 q=chrRef:100-400 qStrand=+ blocks 100-250/100-250 251-401/250-400 +before 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrSrc 1000 100 400 1 100, 0, 100, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 +lifted 299 0 0 0 1 1 0 0 + prot 300 0 300 chrRef 1000 100 399 2 150,149, 0,151, 100,250, + strand='+' isProtein=0 qSize=300 blockSizes[0]=150 pslCheck errors=0 + +== mRNA, chain on the same strand +chain: t=chrSrc:100-400 q=chrRef:100-400 qStrand=+ blocks 100-400/100-400 +before 300 0 0 0 0 0 0 0 + mrna 300 0 300 chrSrc 1000 100 400 1 300, 0, 100, + strand='+' isProtein=0 qSize=300 blockSizes[0]=300 pslCheck errors=0 +lifted 300 0 0 0 0 0 0 0 + mrna 300 0 300 chrRef 1000 100 400 1 300, 0, 100, + strand='+' isProtein=0 qSize=300 blockSizes[0]=300 pslCheck errors=0 + +== mRNA, chain on the opposite strand +chain: t=chrSrc:600-900 q=chrRef:600-900 qStrand=- blocks 600-900/600-900 +before 300 0 0 0 0 0 0 0 + mrna 300 0 300 chrSrc 1000 600 900 1 300, 0, 600, + strand='+' isProtein=0 qSize=300 blockSizes[0]=300 pslCheck errors=0 +lifted 300 0 0 0 0 0 0 0 - mrna 300 0 300 chrRef 1000 100 400 1 300, 0, 100, + strand='-' isProtein=0 qSize=300 blockSizes[0]=300 pslCheck errors=0 + +== no chain over the alignment +chain: t=chrSrc:100-400 q=chrRef:100-400 qStrand=+ blocks 100-400/100-400 +before 100 0 0 0 0 0 0 0 ++ prot 100 0 100 chrSrc 1000 700 1000 1 100, 0, 700, + strand='++' isProtein=1 qSize=100 blockSizes[0]=100 pslCheck errors=0 +lifted did not lift + +passed