Phase 5 - BYOB Backend (TASK-007A/B): - LocalSQL Adapter with full CloudStore API compatibility - QueryBuilder translates Parse-style queries to SQL - SchemaManager with PostgreSQL/Supabase export - LocalBackendServer with REST endpoints - BackendManager with IPC handlers for Electron - In-memory fallback when better-sqlite3 unavailable Phase 3 - GitHub Panel (GIT-004): - Issues tab with list/detail views - Pull Requests tab with list/detail views - GitHub API client with OAuth support - Repository info hook integration Phase 3 - Editor UX Bugfixes (TASK-013): - Legacy runtime detection banners - Read-only enforcement for legacy projects - Code editor modal close improvements - Property panel stuck state fix - Blockly node deletion and UI polish Phase 11 - Cloud Functions Planning: - Architecture documentation for workflow automation - Execution history storage schema design - Canvas overlay concept for debugging Docs: Updated LEARNINGS.md and COMMON-ISSUES.md
6.4 KiB
BUG-2: Blockly Node Randomly Deleted on Tab Close
Priority: P0 - Data loss risk
Status: 🔴 Research
Introduced in: Phase 3 Task 12 (Blockly integration)
Symptoms
- Add a Logic Builder (Blockly) node to canvas ✅
- Open the Blockly editor tab (click "Edit Logic Blocks") ✅
- Add some blocks in the Blockly editor ✅
- Close the Blockly editor tab ✅
- SOMETIMES the Logic Builder node disappears from canvas ❌
Frequency: Intermittent - doesn't happen every time (need to determine success rate)
User Impact
- Severity: Critical - Data loss
- Frequency: Intermittent (need testing to determine %)
- Frustration: Extremely high - losing work is unacceptable
- Workaround: None - just have to be careful and check after closing
Initial Hypotheses
Hypothesis 1: Race Condition in Save/Close
When closing tab, workspace might not be saved before close event completes:
- User clicks close button
- Tab starts closing
- Workspace save triggered but async
- Tab closes before save completes
- Some cleanup logic runs
- Node gets deleted?
Hypothesis 2: Event Bubbling to Canvas
Close button click might bubble through to canvas:
- Click close button on tab
- Event bubbles to canvas layer
- Canvas interprets as "click empty space"
- Triggers deselect
- Some condition causes node deletion instead of just deselection
Hypothesis 3: Keyboard Shortcut Conflict
Accidental Delete key press during close:
- Tab is closing
- User presses Delete (or Esc triggers something)
- Node is selected in background
- Delete key removes node
Hypothesis 4: Node Lifecycle Cleanup Bug
Tab close triggers node cleanup by mistake:
- Tab close event fires
- Cleanup logic runs to remove tab from state
- Logic accidentally also removes associated node
- Node deleted from graph
Investigation Tasks
Step 1: Reproduce Consistently
- Test closing tab 20 times, track success vs failure
- Try different timing (close immediately vs wait a few seconds)
- Try with empty workspace vs with blocks
- Try with multiple Blockly nodes
- Check if it happens on first close vs subsequent closes
Step 2: Add Logging
Add comprehensive logging to trace node lifecycle:
// In CanvasTabs.tsx - tab close handler
console.log('[CanvasTabs] Closing Blockly tab for node:', nodeId);
// In nodegrapheditor.ts - node deletion
console.log('[NodeGraphEditor] Node being deleted:', nodeId, 'Reason:', reason);
// In logic-builder.js runtime node
console.log('[LogicBuilder] Node lifecycle event:', event, nodeId);
Step 3: Check Workspace Save Timing
- Verify
handleBlocklyWorkspaceChangeis called before close - Add timing logs to see save vs close race
- Check if workspace parameter is actually saved to node model
Step 4: Event Flow Analysis
- Trace all events fired during tab close
- Check if any events reach canvas
- Look for stopPropagation calls
Step 5: Review Cleanup Logic
- Check
CanvasTabsContextcleanup on unmount - Review node selection state during close
- Look for any "remove node if X condition" logic
Files to Investigate
-
packages/noodl-editor/src/editor/src/views/CanvasTabs/CanvasTabs.tsx- Tab close handler
- Workspace change handler
- Event propagation
-
packages/noodl-editor/src/editor/src/contexts/CanvasTabsContext.tsx- Tab state management
- Cleanup logic
- Node ID mapping
-
packages/noodl-editor/src/editor/src/views/nodegrapheditor.ts- Node deletion logic
- Selection state during tab operations
- Event handlers that might trigger deletion
-
packages/noodl-runtime/src/nodes/std-library/logic-builder.js- Runtime node lifecycle
- Parameter update handlers
- Any cleanup logic
-
packages/noodl-editor/src/editor/src/views/BlocklyEditor/BlocklyWorkspace.tsx- Workspace save logic
- Component unmount/cleanup
Proposed Solutions (Pending Investigation)
Solution A: Ensure Save Before Close
const handleCloseTab = async (nodeId: string) => {
console.log('[CanvasTabs] Closing tab for node:', nodeId);
// Save workspace first
await saveWorkspace(nodeId);
// Then close tab
removeTab(nodeId);
};
Solution B: Add Confirmation for Unsaved Changes
const handleCloseTab = (nodeId: string) => {
if (hasUnsavedChanges(nodeId)) {
// Show confirmation dialog
showConfirmDialog({
message: 'Close without saving changes?',
onConfirm: () => removeTab(nodeId)
});
} else {
removeTab(nodeId);
}
};
Solution C: Prevent Event Bubbling
const handleCloseClick = (e: React.MouseEvent, nodeId: string) => {
e.stopPropagation(); // Prevent bubbling to canvas
e.preventDefault();
closeTab(nodeId);
};
Solution D: Guard Against Accidental Deletion
// In node deletion logic
const deleteNode = (nodeId: string, source: string) => {
// Don't delete if associated Blockly tab is open
if (blocklyTabOpenForNode(nodeId)) {
console.warn('[NodeGraphEditor] Prevented deletion of node with open Blockly tab');
return;
}
// Proceed with deletion
actuallyDeleteNode(nodeId);
};
Testing Plan
Reproduction Testing
- Create Logic Builder node
- Open editor, add blocks, close tab
- Repeat 20 times, track failures
- Try different scenarios (empty, with blocks, multiple nodes)
- Document exact conditions when it fails
With Logging
- Add comprehensive logging
- Reproduce the bug with logs active
- Analyze log sequence to find root cause
- Identify exact point where deletion occurs
After Fix
- Test tab close 50 times - should NEVER delete node
- Test with multiple Blockly nodes open
- Test rapid open/close cycles
- Test with unsaved changes
- Test with saved changes
- Verify workspace is properly saved on close
Success Criteria
- Can close Blockly tab 100 times without a single node deletion
- Workspace is always saved before tab closes
- No event bubbling causes unintended canvas clicks
- No race conditions between save and close
- Logging shows clean lifecycle with no errors
Related Issues
This might be related to:
- Tab state management from Phase 3 Task 12
- Node selection state management
- Canvas event handling
Last Updated: January 13, 2026