EU-Utility/docs/EU_UTILITY_IMPROVEMENT_PLAN.md

20 KiB

EU-Utility Improvement Plan

Comprehensive Code Review & Analysis
Date: February 14, 2026
Analyst: AI Code Review System
Scope: Full codebase analysis of EU-Utility v2.0


1. Executive Summary

Top 10 Critical Issues

# Issue Severity Impact File(s)
1 No Input Validation on File Operations Critical Data corruption, security plugin_manager.py, settings.py, multiple plugins
2 Race Conditions in Event Bus Critical Data loss, crashes event_bus.py
3 Missing Exception Handling in OCR Thread Critical App crash game_reader/plugin.py
4 Hardcoded Paths Without Validation High Cross-platform failures log_reader.py, settings.py
5 No Rate Limiting on Nexus API High API bans, poor UX nexus_api.py
6 Memory Leaks in Plugin UI High Performance degradation overlay_window.py, plugins
7 Unvalidated JSON Parsing High Crashes on corrupt data All plugins with data files
8 No Cleanup of QThreads Medium Resource leaks skill_scanner/plugin.py, game_reader/plugin.py
9 Missing Type Hints Medium Maintenance burden Entire codebase
10 No Logging Framework Medium Debugging difficulties Entire codebase

Quick Stats

  • Total Files Analyzed: 50+
  • Core Modules: 15
  • Plugins: 26
  • Lines of Code: ~15,000+
  • Critical Issues: 4
  • High Priority Issues: 12
  • Medium Priority Issues: 28

2. Architecture Review

2.1 Strengths

  1. Well-Structured Plugin System

    • Clean BasePlugin abstract class
    • Proper lifecycle management (initialize, get_ui, shutdown)
    • Good separation of concerns between core and plugins
  2. Comprehensive Service Layer

    • OCR Service with multiple backend support
    • HTTP Client with caching and retry logic
    • Event Bus with typed events
    • Task Manager for background operations
  3. Cross-Platform Considerations

    • Windows-specific features gracefully degrade on Linux
    • Platform detection in window_manager.py
    • Fallback mechanisms for OCR backends
  4. Modern Python Patterns

    • Dataclasses for data structures
    • Type hints (partial)
    • Singleton pattern for services
    • Context managers where appropriate

2.2 Weaknesses

  1. Tight Coupling to PyQt6

    • No abstraction layer for UI framework
    • Difficult to test without GUI
    • Blocks headless operation
  2. Global State Management

    • Heavy reliance on singletons
    • Difficult to mock for testing
    • Potential for circular imports
  3. No Dependency Injection

    • Services directly instantiate dependencies
    • Hard to swap implementations
    • Testing requires monkey-patching
  4. Inconsistent Error Handling

    • Mix of try/except, error returns, and exceptions
    • No unified error response format
    • Silent failures in many places
  5. Missing Abstraction Layers

    • Direct file system access everywhere
    • No repository pattern for data access
    • No configuration abstraction

3. Performance Analysis

3.1 Identified Bottlenecks

Component Issue Impact Recommendation
OCR Service Synchronous initialization blocks UI High startup delay Move to background thread
Event Bus Lock contention on high-frequency events Reduced throughput Use lock-free queues
HTTP Client Blocking I/O in main thread UI freezing Use async/await
Plugin Manager Synchronous plugin discovery Slow startup Lazy loading
Log Reader 500ms polling interval CPU waste Use file system events
Screenshot Full-screen capture on every OCR Memory pressure Region-based capture

3.2 Memory Usage Issues

  1. Unbounded Caches

    • EventBus history limited to 1000 events (good)
    • HTTPClient cache has no size limit (bad)
    • Plugin data files loaded entirely into memory (bad)
  2. UI Widget Leaks

    # In overlay_window.py - widgets not properly deleted
    while self.plugin_stack.count() > 0:
        widget = self.plugin_stack.widget(0)
        self.plugin_stack.removeWidget(widget)  # Not deleted!
    
  3. Image Retention

    • Screenshots kept in memory indefinitely
    • No LRU cache for OCR images

3.3 Optimization Recommendations

  1. Implement Async Operations

    # Current (blocking)
    result = api.nexus_search(query)
    
    # Recommended (async)
    result = await api.nexus_search_async(query)
    
  2. Add Connection Pooling

    • HTTP client should reuse connections
    • Current implementation creates new session per request
  3. Lazy Loading for Plugins

    • Only load plugin UI when first viewed
    • Current: All UIs created at startup
  4. Image Compression

    • Compress screenshots before OCR
    • Use lower resolution for text detection

4. Code Quality Issues

4.1 Error Handling Deficiencies

Issue: Bare Except Clauses

Files: Multiple plugins

# BAD - Catches everything including KeyboardInterrupt
try:
    data = json.load(f)
