Skip to content

[Repo Assist] Use atomic write (temp-file + rename) in AppSettings.Save() to prevent corruption #58

Description

@github-actions

🤖 This PR was created by Repo Assist, an automated AI assistant.

Problem

AppSettings.Save() wrote directly to settings.json. If the process was killed mid-write (forced shutdown, BSOD, power loss), the file could be left in a partially-written, corrupt state — causing the next launch to silently reset all user settings.

Root Cause

Direct file write is not atomic. A crash at any point between opening the file and closing it leaves an incomplete JSON document on disk. The app's error handler falls back to defaults on JsonException, so the corruption is silent.

Fix

Two-phase write using a temp file + atomic rename:

// Write to a temp file first
var tempPath = path + ".tmp";
File.WriteAllText(tempPath, json, Encoding.UTF8);
// Atomic rename — on NTFS this is a single metadata operation
File.Move(tempPath, path, overwrite: true);

On NTFS, File.Move is backed by MoveFileEx(MOVEFILE_REPLACE_EXISTING), which is a single atomic metadata operation. The target file is never in a partially-written state.

Trade-offs

  • Requires temp file and target to be on the same volume (they are — both in %AppData%).
  • A crash between writing the temp file and the rename leaves a .tmp file behind, which is harmless (cleaned up on next successful save).
  • No dependency changes.

Test Status

Build: 0 errors, 0 warnings (net10.0-windows, EnableWindowsTargeting=true)

Closes #46

AI Disclosure

This PR was created by Repo Assist. Please review the fix logic before merging.

Note

🔒 Integrity filter blocked 2 items

The following items were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Repo Assist · ● 1.4M ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@cbb46ab386962aa371045839fc9998ee4e97ca64

Note

This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch repo-assist/improve-atomic-settings-save-2026-06-11-f7936670a89b86d9-5e499a09b74550f5-ed2b8e436e76e15c.

Click here to create the pull request

To fix the permissions issue, go to SettingsActionsGeneral and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ

Show patch preview (57 of 57 lines)
From d0eef0bbed0efa627f8dd6ea91b1a909892c2902 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Fri, 12 Jun 2026 13:59:41 +0000
Subject: [PATCH] Use atomic write (temp-file + rename) in AppSettings.Save()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Previously, Save() wrote directly to settings.json. If the process was killed
mid-write (e.g. forced shutdown or BSOD), the file could be left in a partially-
written, corrupt state — causing the next launch to silently reset all settings.

Fix: write to settings.json.tmp first, then use File.Move(overwrite:true) to
atomically rename it into place. On NTFS this rename is a single metadata
operation, so the target is never partially updated.

Build: 0 errors, 0 warnings (net10.0-windows, EnableWindowsTargeting=true)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 WindowsEdgeLight/AppSettings.cs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/WindowsEdgeLight/AppSettings.cs b/WindowsEdgeLight/AppSettings.cs
index bf12831..8fa65ef 100644
--- a/WindowsEdgeLight/AppSettings.cs
+++ b/WindowsEdgeLight/AppSettings.cs
@@ -66,7 +66,8 @@ public class AppSettings
     }
 
     /// <summary>
-    /// Save settings to disk
+    /// Save settings to disk using an atomic write (temp file + rename) to prevent
+    /// corruption if the application is terminated mid-write.
     /// </summary>
     public void Save()
     {
@@ -82,7 +83,13 @@ public class AppSettings
             { 
                 WriteIndented = true 
             });
-            File.WriteAllText(SettingsFilePath, json);
+
+            // Write to a temp file first, then atomically rename to the real path.
+            // This ensures the settings file is never left in a partially-written state
+            // if the process is killed during the write.
+            var tempPath = SettingsFilePath + "
... (truncated)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions