335 lines
10 KiB
Markdown
335 lines
10 KiB
Markdown
|
|
# Phase 1.2: Configuration Management Overhaul - Implementation Plan
|
||
|
|
|
||
|
|
**Status**: In Progress
|
||
|
|
**Started**: January 2025
|
||
|
|
**Target Completion**: 2 days
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ Completed (January 24, 2025)
|
||
|
|
|
||
|
|
### 1. Configuration Inventory
|
||
|
|
- Found 4 `optimization_config.json` files
|
||
|
|
- Found 5 `workflow_config.json` files
|
||
|
|
- Analyzed bracket_V3 (old format) vs drone_gimbal (new format)
|
||
|
|
|
||
|
|
### 2. Schema Analysis
|
||
|
|
Documented critical inconsistencies:
|
||
|
|
- Objectives: `"goal"` (new) vs `"type"` (old)
|
||
|
|
- Design vars: `"parameter"` + `"bounds": [min, max]` (new) vs `"name"` + `"min"/"max"` (old)
|
||
|
|
- Constraints: `"threshold"` (new) vs `"value"` (old)
|
||
|
|
- Location: `1_setup/` (correct) vs root directory (incorrect)
|
||
|
|
|
||
|
|
### 3. JSON Schema Design
|
||
|
|
Created [`optimization_engine/schemas/optimization_config_schema.json`](../../optimization_engine/schemas/optimization_config_schema.json):
|
||
|
|
- Based on drone_gimbal format (cleaner, matches create-study skill)
|
||
|
|
- Validates all required fields
|
||
|
|
- Supports Protocol 10 (single-objective) and Protocol 11 (multi-objective)
|
||
|
|
- Includes extraction spec validation
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔨 Remaining Implementation Tasks
|
||
|
|
|
||
|
|
### Task 1: Implement ConfigManager Class
|
||
|
|
**Priority**: HIGH
|
||
|
|
**File**: `optimization_engine/config_manager.py`
|
||
|
|
|
||
|
|
```python
|
||
|
|
"""Configuration validation and management for Atomizer studies."""
|
||
|
|
|
||
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Dict, List, Any, Optional
|
||
|
|
import jsonschema
|
||
|
|
|
||
|
|
class ConfigValidationError(Exception):
|
||
|
|
"""Raised when configuration validation fails."""
|
||
|
|
pass
|
||
|
|
|
||
|
|
class ConfigManager:
|
||
|
|
"""Manages and validates optimization configuration files."""
|
||
|
|
|
||
|
|
def __init__(self, config_path: Path):
|
||
|
|
"""
|
||
|
|
Initialize ConfigManager with path to optimization_config.json.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
config_path: Path to optimization_config.json file
|
||
|
|
"""
|
||
|
|
self.config_path = Path(config_path)
|
||
|
|
self.schema_path = Path(__file__).parent / "schemas" / "optimization_config_schema.json"
|
||
|
|
self.config: Optional[Dict[str, Any]] = None
|
||
|
|
self.validation_errors: List[str] = []
|
||
|
|
|
||
|
|
def load_schema(self) -> Dict[str, Any]:
|
||
|
|
"""Load JSON schema for validation."""
|
||
|
|
with open(self.schema_path, 'r') as f:
|
||
|
|
return json.load(f)
|
||
|
|
|
||
|
|
def load_config(self) -> Dict[str, Any]:
|
||
|
|
"""Load configuration file."""
|
||
|
|
if not self.config_path.exists():
|
||
|
|
raise FileNotFoundError(f"Config file not found: {self.config_path}")
|
||
|
|
|
||
|
|
with open(self.config_path, 'r') as f:
|
||
|
|
self.config = json.load(f)
|
||
|
|
return self.config
|
||
|
|
|
||
|
|
def validate(self) -> bool:
|
||
|
|
"""
|
||
|
|
Validate configuration against schema.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if valid, False otherwise
|
||
|
|
"""
|
||
|
|
if self.config is None:
|
||
|
|
self.load_config()
|
||
|
|
|
||
|
|
schema = self.load_schema()
|
||
|
|
self.validation_errors = []
|
||
|
|
|
||
|
|
try:
|
||
|
|
jsonschema.validate(instance=self.config, schema=schema)
|
||
|
|
# Additional custom validations
|
||
|
|
self._validate_design_variable_bounds()
|
||
|
|
self._validate_multi_objective_consistency()
|
||
|
|
self._validate_file_locations()
|
||
|
|
return True
|
||
|
|
except jsonschema.ValidationError as e:
|
||
|
|
self.validation_errors.append(str(e))
|
||
|
|
return False
|
||
|
|
|
||
|
|
def _validate_design_variable_bounds(self):
|
||
|
|
"""Ensure bounds are valid (min < max)."""
|
||
|
|
for dv in self.config.get("design_variables", []):
|
||
|
|
bounds = dv.get("bounds", [])
|
||
|
|
if len(bounds) == 2 and bounds[0] >= bounds[1]:
|
||
|
|
self.validation_errors.append(
|
||
|
|
f"Design variable '{dv['parameter']}': min ({bounds[0]}) must be < max ({bounds[1]})"
|
||
|
|
)
|
||
|
|
|
||
|
|
def _validate_multi_objective_consistency(self):
|
||
|
|
"""Validate multi-objective settings consistency."""
|
||
|
|
n_objectives = len(self.config.get("objectives", []))
|
||
|
|
protocol = self.config.get("optimization_settings", {}).get("protocol")
|
||
|
|
sampler = self.config.get("optimization_settings", {}).get("sampler")
|
||
|
|
|
||
|
|
if n_objectives > 1:
|
||
|
|
# Multi-objective must use protocol_11 and NSGA-II
|
||
|
|
if protocol != "protocol_11_multi_objective":
|
||
|
|
self.validation_errors.append(
|
||
|
|
f"Multi-objective optimization ({n_objectives} objectives) requires protocol_11_multi_objective"
|
||
|
|
)
|
||
|
|
if sampler != "NSGAIISampler":
|
||
|
|
self.validation_errors.append(
|
||
|
|
f"Multi-objective optimization requires NSGAIISampler (got {sampler})"
|
||
|
|
)
|
||
|
|
|
||
|
|
def _validate_file_locations(self):
|
||
|
|
"""Check if config is in correct location (1_setup/)."""
|
||
|
|
if "1_setup" not in str(self.config_path.parent):
|
||
|
|
self.validation_errors.append(
|
||
|
|
f"Config should be in '1_setup/' directory, found in {self.config_path.parent}"
|
||
|
|
)
|
||
|
|
|
||
|
|
def get_validation_report(self) -> str:
|
||
|
|
"""Get human-readable validation report."""
|
||
|
|
if not self.validation_errors:
|
||
|
|
return "✓ Configuration is valid"
|
||
|
|
|
||
|
|
report = "✗ Configuration validation failed:\n"
|
||
|
|
for i, error in enumerate(self.validation_errors, 1):
|
||
|
|
report += f" {i}. {error}\n"
|
||
|
|
return report
|
||
|
|
|
||
|
|
# Type-safe accessor methods
|
||
|
|
|
||
|
|
def get_design_variables(self) -> List[Dict[str, Any]]:
|
||
|
|
"""Get design variables with validated structure."""
|
||
|
|
if self.config is None:
|
||
|
|
self.load_config()
|
||
|
|
return self.config.get("design_variables", [])
|
||
|
|
|
||
|
|
def get_objectives(self) -> List[Dict[str, Any]]:
|
||
|
|
"""Get objectives with validated structure."""
|
||
|
|
if self.config is None:
|
||
|
|
self.load_config()
|
||
|
|
return self.config.get("objectives", [])
|
||
|
|
|
||
|
|
def get_constraints(self) -> List[Dict[str, Any]]:
|
||
|
|
"""Get constraints with validated structure."""
|
||
|
|
if self.config is None:
|
||
|
|
self.load_config()
|
||
|
|
return self.config.get("constraints", [])
|
||
|
|
|
||
|
|
def get_simulation_settings(self) -> Dict[str, Any]:
|
||
|
|
"""Get simulation settings."""
|
||
|
|
if self.config is None:
|
||
|
|
self.load_config()
|
||
|
|
return self.config.get("simulation", {})
|
||
|
|
|
||
|
|
|
||
|
|
# CLI tool for validation
|
||
|
|
if __name__ == "__main__":
|
||
|
|
import sys
|
||
|
|
|
||
|
|
if len(sys.argv) < 2:
|
||
|
|
print("Usage: python config_manager.py <path_to_optimization_config.json>")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
config_path = Path(sys.argv[1])
|
||
|
|
manager = ConfigManager(config_path)
|
||
|
|
|
||
|
|
try:
|
||
|
|
manager.load_config()
|
||
|
|
is_valid = manager.validate()
|
||
|
|
print(manager.get_validation_report())
|
||
|
|
sys.exit(0 if is_valid else 1)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Error: {e}")
|
||
|
|
sys.exit(1)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Dependencies**: Add to requirements.txt:
|
||
|
|
```
|
||
|
|
jsonschema>=4.17.0
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 2: Create Configuration Migration Tool
|
||
|
|
**Priority**: MEDIUM
|
||
|
|
**File**: `optimization_engine/config_migrator.py`
|
||
|
|
|
||
|
|
Tool to automatically migrate old-format configs to new format:
|
||
|
|
- Convert `"type"` → `"goal"` in objectives
|
||
|
|
- Convert `"min"/"max"` → `"bounds": [min, max]` in design variables
|
||
|
|
- Convert `"name"` → `"parameter"` in design variables
|
||
|
|
- Convert `"value"` → `"threshold"` in constraints
|
||
|
|
- Move config files to `1_setup/` if in wrong location
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 3: Integration with run_optimization.py
|
||
|
|
**Priority**: HIGH
|
||
|
|
|
||
|
|
Add validation to optimization runners:
|
||
|
|
```python
|
||
|
|
# At start of run_optimization.py
|
||
|
|
from optimization_engine.config_manager import ConfigManager
|
||
|
|
|
||
|
|
# Load and validate config
|
||
|
|
config_manager = ConfigManager(Path(__file__).parent / "1_setup" / "optimization_config.json")
|
||
|
|
config_manager.load_config()
|
||
|
|
|
||
|
|
if not config_manager.validate():
|
||
|
|
print(config_manager.get_validation_report())
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
print("✓ Configuration validated successfully")
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 4: Update create-study Claude Skill
|
||
|
|
**Priority**: HIGH
|
||
|
|
**File**: `.claude/skills/create-study.md`
|
||
|
|
|
||
|
|
Update skill to reference the JSON schema:
|
||
|
|
- Add link to schema documentation
|
||
|
|
- Emphasize validation after generation
|
||
|
|
- Include validation command in "Next Steps"
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 5: Create Configuration Documentation
|
||
|
|
**Priority**: HIGH
|
||
|
|
**File**: `docs/CONFIGURATION_GUIDE.md`
|
||
|
|
|
||
|
|
Comprehensive documentation covering:
|
||
|
|
1. Standard configuration format (with drone_gimbal example)
|
||
|
|
2. Field-by-field descriptions
|
||
|
|
3. Validation rules and how to run validation
|
||
|
|
4. Common validation errors and fixes
|
||
|
|
5. Migration guide for old configs
|
||
|
|
6. Protocol selection (10 vs 11)
|
||
|
|
7. Extractor mapping table
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 6: Validate All Existing Studies
|
||
|
|
**Priority**: MEDIUM
|
||
|
|
|
||
|
|
Run validation on all existing studies:
|
||
|
|
```bash
|
||
|
|
# Test validation tool
|
||
|
|
python optimization_engine/config_manager.py studies/drone_gimbal_arm_optimization/1_setup/optimization_config.json
|
||
|
|
python optimization_engine/config_manager.py studies/bracket_stiffness_optimization_V3/optimization_config.json
|
||
|
|
|
||
|
|
# Expected: drone passes, bracket_V3 fails with specific errors
|
||
|
|
```
|
||
|
|
|
||
|
|
Create migration plan for failing configs.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 7: Migrate Legacy Configs
|
||
|
|
**Priority**: LOW (can defer to Phase 1.3)
|
||
|
|
|
||
|
|
Migrate all legacy configs to new format:
|
||
|
|
- bracket_stiffness_optimization_V3
|
||
|
|
- bracket_stiffness_optimization_V2
|
||
|
|
- bracket_stiffness_optimization
|
||
|
|
|
||
|
|
Keep old versions in `archive/` for reference.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Success Criteria
|
||
|
|
|
||
|
|
Phase 1.2 is complete when:
|
||
|
|
- [x] JSON schema created and comprehensive
|
||
|
|
- [ ] ConfigManager class implemented with all validation methods
|
||
|
|
- [ ] Validation integrated into at least 1 study (drone_gimbal)
|
||
|
|
- [ ] Configuration documentation written
|
||
|
|
- [ ] create-study skill updated with schema reference
|
||
|
|
- [ ] Migration tool created (basic version)
|
||
|
|
- [ ] All tests pass on drone_gimbal study
|
||
|
|
- [ ] Phase 1.2 changes committed with clear message
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Testing Plan
|
||
|
|
|
||
|
|
1. **Schema Validation Test**:
|
||
|
|
- Valid config passes ✓
|
||
|
|
- Invalid configs fail with clear errors ✓
|
||
|
|
|
||
|
|
2. **ConfigManager Test**:
|
||
|
|
- Load valid config
|
||
|
|
- Validate and get clean report
|
||
|
|
- Load invalid config
|
||
|
|
- Validate and get error details
|
||
|
|
|
||
|
|
3. **Integration Test**:
|
||
|
|
- Run drone_gimbal study with validation enabled
|
||
|
|
- Verify no performance impact
|
||
|
|
- Check validation messages appear correctly
|
||
|
|
|
||
|
|
4. **Migration Test**:
|
||
|
|
- Migrate bracket_V3 config
|
||
|
|
- Validate migrated config
|
||
|
|
- Compare before/after
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Next Phase Preview
|
||
|
|
|
||
|
|
**Phase 1.3: Error Handling & Logging** will build on this by:
|
||
|
|
- Adding structured logging with configuration context
|
||
|
|
- Error recovery using validated configurations
|
||
|
|
- Checkpoint system that validates config before saving
|
||
|
|
|
||
|
|
The clean configuration management from Phase 1.2 enables reliable error handling in Phase 1.3.
|