name: leak-guard description: | INTERNAL DEV WORKFLOW for WpfHexEditor — Claude self-invokes after editing C# files that touch IDisposable, events, FileStream, Process, Timer, or files under Services/, *Manager.cs, *Service.cs, Watcher, *Adapter.cs. Detects: event handlers added without unsubscribe, IDisposable without Dispose, missing GC.SuppressFinalize, FileStream without using, Timer not stopped, Process not disposed, static event collections, weak-event candidates, hardcoded secrets. Skip on: Tests/, Samples/, *.Designer.cs, *.g.cs, generated code.
leak-guard (internal)
Static guard for memory/handle/event leaks and secret hygiene (75+ IDisposable implementations, lots of file watching, long-lived LSP handlers).
When I invoke
| Situation | Run? |
|---|---|
Edit .cs with IDisposable/event/+=, or FileStream/File.Open/Process/Timer |
yes |
Edit under Services/, *Manager.cs, *Service.cs, *Watcher*, *Adapter.cs |
yes |
Tests/, Samples/, *.Designer.cs, *.g.cs, rename/comment only |
no |
Pipeline
scripts/leak-scan.ps1 -Files <paths> → Leaks: <summary> or OK + per-issue lines.
Suppress: // leak-ok: <reason> on the offending line.
9 rules
| Rule | Sev | Detected via |
|---|---|---|
event-no-unsubscribe |
warn | += on event without matching -= in Dispose/Unloaded of same class |
idisposable-no-dispose |
error | : IDisposable without Dispose() method body |
dispose-no-suppress-finalize |
warn | ~Class() finalizer + Dispose() lacks GC.SuppressFinalize(this) |
filestream-no-using |
warn | new FileStream(/File.Open( not in using, not a field |
timer-no-stop |
warn | new (DispatcherTimer|Timer|System.Timers.Timer)( field without Stop()/Dispose() reference |
process-no-dispose |
warn | Process.Start/new Process( without using, result assigned to local |
static-event-collection |
error | public static event OR static List/Dict/HashSet mutated by instance methods |
weak-event-candidate |
warn | += on Application.Current.*, Dispatcher.*, or *.Instance.* from UserControl/Window |
secret-in-source |
error | (api[_-]?key|password|secret|token)\s*=\s*"[A-Za-z0-9+/=]{16,}" |
secret-in-source skips // fixture lines and Tests/Fixtures/. Full rule detail: references/leak-rules.md.
Output
Leaks: 2 event-no-unsubscribe, 1 timer-no-stop | 0 secrets
FileMonitorService.cs:42 event-no-unsubscribe _watcher.Changed += OnFileChanged (no -= in Dispose)
HighlightPipelineService.cs:128 timer-no-stop DispatcherTimer field never .Stop()
Static single-file analysis only. No runtime profiling, code rewrite, or cross-file tracking.
Maintenance
New leak pattern → row in references/leak-rules.md + extend $rules in leak-scan.ps1.
New long-lived host singleton → add to weak-event-candidate source list in script.