Review sweep: fix real bugs found across the service + per-app + settings changes

Parallel code review of this session's changes surfaced several real bugs; fixed the
substantive ones (judgment/cleanup calls held for Ed):

- HIGH Clearing "remembered peers" was resurrected on the next launch: the per-profile
  -> global migration re-ran every startup and re-unioned the profile file's stale copy.
  Added a one-time AppConfig.RememberedPeersMigrated marker so migration runs once and a
  cleared list stays cleared. Self-test pins the clear-then-reload scenario.
- MED PushModeWasapiBackend.Start rethrew on a device-open failure; nothing up the stack
  wraps it, so device churn (a push-eligible single WASAPI source unplugged mid-open)
  could crash the app. Now logs and stays stopped like MixingEngine/ASIO; the device
  watcher / self-heal re-open when a device returns.
- MED Service self-heal: (a) the re-open "no send sources" path left PerformanceMode ON
  and presence up while streaming nothing - now releases cleanly; (b) the 3-attempt
  ladder never refunded, so 3 hiccups over a days-long stint meant permanent silence -
  now refunds when real audio is heard, and resets on a device hot-plug.
- MED ApplyProfile resolved peers (DNS) and enumerated devices INSIDE the gate lock -
  a boot-time DNS hang as SYSTEM stalled Suspend()/yield/self-heal. Moved outside the lock.
- LOW AudioSessionStartWatcher leaked the AudioSessionManager on every Rehook (the WASAPI
  handle-leak fingerprint) - now disposed. New lifecycle self-test.
- LOW stale docstrings (send-all master toggle; ServiceUpdate in-place scheme; Profile
  .SendAllApplications "neither reads nor writes").

Gate: 42/42 (added peers-migration + session-watcher-lifecycle tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-07-17 15:49:01 +01:00
co-authored by Claude Opus 4.8
parent 4b2baa58b5
commit 984bcd042e
10 changed files with 143 additions and 44 deletions
+7 -2
View File
@@ -99,10 +99,15 @@ public sealed class AppConfig
/// <summary>Machine-wide remembered PEER entries — ONE shared address book across all profiles
/// (Ed, 2026-07: both remembered lists live in global, not the profile). Before this the list rode
/// in each profile's JSON, so it was per-profile in practice; each old profile's legacy list is
/// unioned in here the first time it's opened (RemSoundSettingsStore.ApplyProfile). Null = none yet.
/// Cleared from Preferences → General.</summary>
/// unioned in here ONCE (RemSoundSettingsStore.MigrateRememberedPeersToGlobal, gated by
/// <see cref="RememberedPeersMigrated"/>). Null = none yet. Cleared from Preferences → General.</summary>
public List<string>? RememberedPeers { get; set; }
/// <summary>Set true after the one-time migration of a profile's legacy per-profile peers into
/// <see cref="RememberedPeers"/>. Without this the migration re-ran every launch and re-unioned the
/// profile file's stale copy — which silently resurrected peers the user had just cleared.</summary>
public bool RememberedPeersMigrated { get; set; }
/// <summary>Machine-wide remembered APPLICATION process names (lower-case) — the shared "apps I
/// send" address book, companion to <see cref="RememberedPeers"/>. Before 2026-07-16 this only
/// lived in the in-memory settings cache, which silently forgot the list on every app exit. Null =