## Documentation Updates - DASHBOARD.md: Updated to V3.0 with Canvas V3 features, file browser, introspection - DASHBOARD_IMPLEMENTATION_STATUS.md: Marked Canvas V3 features as COMPLETE - CANVAS.md: New comprehensive guide for Canvas Builder V3 with all features - CLAUDE.md: Added dashboard quick reference and Canvas V3 features ## Canvas V3 Features Documented - File Browser: Browse studies directory for model files - Model Introspection: Auto-discover expressions, solver type, dependencies - One-Click Add: Add expressions as design variables instantly - Claude Bug Fixes: WebSocket reconnection, SQL errors resolved - Health Check: /api/health endpoint for monitoring ## Backend Services - NX introspection service with expression discovery - File browser API with type filtering - Claude session management improvements - Context builder enhancements ## Frontend Components - FileBrowser: Modal for file selection with search - IntrospectionPanel: View discovered model information - ExpressionSelector: Dropdown for design variable configuration - Improved chat hooks with reconnection logic ## Plan Documents - Added RALPH_LOOP_CANVAS_V2/V3 implementation records - Added ATOMIZER_DASHBOARD_V2_MASTER_PLAN - Added investigation and sync documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
313 lines
9.6 KiB
Markdown
313 lines
9.6 KiB
Markdown
# Canvas Deep Fix Investigation
|
|
|
|
**Date**: January 16, 2026
|
|
**Status**: ✅ IMPLEMENTATION COMPLETE
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
Four critical issues have been identified that are blocking Canvas functionality:
|
|
|
|
| # | Issue | Root Cause | Severity |
|
|
|---|-------|------------|----------|
|
|
| 1 | Claude Chat Not Working | `asyncio.create_subprocess_exec` fails on Windows | CRITICAL |
|
|
| 2 | Expressions Can't Connect to Model | ModelNode has `inputs={0}` - no input handle | CRITICAL |
|
|
| 3 | File Browser Only Shows Studies | Web API can't access OS file system | HIGH |
|
|
| 4 | Introspection is Fake | Only reads config files, not actual NX models | HIGH |
|
|
|
|
---
|
|
|
|
## Issue 1: Claude Chat NotImplementedError
|
|
|
|
### Root Cause
|
|
```python
|
|
# session_manager.py line 138
|
|
process = await asyncio.create_subprocess_exec(...)
|
|
```
|
|
|
|
On Windows, `asyncio.create_subprocess_exec` raises `NotImplementedError` because Windows doesn't support the ProactorEventLoop subprocess methods the same way Unix does.
|
|
|
|
### Evidence
|
|
```
|
|
Traceback:
|
|
File "session_manager.py", line 138, in create_session
|
|
process = await asyncio.create_subprocess_exec(
|
|
File "asyncio\subprocess.py", line 218, in create_subprocess_exec
|
|
File "asyncio\base_events.py", line 498, in _make_subprocess_transport
|
|
raise NotImplementedError
|
|
NotImplementedError
|
|
```
|
|
|
|
### Solution
|
|
Replace async subprocess with synchronous subprocess + ThreadPoolExecutor:
|
|
|
|
```python
|
|
import subprocess
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
|
|
executor = ThreadPoolExecutor(max_workers=4)
|
|
|
|
async def create_session(...):
|
|
# Instead of asyncio.create_subprocess_exec
|
|
loop = asyncio.get_event_loop()
|
|
process = await loop.run_in_executor(
|
|
executor,
|
|
lambda: subprocess.Popen(
|
|
["claude", "--print", ...],
|
|
stdin=subprocess.PIPE,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
cwd=str(ATOMIZER_ROOT),
|
|
)
|
|
)
|
|
```
|
|
|
|
**OR** - Simpler approach: Skip session-based subprocess entirely, use HTTP streaming for chat:
|
|
|
|
The `/api/claude/chat/stream` endpoint already works (it uses `claude_cli_agent.py` which runs Claude one-shot). The WebSocket session approach is over-engineered for the use case.
|
|
|
|
### Fix Strategy
|
|
1. Make `create_session` return a "virtual" session (no subprocess)
|
|
2. Route all messages through HTTP streaming endpoint
|
|
3. Keep conversation history in `ConversationStore` database
|
|
4. WebSocket just wraps the HTTP streaming calls
|
|
|
|
---
|
|
|
|
## Issue 2: Expressions Can't Connect to Model
|
|
|
|
### Root Cause
|
|
|
|
**ModelNode.tsx:**
|
|
```tsx
|
|
<BaseNode {...props} icon={...} iconColor="text-blue-400" inputs={0}>
|
|
```
|
|
`inputs={0}` means Model has **NO input handle** - nothing can connect TO it!
|
|
|
|
**DesignVarNode.tsx:**
|
|
```tsx
|
|
<BaseNode {...props} icon={...} iconColor="text-emerald-400">
|
|
```
|
|
Uses defaults (`inputs=1, outputs=1`) but DesignVar should have:
|
|
- `inputs=0` (it's a source node)
|
|
- `outputs=1` (connects to Model)
|
|
|
|
### Visual Problem
|
|
```
|
|
Current (WRONG):
|
|
DesignVar ←─ Model ──→ Solver
|
|
↑ ↓
|
|
(has input) (has output only)
|
|
|
|
Should be:
|
|
DesignVar ──→ Model ──→ Solver
|
|
↓ ↑↓
|
|
(output) (input & output)
|
|
```
|
|
|
|
### Fix Required
|
|
|
|
**ModelNode.tsx** - Add input handle:
|
|
```tsx
|
|
<BaseNode {...props} icon={...} iconColor="text-blue-400" inputs={1} outputs={1}>
|
|
```
|
|
|
|
**DesignVarNode.tsx** - Remove input handle:
|
|
```tsx
|
|
<BaseNode {...props} icon={...} iconColor="text-emerald-400" inputs={0} outputs={1}>
|
|
```
|
|
|
|
**SurrogateNode.tsx** - Should be terminal (no output):
|
|
```tsx
|
|
<BaseNode {...props} icon={...} iconColor="text-pink-400" inputs={1} outputs={0}>
|
|
```
|
|
|
|
---
|
|
|
|
## Issue 3: File Browser Only Shows Studies Folder
|
|
|
|
### Root Cause
|
|
The current `FileBrowser.tsx` uses fetch to `/api/files/list` which only lists files within the `studies/` directory. The user wants:
|
|
|
|
1. Native OS file picker to select files from ANYWHERE
|
|
2. Import selected files into the study folder
|
|
3. Copy all related files (.prt, .sim, .fem, _i.prt, etc.)
|
|
|
|
### Web Browser Limitation
|
|
Browsers can't access the local file system directly for security. Options:
|
|
|
|
**Option A: File System Access API** (Chrome/Edge only)
|
|
```typescript
|
|
const handle = await window.showOpenFilePicker({
|
|
types: [{ description: 'NX Files', accept: { '*/*': ['.sim', '.prt', '.fem'] } }]
|
|
});
|
|
const file = await handle.getFile();
|
|
// Upload to backend
|
|
```
|
|
|
|
**Option B: Traditional File Input**
|
|
```tsx
|
|
<input type="file" accept=".sim,.prt,.fem,.afem" onChange={handleFileUpload} />
|
|
```
|
|
Then upload to backend which saves to study folder.
|
|
|
|
**Option C: Backend Path Input + Validation**
|
|
User enters full Windows path (e.g., `C:\NX_Models\bracket.prt`), backend validates and copies.
|
|
|
|
### Recommended Solution
|
|
Combine B + C:
|
|
1. File input for direct upload (drag & drop)
|
|
2. Path input for network drives/existing paths
|
|
3. Backend endpoint to copy/import files
|
|
|
|
---
|
|
|
|
## Issue 4: Introspection is Fake
|
|
|
|
### Root Cause
|
|
Current `nx_introspection.py` does NOT actually read NX files. It only:
|
|
- Reads `optimization_config.json` for existing design variables
|
|
- Infers expressions based on folder names ("mirror" → suggest mirror expressions)
|
|
- Guesses solver type from file names
|
|
|
|
### What Real Introspection Needs
|
|
|
|
**For .prt files (NX Part):**
|
|
- Use NX Open API to read expressions
|
|
- Get expression names, values, units, formulas
|
|
- Requires NX to be installed and licensed
|
|
|
|
**For .sim files (Simulation):**
|
|
- Parse XML-like structure or use NX Open
|
|
- Get solver type, boundary conditions, loads
|
|
- Identify linked .fem and .prt files
|
|
|
|
**For .fem files (FEM):**
|
|
- Get mesh statistics (nodes, elements)
|
|
- Material properties
|
|
- Element types used
|
|
|
|
**For .op2 files (Results):**
|
|
- Use PyNastran to read binary results
|
|
- Extract displacement, stress, frequency data
|
|
- Get node/element IDs for specific extractions
|
|
|
|
### Implementation Approach
|
|
|
|
**Phase 1: File Discovery (no NX needed)**
|
|
```python
|
|
def discover_related_files(sim_path: Path) -> List[Dict]:
|
|
"""Find all related files by naming convention"""
|
|
# model_sim1.sim → model.prt, model_fem1.fem, model_fem1_i.prt
|
|
```
|
|
|
|
**Phase 2: Config-based Expression Discovery**
|
|
```python
|
|
def discover_expressions_from_config(study_dir: Path) -> List[Dict]:
|
|
"""Read optimization_config.json for design variables"""
|
|
```
|
|
|
|
**Phase 3: NX Open Integration (requires NX)**
|
|
```python
|
|
def introspect_with_nx_open(prt_path: Path) -> Dict:
|
|
"""Use NX Open API to read actual expressions"""
|
|
# This requires NX to be running
|
|
# Use the existing nx_journals/ infrastructure
|
|
```
|
|
|
|
**Phase 4: OP2 Result Analysis (PyNastran)**
|
|
```python
|
|
def analyze_op2_results(op2_path: Path) -> Dict:
|
|
"""Read OP2 file to discover available result types"""
|
|
from pyNastran.op2.op2 import OP2
|
|
op2 = OP2()
|
|
op2.read_op2(str(op2_path))
|
|
# Return available subcases, result types, etc.
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Fix Claude Chat (CRITICAL - 30 min)
|
|
1. Modify `create_session` to not spawn subprocess
|
|
2. Keep session metadata in database only
|
|
3. Route all messages through HTTP streaming
|
|
4. WebSocket wraps HTTP calls
|
|
|
|
### Phase 2: Fix Node Handles (CRITICAL - 15 min)
|
|
1. Update `ModelNode.tsx`: `inputs={1}`
|
|
2. Update `DesignVarNode.tsx`: `inputs={0}, outputs={1}`
|
|
3. Update `SurrogateNode.tsx`: `outputs={0}`
|
|
4. Test connections work correctly
|
|
|
|
### Phase 3: Native File Import (HIGH - 45 min)
|
|
1. Add file upload input to FileBrowser
|
|
2. Create backend `/api/files/upload` endpoint
|
|
3. Add path input with validation
|
|
4. Create `/api/files/import` for path-based import
|
|
5. Copy all related files to study folder
|
|
|
|
### Phase 4: Real Introspection Service (HIGH - 2 hours)
|
|
1. File discovery by naming convention
|
|
2. OP2 analysis with PyNastran
|
|
3. NX Open integration (optional, requires NX running)
|
|
4. Return comprehensive file metadata
|
|
|
|
### Phase 5: Integration Testing (30 min)
|
|
1. Test complete workflow: Select model → Introspect → Add Design Vars → Connect → Execute
|
|
2. Fix any remaining issues
|
|
|
|
---
|
|
|
|
## Files to Modify
|
|
|
|
### Backend
|
|
- `session_manager.py` - Fix Windows subprocess issue
|
|
- `files.py` - Add upload/import endpoints
|
|
- `nx_introspection.py` - Real introspection logic
|
|
|
|
### Frontend
|
|
- `ModelNode.tsx` - Add input handle
|
|
- `DesignVarNode.tsx` - Remove input, keep output
|
|
- `SurrogateNode.tsx` - Remove output
|
|
- `FileBrowser.tsx` - Add file upload, path input
|
|
- `IntrospectionPanel.tsx` - Display real introspection data
|
|
|
|
---
|
|
|
|
## Estimated Total Time: 4-5 hours
|
|
|
|
---
|
|
|
|
## Implementation Summary (Completed)
|
|
|
|
### Phase 1: Claude Chat Windows Fix ✅
|
|
**File**: `atomizer-dashboard/backend/api/services/session_manager.py`
|
|
- Replaced `asyncio.create_subprocess_exec` with `subprocess.Popen`
|
|
- Used `ThreadPoolExecutor` with `run_in_executor()` for async compatibility
|
|
- Made sessions stateless (no persistent subprocess)
|
|
- Each message handled via one-shot CLI call with 5-minute timeout
|
|
|
|
### Phase 2: Node Handles ✅
|
|
**Files**:
|
|
- `ModelNode.tsx`: Changed `inputs={0}` to `inputs={1}` (now accepts connections)
|
|
- `DesignVarNode.tsx`: Added `inputs={0} outputs={1}` (source node)
|
|
|
|
### Phase 3: Native File Import ✅
|
|
**Files**:
|
|
- `files.py`: Added `/validate-path`, `/import-from-path`, `/upload` endpoints
|
|
- `FileBrowser.tsx`: Complete rewrite with 3 tabs:
|
|
- Browse Studies (existing)
|
|
- Import Path (paste Windows path, validate, import related files)
|
|
- Upload Files (drag & drop)
|
|
|
|
### Phase 4: Real NX Introspection ✅
|
|
**File**: `atomizer-dashboard/backend/api/services/nx_introspection.py`
|
|
- Added PyNastran OP2 parsing (displacements, eigenvectors, stress)
|
|
- BDF/DAT file analysis (mass, grid count, element counts, solver type)
|
|
- Study database queries for expression discovery
|
|
- Related file discovery by naming convention
|
|
- Result file discovery with trial folder detection
|