@@ -336,21 +336,46 @@ async function archiveTableChildren(context: CascadeChildrenContext): Promise<nu
336336/**
337337 * Restores the tables this cascade archived, through the canonical table restore so a table
338338 * whose name was taken while it was gone is renamed instead of tripping the active-name
339- * unique index.
339+ * unique index. If a later member fails, the successful prefix is re-archived under the
340+ * original timestamp so no active referrer can point at a still-archived cohort target.
340341 */
341342async function restoreTableChildren ( context : CascadeChildrenContext ) : Promise < number > {
342- const { restoreTable } = await import ( '@/lib/table/service' )
343+ const { deleteTables , restoreTable } = await import ( '@/lib/table/service' )
343344 const ids = await selectChildIds ( FOLDER_RESOURCES . table , context , 'archived' )
344345 const restoringFolderIds = new Set ( context . folderIds )
345346 const restoringTableIds = new Set ( ids )
346-
347- for ( const id of ids ) {
348- // restoreFolder fires one folder-level live-list notify for the whole subtree.
349- await restoreTable ( id , `folder-cascade-${ context . folderIds [ 0 ] } ` , {
350- restoringFolderIds,
351- restoringTableIds,
352- skipNotify : true ,
353- } )
347+ const restoredIds : string [ ] = [ ]
348+
349+ try {
350+ for ( const id of ids ) {
351+ // restoreFolder fires one folder-level live-list notify for the whole subtree.
352+ await restoreTable ( id , `folder-cascade-${ context . folderIds [ 0 ] } ` , {
353+ restoringFolderIds,
354+ restoringTableIds,
355+ skipNotify : true ,
356+ } )
357+ restoredIds . push ( id )
358+ }
359+ } catch ( error ) {
360+ const rollback = await deleteTables (
361+ restoredIds ,
362+ `folder-restore-rollback-${ context . folderIds [ 0 ] } ` ,
363+ {
364+ expectedWorkspaceId : context . workspaceId ,
365+ archivedAt : context . timestamp ,
366+ skipNotify : true ,
367+ archiveAsCohort : true ,
368+ }
369+ )
370+ if ( rollback . terminalError ) throw rollback . terminalError
371+ if (
372+ rollback . failed . length > 0 ||
373+ rollback . notFound . length > 0 ||
374+ rollback . archived . length !== restoredIds . length
375+ ) {
376+ throw new OrchestrationError ( 'internal' , 'Failed to roll back the table restore cohort' )
377+ }
378+ throw error
354379 }
355380
356381 return ids . length
0 commit comments