Skip to content

Commit 99ad6d1

Browse files
kubafloCopilot
andauthored
Add AI memory-leak scanner + fixer agentic workflows (dotnet#36342)
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! > [!NOTE] > 🤖 **AI-generated PR.** These workflows, and this description, were produced with AI assistance. Please review carefully before merging. ## Summary Adds two [gh-aw](https://github.com/github/gh-aw) agentic workflows that proactively **find** and **fix** managed, cross-platform memory leaks in MAUI — turning the AI-driven leak-hunting flow several contributors already run by hand (scan → repro → measure → file → fix) into a repeatable, reviewable pipeline. **Design principle: only empirically-proven leaks.** The scanner files an issue **only** when a plain `dotnet test` demonstrates the leak; the fixer opens a PR **only** with a red→green regression test proving the fix. There is no "you're missing a test" / coverage-gap mode — every artifact is backed by a passing/failing test. **Key property:** neither workflow needs an emulator/simulator or a MAUI source build to *detect* a leak — the leak signature is proven by a `dotnet test` against the **shipped `Microsoft.Maui.Controls` NuGet package** on the plain library TFM, so detection runs on a standard GitHub-hosted runner. Only 4 files are added — the workflow source (`.md`) and its compiled artifact (`.lock.yml`) for each: ``` .github/workflows/daily-leak-hunter.md + .lock.yml .github/workflows/leak-fixer.md + .lock.yml ``` --- ## 1. `daily-leak-hunter` — the scanner (files `[leak-scan]` issues) **Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). Files **only empirically-proven `[leak-scan]` issues** — up to **8 per run**. 1. **Sweeps every focus area** of the managed surface (`src/Core/src`, `src/Controls/src/Core`, `src/Essentials/src`) in one run — it does not stop after the first find. 2. Each focus area is **seeded with proven MAUI leak signatures** (from the community's known-leak catalog) so the hunt targets where leaks actually live: shared publisher → strong `CollectionChanged`/`PropertyChanged` (e.g. `Picker.ItemsSource`, `TableRoot`, `SelectedItems`, `GradientStops`), shared `ICommand` → `CanExecuteChanged` (`ListView.RefreshCommand`, `SwipeItemView.Command`, `BackButtonBehavior.Command`), VSM state triggers → `DeviceDisplay.MainDisplayInfoChanged`, and static/`ResourceDictionary` roots. 3. For each candidate it writes a standalone control / leaky / mitigation xUnit repro (referencing the shipped package, no source build) and measures retention with `WeakReference` + a forced GC. All candidates go in **one test project** (one `[Fact]` each, one restore/run). 4. It files a `[leak-scan]` issue **only for each leak the test confirms** — the leaky scenario retains while **both** the control and the mitigation release. A false positive is treated as worse than a quiet run; unconfirmed candidates are dropped. **If a run proves nothing, it files nothing** (no fallback mode). **De-dup & safety:** skips a leak already covered by one of *its own* open `[leak-scan]` issues; never touches product or test code (read-only + `create-issue`); `noop: report-as-issue: false`. --- ## 2. `leak-fixer` — the fixer (opens draft `[leak-fix]` PRs) **Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). At most **one action per run**, with de-dup + a 3-attempt cap. It picks the **higher-priority** of two tracks: ### Track C — respond to review feedback (checked first) Before doing new work, it checks whether one of *its own* open `[leak-fix]` PRs (**hosted on this repo** — fork-hosted heads it can't push to are left for a human) has an **unaddressed `CHANGES_REQUESTED` review**. If so it works on that PR: **applies** the valid requested changes (pushes a commit, re-validated so the PR's own test still holds) and/or **posts a comment pushing back** on any request that is wrong, would regress behaviour, or asks for a mute. A loop-guard (act only on a review newer than the PR's last commit *and* the workflow's last comment) prevents re-processing the same review. ### Track A — `[leak-scan]` runtime leak → `[leak-fix]` PR For the selected proven leak it: 1. Writes a focused regression test in `Controls.Core.UnitTests`. 2. Builds MAUI **from source** and confirms the test **FAILS on `main`** — proving it catches the leak. 3. Implements the minimal, idiomatic managed fix — a weak subscription / teardown mirroring the existing `WeakEventManager` / `WeakNotify*Proxy` patterns. 4. Rebuilds and confirms the **same test now PASSES**, no neighbouring regressions. 5. Opens a **draft `[leak-fix]` PR** with `Fixes #N` and the red→green evidence. ### Safety - Enforces red→green **in both directions** — a fix without a demonstrated failing-then-passing test is rejected. - **Never** mutes / skips / disables a test; rejects its own attempt if the only thing that goes green is a mute — **including when a review asks for one** (it pushes back with a comment instead). - **One action per run** — Track C review-response *or* one new Track A `[leak-fix]` PR, never both. - Writes only via scoped safe-outputs (agent job is read-only); PR branches are limited to `leak-fix/**`, changes to managed `src/**` (+ `PublicAPI.Unshipped.txt`). - Skips cleanly if already fixed on `main`, out of scope (needs a device fix), or attempt-capped. --- ## Validated end-to-end on **dotnet/maui itself** (pre-merge) Both workflows were executed on this repo's own Actions infrastructure (via short-lived `push`-triggered test branches, since `workflow_dispatch` only lights up once a workflow is on `main`). Real outputs, all on **dotnet/maui**: - **Multi-leak in one run** — a single hunter run filed **5** distinct proven `[leak-scan]` issues via the catalog-seeded sweep: dotnet#36343 `SwipeItemView.Command`, dotnet#36344 `ListView.RefreshCommand`, dotnet#36345 `Shell BackButtonBehavior.Command` (all `ICommand.CanExecuteChanged`), dotnet#36346 `Picker.ItemsSource`, dotnet#36347 `IndicatorView.ItemsSource` (`CollectionChanged`). dotnet#36344 and dotnet#36345 are leaks not previously tracked upstream. - **Proven-only** — a later run filed `[leak-scan]` dotnet#36350 `CollectionView.SelectedItems` and (correctly) **nothing else**, having de-duped the already-filed leaks. - **Track A fix** — dotnet#36309 `[leak-fix] Fix ResourceDictionary MergedDictionaries memory leak` (regression test red→green + managed fix). - **Track C review-response** — on dotnet#36253 the fixer independently re-read the code, agreed with the reviewer's findings, validated the reviewer's `WeakEventManager` approach (24/24, red→green), and posted the concrete fix. --- ## Notes for reviewers - Everything the workflows file/open is **AI-generated** and clearly labelled as such; treat them as high-quality drafts for human review. - The workflows are self-contained (`.md` source + compiled `.lock.yml`); merging them enables the `schedule` triggers on `main`. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 580ef8a commit 99ad6d1

4 files changed

Lines changed: 4118 additions & 0 deletions

File tree

0 commit comments

Comments
 (0)