fix(ui): Reactivität — Description-Save-Race, UsageMonitor-Leak, Listen-Live-Refresh
Drei unabhängige Reactivity-Bugs aus dem Polish-Audit 2026-08-20: 1. Description-Autosave überschrieb den falschen Task, weil SaveDescriptionAsync Task.Id/EditableDescription erst nach dem 400ms-Debounce las statt Row+Wert an der Aufrufstelle zu capturen (wie SaveTitleAsync es schon tat). Bind() cancelt jetzt zusätzlich einen laufenden Title-/Description-Save der vorherigen Row. 2. UsageMonitorModalViewModel abonnierte UsageUpdatedEvent erst nach dem Erst-Load-Await — schloss man das Modal währenddessen, lief das Unsubscribe in Close() ins Leere und die VM hing für immer am WorkerClient. Ein _isClosed-Flag wird jetzt nach dem Await geprüft, bevor abonniert wird. 3. Per MCP erstellte Listen blieben unsichtbar: RefreshRowAsync hatte keinen Add-Zweig für unbekannte Ids und verglich zudem die falsche Id-Form (der Worker broadcastet die rohe DB-Id, nie die "user:"-prefixte Row-Id). Ein Reconnect lud zudem nur Counts statt der vollen Listen neu.
This commit is contained in:
@@ -155,6 +155,24 @@ public class UsageMonitorModalViewModelTests
|
||||
Assert.False(vm.IsBusy);
|
||||
}
|
||||
|
||||
// ── Leak on early close (Polish-Audit 2026-08-20 #2) ────────────────────
|
||||
|
||||
[Fact]
|
||||
public async Task LoadAsync_ClosedBeforeSnapshotArrives_NeverSubscribesToUsageUpdated()
|
||||
{
|
||||
var worker = new FakeWorker { SnapshotGate = new TaskCompletionSource<UsageSnapshotDto?>() };
|
||||
var vm = new UsageMonitorModalViewModel(worker);
|
||||
|
||||
var load = vm.LoadAsync();
|
||||
vm.CloseCommand.Execute(null);
|
||||
worker.SnapshotGate.SetResult(Snapshot(new[] { Limit("session") }));
|
||||
await load;
|
||||
|
||||
worker.RaiseUsageUpdated(Snapshot(new[] { Limit("session"), Limit("weekly_all") }));
|
||||
|
||||
Assert.Null(vm.Snapshot);
|
||||
}
|
||||
|
||||
// ── Manual refresh ──────────────────────────────────────────────────────
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user