Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
Download tar.gz
Implements Phase 6 tasks 1-4:
Task 1: Add physicalLayout() to layout.ts
- Exports new physical layout function with tighter spacing
- Uses dagre top-to-bottom layout for PE cluster visualization
Task 2: Add PE cluster, cross-PE, and intra-PE styles to style.ts
- PE cluster parent nodes: rounded rectangle with solid border
- Cross-PE edges: thicker, darker (3px, #5c6bc0)
- Intra-PE edges: lighter (1.5px, #bbb)
Task 3: Add view toggle and physical element building to main.ts
- buildPhysicalLabel(): formats nodes with [iram:offset, ctx:slot] annotations
- buildPhysicalElements(): creates PE cluster nodes and assigns children
- View mode tracking: logical (default) or physical
- Toggle button in index.html switches between views
- Physical view only available when stage == 'allocate'
- Disables toggle and reverts to logical if graph becomes incomplete
Task 4: Manual verification
- esbuild bundle succeeds without errors (1.2mb)
- Full test suite passes: 608/608 tests
- Frontend builds successfully with npm run build
Acceptance criteria covered:
- AC3.1: Nodes grouped into PE cluster boxes by PE ID
- AC3.2: Nodes annotated with IRAM offset and context slot
- AC3.3: Cross-PE edges visually distinct from intra-PE
- AC3.4: Physical view unavailable when stage != 'allocate'
- Add types.ts: TypeScript interfaces matching graph JSON from backend
- GraphNode, GraphEdge, GraphRegion, GraphUpdate types
- SourceLoc, AddrInfo, GraphError interfaces
- Add style.ts: cytoscape stylesheet for logical view
- Node styling: circular ellipses with centered labels
- Category-based colors from backend (arithmetic, logic, comparison, etc.)
- Edge annotations: port labels at target, branch labels at source
- Function regions: dashed bounding boxes
- Error styling: red dashed borders
- Add layout.ts: dagre hierarchical layout configuration
- Top-to-bottom layout with configurable spacing
- Settings: rankDir=TB, nodeSep=60, rankSep=80, edgeSep=20
- Rewrite main.ts: WebSocket client and graph rendering
- Connect to ws://host/ws, receive graph_update JSON messages
- Convert JSON to cytoscape elements with proper labels and styling
- buildLabel: includes opcode + constant value when present
- buildElements: creates nodes, regions, and edges from update
- renderGraph: batch update with dagre layout and auto-fit
- Auto-reconnect on WebSocket close (2s timeout)
- Handle routing ops: source labels (T/F) from source_port
- Handle regions: compound parent nodes for functions
All modules verified to build with esbuild. Bundle size: 1.2MB.
Test suite: 608/608 tests passing.
Critical Issue 1: Remove dual initialization (lifespan + _ensure_initialized)
- Removed _ensure_initialized() function entirely
- Removed call to _ensure_initialized() from websocket_endpoint
- lifespan context manager is now the only init path
- Prevents resource leak from creating Observer instances twice
Critical Issue 2: Fix test_rapid_file_changes_debounced debounce test
- Removed bare 'except Exception: pass' that caught AssertionError
- Rewritten to properly count update messages in a time window
- Test now properly verifies debounce behavior (3 rapid changes -> 1 update)
Important Issue 1: Fix ConnectionManager.disconnect() ValueError
- Added try/except to handle case where websocket already removed by broadcast
- Prevents crash if disconnect() called after broadcast() removed the connection
Important Issue 2: Add exception handling in _on_file_change()
- Wrapped _reassemble() in try/except
- On failure, keeps current_json unchanged (doesn't broadcast incomplete state)
- Prevents timer thread crash that would stop live reload
Important Issue 3: Add exception handling in _reassemble()
- Wrapped source_path.read_text() in try/except
- On file read errors, returns error JSON structure with parse_error message
- Handles FileNotFoundError, OSError, UnicodeDecodeError
Minor Issue 1: Remove unused imports from server.py
- Removed: json, time, PipelineResult
- threading is still needed for DebouncedFileHandler
Minor Issue 2: Remove unused json import from test
- Removed: json
- time is still needed for sleep() and timing
All 608 tests pass. Tests updated to use TestClient context manager so
lifespan is triggered correctly.
Implements Task 1 of Phase 4: Backend Server with WebSocket.
- Create dfgraph/server.py with FastAPI app serving frontend static files
- Implement WebSocket endpoint at /ws that sends graph JSON on connect
- Add file watcher with 300ms debounce that re-assembles graph on changes
- Use ConnectionManager for broadcasting updates to connected clients
- Use lifespan context manager for startup/shutdown
- Support TestClient for unit testing without full event loop