except:
    pass

# GOOD - Specific exception handling
try:
    data = json.load(f)
except json.JSONDecodeError as e:
    logger.error(f"Invalid JSON in {file_path}: {e}")
    data = {}
except IOError as e:
    logger.error(f"Failed to read {file_path}: {e}")
    raise DataLoadError from e

Issue: Silent Failures

File: core/plugin_manager.py:52-55

# Current
try:
    return json.loads(config_path.read_text())
except json.JSONDecodeError:
    pass  # Silent failure!

# Recommended
try:
    return json.loads(config_path.read_text())
except json.JSONDecodeError as e:
    logger.warning(f"Corrupted config file, using defaults: {e}")
    self._backup_corrupted_config(config_path)
    return self._get_default_config()

4.2 Type Safety Issues

Missing Type Hints

Coverage: ~40% of functions lack proper type hints

Priority files to annotate:

  1. core/plugin_api.py - Public API surface
  2. core/event_bus.py - Critical for event handling
  3. plugins/base_plugin.py - Base class for all plugins

Optional/None Confusion

File: core/ocr_service.py:45-50

# Current - unclear return type
def capture_screen(self, region=None):
    # Returns Image.Image or raises
    pass

# Recommended
def capture_screen(self, region: Optional[Tuple[int, int, int, int]] = None) -> Image.Image:
    """Capture screen or region.
    
    Args:
        region: (x, y, width, height) or None for full screen
        
    Returns:
        PIL Image
        
    Raises:
        RuntimeError: If screenshot service unavailable
    """

4.3 Code Duplication

Pattern: File Loading

Found in: 12+ plugins

# Duplicated pattern
data_file = Path("data/something.json")
data_file.parent.mkdir(parents=True, exist_ok=True)
if data_file.exists():
    try:
        with open(data_file, 'r') as f:
            data = json.load(f)
    except:
        data = {}

Solution: Create DataStore utility class

Pattern: UI Styling

Found in: All plugins

Each plugin defines its own styles instead of using shared styles from eu_styles.py.

4.4 Specific File Issues

core/main.py

  • Line 45-50: No graceful degradation if keyboard library fails
  • Line 120-150: Service initialization not parallelized
  • Line 200-220: Missing cleanup on startup failure

core/plugin_manager.py

  • Line 85-95: Plugin discovery can hang on malformed plugins
  • Line 120-140: No timeout on plugin initialization
  • Line 180-200: Hotkey triggering not thread-safe

plugins/game_reader/plugin.py

  • Line 45-80: OCR thread has no cancellation mechanism
  • Line 100-120: Screenshot temp file not cleaned up on crash
  • Line 150-180: No validation of OCR result before processing

5. Security Audit

5.1 Critical Vulnerabilities

1. Path Traversal in Plugin Loading

File: core/plugin_manager.py:85-95

# VULNERABLE - No path validation
spec = importlib.util.spec_from_file_location(module_name, plugin_file)

Risk: Malicious plugin could access files outside plugin directory

Fix:

from pathlib import Path

def _validate_plugin_path(self, plugin_file: Path) -> bool:
    """Ensure plugin file is within allowed directories."""
    resolved = plugin_file.resolve()
    allowed_paths = [Path(d).resolve() for d in self.PLUGIN_DIRS]
    return any(str(resolved).startswith(str(allowed)) for allowed in allowed_paths)

2. Code Injection via Log Parsing

File: core/log_reader.py:85-95

# VULNERABLE - Regex patterns could be exploited
PATTERNS = {
    'skill_gain': re.compile(r'(.+?)\s+has\s+improved...'),
}

Risk: Crafted log lines could cause ReDoS (Regular Expression Denial of Service)

Fix: Add regex timeout and complexity limits

3. Unsafe Deserialization

File: Multiple plugins

# VULNERABLE - Loading untrusted JSON
data = json.load(f)  # Could contain malicious data

Risk: While json.load is safer than pickle, nested structures could cause memory exhaustion

Fix: Implement depth and size limits

5.2 Medium Risk Issues

1. No HTTPS Certificate Validation

File: core/nexus_api.py:180-200

The requests library validates by default, but no pinning is implemented.

2. Sensitive Data in Logs

File: core/plugin_api.py

API keys or tokens could be logged in error messages.

3. Temp File Race Condition

File: plugins/game_reader/plugin.py:60-70

# VULNERABLE
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
    screenshot_path = tmp.name  # Predictable path

5.3 Security Recommendations

  1. Implement Plugin Signing

    • Verify plugin integrity before loading
    • Whitelist approved plugins
  2. Add Sandboxing

    • Restrict plugin file system access
    • Network access controls
  3. Input Sanitization

    • Validate all external inputs
    • Escape log message content
  4. Secure Defaults

    • Disable plugins by default
    • Require explicit user approval

