fix(central-ui): Flow Debugger prediction overlay matches by kind and title (arch-review F10)

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-06 14:10:44 -04:00
parent cccef7b2f4
commit 688136de85
2 changed files with 30 additions and 2 deletions
@@ -193,6 +193,30 @@ public class FlowGraphViewTests : BunitContext
Assert.True(int.Parse(ghost.GetAttribute("data-column")!) > realMax);
}
[Fact]
public void Overlay_TwoPredictedRouteCalls_RealSecondCallMatchesByTitle_FirstIsTheGhost()
{
// The run only ever made the second of two predicted route calls (a branch skipped the first).
// Matching by kind alone would pair the real "B.Y" step with the first predicted node ("A.X")
// and leave "B.Y" as the ghost — wrong: "A.X" is the one that never ran.
var step = new FlowStep(Guid.NewGuid(), null, null, FlowStepKind.RouteCall, FlowLane.Central, "B.Y", null,
T0, 5, FlowStepOutcome.Ok, null, null, null, null, null, null, "B.Y", null);
var graph = new FlowGraph([step], [], false, false);
var predicted = new PredictedFlow(
[
new("n1", FlowStepKind.RouteCall, FlowLane.Central, "A.X", false, null),
new("n2", FlowStepKind.RouteCall, FlowLane.Central, "B.Y", false, null),
], []);
var layout = FlowGraphView.ComputeLayout(graph, predicted);
var real = Assert.Single(layout.Nodes, n => n.Step != null);
Assert.Equal("B.Y", real.Predicted?.Title);
var ghost = Assert.Single(layout.Nodes, n => n.Ghost);
Assert.Equal("p:n1", ghost.Key);
Assert.Equal("A.X", ghost.Predicted?.Title);
}
[Fact]
public void Render_UnderGermanCulture_CoordinatesStayInvariant()
{