Compare current architecture metrics against the proposed architecture after applying simulated changes.
(
config_path: str = typer.Argument(..., help="Path to the simulation JSON configuration file."),
path: Optional[str] = typer.Argument(None, help="Path to the directory to simulate. Defaults to the current directory."),
context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
)
| 170 | |
| 171 | @simulate_app.command("compare") |
| 172 | def simulate_compare( |
| 173 | config_path: str = typer.Argument(..., help="Path to the simulation JSON configuration file."), |
| 174 | path: Optional[str] = typer.Argument(None, help="Path to the directory to simulate. Defaults to the current directory."), |
| 175 | context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"), |
| 176 | ): |
| 177 | """ |
| 178 | Compare current architecture metrics against the proposed architecture after applying simulated changes. |
| 179 | """ |
| 180 | load_cgc_credentials(context) |
| 181 | repo_path = get_repo_path(path) |
| 182 | |
| 183 | cfg_file = Path(config_path) |
| 184 | if not cfg_file.exists(): |
| 185 | console.print(f"[bold red]Scenario configuration file not found:[/bold red] {config_path}") |
| 186 | raise typer.Exit(code=1) |
| 187 | |
| 188 | try: |
| 189 | with open(cfg_file, "r") as f: |
| 190 | scenario = json.load(f) |
| 191 | except Exception as e: |
| 192 | console.print(f"[bold red]Failed to parse scenario JSON file:[/bold red] {e}") |
| 193 | raise typer.Exit(code=1) |
| 194 | |
| 195 | services = _initialize_services(context) |
| 196 | db_manager = services[0] |
| 197 | |
| 198 | try: |
| 199 | baseline = CodeGraphTwin(repo_path).load_from_db(db_manager) |
| 200 | simulated = CodeGraphTwin(repo_path).load_from_db(db_manager) |
| 201 | |
| 202 | # Apply simulated steps |
| 203 | steps = scenario.get("steps", []) |
| 204 | for step in steps: |
| 205 | stype = step.get("type") |
| 206 | if stype == "decompose": |
| 207 | simulated.decompose_service(step.get("mapping", {})) |
| 208 | elif stype == "remove_dependency": |
| 209 | simulated.remove_dependency(step.get("source"), step.get("target"), step.get("rel_type")) |
| 210 | elif stype == "add_dependency": |
| 211 | simulated.add_dependency(step.get("source"), step.get("target"), step.get("rel_type")) |
| 212 | elif stype == "remove_node": |
| 213 | simulated.remove_node(step.get("node_id")) |
| 214 | |
| 215 | diff = baseline.compare_scenarios(simulated) |
| 216 | |
| 217 | # Render comparison table |
| 218 | table = Table(title=f"Scenario Comparison: Baseline vs {scenario.get('name', 'Simulated')}", show_header=True, header_style="bold cyan") |
| 219 | table.add_column("Metric", style="bold") |
| 220 | table.add_column("Baseline Value", justify="right") |
| 221 | table.add_column("Simulated Value", justify="right") |
| 222 | table.add_column("Change (Delta)", justify="right") |
| 223 | |
| 224 | def format_delta(val): |
| 225 | if val > 0: |
| 226 | return f"[green]+{val}[/green]" |
| 227 | elif val < 0: |
| 228 | return f"[red]{val}[/red]" |
| 229 | return "[dim]0[/dim]" |
nothing calls this directly
no test coverage detected