You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The live lock/blocking graph groups related sessions into visual clusters, drawing a soft colored "hull" (a rounded blob) behind each cluster's nodes. For most clusters this looks correct, but for small clusters (especially exactly 3 nodes) whose force-simulated layout ends up roughly collinear (all three nodes nearly in a line), the hull renders as a dramatically oversized, stretched oval that extends far beyond the actual nodes — sometimes 2-3x wider than it should be.
I'll be honest: I don't fully understand the root cause, and I've tried several fixes that either didn't work or traded this problem for a different one. I'm opening this as a "good first issue" for anyone who enjoys this kind of geometry/rendering puzzle — I'd genuinely appreciate a fresh set of eyes.
Where the bug lives
Relevant files:
web/src/shared/utils/graph/clusterLayout.ts — lays out each cluster's nodes independently via d3-force (a pinned "hub" node + force-directed spokes). For a 3-node component, this can produce a nearly-collinear layout (no strong force pushes 3 points into a non-degenerate 2D spread).
web/src/shared/utils/graph/packing.ts — tiles each component's bounding box next to the others (COMPONENT_PADDING = 140), no overlap between components' raw node boxes.
web/src/shared/utils/graph/hulls.ts — computes a convex hull (d3-polygon's polygonHull) around each component's final node positions, then pushes every hull vertex outward from the hull centroid by a fixed HULL_PADDING = 36px.
web/src/features/lock-graph/components/ClusterHulls.tsx — takes the padded hull polygon and renders it as one smooth SVG <path>.
What's been tried (all in ClusterHulls.tsx), none fully worked
d3-shape's curveCatmullRomClosed (original/current implementation on main, still there as the fallback since nothing else has worked better): fits one smooth interpolating spline through all the padded hull points. Looks great for clusters with a reasonable node count in a roughly round/organic arrangement. Fails: for near-collinear point sets, Catmull-Rom's tangent estimation (derived from neighboring point positions) produces large, nearly-parallel tangents, causing the closed spline to massively overshoot in both directions — this is the bug.
curveCardinalClosed with a dynamically computed tension (based on a PCA eigenvalue ratio of the hull points, meant to detect "how flat/collinear" the shape is and increase tension — which shrinks tangent magnitude — only for flat shapes, leaving round shapes untouched at tension=0, mathematically identical to Catmull-Rom). This was numerically verified against synthetic test coordinates I constructed myself (approximating the screenshot) and looked correct in isolated Node.js testing. When actually deployed and viewed live, it did not visibly fix the problem — the overshoot was still present in the real app. I suspect my synthetic test coordinates didn't accurately represent the real geometry/scale involved, so the tension calibration may be off in a way I couldn't catch without live browser access.
Local per-corner rounding instead of a global spline (a hand-written function producing a closed path where each polygon corner is rounded independently via a quadratic Bezier anchored at fixed-radius points along each adjacent edge — mathematically guaranteed to never extend beyond the original polygon and never shrink more than the fixed rounding radius, regardless of point count/arrangement). Tried at two different radii (20px, then 50px). Also did not visibly fix the specific 3-node overshoot case when deployed, and at the smaller radius it made larger/organic clusters look visibly worse (sharp, faceted "cut corner" polygon edges instead of the smooth blob look approach Add SQLite-backed persistent history, replay windowing, and 4 new rea… #1 produces for those cases) — a regression a maintainer explicitly rejected after seeing it rendered.
Whether the actual right fix belongs upstream in clusterLayout.ts instead (e.g., preventing 3-node components from ever landing in a near-collinear configuration in the first place, via a minimum-angle constraint on the force simulation) rather than trying to patch the rendering of an already-degenerate hull downstream.
Screenshots
I have several screenshots showing the failure (a 3-node cluster with an oversized stretched-oval hull) across multiple attempted fixes — happy to attach exact ones on request, or a maintainer can reproduce by looking at any 3-node blocking chain where the force layout happens to place the nodes roughly in a line (this seems to happen fairly often with exactly 3 nodes).
What I'd love help with
A correct diagnosis of why the overshoot happens (my working theory is Catmull-Rom tangent estimation on near-collinear points, but I'm not 100% sure that's the whole story given the fixes above didn't work as expected)
A fix that (a) doesn't regress the current good-looking behavior for normal/larger/organic clusters, and (b) actually, verifiably fixes the small-cluster case — ideally with a way to verify it that doesn't require me eyeballing screenshots back and forth
Alternatively, a case for why fixing this upstream (in the force layout, before hull computation) is simpler/more robust than anything downstream in the rendering
Summary
The live lock/blocking graph groups related sessions into visual clusters, drawing a soft colored "hull" (a rounded blob) behind each cluster's nodes. For most clusters this looks correct, but for small clusters (especially exactly 3 nodes) whose force-simulated layout ends up roughly collinear (all three nodes nearly in a line), the hull renders as a dramatically oversized, stretched oval that extends far beyond the actual nodes — sometimes 2-3x wider than it should be.
I'll be honest: I don't fully understand the root cause, and I've tried several fixes that either didn't work or traded this problem for a different one. I'm opening this as a "good first issue" for anyone who enjoys this kind of geometry/rendering puzzle — I'd genuinely appreciate a fresh set of eyes.
Where the bug lives
Relevant files:
web/src/shared/utils/graph/clusterLayout.ts— lays out each cluster's nodes independently viad3-force(a pinned "hub" node + force-directed spokes). For a 3-node component, this can produce a nearly-collinear layout (no strong force pushes 3 points into a non-degenerate 2D spread).web/src/shared/utils/graph/packing.ts— tiles each component's bounding box next to the others (COMPONENT_PADDING = 140), no overlap between components' raw node boxes.web/src/shared/utils/graph/hulls.ts— computes a convex hull (d3-polygon'spolygonHull) around each component's final node positions, then pushes every hull vertex outward from the hull centroid by a fixedHULL_PADDING = 36px.web/src/features/lock-graph/components/ClusterHulls.tsx— takes the padded hull polygon and renders it as one smooth SVG<path>.What's been tried (all in
ClusterHulls.tsx), none fully workedd3-shape'scurveCatmullRomClosed(original/current implementation onmain, still there as the fallback since nothing else has worked better): fits one smooth interpolating spline through all the padded hull points. Looks great for clusters with a reasonable node count in a roughly round/organic arrangement. Fails: for near-collinear point sets, Catmull-Rom's tangent estimation (derived from neighboring point positions) produces large, nearly-parallel tangents, causing the closed spline to massively overshoot in both directions — this is the bug.curveCardinalClosedwith a dynamically computedtension(based on a PCA eigenvalue ratio of the hull points, meant to detect "how flat/collinear" the shape is and increase tension — which shrinks tangent magnitude — only for flat shapes, leaving round shapes untouched attension=0, mathematically identical to Catmull-Rom). This was numerically verified against synthetic test coordinates I constructed myself (approximating the screenshot) and looked correct in isolated Node.js testing. When actually deployed and viewed live, it did not visibly fix the problem — the overshoot was still present in the real app. I suspect my synthetic test coordinates didn't accurately represent the real geometry/scale involved, so the tension calibration may be off in a way I couldn't catch without live browser access.Local per-corner rounding instead of a global spline (a hand-written function producing a closed path where each polygon corner is rounded independently via a quadratic Bezier anchored at fixed-radius points along each adjacent edge — mathematically guaranteed to never extend beyond the original polygon and never shrink more than the fixed rounding radius, regardless of point count/arrangement). Tried at two different radii (20px, then 50px). Also did not visibly fix the specific 3-node overshoot case when deployed, and at the smaller radius it made larger/organic clusters look visibly worse (sharp, faceted "cut corner" polygon edges instead of the smooth blob look approach Add SQLite-backed persistent history, replay windowing, and 4 new rea… #1 produces for those cases) — a regression a maintainer explicitly rejected after seeing it rendered.
What I genuinely don't understand
NODE_CENTER_OFFSET, viewport transform inClusterHulls.tsx) that I'm not accounting for correctly.clusterLayout.tsinstead (e.g., preventing 3-node components from ever landing in a near-collinear configuration in the first place, via a minimum-angle constraint on the force simulation) rather than trying to patch the rendering of an already-degenerate hull downstream.Screenshots
I have several screenshots showing the failure (a 3-node cluster with an oversized stretched-oval hull) across multiple attempted fixes — happy to attach exact ones on request, or a maintainer can reproduce by looking at any 3-node blocking chain where the force layout happens to place the nodes roughly in a line (this seems to happen fairly often with exactly 3 nodes).
What I'd love help with
Labels:
bug,good first issue