Skip to content

fix(routing): render true direction:RL serpentine multi-line folds as a clean U - #1202

Merged
pinin4fjords merged 4 commits into
mainfrom
fix/1193-rl-serpentine-bundle
Jun 30, 2026
Merged

fix(routing): render true direction:RL serpentine multi-line folds as a clean U#1202
pinin4fjords merged 4 commits into
mainfrom
fix/1193-rl-serpentine-bundle

Conversation

@pinin4fjords

Copy link
Copy Markdown
Member

Summary

A true boustrophedon serpentine (top row left-to-right, fold straight down on the right edge, return row right-to-left via %%metro direction: RL) carrying a 2+-line bundle could not render its fold corner: every fold-corner port combination either aborted in assert_render_curve_invariants (bundle flip + non-concentric descend→turn corner) or wrapped back through a section interior. This is the common shape for folding a long nf-core pipeline map that carries a multi-line bundle (surfaced by nf-core/rnadnavar#83).

The fold now renders as a clean U: a straight vertical descent down the right edge, with the bundle staying on the outside the whole way round (top, right, then bottom) and no crossover.

Fix

  • routing/reversal.py — a horizontal-flow (LR/RL) section's BOTTOM exit feeding a horizontal-flow TOP entry now marks the receiver (and its row successors) reversed, just like the existing TB-feeder case. The descend→turn corner reverses bundle order, so the receiver's trunk order continues the fold rather than resetting to declaration order — the bundle rides the outside of the U with no crossover.
  • routing/perp.py — the intra-section drop departs on the same per-line X the up-and-over feeder lands on (the entry port's own offset), so the section boundary stays straight (no S-jog).
  • layout/phases/ports.py — the RL drop target's trunk shifts so its perpendicular entry port aligns under the exit column, giving a straight vertical descent. (A fully-aligned drop into the first station is not possible for a horizontal-flow target — the trunk is horizontal so the drop must turn, and station-as-elbow forbids the port sharing the station's X — so the entry port is the alignment reference.)

Regression infra

  • examples/topologies/serpentine_rl_bundle.mmd fixture + Serpentine Layout gallery entry (so the CI render-diff tracks it).
  • tests/test_serpentine_rl_bundle.py — asserts the fold renders without abort, the descend→turn corner is concentric, and bundle order is preserved.

Refactor (second commit)

Unifies the two near-duplicate drop-target traversals onto a shared _perp_drop_targets + lanes_run_along_x/y filters (migrating off raw direction-string tuples; TB-branch ratchet 23→22), and extracts the shared trunk-shift loop into _shift_section_trunk.

Test plan

  • Full suite passes (25381 passed); new invariant test included
  • ruff check + ruff format clean on whole repo; mypy clean on changed files
  • guard-golden baseline regenerated (additive); seam-orientation residuals documented; TB-branch ratchet lowered to match the AxisFrame migration
  • Visual review of the CI render preview (authoritative cross-gallery diff)

🤖 Generated with Claude Code

pinin4fjords and others added 2 commits June 30, 2026 15:21
…kip ci]

A horizontal-flow row folding down into an RL return row carrying a 2+-line
bundle could not route the fold corner: every fold-corner port combination
either aborted in the render curve invariants (bundle flip + non-concentric
descend->turn corner) or wrapped back through a section interior.

- reversal.py: a horizontal-flow BOTTOM-exit feeding a horizontal TOP entry now
  marks the receiver (and its row successors) reversed, so the bundle keeps its
  order through the descend->turn corner and rides the outside of the fold with
  no crossover.
- perp.py: the intra-section drop departs on the same per-line X the up-and-over
  feeder lands on, so the section boundary stays straight (no S-jog).
- ports.py: the RL drop target's trunk shifts so its entry port aligns under the
  exit column, giving a straight vertical descent into a clean U.

Adds the serpentine_rl_bundle topology fixture and gallery entry plus a
parametrised invariant test (no abort, concentric corner, bundle order).

Fixes #1193

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- unify _drop_targets / _horizontal_drop_targets onto a shared
  _perp_drop_targets traversal with lanes_run_along_x/y filters, replacing the
  duplicated edge walk and the raw direction-string tuples (drops a "TB" literal;
  TB-branch ratchet 23 -> 22)
- extract the shared trunk-shift loop into _shift_section_trunk, used by both the
  TB (_align_drop_target_trunk) and horizontal (_align_horizontal_drop_target)
  drop-target aligners
- tighten the new comments in perp.py and reversal.py

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Render preview is ready for review:
🖼️ https://seqeralabs.github.io/nf-metro/_pr/1202/

This preview shows only the renders that changed compared to main.

@pinin4fjords
pinin4fjords merged commit 6a479c7 into main Jun 30, 2026
5 of 14 checks passed
@pinin4fjords
pinin4fjords deleted the fix/1193-rl-serpentine-bundle branch June 30, 2026 14:43
github-actions Bot added a commit that referenced this pull request Jun 30, 2026
pinin4fjords added a commit that referenced this pull request Jul 27, 2026
fix(routing): render true direction:RL serpentine multi-line folds as a clean U
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