## Summary of the Pull Request
Replaces the retired GitHub Models-based automatic issue triage and
deduplication flows with the GitHub Agentic Workflow proven in the
`niels9001/powertoys-ai-triage-sandbox`.
This PR also:
- aligns `Needs-Author-Feedback` closure to 7 days for issues and PRs;
- removes the automatic GitHub Models issue/PR labeler;
- removes the automatic GitHub Models new-issue deduplicator;
- removes the Azure Pipelines XAML Styler verification step while
retaining the
local styling script.
This is a draft because production rollout still requires the
appropriate
privacy and Responsible AI reviews.
## Issue triage rules
### Triggers and refresh behavior
- Runs when an issue is opened, edited, or reopened.
- Runs when the issue author attaches a `PowerToysReport_*.zip` in a
comment.
- Maintainers can force regeneration with `/triage refresh`.
- Ignores unrelated comments, unchanged issue edits, PR comments, and
bot-initiated reopens.
- Uses per-issue concurrency so a newer run supersedes an older run.
- Maintains one canonical triage comment instead of adding repeated bot
comments.
### Comment format
- Separates **For the issue author** from **For the PowerToys team**.
- Mentions the author once and lists each requested action as a bullet.
- Distinguishes blocking **Needed** actions from non-blocking
**Recommended**
actions.
- Shows the product, issue kind, reported PowerToys version, concise
summary,
diagnostic findings, possible duplicates, and collapsed investigation
checks.
- Ends with a short disclosure that triage is AI-assisted and
maintainers make
final decisions.
### Classification and labels
- Detects PowerToys bug-template issues deterministically.
- Reads the selected product area and adds a matching primary
`Product-*`
label.
- Handles production aliases such as FancyZones Editor and File Explorer
preview/thumbnail areas.
- Product labeling is additive: existing product and maintainer labels
are
never removed.
- Normalizes the reported PowerToys version and adds a matching version
label
when one exists.
- Applies `Needs-Author-Feedback` only when blocking information or an
English
translation is required.
- Removes `Needs-Author-Feedback` when the issue becomes actionable.
### PowerToys version rule
- Compares the reported version with the latest stable PowerToys GitHub
release.
- Older versions receive a recommended update-and-retest action.
- Current versions, newer preview/dev versions, missing versions, and
release
lookup failures are not flagged as outdated.
- Updating is advisory and does not block triage by itself.
### Reproduction rule
- Concrete actions plus an observed result are sufficient.
- Concise steps can use the separate Actual Behavior section as the
observed
result.
- Passive or intermittent failures are sufficient when the
timing/trigger and
observed failure are clear.
- Vague statements without an actionable scenario remain insufficient.
- Clearly non-English steps are not treated as missing; reproduction is
reassessed after the author translates the issue.
### Language rule
- Classifies author-written prose as English, non-English, or uncertain.
- Ignores template headings, code, logs, filenames, URLs, hidden
comments, and
quoted text.
- Clearly non-English issues ask the author to translate the title and
description to English.
- Short, mixed, code-heavy, or uncertain text is not flagged.
### Diagnostic report rule
- A report is **required** for diagnostic-heavy failures: crashes,
hangs,
startup/load failures, installation/update failures, performance
failures,
and service/driver/shell-integration failures.
- A report is **optional** for clear reproducible UI/visual defects.
- A report is **recommended**, but not blocking, for other actionable
bugs.
- Missing or rejected reports block only when the deterministic
requirement is
`REQUIRED`.
### Diagnostic report privacy and safety
- Accepts only PowerToys report attachment URLs matching the expected
pattern.
- Enforces archive size, decompressed size, file-count, per-file, path
traversal, and encryption limits.
- Selects only bounded relevant metadata and product-log evidence.
- Redacts email addresses, IP addresses, user paths, URLs, GUIDs, SIDs,
identity fields, tokens, secrets, and passwords.
- Sends only the sanitized evidence to Copilot.
- Never sends the raw ZIP or extracted files to Copilot, logs,
artifacts, or
repository storage.
- Deletes the temporary archive after processing.
### Duplicate rule
- Searches only older issues using focused product, title/body, and
exact
technical-signal queries.
- Ranks candidates deterministically before Copilot runs.
- Copilot judges only the supplied candidates and returns at most five
high-confidence matches.
- Similar product area alone is not enough; the underlying request or
failure
must match.
- The model never closes an issue directly.
- The workflow submits the strongest match as a native GitHub
duplicate-close
suggestion.
- **When a maintainer accepts the suggestion, GitHub automatically
closes the
issue as a duplicate and links it to the selected canonical issue.**
- Declining the suggestion leaves the issue open.
- A defensive safeguard reopens the issue and fails the run if GitHub
applies
the close without holding it for review.
### AI cost and permission controls
- Uses the `small` model alias.
- Maximum 5 turns and 10 AI credits per run.
- Maximum 300 AI credits per day.
- Maximum 5 runs per user per 60-minute window.
- Content hashing skips unchanged work before inference.
- The agent receives only `contents: read`, `issues: read`, and
`copilot-requests: write`.
- A separate validated safe-output job receives `issues: write`.
## Seven-day author-feedback lifecycle
The existing Microsoft GitHub Policy Service configuration remains
responsible
for stale closure:
- Open issues with `Needs-Author-Feedback` and no activity for 7 days
are
closed with an explanatory comment.
- Open PRs with `Needs-Author-Feedback` and no activity for 7 days are
closed
with an explanatory comment.
- An author comment removes `Needs-Author-Feedback` and returns the
issue/PR to
team triage.
- An author push removes `Needs-Author-Feedback` from a PR.
- Manually removing the label immediately makes the issue or PR
ineligible for
scheduled closure.
## Deprecated automation
- Deletes `.github/workflows/automatic-issue-deduplication.yml`.
- Deletes `.github/workflows/auto-labeler.yml`.
- Automatic PR product labeling from the old Models workflow is
intentionally
not replaced in this PR; a production PR ownership/path map should be
agreed
separately.
- Keeps the manual batch deduplication workflow unchanged.
- Removes the passive XAML Styler verification step from
`.pipelines/v2/templates/job-build-project.yml`.
- Keeps `.pipelines/applyXamlStyling.ps1` available for local developer
use.
## Validation Steps Performed
- Compiled `.github/workflows/issue-triage.md` with `gh aw compile`.
- Ran 32 focused Python tests for issue parsing, duplicate retrieval,
version
checks, reproduction rules, language signals, archive validation, report
selection, redaction, and output privacy.
- Parsed the changed workflow and resource-management YAML.
- Verified the required production labels exist.
- Tested the workflow against the latest 20 PowerToys issues in the
sandbox;
all 20 produced one canonical comment.
- Verified live variants for outdated versions, intermittent/passive
reproduction, non-English issues, rejected and analyzed reports,
optional UI
reports, and title-only issues.
## PR Checklist
- [ ] **Communication:** Discussed with core contributors.
- [x] **Tests:** Added/updated and all focused tests pass.
- [ ] **Privacy / Responsible AI:** Complete required production reviews
before
enabling.
- [x] **Localization:** No product UI strings are added.
- [x] **Dev docs:** Updated repository automation documentation.
- [x] **New binaries:** None.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18a9b8ad-fd7e-4b9d-a06c-5e350bcde9d7
Copilot-Session: fd512b9b-db6f-4004-a65b-aa49404d568d
## Summary
Adds fabricbot rules to manage the `Needs-Author-Feedback` label
lifecycle for **pull requests**, complementing the existing issue
management rules in `resourceManagement.yml`.
This is a **simpler alternative** to the GitHub Actions workflow
approach (PR #48812), trading advanced features (draft conversion,
author-specific activity tracking) for zero-maintenance fabricbot
automation.
## Behavior
### Flow diagram
```
┌──────────────────────────────────────────────────────────────────────┐
│ Maintainer adds "Needs-Author-Feedback" label to a PR │
└──────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐ ┌──────────────────────────────────┐
│ 7 days, no activity │────►│ Add "Status-No recent activity" │
│ │ │ + post warning comment │
└─────────────────────────────────────┘ └──────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────┐ ┌──────────────────────────────────┐
│ 7 more days (14 total), no activity│────►│ Close PR + post closing comment │
└─────────────────────────────────────┘ └──────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ Author pushes commits OR comments on PR (at any point) │
└──────────────────────────────────────────────────────────────────────┘
│
▼
Remove "Needs-Author-Feedback" → Add "Needs-Triage"
Remove "Status-No recent activity" (if present)
```
### Scheduled searches (every 6 hours)
| Condition | Action |
|-----------|--------|
| PR + `Needs-Author-Feedback` + 7 days inactive + no `Status-No recent
activity` | Add `Status-No recent activity` label + warning comment |
| PR + `Needs-Author-Feedback` + `Status-No recent activity` + 7 more
days inactive | Post closing comment + close PR |
### Event responders
| Trigger | Action |
|---------|--------|
| Author comments on PR (`Issue_Comment` + `issueAuthor`) | Remove
`Needs-Author-Feedback`, add `Needs-Triage` + `Needs-Team-Response` |
| Author pushes commits (`Pull_Request` + `Synchronize` + `issueAuthor`)
| Remove `Needs-Author-Feedback`, add `Needs-Triage` |
| Any PR update activity | Remove `Status-No recent activity` |
### Bot messages
**Warning (at 7 days):**
> This pull request has been automatically marked as stale because it
has been marked as requiring author feedback but has not had any
activity for **7 days**. It will be closed if no further activity occurs
**within 7 days of this comment**. To keep this PR active, please push
your changes or leave a comment.
**Closing (at 14 days):**
> This pull request has been automatically closed because it has been
marked as requiring author feedback but has not had any activity for
**14 days**. If you would like to continue working on this, please
reopen the PR and push your changes.
## Comparison with GitHub Actions workflow (PR #48812)
| Feature | This PR (fabricbot) | PR #48812 (Actions) |
|---------|-------------------|-------------------|
| Convert to draft at 7 days | ❌ Not supported | ✅ Via GraphQL |
| Close at 14 days | ✅ | ✅ |
| Author-specific activity tracking | ❌ Any activity resets timer | ✅
Only author activity counts |
| Bot comment resets timer | ⚠️ Yes (fabricbot limitation) | ✅ No
(filtered out) |
| Maintenance burden | None (fabricbot managed) | Low (workflow file) |
| Testing before merge | ❌ No local testing | ✅ `workflow_dispatch` +
dry-run |
| Review comment detection | ❌ Only issue comments | ✅ Reviews + inline
comments |
## Trade-offs
**Pros:**
- Zero maintenance — fabricbot is a managed service
- Consistent with existing issue management patterns in the same file
- No workflow YAML to debug or maintain
**Cons:**
- No draft conversion (fabricbot cannot call GraphQL)
- `noActivitySince` counts **all** activity — bot comments, maintainer
comments, and label changes all reset the inactivity timer
- Cannot distinguish author activity from other activity
- No way to test locally or with dry-run before merge
## Relationship to existing automation
Mirrors the existing issue rules (lines 11-43) which use the same
pattern:
- Issues: 5 days → warning, 5 more days → close
- PRs (this change): 7 days → warning, 7 more days → close
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reopens the change from #46743 (which appears to be broken) on a fresh
branch.
Original author: @daverayment
## Summary
GitHub newcomers can be confused by the current duplicate resolution
message, as it doesn't clearly point to the original referenced issue -
see
https://github.com/microsoft/PowerToys/issues/46347#issuecomment-4103681050.
They may not realise that the #12345 in the duplicate comment is the
relevant link.
This small wording update to the duplicate resolution message tightens
up wording slightly and includes reference to the prior `/dup #nnn`
comment so newcomers don't miss it.
### Before
> Hi! We've identified this issue as a duplicate of another one that
already exists on this Issue Tracker. This specific instance is being
closed in favor of tracking the concern over on the referenced thread.
Thanks for your report!
### After
> We've identified this issue as a duplicate of an existing one and are
closing this thread so discussion stays in one place.<br/><br/>Please
see the comment above for the link to the original tracking issue, and
feel free to subscribe there for updates.
## Validation Steps Performed
N/A - bot reply text change only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary
Adds a GitHub Action workflow that **automatically applies `Product-*`
labels** to issues, reducing manual triage effort.
### How it works
**Two-tier approach:**
1. **Deterministic mapping** — Parses the structured "Area(s) with
issue?" dropdown from bug report templates and maps selections to the
correct `Product-` label via a hardcoded lookup table.
2. **AI inference (Copilot fallback)** — When no product is resolved
from the structured field (e.g., feature requests without the area
field), calls GitHub Models API (`gpt-4.1-mini`) to infer the product
from issue title + body.
### Trigger modes
| Trigger | Use case |
|---------|----------|
| `issues: [opened]` | Auto-labels every new issue |
| `workflow_dispatch` (single) | Test on one specific issue with dry-run
|
| `workflow_dispatch` (batch) | Process all open issues missing Product-
labels |
### Safety features
- **Label validation** — checks each label exists in the repo before
applying
- **Dry-run mode** — logs what would happen without modifying issues
- **Concurrency control** — prevents duplicate runs
- **Conservative AI prompt** — only labels products the issue is
*primarily* about
### Testing performed
Tested locally against 10 real issues with `Needs-Triage` and no
`Product-*` label:
- **6/10 resolved deterministically** (correct labels applied via `gh
issue edit`)
- **4/10 tested AI inference** via GitHub Models API:
- #47482 (CmdPal Dock) → `Product-Command Palette` ✅
- #47474 (grab and move + fancy zones) → `Product-FancyZones` ✅
- #47476 (modular download) → `[]` (correctly abstained) ✅
- #47478 (Quick Access pinning) → improved prompt to avoid over-labeling
### Files changed
| File | Purpose |
|------|---------|
| `.github/workflows/auto-label-product.yml` | The GitHub Action |
| `.github/policies/resourceManagement.yml` | Removed redundant
Workspaces-only regex rule |
| `tools/Test-AutoLabelProduct.ps1` | Local PowerShell test script for
dry-run testing |
### Mapping validated against actual repo labels
Confirmed all label names in the mapping exist in the repo via `gh label
list --search "Product-"`.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [ ] Closes: #xxx
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed