Found during the generalization audit (#125). Not currently listed there.
Problem
Indel tolerance in reference-based motif search is hardcoded to the geometry of a 7-bp tRNA motif:
https://github.com/rnabioco/leech/blob/main/src/leech/io/motif_search.py#L78-L86
if allow_edge_indels:
# Only check core region (exclude ±3bp edges for 7bp motif)
# For CCATGGC (7bp), this checks only middle position (amino acid site)
motif_len = ref_end - ref_start
edge_tolerance = min(3, motif_len // 2) # ±3bp or half motif length
and again at :358-366:
# Lenient check when accepting indels - within ±3bp tolerance
length_ok = abs(mapped_len - motif_len) <= 3
The 3 is tuned to CCATGGC. For a 2-bp motif, min(3, motif_len // 2) collapses the protected core to nothing. For a 15-bp motif, a <= 3 length tolerance is far tighter than the ±3 edge exclusion implies. Neither constant scales.
Suggested fix
Parameterize on the searcher: edge_tolerance: int | None = None (defaulting to motif_len // 2, so the protected core is always the single focus base) and max_length_delta: int | None = None (defaulting to something derived from motif length).
Better still, define the protected region relative to motif_offset rather than as a symmetric edge exclusion — motif_offset already names the position that matters, and the comment at :80 says the intent was exactly that.
Found during the generalization audit (#125). Not currently listed there.
Problem
Indel tolerance in reference-based motif search is hardcoded to the geometry of a 7-bp tRNA motif:
https://github.com/rnabioco/leech/blob/main/src/leech/io/motif_search.py#L78-L86
and again at
:358-366:The
3is tuned toCCATGGC. For a 2-bp motif,min(3, motif_len // 2)collapses the protected core to nothing. For a 15-bp motif, a<= 3length tolerance is far tighter than the ±3 edge exclusion implies. Neither constant scales.Suggested fix
Parameterize on the searcher:
edge_tolerance: int | None = None(defaulting tomotif_len // 2, so the protected core is always the single focus base) andmax_length_delta: int | None = None(defaulting to something derived from motif length).Better still, define the protected region relative to
motif_offsetrather than as a symmetric edge exclusion —motif_offsetalready names the position that matters, and the comment at:80says the intent was exactly that.