Fix what's-new re-appearing after a failed update (held for next release)
Replace the running-version-vs-saved-version trigger for the "what's new" popup with a one-shot marker the updater writes ONLY on a successful update (UpdateApplier success path). A failed/rolled-back update never writes it (and clears any stale one), so it can no longer re-trigger what's-new — the old best-effort flag save could lose a race during the update churn and leave the version mismatched, which was the bug. New WhatsNewMarker seam (Write/Exists/Consume) + a SelfTest case for the consume-once contract. MaybeShowWhatsNewAfterUpdate now shows iff the marker is present, then deletes it; still records LastWhatsNewVersion for the import-offer's upgrade detection. Not released yet — bundling with the connection-retry (#15) work in the next release. No version bump, no manual change (internal fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
36431d6d39
commit
e710834458
@@ -57,6 +57,7 @@ internal static class SelfTest
|
||||
RunStep(results, "Server wire-format compatibility", ServerWireCompat);
|
||||
RunStep(results, "App settings save and reload", SettingsRoundTrip);
|
||||
RunStep(results, "Profile save and reload", ProfileRoundTrip);
|
||||
RunStep(results, "What's-new update marker", WhatsNewMarkerRoundTrip);
|
||||
RunStep(results, "Diagnostics report privacy", DiagnosticsPrivacy);
|
||||
RunStep(results, "Bundled resources present", ResourcesPresent);
|
||||
RunStep(results, "Dialog accessibility (names + mnemonics)", AccessibilityAudit);
|
||||
@@ -131,6 +132,29 @@ internal static class SelfTest
|
||||
return "AES-256-GCM, PBKDF2 fingerprint, on-disk scramble";
|
||||
}
|
||||
|
||||
/// <summary>The "what's new after a successful update" marker round-trips: present after Write,
|
||||
/// Consume removes it exactly once, and a second Consume is a no-op. This is the contract the bug
|
||||
/// fix rests on — a failed update writes no marker (no popup); a success writes one (shown once).</summary>
|
||||
private static string? WhatsNewMarkerRoundTrip()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "rs-selftest-whatsnew-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
Check(!WhatsNewMarker.Exists(dir), "a fresh folder must have no marker");
|
||||
WhatsNewMarker.Write(dir);
|
||||
Check(WhatsNewMarker.Exists(dir), "marker must exist after Write");
|
||||
Check(WhatsNewMarker.Consume(dir), "Consume must report it removed the marker");
|
||||
Check(!WhatsNewMarker.Exists(dir), "marker must be gone after Consume");
|
||||
Check(!WhatsNewMarker.Consume(dir), "a second Consume must be a no-op (shown exactly once)");
|
||||
return "write / exists / consume-once / idempotent";
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { Directory.Delete(dir, recursive: true); } catch { /* best-effort temp cleanup */ }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The packet header writes and reads back for every type, and malformed packets
|
||||
/// (too short, bad magic, wrong version) are rejected rather than mis-parsed. Plus the PCM
|
||||
/// multi-part sub-header round-trips.</summary>
|
||||
|
||||
Reference in New Issue
Block a user