dispose-safe teardown for KeymapService + ClaudeConfig; cover the

claude extension lifecycle

make test-integration failed at widget-tree finalization: the
palette's dispose() clears its scope flag, which during app teardown
runs AFTER KernelServices.dispose() has disposed the KeymapService —
notifyListeners asserted. Scope-flag mutations now use the same
fire-and-forget guard SettingsStore established. Same family in
ClaudeConfig: activation's unawaited load() could notify (and start
watchers on) a disposed notifier when a teardown raced it.

The claude extension's activation lifecycle and command success paths
are now exercised end-to-end through the kernel fixture — the file
entered the coverage denominator with the T-391 failure-path tests,
so per the ratchet discipline the rest of it gets covered too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 01:55:56 +02:00
co-authored by Claude Fable 5
parent 4443e1c834
commit 99dc52052a
3 changed files with 127 additions and 2 deletions
+19 -2
View File
@@ -167,20 +167,37 @@ class KeymapService extends ChangeNotifier {
return km.match(sequence, _scope).exact;
}
/// Scope-flag producers clear their flags from widget dispose() — which
/// during app teardown runs AFTER KernelServices.dispose() has disposed
/// this notifier. Tolerate that ordering instead of asserting (the same
/// fire-and-forget pattern SettingsStore uses).
bool _disposed = false;
@override
void dispose() {
_disposed = true;
super.dispose();
}
void _safeNotify() {
if (_disposed) return;
notifyListeners();
}
/// Set a named scope flag. Producers should call this when their
/// state changes so when-clauses re-evaluate correctly. Notifies
/// listeners when the value actually changes.
void setScopeFlag(String name, bool value) {
if (_scope[name] == value) return;
_scope[name] = value;
notifyListeners();
_safeNotify();
}
/// Clear a named scope flag.
void clearScopeFlag(String name) {
if (!_scope.containsKey(name)) return;
_scope.remove(name);
notifyListeners();
_safeNotify();
}
/// Switch presets. Persists the new preset name to settings and