Skip to content

fix(layout): Harden edge routing robustness and add channel fallback diagnostics#46

Merged
mhiro2 merged 5 commits into
mainfrom
fix/layout-robustness-and-escape
Apr 10, 2026
Merged

fix(layout): Harden edge routing robustness and add channel fallback diagnostics#46
mhiro2 merged 5 commits into
mainfrom
fix/layout-robustness-and-escape

Conversation

@mhiro2

@mhiro2 mhiro2 commented Apr 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Escape D2 special characters (<, >, {, }, |) in label output to prevent malformed
    diagram syntax
  • Replace partial_cmp().unwrap_or(Equal) with total_cmp() for robust float comparisons in
    node ordering and obstacle distance
  • Replace try_from().expect() with saturating fallbacks to eliminate potential panics in
    channel candidate generation
  • Refactor route_edges_with_diagnostics into discrete routing and finalization phases for
    maintainability
  • Track channel fallback activations in routing diagnostics for observability

Changes

  • 9541cba : fix(diagram_export): escape D2 special characters <, >, {, }, |
    • Escape <, >, {, }, | in d2_escape() to produce valid D2 syntax
    • Add unit and integration tests for D2 special character escaping
  • 24910be : fix(layout): replace partial_cmp().unwrap_or(Equal) with total_cmp
    • Use total_cmp() for float comparisons in barycenter and median node ordering
    • Use total_cmp() for obstacle distance comparison
  • fc259f8 : fix(layout): replace try_from().expect() with saturating fallback
    • Replace try_from().expect() with unwrap_or(u32::MAX) / unwrap_or(u16::MAX) in channel
      candidate generation
    • Use saturating_add for bypass candidate order to avoid overflow
  • c021ebb : refactor(layout): split route_edges_with_diagnostics into phases
    • Extract route_single_edge() with SingleEdgeRoutingContext and SingleEdgeResult structs
    • Extract finalize_routed_edge() for label placement and PositionedEdge construction
    • Separate routing and finalization into distinct loop phases
  • a1f1968 : feat(layout): emit channel_fallback_activations diagnostic
    • Add channel_fallback_activations field to PositionedGraphRoutingDebug and
      RoutingDiagnostics
    • Emit debug log when edge falls back to simple backbone routing
    • Add test verifying diagnostic count when all channel candidates are blocked

mhiro2 added 5 commits April 10, 2026 18:29
d2_escape only handled backslash, double-quote, newline, and carriage
return. D2 treats angle brackets, braces, and pipe as structural
delimiters in node/edge labels, so unescaped occurrences in table or
FK names could produce invalid D2 output.
Barycenter and median sort in order.rs, and obstacle distance
comparison in obstacle.rs, used partial_cmp with a fallback to Equal.
If NaN leaked into coordinates the sort would lose determinism and
produce unreproducible layout differences. f64::total_cmp / f32::total_cmp
give a consistent total order that treats NaN deterministically.
Integer conversions (usize → u32/u16) in channel candidate generation
used expect(), which would panic on extremely large graphs. Replace
with unwrap_or(MAX) / saturating_add so overflow degrades gracefully
instead of crashing.
Extract route_single_edge (per-edge path computation) and
finalize_routed_edge (label placement) from the monolithic 300+ line
function. The orchestrator now delegates to these helpers, making each
phase independently testable and easier to debug.
When obstacle_aware_channel_for_edge fails to find any viable channel
candidate and the router falls back to simple backbone routing, this
is now counted in RoutingDiagnostics and surfaced in the layout-json
debug output. A dedicated test verifies the diagnostic fires when a
large blocker node covers the entire inter-rank channel space.
@mhiro2 mhiro2 self-assigned this Apr 10, 2026
@mhiro2 mhiro2 added the enhancement New feature or request label Apr 10, 2026
@github-actions

Copy link
Copy Markdown

Code Metrics Report

main (d0c858e) #46 (eb2e781) +/-
Coverage 94.1% 94.1% +0.0%
Test Execution Time 1m39s 1m42s +3s
Details
  |                     | main (d0c858e) | #46 (eb2e781) |  +/-  |
  |---------------------|----------------|---------------|-------|
+ | Coverage            |          94.1% |         94.1% | +0.0% |
  |   Files             |             73 |            73 |     0 |
  |   Lines             |          29749 |         29862 |  +113 |
+ |   Covered           |          28004 |         28117 |  +113 |
- | Test Execution Time |          1m39s |         1m42s |   +3s |

Code coverage of files in pull request scope (95.4% → 95.5%)

Files Coverage +/- Status
crates/relune-layout/src/diagram_export.rs 94.1% +0.2% modified
crates/relune-layout/src/layout.rs 95.2% +0.1% modified
crates/relune-layout/src/order.rs 99.2% -0.1% modified
crates/relune-layout/src/route/obstacle.rs 91.6% 0.0% modified

Reported by octocov

@mhiro2
mhiro2 merged commit c1721cb into main Apr 10, 2026
3 checks passed
@mhiro2
mhiro2 deleted the fix/layout-robustness-and-escape branch April 10, 2026 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant