# 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 <class>`
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 <method> from <Class>`
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`