Universe State Isolation Fix

Fixed cross-universe state pollution in Vibe Universe Generator

Universe State Isolation Fix

Problem: Generator "Stuck" Showing Stale State

Symptoms

Root Cause

SessionStorage key was NOT universe-scoped:

// BEFORE (Bug):
private readonly GENERATION_STATE_KEY = 'vibe-universe:generation-state';

// Problem: Same key for ALL universes
// Universe A state → Universe B restoration = wrong state!

When restoreGenerationState() ran in ngOnInit(), it used the global key and restored whatever was last saved, regardless of which universe you're in.


Solution

1. Universe-Scoped Storage Keys

// AFTER (Fixed):
private getGenerationStateKey(universeId: string): string {
  return `vibe-universe:${universeId}:generation-state`;
}

// Each universe has its own state:
// - 'vibe-universe:universe_123:generation-state'
// - 'vibe-universe:universe_456:generation-state'

Changes:

2. Universe Switch Detection

Added an effect that watches universeContext.universeId() and automatically resets the generator when switching universes:

effect(() => {
  const currentUniverseId = this.universeContext.universeId();
  
  if (!currentUniverseId) {
    this.lastUniverseId = null;
    return;
  }
  
  // Universe switched - clear generator to fresh state
  if (this.lastUniverseId && currentUniverseId !== this.lastUniverseId) {
    this.logger.info('🔄 Universe switched, resetting generator', {
      from: this.lastUniverseId,
      to: currentUniverseId
    });
    
    // Clear stale state completely
    this.mode.set('input');
    this.workflowState.reset();
    this.modulesGenerated.set([]);
    this.pendingAutoSync.set(false);
    
    // Restore state for the NEW universe
    this.restoreGenerationState();
  }
  
  this.lastUniverseId = currentUniverseId;
});

3. Auto-Sync Protection

Enhanced the pendingAutoSync retry effect to prevent cross-universe pollution:

effect(() => {
  if (!this.pendingAutoSync()) return;
  const universeId = this.universeContext.universeId();
  const manifest = this.generatedManifest();
  
  // CRITICAL: Only retry if manifest belongs to current universe
  if (this.lastUniverseId !== universeId) {
    this.logger.warn('⚠️ Skipping auto-sync retry - universe mismatch');
    this.pendingAutoSync.set(false);
    return;
  }
  
  this.autoSyncModulesToCanvas();
});

Additional Improvements

Empty Canvas Save Protection

File: canvas-builder.component.ts

Added double-check with backend before allowing empty saves:

if (!options?.allowEmpty && modules.length === 0) {
  const existingStructure = this.universeModuleService.structure(universeId)();
  if (existingStructure.length > 0) {
    return; // Signal says there's structure - skip save
  }
  
  // Double-check with backend (signal might be stale)
  const backendModules = await firstValueFrom(
    this.universeModuleService.load(universeId, { force: true })
  );
  if (backendModules.length > 0) {
    this.logger.warn('⚠️ Skipping empty save - backend has modules');
    return;
  }
}

This prevents:

  1. Canvas from wiping structure if signal is stale
  2. Race conditions during Vibe → Canvas handoffs

Structure Signal Sync

File: universe-module.service.ts

When loading modules, also update the structure signal for consistency:

private loadFlatArchitecture(universeId: string): Observable<UniversalModule[]> {
  return this.spaceApi.hydrateUniverseStructure(space.id, universeId).pipe(
    map(modules => {
      const treeSignal = this.getSignal(universeId);
      const structureSignal = this.getStructureSignal(universeId);
      
      treeSignal.set(modules as UniversalModule[]);
      
      // NEW: Also update structure signal for consistency
      const structure = this.moduleTreeToFlat(modules, space.id, universeId).structure;
      structureSignal.set(structure);
      
      return modules;
    })
  );
}

Testing Checklist


Impact

Before:

After:


Files Changed

  1. vibe-universe-generator.component.ts - Universe-scoped keys + switch detection
  2. canvas-builder.component.ts - Enhanced empty save protection
  3. universe-module.service.ts - Structure signal sync on load

Related Issues Fixed