Root Cause
The difference comes from the round-trip through globalRoutingToBox → ODB guide rectangles → boxToGlobalRouting. This reconstruction of routes_[db_net] is not a perfect inverse, causing two concrete asymmetries:
1. Via duplication in loadGuidesFromDB
In saveGuides, for vias that cover a pin, two dbGuide objects are written per via (one per direction):
auto guide1 = dbGuide::create(db_net, layer1, layer2, box, ...);
auto guide2 = dbGuide::create(db_net, layer2, layer1, box, ...);
But loadGuidesFromDB reads both back unconditionally and inserts two via GSegments into routes_[db_net]. The original FastRoute routes_ had only one. Since mergeSegments never touches vias, these extra segments persist and shift the segment index table used by addJumperOnSegments.
2. mergeSegments is order-sensitive
mergeSegments scans linearly and only merges consecutive pairs. In Scenario 1, segments come from FastRoute in tree-traversal order, so collinear segments tend to be adjacent. In Scenario 2, boxToGlobalRouting decomposes each guide rectangle into individual tile-to-tile segments and appends them in guide-storage order. If same-layer adjacent segments from different guides end up non-consecutive in the vector, mergeSegments won't merge them, leaving longer segments in Scenario 1 that are split in Scenario 2 (or vice versa), changing which segment index a jumper cut lands on.
Root Cause
The difference comes from the round-trip through globalRoutingToBox → ODB guide rectangles → boxToGlobalRouting. This reconstruction of routes_[db_net] is not a perfect inverse, causing two concrete asymmetries:
1. Via duplication in loadGuidesFromDB
In
saveGuides, for vias that cover a pin, two dbGuide objects are written per via (one per direction):But
loadGuidesFromDBreads both back unconditionally and inserts two via GSegments intoroutes_[db_net]. The original FastRouteroutes_had only one. SincemergeSegmentsnever touches vias, these extra segments persist and shift the segment index table used byaddJumperOnSegments.2.
mergeSegmentsis order-sensitivemergeSegmentsscans linearly and only merges consecutive pairs. In Scenario 1, segments come from FastRoute in tree-traversal order, so collinear segments tend to be adjacent. In Scenario 2,boxToGlobalRoutingdecomposes each guide rectangle into individual tile-to-tile segments and appends them in guide-storage order. If same-layer adjacent segments from different guides end up non-consecutive in the vector,mergeSegmentswon't merge them, leaving longer segments in Scenario 1 that are split in Scenario 2 (or vice versa), changing which segment index a jumper cut lands on.