From 4d70df76fc5601c8b556b1d75a749bc2e96e0f79 Mon Sep 17 00:00:00 2001 From: openclaw Date: Tue, 24 Mar 2026 08:19:40 +0000 Subject: [PATCH] feat(graph): map node status from FileStatus via source_file (GAP-B1) Co-Authored-By: Claude Opus 4.6 --- .../app/modules/graph/application/services.py | 23 +++++++++++++++---- backend/tests/test_graph_service.py | 18 +++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/backend/app/modules/graph/application/services.py b/backend/app/modules/graph/application/services.py index 2a6a0cc..a0c9a35 100644 --- a/backend/app/modules/graph/application/services.py +++ b/backend/app/modules/graph/application/services.py @@ -16,15 +16,28 @@ _GROUPS = [ ] +_SOURCE_FILES: dict[str, str] = { + "capability": "business-architecture/02-capability-map.csv", + "module": "application-architecture/02-modules.csv", + "entity": "data-architecture/01-entities.csv", + "runtime_component": "technology-architecture/01-runtime-components.csv", +} + + class GraphService: """Constructs a panorama graph and supports neighbor queries.""" - def build_panorama(self, scan_result: ScanResult) -> GraphView: + def build_panorama(self, scan_result: ScanResult, *, design_dir: str = "") -> GraphView: """Build a full panorama GraphView from a ScanResult (9-step algorithm).""" nodes: list[GraphNode] = [] edges: list[GraphEdge] = [] node_ids: set[str] = set() + # Build file-status lookup from ScanResult + file_status_map: dict[str, str] = { + fs.path: fs.status.value for fs in scan_result.file_statuses + } + # Step 1: groups are always the fixed 5 groups = list(_GROUPS) @@ -35,7 +48,7 @@ class GraphService: id=node_id, type="capability", label=cap.name, - status="unknown", + status=file_status_map.get(_SOURCE_FILES["capability"], "unknown"), group_id="business", )) node_ids.add(node_id) @@ -47,7 +60,7 @@ class GraphService: id=node_id, type="module", label=mod.name, - status="unknown", + status=file_status_map.get(_SOURCE_FILES["module"], "unknown"), group_id="application", )) node_ids.add(node_id) @@ -59,7 +72,7 @@ class GraphService: id=node_id, type="entity", label=ent.name, - status="unknown", + status=file_status_map.get(_SOURCE_FILES["entity"], "unknown"), group_id="data", )) node_ids.add(node_id) @@ -71,7 +84,7 @@ class GraphService: id=node_id, type="runtime_component", label=rc.name, - status="unknown", + status=file_status_map.get(_SOURCE_FILES["runtime_component"], "unknown"), group_id="technology", )) node_ids.add(node_id) diff --git a/backend/tests/test_graph_service.py b/backend/tests/test_graph_service.py index 8ce5f1c..5954838 100644 --- a/backend/tests/test_graph_service.py +++ b/backend/tests/test_graph_service.py @@ -17,6 +17,11 @@ def scan_result(): return svc.scan(project) +@pytest.fixture +def design_dir(): + return "/workspace/arch-design-agent-skill-dashboard/design" + + @pytest.fixture def graph_service(): return GraphService() @@ -86,3 +91,16 @@ def test_graph_node_has_parent_field(graph_service, scan_result): view = graph_service.build_panorama(scan_result) for node in view.nodes: assert hasattr(node, 'parent') + + +def test_panorama_nodes_have_real_status(graph_service, scan_result, design_dir): + view = graph_service.build_panorama(scan_result, design_dir=design_dir) + statuses = {n.status for n in view.nodes} + assert statuses != {"unknown"}, "All nodes still have status='unknown' — status mapping not working" + + +def test_panorama_status_values_are_valid(graph_service, scan_result, design_dir): + view = graph_service.build_panorama(scan_result, design_dir=design_dir) + valid_statuses = {"ok", "sparse", "missing", "template-residue", "placeholder-heavy", "unknown"} + for node in view.nodes: + assert node.status in valid_statuses, f"Node {node.id} has invalid status '{node.status}'"