feat: use mtime+size fingerprint for stale-file check (#17)

MainWindow._loaded_mtime -> _loaded_stat (core.ConfigStat), populated
via core.config_fingerprint() at load/save time. The save-path stale
check now compares the full fingerprint (mtime AND size) instead of
bare mtime equality.
This commit is contained in:
2026-07-07 20:33:38 -04:00
parent 5d59c1c423
commit f1935fe320
+11 -8
View File
@@ -1104,7 +1104,7 @@ class MainWindow(QMainWindow):
self.full_config: dict = {}
self.servers: list[core.ServerEntry] = []
self.current_profile: core.Profile | None = None
self._loaded_mtime: float | None = None
self._loaded_stat: core.ConfigStat | None = None
self.dirty = False
self._suppress_table = False
self._suppress_sel = False
@@ -1380,7 +1380,7 @@ class MainWindow(QMainWindow):
return
self.full_config = cfg
repaired = True
self._loaded_mtime = core.config_mtime(profile.path)
self._loaded_stat = core.config_fingerprint(profile.path)
self.current_profile = profile
self.servers = core.extract_servers(self.full_config)
self.dirty = False
@@ -1719,11 +1719,14 @@ class MainWindow(QMainWindow):
return
# Stale-file check: if the file changed on disk since we loaded it, prompt.
disk_mtime = core.config_mtime(self.current_profile.path)
# Compare mtime AND size (not mtime alone) so a concurrent external write
# that lands within the mtime resolution window, or that restores the
# original mtime, still gets caught.
disk_stat = core.config_fingerprint(self.current_profile.path)
if (
disk_mtime is not None
and self._loaded_mtime is not None
and disk_mtime != self._loaded_mtime
disk_stat is not None
and self._loaded_stat is not None
and disk_stat != self._loaded_stat
):
changed_keys, server_diff = core.external_change_summary(
self.full_config, self.current_profile.path
@@ -1744,7 +1747,7 @@ class MainWindow(QMainWindow):
QMessageBox.critical(self, "Save failed", str(e))
return
self.full_config = fresh
self._loaded_mtime = core.config_mtime(self.current_profile.path)
self._loaded_stat = core.config_fingerprint(self.current_profile.path)
self.current_profile.config_exists = True
self.dirty = False
self.save_btn.setEnabled(False)
@@ -1762,7 +1765,7 @@ class MainWindow(QMainWindow):
except Exception as e:
QMessageBox.critical(self, "Save failed", str(e))
return
self._loaded_mtime = core.config_mtime(self.current_profile.path)
self._loaded_stat = core.config_fingerprint(self.current_profile.path)
self.current_profile.config_exists = True
self.dirty = False
self.save_btn.setEnabled(False)