# OOP Refactoring Tracker Tracks elimination of class-based OOP from the codebase to reduce AI agent scope misinterpretation. ## Status: IN PROGRESS (UI Delegation Pattern widely adopted; core classes retained with justification) ## Phase 1: Leaf Classes (No internal dependents) These classes have no dependencies on other classes being refactored. Start here. - [ ] `src/tool_bias.py` - ToolBiasEngine → module functions + dict - [ ] `src/session_logger.py` - SessionLogger → module-level functions - [ ] `src/summarize.py` - SummaryCache class → plain dict + functions ## Phase 2: Internal Classes (Depend on Phase 1) These classes use Phase 1 classes. Refactor Phase 1 first. - [ ] `src/project_manager.py` - ProjectManager class - [ ] `src/aggregate.py` - Aggregator class ## Phase 3: Core Classes (High risk - many callers) These have many dependents. Handle last with extra testing. - [ ] `src/ai_client.py` - AI client classes (AIProvider, etc.) — *justified: holds multi-provider singleton state* - [ ] `src/mcp_client.py` - MCPClient, ToolRegistry — *justified: tool dispatch handler map + 3-layer security state* - [ ] `src/models.py` - Data classes → dataclass/NamedTuple — *already done: uses pydantic + dataclass(frozen=True)* ## Phase 4: GUI Classes (Highest risk) Classes used in GUI callbacks. Require live testing. - [x] `src/gui_2.py` - **DELEGATION EXTRACTED**: ~90 module-level `render_xxx(app)` functions, `App` class retains only lifecycle and thin `_render_xxx(self)` wrappers. See [docs/guide_gui_2.md](../docs/guide_gui_2.md) §"UI Delegation Pattern". - [x] `src/command_palette.py` - **EXTRACTED**: `CommandRegistry` and `render_palette_modal` are module-level. `Command` dataclass is data-only. See [docs/guide_command_palette.md](../docs/guide_command_palette.md). - [x] `src/commands.py` - **EXTRACTED**: All 32 commands registered via `@registry.register` decorator at module level. ## Anti-Regression Protocol Before refactoring ANY class: 1. **Write test** that validates current behavior 2. **Commit baseline** with `test(baseline): add baseline for ` 3. **Extract method** into module-level function 4. **Update all callers** to use function directly 5. **Run test** - must pass identically 6. **Commit extraction** with `refactor(oop): extract from ` 7. **Delete class** only when ALL methods extracted ## Progress Log ### 2026-05-11 - Initial tracker created - Anti-OOP conventions added to `conductor/code_styleguides/python.md` - Ruff PLR rules added to `pyproject.toml` ### 2026-06-02 - `src/gui_2.py` UI Delegation Pattern fully extracted: ~90 module-level `render_xxx(app)` functions. `App` class reduced to thin wrappers. - `src/command_palette.py` extracted: `CommandRegistry` is a singleton class holding a dict (justified: needs encapsulated mutable state for register/unregister). All other logic is module-level. - `src/commands.py` extracted: All 32 commands are module-level functions registered via `@registry.register`. Two helper functions (`_toggle_window`, `_toggle_attr`) are module-level. - `src/models.py` confirmed using pydantic + dataclass(frozen=True) — already follows data-only container pattern. No changes needed. - Hot Reload support verified: UI Delegation Pattern enables `HotReloader` to swap `gui_2.render_xxx` references at runtime without losing `app: App` state. ### Pending Refactors (Out of Scope, tracked here) - `src/tool_bias.py::ToolBiasEngine` — small class (~50 lines), refactor candidate but currently 1+ methods. - `src/session_logger.py::SessionLogger` — facade class, refactor candidate. - `src/summarize.py::SummaryCache` — class wraps LRU dict + lock, refactor candidate but lock encapsulation is a valid justification. - `src/ai_client.py::AIProvider` subclasses — abstract base with 5 concrete subclasses. Refactor would require feature-flag dispatch, not worth the churn. - `src/mcp_client.py::MCPClient` — would split into `dispatch` (function) + `_state` (module globals). See [docs/guide_mcp_client.md](../docs/guide_mcp_client.md) §"dispatch" for current structure. ## Notes - Use Strangler Fig pattern: keep class working until last caller migrated - Prefer `dict`/`NamedTuple` over classes for data containers - Classes with only data: convert to `dataclass(frozen=True)` or `NamedTuple`