# State Change Logging System Design
## Overview
This document describes the comprehensive state change logging system designed to support the gradual migration from `EnhancedTuiApp` to `AppStateContainer` with full visibility into all state mutations.
## Design Philosophy
**"Tiny Steps with Complete Visibility"** - Rather than doing large refactoring that leads to 8-hour regression fixes, we implement state migration in 30+ tiny iterations with comprehensive logging to track every change.
## Architecture Components
### 1. TUI Layer Macros (Call Site Logging)
**Location**: `src/enhanced_tui.rs` lines 67-92
**Purpose**: Track all state mutations happening in the TUI layer with caller context
#### Available Macros:
```rust
// Log a state field change with old → new values
log_state_change!(self, "field_name", old_value, new_value, "caller_function");
// Log setting a state field to a new value
log_state_set!(self, "field_name", new_value, "caller_function");
// Log clearing/resetting a state field
log_state_clear!(self, "field_name", old_value, "caller_function");
```
#### Implementation:
```rust
macro_rules! log_state_change {
($self:expr, $field:expr, $old:expr, $new:expr, $caller:expr) => {
if let Some(ref services) = $self.service_container {
services.debug_service.info(
"StateManager",
format!("[{}] {} changed: {} -> {} (in {})",
chrono::Local::now().format("%H:%M:%S%.3f"),
$field, $old, $new, $caller
),
);
}
};
}
```
### 2. Helper Methods Pattern (Migration Bridge)
**Location**: `src/enhanced_tui.rs` starting around line 250
**Purpose**: Provide abstracted access to state during migration with logging
#### Design Pattern:
```rust
// Getter - abstracts whether data comes from local field or AppStateContainer
fn get_jump_to_row_input(&self) -> String {
if let Some(ref container_arc) = self.state_container {
container_arc.jump_to_row().input.clone()
} else {
self.jump_to_row_input.clone()
}
}
// Setter - logs every mutation with caller tracking
fn set_jump_to_row_input(&mut self, input: String) {
let old_value = self.jump_to_row_input.clone();
self.jump_to_row_input = input.clone();
log_state_change!(self, "jump_to_row_input", old_value, input, "set_jump_to_row_input");
}
```
#### Benefits:
- **Gradual Migration**: Code can be updated to use helpers before moving data
- **Call Site Visibility**: Every mutation shows where it happened
- **Fallback Safety**: Works with both old and new state locations
- **Zero Regression Risk**: Changes are atomic and reversible
### 3. AppStateContainer Internal Logging
**Location**: `src/app_state_container.rs`
**Purpose**: Log internal state container operations and transitions
#### Debug Service Integration:
- Uses `RefCell<Option<DebugService>>` for interior mutability through Arc
- Injected during initialization: `state_arc.set_debug_service(services.debug_service.clone_service())`
- Located at: `src/enhanced_tui.rs:525`
#### Active Logging Areas:
```rust
// Mode transitions
pub fn enter_mode(&mut self, mode: AppMode) -> Result<()> {
let current = self.current_mode();
if let Some(ref debug_service) = *self.debug_service.borrow() {
debug_service.info("AppStateContainer",
format!("MODE TRANSITION: {:?} -> {:?}", current, mode));
}
// ... rest of implementation
}
// Help state changes
pub fn set_help_visible(&mut self, visible: bool) {
let old_value = self.show_help;
self.show_help = visible;
if let Some(ref debug_service) = *self.debug_service.borrow() {
debug_service.info("AppStateContainer",
format!("Help visibility changed: {} -> {} (in set_help_visible)", old_value, visible));
}
}
```
### 4. Service Container Integration
**Location**: `src/enhanced_tui.rs:520-535`
**Purpose**: Wire up the debug service dependency injection
```rust
// Initialize service container and help widget
let (service_container, help_widget) = if let Some(ref state_arc) = state_container {
let services = ServiceContainer::new(state_arc.clone());
// Inject debug service into AppStateContainer (now works with RefCell)
state_arc.set_debug_service(services.debug_service.clone_service());
// Create help widget and set services
let mut widget = HelpWidget::new();
widget.set_services(services.clone_for_widget());
(Some(services), widget)
} else {
(None, HelpWidget::new())
};
```
## Logging Output & Visibility
### F5 Debug View
All logging from both TUI layer and AppStateContainer appears in the F5 debug view with:
- **Timestamps**: `[HH:MM:SS.fff]` format
- **Component**: `StateManager` vs `AppStateContainer`
- **Context**: Caller function names
- **State Changes**: `old_value -> new_value` format
### Example Log Output:
```
[14:23:45.123] jump_to_row_input changed: "" -> "42" (in set_jump_to_row_input)
[14:23:45.124] Help visibility changed: false -> true (in set_help_visible)
[14:23:45.125] MODE TRANSITION: Command -> Help
[14:23:45.126] Mode stack: [Command, Help]
```
## Migration Strategy
### Current Status (V12 Branch)
- ✅ Logging macros implemented
- ✅ Debug service integration complete
- ✅ Helper methods for jump_to_row and help state
- ✅ AppStateContainer mode transition logging
- ✅ Service container dependency injection
### Next Steps
1. **Add more helper methods** for other state fields (input_text, table_state, etc.)
2. **Roll out macro usage** to all state mutations in EnhancedTuiApp
3. **Test migration** of individual fields using helper pattern
4. **Verify F5 logging** shows all state changes during operations
### Migration Pattern per Field:
1. **Add helper methods** (get_field/set_field)
2. **Update all call sites** to use helpers
3. **Test thoroughly** with logging verification
4. **Move data** from EnhancedTuiApp to AppStateContainer
5. **Update helper** to use AppStateContainer
6. **Verify** no regressions with continued logging
## Technical Details
### Arc Mutability Solution
**Problem**: `Arc<AppStateContainer>` prevents mutable access for debug service injection
**Solution**: Use `RefCell<Option<DebugService>>` in AppStateContainer for interior mutability
### Caller Tracking
All macros require explicit caller parameter to provide context about where state changes originate, enabling quick debugging of unexpected mutations.
### Performance Considerations
- Logging is conditional on debug service availability
- Timestamps only generated when logging occurs
- String formatting only happens during actual log calls
## Files Modified
- `src/enhanced_tui.rs` - Logging macros, helper methods, service integration
- `src/app_state_container.rs` - Interior mutability, debug service integration, internal logging
- `src/service_container.rs` - Debug service dependency injection support
This logging system ensures complete visibility during the "tiny steps" migration approach, preventing regression issues and providing clear audit trails for all state mutations.