From 9da085018e8e823b8e2e741abdaef4f47b1945dd Mon Sep 17 00:00:00 2001 From: Lum1104 Date: Sun, 3 May 2026 16:04:57 +0800 Subject: [PATCH] chore(dashboard): address Task 4 review minors - Length-prefix the inter-container bucket key to eliminate collision risk when container ids contain the separator (e.g. folder names with spaces). Adds a regression test. - Rename AggregatedContainerEdge.types -> edgeTypes for symmetry with the existing LayerEdgeAggregation.edgeTypes field. - Drop the as-cast in the test helper by giving it the real EdgeType literal type and a complete object shape. - Reword the JSDoc to match what the function actually does (silently drop unmapped endpoints; callers needing strict can pre-filter). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../utils/__tests__/edgeAggregation.test.ts | 24 +++++++++++++++--- .../dashboard/src/utils/edgeAggregation.ts | Bin 5613 -> 5839 bytes 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/understand-anything-plugin/packages/dashboard/src/utils/__tests__/edgeAggregation.test.ts b/understand-anything-plugin/packages/dashboard/src/utils/__tests__/edgeAggregation.test.ts index 54b6323..3b41edc 100644 --- a/understand-anything-plugin/packages/dashboard/src/utils/__tests__/edgeAggregation.test.ts +++ b/understand-anything-plugin/packages/dashboard/src/utils/__tests__/edgeAggregation.test.ts @@ -1,9 +1,12 @@ import { describe, it, expect } from "vitest"; import { aggregateContainerEdges } from "../edgeAggregation"; -import type { GraphEdge } from "@understand-anything/core/types"; +import type { GraphEdge, EdgeType } from "@understand-anything/core/types"; -const ce = (source: string, target: string, type: string = "calls"): GraphEdge => - ({ source, target, type }) as GraphEdge; +const ce = (source: string, target: string, type: EdgeType = "calls"): GraphEdge => ({ + source, + target, + type, +}); describe("aggregateContainerEdges", () => { it("returns empty arrays for empty input", () => { @@ -36,7 +39,7 @@ describe("aggregateContainerEdges", () => { expect(agg.sourceContainerId).toBe("auth"); expect(agg.targetContainerId).toBe("cart"); expect(agg.count).toBe(3); - expect(agg.types.sort()).toEqual(["calls", "imports"]); + expect(agg.edgeTypes.sort()).toEqual(["calls", "imports"]); }); it("treats opposite directions as separate aggregated edges", () => { @@ -58,4 +61,17 @@ describe("aggregateContainerEdges", () => { expect(r.intraContainer).toEqual([]); expect(r.interContainerAggregated).toEqual([]); }); + + it("does not collide when container ids contain the separator character", () => { + // Pre-fix: key was `${sc} ${tc}` so `("x y", "z")` and `("x", "y z")` + // would both map to `"x y z"`. Length-prefix on source prevents this. + const m = new Map([ + ["a", "x y"], + ["b", "z"], + ["c", "x"], + ["d", "y z"], + ]); + const r = aggregateContainerEdges([ce("a", "b"), ce("c", "d")], m); + expect(r.interContainerAggregated).toHaveLength(2); + }); }); diff --git a/understand-anything-plugin/packages/dashboard/src/utils/edgeAggregation.ts b/understand-anything-plugin/packages/dashboard/src/utils/edgeAggregation.ts index 5bbeee89a0b5b371149bcf904749ba6fc173d6ac..3e47a7e60b23a0e0ccec6fcd3c0cbca8e9d18645 100644 GIT binary patch delta 389 zcmXw!ze)o^7{t9o!5{?9pL#e1jo~hR#L8B%iI7B*EVp0omYloi?k0FhOlf1GT;pR1 zc>&+R&bP3$5)?NH`MQCb-#7Es{0QDg<(K!y{JDJX&5RoBh@dnq(=k~j%s?uTv^s~7 zB^+TO6{n6mRnjscNe{p@!HCqE(i~i?EF*r5h@~lM1Dh}lNyNcmtQL`7P;MLqCQ;** zBhwTNMQX{@#raOX`1Q8uSG!ejlXy&>;&$(6)@tF5WNeebnTO)eQC)o1)+j{lG7#LX zm5}kuMj6x0DqVs*M~av{ufn0xl5#}FhWU#L%)ljk0$)SkBNcbbs~V@L*H+N zON9Go>@s(P!T!C8Lbu&@o3asg(-03JEIJ#mTh_lLJJufwBigCIa0NCd$XiS5jG! TT5P2dt*56~rdKk#N-PurMyNXn