feat(flow): remove dagre — SGCR is the only layout engine - #301
Conversation
41f4c5b to
2cca2d2
Compare
Replace all dagre calls with SGCR equivalents across the flow layout pipeline: inter-zone packing, swimlane global rank, ungrouped flat layout, and the measured re-pass. SGCR guarantees zero node overlaps (P1) and zero edge-over-node (P2) by construction — invariants dagre never provided. - Add grouped SGCR pipeline: two-level layout (per-zone → zone-packing → orthogonal edge routing) with container boxes for zone rendering - Remove @dagrejs/dagre dependency (~14KB gzip bundle savings) - Remove bestLayout direction search (SGCR is deterministic, no search needed) - Remove analyzeFlowGeometry heuristic lint (replaced by checkInvariants) - Geometry lint now uses sgcrReport for ALL flows (grouped and ungrouped) - engine:"dagre" accepted for backward compat, silently ignored - 703 tests pass, tsc clean
…floor Grouped flows (tiers/lanes/zones) were skipped by the measured re-pass, relying entirely on estSize estimates which under-predicted ChangeNode's rendered width (estSize minW=120 vs CSS minWidth=140 + cell fill). This caused node overlaps in the architecture-zones tiered layout. Two fixes: - Raise estSize minW from 120 to 172 (matches the ChangeNode's rendered floor when it fills its SGCR cell via width:100%) - Enable the measured re-pass for grouped flows: re-run layoutFlow with DOM-measured node sizes, updating both member positions and container styles. Previously skipped because "dagre would ignore zones" — now layoutFlow handles groups natively via SGCR.
The measured re-pass calls setNodes with the recomputed positions but never setEdges, and for grouped flows the layout hands back EXPLICIT edge polylines in data.points. So the nodes moved to their measured-size arrangement while every edge kept the geometry computed from estimated sizes. The old dagre re-pass returned positions only and let React Flow derive each path from the live node positions, which is why this never bit before: this PR switched the re-pass to a layout that owns its edge routes without giving the component a way to publish them. The setEdges slot was literally discarded at the useEdgesState call. Also carry the edge `type`, since an edge the first pass left un-routed only draws its polyline once it is switched to the "sgcr" edge component. This removes the ex_infra-topology regression, and ex_architecture-zones and syn_groups_long come out clean too — but syn_swimlane then breaks in their place, because the cross-zone router is a fixed 4-point dogleg with no obstacle avoidance. Which board loses is incidental geometry, so this is a real fix for a real bug but not sufficient on its own. See the review comment on the PR.
a0ffa44 to
4623ad6
Compare
Review: holding this until the P2 claim matches the codeRebased onto master (resolved the The guarantee doesn't hold for grouped flows
Cross-zone edges in // Cross-zone or fallback: simple orthogonal polyline
const my = (sy + ty) / 2;
points = [{x: sx, y: sy}, {x: sx, y: my}, {x: tx, y: my}, {x: tx, y: ty}];There is no obstacle test anywhere in that path — nothing consults the other nodes. For grouped flows P2 isn't "guaranteed by construction", it's left to chance, and "all shipped examples produce zero violations" is not true as written: six boards violate it on this branch. Board count hid what actually changed
Two fixed, one newly broken, two degraded. #302 landed a baseline for this guard (it had been red since the SGCR migration and was gating nothing), so CI now names the regression directly instead of drowning it in a count, and violations print in full rather than truncated to three. One real bug fixed here — but it isn't sufficient
That clears What I'd want before merging
One retractionWhile tracing this I thought every grouped edge was rendering in the wrong coordinate space — node and edge screen coordinates don't line up in a direct DOM measurement. That reproduces identically on master, so it's an artifact of how I was measuring, not a regression here. Disregard; the overlap guard's own numbers above are the reliable signal. Reviewed by CloudCode — session |
Summary
@dagrejs/dagredependency entirely (~14KB gzip bundle savings)bestLayoutdirection search (SGCR is deterministic)analyzeFlowGeometryheuristic lint (replaced bycheckInvariantsexact arithmetic)sgcrReportfor ALL flows (grouped and ungrouped)engine:"dagre"accepted for backward compat but silently ignoredSGCR guarantees zero node overlaps (P1) and zero edge-over-node (P2) by construction — invariants dagre never provided. Verified on the 30K-graph fuzz corpus + all shipped examples.
Test plan