@@ -44,6 +44,8 @@ export function useWorkspacePersistence(projectId?: string) {
4444
4545 // Restore on mount
4646 useEffect ( ( ) => {
47+ hasRestoredRef . current = false ;
48+
4749 const persisted = loadTabState ( projectId ) ;
4850 if ( persisted ) {
4951 // First pass: restore what we can from the in-memory cache
@@ -90,9 +92,13 @@ export function useWorkspacePersistence(projectId?: string) {
9092 dispatch ( restoreUiState ( persistedUi ) ) ;
9193 }
9294
93- // Mark restore complete after a tick to let effects settle
95+ // Mark restore complete after two animation frames to ensure
96+ // the Redux state update has propagated and the save effect
97+ // has seen the restored state (prevents saving empty default tabs)
9498 requestAnimationFrame ( ( ) => {
95- hasRestoredRef . current = true ;
99+ requestAnimationFrame ( ( ) => {
100+ hasRestoredRef . current = true ;
101+ } ) ;
96102 } ) ;
97103
98104 return ( ) => {
@@ -156,6 +162,17 @@ export function useWorkspacePersistence(projectId?: string) {
156162 }
157163
158164 saveTimerRef . current = setTimeout ( ( ) => {
165+ // Don't overwrite persisted state with empty default tabs.
166+ // This guards against a race where the save fires before
167+ // restore has populated Redux.
168+ const hasContent = tabs . some ( ( t ) => t . sql . trim ( ) . length > 0 ) ;
169+ if ( ! hasContent && tabs . length <= 1 ) {
170+ const existing = loadTabState ( projectId ) ;
171+ if ( existing && existing . tabs . some ( ( t ) => t . sql . trim ( ) . length > 0 ) ) {
172+ return ; // Don't clobber persisted data with empty state
173+ }
174+ }
175+
159176 // Find max tab counter from current tab IDs
160177 let maxCounter = 1 ;
161178 for ( const t of tabs ) {
0 commit comments