From f4a445bd4bdf5254eefba2a124b270e4fbb5c083 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 17 Jun 2026 19:18:09 -0400 Subject: [PATCH] refactor(src): narrow exception types in Phase 6 batch (8 sites across 3 files) Migrates the 8 try/except sites in provider + adapter + orchestration files by narrowing the exception types from broad 'except Exception' to specific stdlib/domain exceptions. Files and sites: 1. src/aggregate.py:50 (is_absolute_with_drive - PureWindowsPath) except Exception -> except (ValueError, OSError) 2. src/aggregate.py:105 (stats - ast.parse for element count) except Exception -> except (SyntaxError, ValueError) 3. src/aggregate.py:107 (stats outer try) except Exception -> except (OSError, SyntaxError) 4. src/aggregate.py:274 (file read with traceback) except Exception -> except (OSError, UnicodeDecodeError) 5. src/aggregate.py:446 (AST skeleton fallback) except Exception -> except (AttributeError, TypeError, ValueError) 6. src/multi_agent_conductor.py:317 (persona load fallback) except: -> except (OSError, KeyError, AttributeError, TypeError) 7. src/multi_agent_conductor.py:467 (persona apply with print) except Exception -> except (OSError, KeyError, AttributeError, TypeError) 8. src/multi_agent_conductor.py:517 (file view injection) except Exception -> except (OSError, UnicodeDecodeError, AttributeError, TypeError) 9. src/multi_agent_conductor.py:635 (response push with traceback) except Exception -> except (OSError, TypeError, AttributeError) 10. src/models.py:1081 (MCP config load) except Exception -> except (OSError, json.JSONDecodeError, UnicodeDecodeError) Decisions (documented as no-op): - src/dag_engine.py: 0 violations; 1 compliant site; no migration - src/models.py:268 (RAISE AttributeError): legitimate __getattr__ pattern; keep - src/gemini_cli_adapter.py:173-174 (RAISE): try/except + raise for SDK exception conversion; keep as-is (cascading if changed) - src/conductor_tech_lead.py:120 UNCLEAR (Phase 2 decision): keep - src/openai_compatible.py:87 UNCLEAR (Phase 2 decision): keep Tests verified: - tests/test_aggregate_flags.py (2 tests) PASS - tests/test_context_composition_phase6.py (9 tests) PASS - tests/test_tiered_context.py (5 tests) PASS - tests/test_ui_summary_only_removal.py (6 tests) PASS - tests/test_orchestration_logic.py (8 tests) PASS - tests/test_dag_engine.py (9 tests) PASS - tests/test_conductor_tech_lead.py (9 tests) PASS --- src/aggregate.py | 10 +++++----- src/models.py | 2 +- src/multi_agent_conductor.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/aggregate.py b/src/aggregate.py index e2872310..633b7a09 100644 --- a/src/aggregate.py +++ b/src/aggregate.py @@ -47,7 +47,7 @@ def is_absolute_with_drive(entry: str) -> bool: try: p = PureWindowsPath(entry) return p.drive != "" - except Exception: + except (ValueError, OSError): return False def resolve_paths(base_dir: Path, entry: str) -> list[Path]: @@ -100,9 +100,9 @@ def compute_file_stats(abs_path: str) -> dict[str, int]: try: tree = ast.parse(content) stats["ast_elements"] = sum(1 for node in ast.walk(tree) if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))) - except Exception: + except (SyntaxError, ValueError): pass - except Exception: + except (OSError, SyntaxError): pass return stats @@ -271,7 +271,7 @@ def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[ content = f"ERROR: file not found: {path}" mtime = 0.0 error = True - except Exception as e: + except (OSError, UnicodeDecodeError) as e: content = f"ERROR reading {path}:\n{traceback.format_exc()}" mtime = 0.0 error = True @@ -443,7 +443,7 @@ def build_tier3_context(file_items: list[dict[str, Any]], screenshot_base_dir: P try: skeleton = parser.get_skeleton(content) sections.append(f"### `{original}` (AST Skeleton)\n\n```python\n{skeleton}\n```") - except Exception: + except (AttributeError, TypeError, ValueError): sections.append(f"### `{original}`\n\n{summarize.summarise_file(path, content)}") else: sections.append(f"### `{original}`\n\n{summarize.summarise_file(path, content)}") diff --git a/src/models.py b/src/models.py index 4aec68d1..06c4998f 100644 --- a/src/models.py +++ b/src/models.py @@ -1078,7 +1078,7 @@ def load_mcp_config(path: str) -> MCPConfiguration: try: data = json.load(f) return MCPConfiguration.from_dict(data) - except Exception: + except (OSError, json.JSONDecodeError, UnicodeDecodeError): return MCPConfiguration() #endregion: MCP Config diff --git a/src/multi_agent_conductor.py b/src/multi_agent_conductor.py index 5c8b0ee1..9d0c3a24 100644 --- a/src/multi_agent_conductor.py +++ b/src/multi_agent_conductor.py @@ -314,7 +314,7 @@ class ConductorEngine: persona = personas[ticket.persona_id] if persona.preferred_models: models_list = persona.preferred_models - except: + except (OSError, KeyError, AttributeError, TypeError): pass # Fall back to default list model_idx = min(ticket.retry_count, len(models_list) - 1) model_name = models_list[model_idx] @@ -464,7 +464,7 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: preferred_models = persona.preferred_models if persona.tool_preset: persona_tool_preset = persona.tool_preset - except Exception as e: + except (OSError, KeyError, AttributeError, TypeError) as e: print(f"[WARN] Failed to load persona {context.persona_id}: {e}") # Apply tool preset: use persona's tool_preset if available, otherwise fall back to context.tool_preset @@ -514,7 +514,7 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: tokens_after += _count_tokens(view) context_injection += f"\nFile: {file_path}\n{view}\n" - except Exception as e: + except (OSError, UnicodeDecodeError, AttributeError, TypeError) as e: context_injection += f"\nError reading {file_path}: {e}\n" if tokens_before > 0: @@ -632,7 +632,7 @@ def run_worker_lifecycle(ticket: Ticket, context: WorkerContext, context_files: } print(f"[MMA] Pushing Tier 3 response for {ticket.id}, stream_id={response_payload['stream_id']}") _queue_put(event_queue, "response", response_payload) - except Exception as e: + except (OSError, TypeError, AttributeError) as e: print(f"[MMA] ERROR pushing response to UI: {e}\n{traceback.format_exc()}") # Update usage in engine if provided