6. UI/UX Improvements

6.1 Current Pain Points

  1. No Loading States

    • OCR operations block UI without feedback
    • Network requests show no progress
  2. Poor Error Messages

    • Generic "Error" messages
    • No actionable guidance
  3. Inconsistent Styling

    • Each plugin has different button styles
    • No unified color scheme enforcement
  4. No Keyboard Navigation

    • Tab order not defined
    • No shortcuts for common actions

6.2 Design Recommendations

Implement Toast Notifications

# Add to core/notifications.py
class NotificationManager:
    def show_toast(self, message: str, type: str = "info", duration: int = 3000):
        """Show non-intrusive notification."""

Add Loading Indicators

# Add to base_plugin.py
class BasePlugin:
    def show_loading(self, message: str = "Loading..."):
        """Show loading overlay."""
    
    def hide_loading(self):
        """Hide loading overlay."""

Standardize Form Validation

# Add validation utilities
class FormValidator:
    @staticmethod
    def validate_number(value: str, min: float, max: float) -> ValidationResult:
        """Validate numeric input."""

6.3 Accessibility Improvements

  1. Add Screen Reader Support

    • Set proper accessibleName on all widgets
    • Provide text alternatives for icons
  2. High Contrast Mode

    • Add theme option for visibility
    • Respect system accessibility settings
  3. Font Scaling

    • Support system font size changes
    • Allow user-defined scaling

7. Feature Gaps

7.1 Missing vs Competitors

Feature EU-Utility Competitor A Competitor B Priority
Auto-loot tracking Manual only ✓ Auto ✓ Auto P0
Market price alerts P1
Team/Shared tracking P2
Mobile companion P2
Cloud sync P1
Plugin marketplace Basic P2
Analytics dashboard Basic P1
Discord integration P3

7.2 Technical Debt Features

  1. Configuration Management

    • Current: JSON files scattered across codebase
    • Needed: Unified config with validation schema
  2. Data Migration

    • No versioning for data files
    • Breaking changes lose user data
  3. Plugin API Versioning

    • No version compatibility checking
    • Plugins can break on core updates
  4. Update System

    • No auto-update mechanism
    • Manual download required

P0 (Critical)

  1. Automatic Loot Detection

    • Parse chat log for loot messages
    • Auto-populate loot tracker
  2. Session Persistence

    • Save/restore hunting sessions
    • Crash recovery

P1 (High)

  1. Market Price Monitoring

    • Track item prices over time
    • Alert on price changes
  2. Cloud Backup

    • Optional encrypted backup
    • Cross-device sync

P2 (Medium)

  1. Plugin SDK

    • Better documentation
    • Example plugins
    • Debug tools
  2. Mobile App

    • View stats remotely
    • Push notifications

8. Prioritized Action Plan

P0 - Fix Immediately (Critical)

8.1.1 Fix Race Conditions in Event Bus

File: core/event_bus.py Effort: 4 hours Impact: Prevents data loss and crashes

# Add proper locking
from threading import RLock

class EventBus:
    def __init__(self):
        self._lock = RLock()
        self._history_lock = RLock()

8.1.2 Add Input Validation to File Operations

Files: All plugins with file I/O Effort: 8 hours Impact: Prevents data corruption

def safe_json_load(filepath: Path, default: Any = None) -> Any:
    """Safely load JSON with validation."""
    if not filepath.exists():
        return default
    
    # Check file size (prevent memory exhaustion)
    max_size = 10 * 1024 * 1024  # 10MB
    if filepath.stat().st_size > max_size:
        raise FileTooLargeError(f"{filepath} exceeds max size")
    
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
        # Validate JSON structure
        return json.loads(content)

8.1.3 Fix OCR Thread Exception Handling

File: plugins/game_reader/plugin.py Effort: 2 hours Impact: Prevents app crashes

def run(self):
    """Capture screen and perform OCR."""
    try:
        # ... existing code ...
    except Exception as e:
        logger.exception("OCR failed")
        self.error_occurred.emit(f"OCR failed: {str(e)}")
    finally:
        # Always cleanup
        self._cleanup_temp_files()

8.1.4 Implement Proper Resource Cleanup

File: core/main.py, core/overlay_window.py Effort: 4 hours Impact: Prevents memory leaks

P1 - High Priority (Next Sprint)

8.2.1 Add Comprehensive Logging

Files: All core modules Effort: 12 hours Impact: Debugging, monitoring

# Replace print statements
import logging

logger = logging.getLogger(__name__)
logger.info("Plugin loaded: %s", plugin_name)
logger.warning("Config file corrupted, using defaults")
logger.error("Failed to initialize OCR service", exc_info=True)

8.2.2 Implement Type Hints

Files: Core API surface Effort: 16 hours Impact: Maintainability, IDE support

8.2.3 Add Unit Tests

