fix: updater survives Settings saves + cache unsniffable MLGs (v1.6.1)

Two reliability fixes for the Series 3 tray app:

1. Auto-updater no longer dies on a Settings save. _restart_watcher
   set+replaced the shared stop_event that the updater loop also keyed
   off, so saving settings could kill the updater thread (race). Give
   the updater its own app-lifetime event (_app_stop). Same fix as
   thor-watcher 0.4.1.

2. Unsniffable .MLG files are now cached, so each is sniffed + logged
   once per session instead of every 5-min scan. A long-lived autocall
   folder with a few hundred unidentifiable files was flooding the log
   (~600K lines in 10 days) and re-reading every header each scan.

Adds test_series3_tray.py (4 lifecycle tests) and test_scan_latest.py
(2 scan tests). Full suite 50 passing. Bump to v1.6.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 20:08:03 +00:00
parent e6e4c94f19
commit aa341c7342
8 changed files with 170 additions and 15 deletions
+10 -7
View File
@@ -237,13 +237,16 @@ def scan_latest(
uid = cached[1]
else:
uid = sniff_unit_from_mlg(fpath, header_bytes)
if not uid:
# If unsniffable but very recent, log for later inspection
if (recent_cutoff is not None) and (mtime >= recent_cutoff):
if logger:
logger("[unsniffable-recent] {}".format(fpath))
continue # skip file if no unit ID found in header
# Cache the result either way — including unsniffable (uid=None) —
# so the same file isn't re-sniffed and re-logged on every scan.
cache[fpath] = (mtime, uid)
if (not uid) and (recent_cutoff is not None) and (mtime >= recent_cutoff):
# Log once, on first sight, for later inspection.
if logger:
logger("[unsniffable-recent] {}".format(fpath))
if not uid:
continue # no unit ID in header — skip (cached above, won't re-log)
if (uid not in latest) or (mtime > latest[uid]["mtime"]):
latest[uid] = {"mtime": mtime, "fname": e.name, "path": fpath}
@@ -253,7 +256,7 @@ def scan_latest(
# --- API heartbeat / SFM telemetry helpers ---
VERSION = "1.6.0"
VERSION = "1.6.1"
def _read_log_tail(log_file: str, n: int = 25) -> Optional[list]: