Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
f556bc5
Run Memory Leak Fixer every 3h instead of every 12h
Copilot Jul 11, 2026
00edaf1
Change Memory Leak Fixer cadence to every 6h (4x/day)
Copilot Jul 11, 2026
b9c61b5
Add de-dup/auto-close + fixed-on-main guard to leak workflows
Copilot Jul 12, 2026
3966e53
Gate new leak-fixer close-issue emissions behind dry_run
Copilot Jul 12, 2026
218f465
Address review: provenance-gate leak-workflow issue closure
Copilot Jul 14, 2026
25e2ec7
Fix prompt-internal consistency from Copilot re-review
Copilot Jul 14, 2026
e85dd91
Align Hard Rule 2 with gate (d) closure conditions
Copilot Jul 14, 2026
c16e059
Unify green-test skipped record string across Hard Rule 2 and Step 6
Copilot Jul 14, 2026
a9231b6
Scope [leak-fix] de-dup/close searches to label:agentic-workflows
Copilot Jul 14, 2026
5e47e5a
Grant hunter pull-requests: read; add --limit to fixer Track C list
Copilot Jul 14, 2026
9bc607b
Fix cross-repo issue-ref false match in leak-fixer close gates
Copilot Jul 14, 2026
a5fbf62
Raise merged [leak-fix] provenance cap to search-API ceiling + warn o…
Copilot Jul 14, 2026
155707c
Tighten leak-fixer issue-ref regex + fix two prompt-clarity nits
Copilot Jul 14, 2026
5b8b853
Raise gate (c) attempt-cap query to search-API ceiling + warn on trun…
Copilot Jul 14, 2026
4715f42
Make fixed-on-main provenance grep robust under set -eo pipefail
Copilot Jul 14, 2026
82dadbe
Require perf/memory-leak label on the destructive close-issue guard
Copilot Jul 14, 2026
e01a5cb
Normalize PR titles with symmetric last-pair extraction in leak-fix g…
Copilot Jul 14, 2026
7aeffee
Respect maintainer re-open in leak-fixer gate (d)
Copilot Jul 15, 2026
ecda5f4
Fix fail-open re-open guard in leak-fixer (fail closed on unverified …
Copilot Jul 15, 2026
95a840d
Prevent duplicate memory leak workflow fixes
Copilot Jul 19, 2026
56abf8d
leak-fixer: slurp paginated timeline + reset shared reopen-override s…
Copilot Jul 21, 2026
fdf16ef
Harden leak dedup: normalize title newlines, guard empty API, fail-cl…
Copilot Jul 21, 2026
9e6d1ee
Make all leak-dedup/cap gates fail-closed, not just the merged fetch
Copilot Jul 21, 2026
2e43376
Create /tmp/gh-aw/agent before first redirect in daily-leak-hunter
kubaflo Jul 21, 2026
bc19a83
Merge branch 'main' into copilot/leak-fix-merged-dedup
kubaflo Aug 1, 2026
a52a6c8
Merge branch 'main' into leak-fixer-3h-schedule
kubaflo Aug 1, 2026
0c284c4
Harden leak dedup: fail-closed title fetch + drop unused pull_request…
Artarmonx5iz Aug 5, 2026
cc8eab8
Merge main into leak-fixer-3h-schedule
Copilot Aug 6, 2026
cebd47e
Merge main into copilot/leak-fix-merged-dedup
Copilot Aug 6, 2026
fe6040a
Address review feedback on leak-fixer/daily-leak-hunter workflows
Copilot Aug 7, 2026
17aa884
Address remaining review feedback on leak dedup (regex, cache stalene…
Copilot Aug 7, 2026
3d5654f
Clarify leak fixer dry-run scope
Copilot Aug 7, 2026
f59f6da
Harden leak workflow provenance and de-dup
Aug 10, 2026
88d48bb
Harden leak workflow duplicate enforcement
Aug 10, 2026
9f0ef53
Test leak provenance with production jq parser
Aug 10, 2026
e688069
Skip jq fixtures when jq is unavailable
Aug 10, 2026
5942948
Ignore release-only open leak fixes
Aug 10, 2026
c8fe130
Harden leak fixer review gates
Aug 12, 2026
d96f884
Address leak workflow review feedback
Aug 12, 2026
2ac8a5d
Harden leak workflow search ceilings
Aug 13, 2026
3eab535
Harden leak fix PR metadata gate
Aug 18, 2026
d0d266f
Harden leak workflow provenance guards
Aug 18, 2026
07d917e
Harden leak workflow provenance handling
Aug 18, 2026
ebb7fb7
Advance leak fixer past completed scans
Aug 18, 2026
82c1681
Verify workflow schedule lock synchronization
Aug 18, 2026
d2f0b65
Harden leak workflow mutation gates
Aug 18, 2026
dc8c4e1
Harden leak de-dup metadata gates
Aug 18, 2026
16b0843
Stabilize leak gate gh failures
Aug 18, 2026
328d70d
Harden native command assertion
Aug 18, 2026
1ef6fd8
Fix independent revert handling
Aug 18, 2026
5a1f032
Reject duplicate leak APIs per batch
Aug 18, 2026
e56a8b0
Align leak hunter batch contract
Aug 18, 2026
002c18a
Harden leak title and revert parsing
Aug 19, 2026
d30e8ca
Isolate cyclic leak revert chains
Aug 19, 2026
18ccaad
Refine cyclic revert sibling handling
Aug 19, 2026
2c26206
Align leak dedup parsing contracts
Aug 19, 2026
4bdafc7
Harden trusted leak dedup gates
Aug 19, 2026
83f6fb7
Document atomic leak-hunter retries
Aug 19, 2026
363b1df
Harden leak workflow remediation gates
Aug 19, 2026
a92c702
Fix leak revert traversal budget
Aug 19, 2026
a40b43d
Harden leak revert discovery
Aug 19, 2026
c0153c9
Scope leak fix attempt cap to authoritative lanes
Aug 19, 2026
cdac18a
Honor server-directed leak retry timing
Aug 19, 2026
9dc16fd
Harden leak hunter branch validation
Aug 19, 2026
d91cf3c
Harden leak de-dup history pagination
Aug 19, 2026
f897d85
Harden leak revert proof verification
Aug 19, 2026
cf4ab22
Harden leak gate input validation
Aug 19, 2026
a0e7f1a
Merge memory leak workflow improvements from #36524
Aug 19, 2026
f51f067
Harden leak workflow snapshot consistency
Aug 19, 2026
efc7266
Harden leak fix provenance gate
Aug 19, 2026
155d4ca
Harden GraphQL array property handling
Aug 19, 2026
4181a78
Harden final leak-fix snapshot consistency
Aug 20, 2026
b818de9
Harden live leak issue validation
Aug 20, 2026
6ddd738
Fix leak dedup title and cycle handling
Aug 20, 2026
5c26450
Harden effective revert traversal bounds
Aug 20, 2026
a9c8c0b
Harden leak API identity and hunter snapshots
Aug 20, 2026
057f820
Harden leak workflow provenance and issue snapshots
Aug 20, 2026
1a41859
Harden leak issue-reference input bound
Aug 20, 2026
86bd6f7
Harden hunter open-fix dedup
Aug 20, 2026
76788e6
Fix leak workflow dedup regressions
Aug 20, 2026
fc2b73f
Validate leak reverts from merge commits
Aug 20, 2026
450c2dc
Merge main into leak workflow hardening
Aug 20, 2026
c266e1f
Address leak workflow review feedback
Aug 20, 2026
0f94f3b
Align leak hunter de-dup documentation
Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/daily-leak-hunter.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 87 additions & 29 deletions .github/workflows/daily-leak-hunter.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ if: |
permissions:
contents: read
issues: read
pull-requests: read

engine:
id: copilot
Expand Down Expand Up @@ -72,7 +73,7 @@ max-daily-ai-credits: -1

tools:
github:
toolsets: [issues, search]
toolsets: [pull_requests, issues, search]
Comment thread
kubaflo marked this conversation as resolved.
Resolved
edit:
bash: ["dotnet", "git", "gh", "find", "ls", "cat", "grep", "head", "tail", "wc", "jq", "tee", "sed", "awk", "tr", "cut", "sort", "uniq", "xargs", "echo", "date", "mkdir", "test", "env", "basename", "dirname", "bash", "sh", "chmod", "curl"]

Expand Down Expand Up @@ -132,11 +133,12 @@ Never push, never open a PR, never comment, never edit product or test code in t
device tests and are out of scope.
4. **Skip weak-proxied code.** If the suspect uses `WeakEventManager`,
`ConditionalWeakTable`, `WeakReference`, or any `Weak*Proxy`, it does not leak β€” move on.
5. **De-dup against THIS SCANNER's own OPEN issues.** Before filing, fetch this workflow's open
`[leak-scan]` issues and skip a leak already covered by one (same rooting API / retention
path). Do NOT suppress a candidate because AdamEssenmacher (or anyone else) has a repro/issue
for it β€” duplicating those is fine. A
candidate whose only prior issue from this scanner is CLOSED may be re-filed.
5. **De-dup against open scanner issues AND merged fixes.** Before testing or filing, skip a
leak already covered by this workflow's open `[leak-scan]` issue (same rooting API /
retention path), or by an exact `[leak-fix]` PR already merged to `main` or
`inflight/current`. Do NOT suppress a candidate merely because AdamEssenmacher (or anyone
else) has a repro/issue for it β€” duplicating those is fine. A candidate whose only prior
scanner issue is CLOSED may be re-filed only when no supported-branch merged fix exists.
6. **Never weaken or disable anything, and never commit code.** You only READ repo source
and (Pass A) ADD a throwaway test under `/tmp`. Never edit product code, never
`[ActiveIssue]`/skip/mute existing tests, never push.
Expand All @@ -150,16 +152,22 @@ Never push, never open a PR, never comment, never edit product or test code in t
candidate with a **standalone** test that references the **shipped `Microsoft.Maui.Controls`
NuGet package** from nuget.org (Step 4) β€” no source build, no workload, no emulator.

## Step 2 β€” Fetch this scanner's own OPEN issues (de-dup)
## Step 2 β€” Fetch open scanner issues and merged fixes (de-dup)

The only de-dup that matters is not posting a second OPEN copy of a leak THIS workflow already
filed. You do **not** care about AdamEssenmacher's repro branches or anyone else's issues β€”
duplicating those is explicitly fine.
Two de-dup sources matter:

1. this workflow's own open `[leak-scan]` issues; and
2. exact `[leak-fix]` PRs already merged to `main` or `inflight/current`.

You do **not** care about AdamEssenmacher's repro branches or anyone else's issues by
themselves β€” duplicating those is explicitly fine. A merged generated fix is different: the
shipped package may still reproduce the old leak even though the fix has already landed in the
active source flow, so filing it again would only create another redundant fix PR.

Fetch this scanner's own open `[leak-scan]` issues (they are filed with the `agentic-workflows`
label) and extract the **rooting API** each one already covers:
label), then fetch merged generated fixes and extract the **rooting API** each artifact covers:

```
```bash
gh issue list --repo "$GITHUB_REPOSITORY" --search '"[leak-scan]" in:title' \
--state open --label agentic-workflows --limit 200 --json number,title,body \
> /tmp/gh-aw/agent/my-open-leakscan.json
Expand All @@ -170,21 +178,69 @@ gh issue list --repo "$GITHUB_REPOSITORY" --search '"[leak-scan]" in:title' \
# Type.Member pair of the first identifier chain: for a fully-qualified title like
# "Microsoft.Maui.Controls.Picker.ItemsSource" this yields "Picker.ItemsSource" (not the
# namespace head "Microsoft.Maui", which would over-collapse distinct leaks to one key).
jq -r '.[].title' /tmp/gh-aw/agent/my-open-leakscan.json \
jq -r '.[].title | gsub("[\r\n]+";" ")' /tmp/gh-aw/agent/my-open-leakscan.json \
| sed -E 's/^\[leak-scan\] *//' \
| awk '{ if (match($0, /[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)+/)) { chain=substr($0,RSTART,RLENGTH); n=split(chain,seg,"."); print seg[n-1]"."seg[n] } else print }' \
| awk '{ if (match($0, /[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)+/)) { chain=substr($0,RSTART,RLENGTH); n=split(chain,seg,"."); print seg[n-1]"."seg[n] } }' \
| sort -u \
> /tmp/gh-aw/agent/already-filed-apis.txt
echo "already-filed rooting APIs:"; cat /tmp/gh-aw/agent/already-filed-apis.txt

# Fetch only this workflow family's exact generated PRs that are already merged into one of
# the two active source-flow branches. Trust live baseRefName, not a stale "Target branch:"
# line in the PR body (PRs can be retargeted before merge).
# Fail-closed: if the fetch errors (transient API/auth/rate-limit) it writes nothing, and jq on
# an empty pipe still emits [] with exit 0 β€” the de-dup would then wrongly conclude "no merged
# fix exists" and re-file a duplicate. Split the fetch from the filter and abort on failure.
if ! gh pr list --repo "$GITHUB_REPOSITORY" --state merged --limit 1000 \
--search '"[leak-fix]" in:title' \
Comment thread
kubaflo marked this conversation as resolved.
Resolved
--json number,title,body,baseRefName,mergedAt,url \
> /tmp/gh-aw/agent/merged-leak-fix-prs-raw.json; then
echo "ERROR: 'gh pr list --state merged [leak-fix]' failed β€” aborting so a transient API/auth/rate-limit error can't empty the merged-fix set and re-file duplicate leaks (fail-closed)." >&2
exit 1
Comment thread
kubaflo marked this conversation as resolved.
Resolved
fi
jq '[.[] |
select(.mergedAt != null) |
select(.title | startswith("[leak-fix] ")) |
select(.baseRefName == "main" or .baseRefName == "inflight/current")]' \
/tmp/gh-aw/agent/merged-leak-fix-prs-raw.json \
> /tmp/gh-aw/agent/merged-leak-fix-prs.json

# Keep the canonical API first so every candidate can be checked with grep -Fx before its
# throwaway repro is written. Preserve PR metadata for a clear skip diagnostic.
jq -r '.[] | [.number, .title, .baseRefName, .url] | @tsv' \
/tmp/gh-aw/agent/merged-leak-fix-prs.json \
| while IFS=$'\t' read -r PR TITLE BASE URL; do
API=$(printf '%s\n' "$TITLE" \
| sed -E 's/^\[leak-fix\] *//' \
| awk '{ if (match($0, /[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)+/)) { chain=substr($0,RSTART,RLENGTH); n=split(chain,seg,"."); print seg[n-1]"."seg[n] } }')
if test -n "$API"; then
printf '%s\t%s\t%s\t%s\t%s\n' "$API" "$PR" "$BASE" "$URL" "$TITLE"
fi
done \
| sort -u \
> /tmp/gh-aw/agent/already-merged-fix-apis.tsv
cut -f1 /tmp/gh-aw/agent/already-merged-fix-apis.tsv | sort -u \
> /tmp/gh-aw/agent/already-merged-fix-apis.txt
echo "already-merged fix APIs:"
cat /tmp/gh-aw/agent/already-merged-fix-apis.tsv
```

- A candidate is **OUT** if its rooting `Type.Member` (e.g. `SwipeItemView.Command`,
`Picker.ItemsSource`) is already in `already-filed-apis.txt`, OR an open `[leak-scan]` issue
otherwise covers the same rooting API / retention path. **Check this for EVERY candidate
before you write its test** β€” re-filing a leak this scanner already has open (even with
different title wording) is the #1 failure mode, so be strict about matching the `Type.Member`.

A candidate whose only prior issue from this scanner is CLOSED may be re-filed.
otherwise covers the same rooting API / retention path, OR it appears in
`already-merged-fix-apis.txt`. **Check this for EVERY candidate before you write its test.**
Comment thread
kubaflo marked this conversation as resolved.
Resolved
- Normalize each candidate with the same last-`Type.Member` extraction above, then use
`grep -Fxq "$API" /tmp/gh-aw/agent/already-merged-fix-apis.txt`; do not use substring
matching.
- For a merged-fix match, print the matching row(s) from
`already-merged-fix-apis.tsv` and record
`skipped: equivalent fix already merged via #<PR> to <baseRefName>`.
- Re-filing a leak this scanner already has open or that already has a merged fix (even with
different issue wording/number) is the primary failure mode, so be strict about the
canonical `Type.Member`.

A candidate whose only prior scanner issue is CLOSED may be re-filed only when its API is
absent from `already-merged-fix-apis.txt`.

# ===================== RUNTIME LEAK HUNT =====================

Expand Down Expand Up @@ -237,10 +293,11 @@ transient object (page / view / view-model / handler) with no teardown**, e.g.:

For each candidate, write down the precise retention path
`root -> ... -> transient` with file:line citations, then cross-check Step 2. **Collect EVERY
distinct candidate** across all focus areas that is not already an open `[leak-scan]` issue β€”
build a candidate list (aim for several). Rank them strongest-first, then confirm as many as
you can in Step 4/5. If β€” after a genuine sweep β€” there is no convincing candidate at all, stop
and create nothing (a quiet run is fine β€” there is no coverage-gap fallback).
distinct candidate** across all focus areas that is not already an open `[leak-scan]` issue and
does not already have a supported-branch merged `[leak-fix]` PR β€” build a candidate list (aim
for several). Rank them strongest-first, then confirm as many as you can in Step 4/5. If β€”
after a genuine sweep β€” there is no convincing candidate at all, stop and create nothing (a
quiet run is fine β€” there is no coverage-gap fallback).

## Step 4 β€” Write a standalone control/leaky/mitigation test (shipped package)

Expand Down Expand Up @@ -305,12 +362,13 @@ no MAUI source build, no emulator.
## Step 6 β€” File the issues (Pass A β€” one per confirmed leak)

For **every** leak Step 5 confirmed, emit a `create-issue` safe-output (up to the 8 cap) β€” one
issue per distinct leak. De-dup each against open `[leak-scan]` issues AND against the other
issues you're filing this run (no two issues for the same rooting API). Each title MUST be of the
form **`[leak-scan] <Type>.<Member> β€” <short mechanism>`** β€” it MUST **lead with the canonical
rooting `Type.Member`** immediately after the tag (e.g. `[leak-scan] SwipeItemView.Command β€” non-weak
ICommand.CanExecuteChanged retains the control`). De-dup (Step 2) matches on that leading
`Type.Member`, so keep it stable and canonical β€” do not reword it run-to-run.
issue per distinct leak. De-dup each against open `[leak-scan]` issues, supported-branch merged
`[leak-fix]` PRs, AND the other issues you're filing this run (no two issues for the same
rooting API). Each title MUST be of the form **`[leak-scan] <Type>.<Member> β€” <short
mechanism>`** β€” it MUST **lead with the canonical rooting `Type.Member`** immediately after the
tag (e.g. `[leak-scan] SwipeItemView.Command β€” non-weak ICommand.CanExecuteChanged retains the
control`). De-dup (Step 2) matches on that leading `Type.Member`, so keep it stable and
canonical β€” do not reword it run-to-run.
Body (markdown):

- A clear **AI-generated** banner naming this workflow.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/leak-fixer.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading