From c31d990644810c2087b70f68fb19a95eb7ff980d Mon Sep 17 00:00:00 2001 From: jedarden Date: Thu, 9 Apr 2026 12:57:17 -0400 Subject: [PATCH] fix(s simulator): fix Close() function bug in VirtualNodeStore The Close() function was incorrectly setting s.closed = false before the final save, which could allow operations to proceed during closure. Fixed by properly managing the closed flag and performing the final save directly without relying on saveLocked(). This fixes the virtual node state management implementation which provides: - Node creation at specified positions with bounds validation - State persistence to disk via JSON - Thread-safe operations with mutex locking - Enable/disable, position updates, role changes, metadata, tags Acceptance criteria met: - Nodes can be created at specified positions - Nodes maintain their state within the virtual space Co-Authored-By: Claude Opus 4.6 --- .../internal/simulator/virtual_state.go | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/mothership/internal/simulator/virtual_state.go b/mothership/internal/simulator/virtual_state.go index 280952f..7ba922d 100644 --- a/mothership/internal/simulator/virtual_state.go +++ b/mothership/internal/simulator/virtual_state.go @@ -552,14 +552,26 @@ func (s *VirtualNodeStore) Close() error { return nil } - s.closed = false + // Mark as closed to prevent new operations during final save + s.closed = true - // Final save before closing - if err := s.saveLocked(); err != nil { - return fmt.Errorf("final save: %w", err) + // Final save before closing (saveLocked checks closed flag, so we need special handling) + data, err := json.MarshalIndent(s.nodes, "", " ") + if err != nil { + return fmt.Errorf("marshal nodes: %w", err) + } + + // Write to temporary file first + tmpPath := s.path + ".tmp" + if err := os.WriteFile(tmpPath, data, 0644); err != nil { + return fmt.Errorf("write temp file: %w", err) + } + + // Atomic rename + if err := os.Rename(tmpPath, s.path); err != nil { + return fmt.Errorf("rename file: %w", err) } - s.closed = true return nil }