Files: Core services Effort: 24 hours Impact: Code reliability

Target coverage:

  • Event Bus: 90%
  • Plugin API: 80%
  • OCR Service: 70%
  • HTTP Client: 80%

8.2.4 Create Data Access Layer

Files: New core/data/ module Effort: 16 hours Impact: Consistency, testability

P2 - Medium Priority (Backlog)

8.3.1 UI/UX Polish

  • Loading indicators
  • Better error messages
  • Consistent styling

8.3.2 Performance Optimizations

  • Async HTTP requests
  • Lazy plugin loading
  • Image caching

8.3.3 Security Hardening

  • Plugin sandboxing
  • Input sanitization
  • Path validation

8.3.4 Documentation

  • API documentation
  • Plugin development guide
  • Architecture decision records

9. Quick Wins (Easy Improvements)

9.1 Low Effort, High Impact

  1. Replace print() with logging (2 hours)

    • Global search/replace with proper log levels
  2. Add docstrings to public APIs (4 hours)

    • Focus on BasePlugin and PluginAPI
  3. Fix bare except clauses (2 hours)

    • Replace except: with except Exception:
  4. Add all to modules (1 hour)

    • Clean up public API surface
  5. Sort imports (1 hour)

    • Use isort for consistency

9.2 Code Quality Quick Fixes

# Before
except:
    pass

# After
except Exception as e:
    logger.debug("Operation failed: %s", e)
# Before
def load_data():
    if file.exists():
        with open(file) as f:
            return json.load(f)

# After
def load_data() -> dict:
    """Load data from file."""
    if not file.exists():
        return {}
    try:
        with open(file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except json.JSONDecodeError as e:
        logger.error("Corrupted data file: %s", e)
        return {}

10. Long-term Architectural Recommendations

10.1 Migration to Async Architecture

Current: Blocking I/O throughout Target: Async/await with Qt event loop integration

# Future architecture
class PluginAPI:
    async def nexus_search(self, query: str) -> List[SearchResult]:
        """Async search that doesn't block UI."""

10.2 Plugin Isolation

Current: Plugins run in same process Target: Plugin sandboxing with IPC

Benefits:

  • Crash isolation
  • Security boundaries
  • Hot reloading

10.3 Data Persistence Layer

Current: JSON files Target: SQLite with migrations

# Future data layer
class DataStore:
    def __init__(self):
        self._db = sqlite3.connect('data/eu_utility.db')
        self._migrations = MigrationManager()

10.4 Testing Infrastructure

Current: No tests Target: Comprehensive test suite

tests/
├── unit/
│   ├── core/
│   │   ├── test_event_bus.py
│   │   ├── test_plugin_api.py
│   │   └── test_ocr_service.py
│   └── plugins/
├── integration/
│   └── test_plugin_loading.py
└── e2e/
    └── test_hunting_session.py

10.5 CI/CD Pipeline

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: [ubuntu, windows, macos]
    steps:
      - uses: actions/checkout@v3
      - name: Run tests
        run: pytest --cov=core tests/
      - name: Type check
        run: mypy core/
      - name: Lint
        run: ruff check .

Appendix A: Critical Bugs to Fix Immediately

  1. Event Bus Race Condition - Can cause crash under load
  2. OCR Thread Exception - App crashes on OCR failure
  3. File Path Traversal - Security vulnerability
  4. Memory Leak in Plugin Reload - UI widgets not deleted
  5. Unbounded HTTP Cache - Can fill disk
  6. No Log Rotation - chat.log parsing can hang
  7. Plugin Init Timeout - Malformed plugins block startup
  8. Settings Corruption - No backup on parse failure

Appendix B: Migration Guide for Plugin Developers

Version 2.0 to 2.1 Changes

  1. New Error Handling Pattern

    # Old
    try:
        data = self.api.ocr_capture()
    except:
        pass
    
    # New
    try:
        data = self.api.ocr_capture()
    except OCRServiceError as e:
        logger.error("OCR failed: %s", e)
        self.show_error("OCR unavailable")
    
  2. Typed Events

    # Old
    self.api.publish_event('loot', {'item': 'Hide'})
    
    # New
    from core.event_bus import LootEvent
    self.api.publish_typed(LootEvent(
        mob_name="Daikiba",
        items=[{"name": "Animal Hide", "value": 0.03}]
    ))
    

Summary

EU-Utility is a well-architected application with a solid plugin system and comprehensive service layer. However, it has accumulated technical debt in error handling, type safety, and testing. The critical issues (race conditions, exception handling, security) should be addressed immediately to ensure stability. The high-priority items (logging, type hints, tests) will significantly improve maintainability.

Estimated effort for full remediation: 120-160 hours Recommended team: 2 developers for 4-6 weeks


Document generated: February 14, 2026
Review scheduled: March 14, 2026