Skip to content

_gap_channel_base still centres against the origin when a column is empty only in the queried row #1882

Description

@pinin4fjords

Problem

_gap_channel_base (src/nf_metro/layout/routing/normalize.py:4865) still centres a gap channel bundle against the coordinate origin when a column has sections elsewhere on the grid but none in the specific row being routed. PR #1876 fixed the sibling case - a column absent from the whole grid - via off_grid_gap_bundle_midpoint (src/nf_metro/layout/routing/common.py:498), but this row-local variant of the same defect remains.

Symptom

examples/topologies/fan_bypass_shared_band.mmd (reproducer below) violates translation-rigidity by D/2 for this reason: its "gap2" channel answers a whole-map translation with only half the expected shift - the same signature #1876 fixed for the grid-absent case, just triggered by an empty row rather than an empty column.

Why the obvious fix doesn't work

Anchoring this case the same way (a fixed clearance off the one row-local edge, mirroring off_grid_gap_bundle_midpoint) was tried and reverted during the #1789/#1876 work: it moves this fixture's gap2 channel from x=353.5 to x=691, which routes a bypass at y=318 straight through the lower_blocker section (bbox x 397-627, y 220-320), tripping _guard_no_route_through_section (src/nf_metro/layout/phases/guards.py:3678) and breaking tests/test_fan_bypass_shared_band.py.

The regression's root cause is separate from the channel-anchoring bug itself: the row-1/row-2 gap in this fixture is 50px, but the inter-row corridor needs INTER_ROW_EDGE_CLEARANCE (src/nf_metro/layout/constants.py:463) + INTER_ROW_HEADER_CLEARANCE (src/nf_metro/layout/constants.py:493) = 78px. _center_inter_row_channel (src/nf_metro/layout/routing/common.py:3100) biases to hi = 370 - 52 = 318, i.e. 2px inside row 1's boxes. Today this only avoids visibly breaking because the buggy origin-centred channel x happens to land left of the blocker - a coincidence, not correctness.

So a correct fix likely needs the row gap to grow to accommodate the corridor's real clearance requirement, before or as part of anchoring the channel - plan-time row-gap growth, not just a channel-anchoring change in isolation.

Reproducer

examples/topologies/fan_bypass_shared_band.mmd:

%%metro title: Junction fan sharing a bypass band
%%metro line: local | Local branch | #2db572
%%metro line: long | Bypass branch | #a855f7
%%metro line: obstacle | Obstacle | #f59e0b
%%metro grid: source | 0,0
%%metro grid: local | 1,0
%%metro grid: blocker | 2,0
%%metro grid: lower_blocker | 2,1
%%metro grid: distant | 3,2

graph LR
    subgraph source [Source]
        %%metro exit: right | local, long
        source_step[Source step]
    end

    subgraph local [Local branch]
        %%metro entry: left | local
        local_step[Local step]
    end

    subgraph blocker [Intervening section]
        blocker_start[Blocker start]
        blocker_end[Blocker end]
        blocker_start -->|obstacle| blocker_end
    end

    subgraph distant [Distant branch]
        %%metro entry: left | long
        distant_step[Distant step]
    end

    subgraph lower_blocker [Lower intervening section]
        lower_start[Lower blocker start]
        lower_end[Lower blocker end]
        lower_start -->|obstacle| lower_end
    end

    source_step -->|local| local_step
    source_step -->|long| distant_step

Scope

Layout/routing: _gap_channel_base (or a row-local counterpart) and row-gap sizing (wherever row gaps get their enforced minimum, e.g. _enforce_min_row_gaps). Diagnosed during the #1789/#1876 work; explicitly out of that PR's scope since the correct fix requires plan-time row-gap growth rather than a channel-anchoring change alone.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglayoutLayout engine, phases, ordering (layout/)routingEdge routing (layout/routing/)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions