CRITICAL FIXES:
1. Parameter Range Parsing Bug
- LLM returns bounds as [min, max] array, but code was looking for 'min'/'max' keys
- This caused all parameters to default to 0-1 range instead of actual mm values
- Example: "20 to 30 mm" was being used as 0.2-1.0mm instead of 20-30mm
2. Missing Workflow Documentation
- Added automatic saving of LLM workflow config to output directory
- Creates llm_workflow_config.json with complete optimization setup
- Includes design variables, bounds, objectives, constraints, engineering features
Changes:
- optimization_engine/llm_optimization_runner.py:
* Lines 205-211: Parse 'bounds' array from LLM output
* Lines 80-84: Save workflow config JSON for transparency
* Maintains backward compatibility with old 'min'/'max' format
Test Results:
BEFORE:
- beam_half_core_thickness: 0.27-0.95mm (WRONG!)
- beam_face_thickness: 0.07-0.73mm (WRONG!)
AFTER:
- beam_half_core_thickness: 20.16-28.16mm (CORRECT!)
- beam_face_thickness: 21.69-24.73mm (CORRECT!)
E2E test now passes with realistic parameter values and proper documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**CRITICAL FIX**: FEM results were identical across trials
**Root Cause**:
The LLM runner was passing design_vars to simulation_runner(), which then passed
them to NX Solver's expression_updates parameter. The solve journal tried to
update hardcoded expression names (tip_thickness, support_angle) that don't exist
in the beam model, causing the solver to ignore updates and use cached geometry.
**Solution**:
Match the working 50-trial optimization workflow:
1. model_updater() updates PRT file via NX import journal
2. Part file is closed/flushed to disk
3. simulation_runner() runs WITHOUT passing design_vars
4. NX solver loads SIM file, which references the updated PRT from disk
5. FEM regenerates with updated geometry automatically
**Changes**:
- llm_optimization_runner.py: Call simulation_runner() without arguments
- run_optimization.py: Remove design_vars parameter from simulation_runner closure
- import_expressions.py: Added theSession.Parts.CloseAll() to flush changes
- test_phase_3_2_e2e.py: Fixed remaining variable name bugs
**Test Results**:
✅ Trial 0: objective 7,315,679
✅ Trial 1: objective 9,158.67
✅ Trial 2: objective 7,655.28
FEM results are now DIFFERENT for each trial - optimization working correctly!
**Remaining Issue**: LLM parsing "20 to 30 mm" as 0-1 range (separate fix needed)