feat(layout): crossing reduction and coordinate assignment for batched builds - #883
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…d builds Langfuse says 98% of apply_ops batches that create nodes carry their connects in the same batch, and 3,120 of 3,581 sampled node creations come through apply_ops -- so the BATCH path is where ~87% of layout quality is decided, not the serial one. It was also the weaker of the two: assign_positions implemented only Sugiyama's step 1. step 1 layer assignment -> which column ALREADY DONE step 2 crossing reduction -> order in column MISSING (ops-array order) step 3 coordinate assignment -> y MISSING (stacked from base_y) Step 2: order each column by the barycentre of its neighbours, forward and backward sweeps, insertion rank as a deterministic tiebreak so replay stays convergent. Three inputs feeding one sampler no longer cross their wires purely because of the order they were authored in. Step 3: centre each node on the mean centre of its predecessors, then push down only as far as column order requires. A one-node column used to sit flush with the top of a five-node column instead of level with the node it feeds. Also: collides() compared movable nodes only against EXISTING workflow nodes, so a new node could be placed on top of a new node PINNED to an explicit `at`. Pinned siblings are now obstacles. Measured on a fixture whose ops are authored in a crossing order: before crossings=3 mean input-alignment deviation=176px after crossings=0 mean input-alignment deviation=0px and on a realistic SDXL graph, alignment deviation 46.6px -> 30.4px. Three regression tests plus a scoring helper, verified red on the parent. The direct-jump collision change (replacing a ROW_GAP-at-a-time march bounded at _GUARD * ROW_GAP = 40,000px) ships WITHOUT a red-green test and is flagged as such in the test file: every fixture tried either missed the collision branch or was cleared by the old march too. Robustness change, not a verified fix. Suite: 45 failures vs 46 on parent, zero introduced.
69b9017 to
a3e1dbb
Compare
|
@coderabbitai review |
This repo is public and the ids reference an internal program board nobody outside can resolve. The section headers say what the tests cover without them.
|
@coderabbitai review |
Swarmhost agentic reviewThe detailed evaluation is available to employees in the internal Slack review thread. Updated by Swarmhost's agentic review process. |
huntcsg
left a comment
There was a problem hiding this comment.
Summary
This PR extends batch layout from longest-path column assignment to a bounded barycentre pass that reorders nodes within columns, then vertically centres movable nodes on already-positioned movable predecessors. It also treats explicitly positioned new nodes as collision obstacles and replaces 40px-at-a-time collision shifts with direct jumps below the blocking rectangle. Three focused tests cover crossing reduction, simple predecessor alignment, and pinned-node collision avoidance.
Risks
- The quoted comprehension is dense, but it is not an unchecked lookup:
predsis populated only for endpoints already present in the movable-node map, every suchadds[p]has asize, and the"pos"filter skips predecessors not yet placed. I do not see a crash path in that line under this function's construction. - The filtering immediately above it excludes pinned new nodes from
preds. Consequently, a movable node connected from a pinned predecessor at[40, 1000]is placed at y=60 rather than centred near y=1000. The same limitation means crossing reduction ignores pinned neighbours. This is not worse than the parent behavior, but it is a meaningful gap in the advertised coordinate assignment for mixed explicit/automatic batches. - The direct-jump collision rewrite changes production behavior without a regression test, as the PR itself notes. Its geometry looks internally consistent, but this is the highest regression risk in the diff.
- The scoring tests cover a clean two-column fixture only; they do not exercise mixed pinned/movable graphs, existing anchors, unequal node heights, long edges, or cyclic/invalid batches.
Stacked on #882. Rebase onto
mainonce that merges.Why the batch path
Langfuse, 600 sampled
apply_opscalls on production traffic:connectops in the same batchapply_opsadd_nodeSo ~87% of layout quality is decided by
assign_positions, not the serial cascade. It is also the weaker of the two placers: it implemented one of Sugiyama's three steps.base_yThat is why a batched build could be correctly layered and still look wrong: three inputs feeding one sampler crossed their wires purely because of the order they were authored in, and a one-node column sat flush with the top of a five-node column instead of level with the node it feeds.
Changes
collides()compared movable nodes only against existing workflow nodes, so a new node could be placed on top of a new node pinned to an explicitat.Measured
A fixture whose ops are deliberately authored in a crossing order:
A realistic SDXL graph: alignment deviation 46.6px → 30.4px, crossings 0 both ways.
The scoring helper lands in the test file so future layout changes are measured rather than eyeballed — that metric is the prerequisite for the A/B/C prototype comparison.
Tests
Three regression tests, verified red on the parent commit and green here. Full suite: 45 failures vs 46 on parent, zero introduced.
One thing shipping unproven
The direct-jump collision change — replacing a
ROW_GAP-at-a-time march bounded at_GUARD * ROW_GAP= 40,000px — has no red-green test, and there is a comment in the test file saying so. Every fixture I tried either did not reach the collision branch or was cleared by the old march as well, so the intended proof (old code exhausts its budget and leaves an overlap) was never demonstrated. Treat it as a robustness and efficiency change, not a verified bug fix.