Skip to content

Commit 5fb67a0

Browse files
authored
Enhance triage skills with updated scoring (#6294)
* Update Generate-FeatureAreaReport.ps1 to only search for area-* feature areas * Add Validate-FeatureAreaReport.ps1 to issue-triage-report skill * Enhance triage skills with updated scoring, confidence, and P-scale labels Scoring System: - New weights: reactions=30%, age=30%, comments=30%, severity=10% - P-scale severity labels: P0=critical, P1=high, P2=medium, P3=low - Confidence scoring with grep-friendly [confidence:XX] format (0-100) Label Consolidation: - Merged Hot + Popular into Popular (>=5 reactions threshold) Contact Schema: - Simplified from {primary, secondary} to single {contact} field - Removed legacy schema backward compatibility Area Suggestions: - Get-IssueDetails.ps1 dynamically fetches area labels via Get-RepositoryLabels.ps1 - area-Notifications covers all notification types (toast, badge, push, wns) - Fixed area-PowerManagement naming Documentation: - Added PowerShell examples alongside Bash for confidence filtering - Updated all SKILL.md files with new configuration details * Revert trending criteria to include recency as a scoring factor * Remove copy of ScoringConfig.json in favor of the filepath * ReportLib.ps1: Remove defaults in Get-ScoringConfig and rely on ScoringConfig.json * ReportLib.ps1: Remove defaults in Get-IssueScore and rely on ScoringConfig.json for severity labels * ReportLib.ps1: Update Get-AreaContacts to rely on area-contacts.json, fails fast on errors * GetHighlightScore.ps1: Use Get-Issue score for calculation. Let this script handle human-readable formatting * ReportLib.ps1: Remove unused thresholds assignment from Get-IssueScore * Skills: updates the label fetching code so Get-RepositoryLabels.ps1 is the source of truth * Create area-keywords.json * Update Get-IssueDetails.ps1 to reference area labels json * Enforce trending_days recency check for Trending highlight label - Add RawUpdateAgeDays to Get-IssueScore (computed from updatedAt) - Require comments >= trending_comments AND updated within trending_days in both Get-HighlightLabels (ReportLib) and Get-DetailedIssueScore - Fix scoring-algorithm.md: comments >= 5 -> >= 10, add trending_days to highlight table and thresholds reference - Add missing trending_days to SKILL.md config example * Update scoring-algorithm.md to walk through scripts and config files * Remove sample json with hardcoded weight values * Correct Validate-FeatureAreaReport.ps1 to use PSScriptRoot instead of System.Management.Automation.InvocationInfo.MyCommand.Path * Remove security label from issue-triage-report skill * Remove keyword classification on area labels and replace with agent instructions * Clean up block word matching in ReportLib.ps1 * Convert script-based confidence scoring in issue-triage-report skill to LLM based confidence scoring (what we originally intended) * Update Get-AreaContacts.ps1 and ReportLib.ps1 to use the contacts/notes schema * Move severity and blocker determination to agent SKILL.md instead of PowerShell script * Add agent assessments for severity and blockers * Remove bucket scoring * Scale weights to percentages and use double loading for point values * Replace outdated severity labels with severity multipliers * Update docs to reflect recent scoring changes * Have human-edited IssueAssesments.json take scoring priority * Fix indentation typo in SKILL.md for issue-triage-report * Minor corrections in SKILL.md and scoring-algorithm.md * Remove labelPriority * Bringing back scores between 0 to 100 * Condense ReadAgentAssessments and ReadIssueAssessments into one ReadAssessments file * Condense Get-AgentAssessmentsPath and Get-IssueAssessmentsPath into one Get-AssessmentsPath file * Remove unused Test-HasLabelMatching * Add Get-IssueScore docs * Move Get-DetailedIssueScore into ReportLib.ps1 * Update Scoring Results section of scoring-algorithm.md * Actually consolidate Read-IssueAssessments and Read-AgentAssessments into ReadAssessments in ReportLib.ps1 * Add instructions to persistent reasoning to files in SKILL.md
1 parent 46b472b commit 5fb67a0

15 files changed

Lines changed: 1268 additions & 621 deletions

.github/skills/issue-triage-report/SKILL.md

Lines changed: 125 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This skill generates comprehensive GitHub Feature Area Status reports that help
1414

1515
1. **Engineering triage meetings** — Create status reports showing open issues, needs-triage counts, and highlighted issues per feature area.
1616

17-
2. **Priority analysis requests** — Identify which issues should get engineering focus based on multi-factor scoring (reactions, age, severity, blockers).
17+
2. **Priority analysis requests** — Identify which issues should get engineering focus based on deterministic scoring (reactions, age, comments) plus agent content assessment.
1818

1919
3. **Feature area health checks** — Assess the health of specific areas by analyzing issue distribution, triage backlog, and proposal counts.
2020

@@ -46,25 +46,7 @@ The area contacts file maps feature areas to team members. This file is **requir
4646
cp .github/skills/issue-triage-report/references/area-contacts.json .user/issue-triage-report/area-contacts.json
4747
```
4848

49-
3. Edit `.user/issue-triage-report/area-contacts.json` with your team's actual contacts:
50-
```json
51-
{
52-
"areaContacts": {
53-
"area-FeatureName": {
54-
"primary": "Primary Contact Name",
55-
"secondary": "Secondary Contact or null",
56-
"notes": "Optional notes"
57-
}
58-
},
59-
"specialAreas": {
60-
"triageOnly": ["area-TriageOnlyExample"],
61-
"crossFunctional": {
62-
"area-CrossTeam": "org/related-repo"
63-
}
64-
},
65-
"lastUpdated": "YYYY-MM"
66-
}
67-
```
49+
3. Edit `.user/issue-triage-report/area-contacts.json` with your team's actual contacts
6850

6951
> **Note**: The `.user/` folder is gitignored, so your team contacts remain private.
7052
@@ -146,16 +128,42 @@ Retrieve or update the area-to-contact mapping configuration.
146128
./scripts/Generate-FeatureAreaReport.ps1 -OutputFormat markdown -HighlightCount 3
147129
```
148130

149-
3. Review highlighted issues and their scores
131+
Before running the command above, have the agent save runtime assessments to:
132+
- `./references/AgentAssessments.json`
133+
134+
This file is loaded automatically at script start and applied as per-run overrides.
135+
Every assessed issue entry must include agent reasoning in the `reasoning` field.
136+
137+
Required per-issue schema in `assessments`:
138+
- `severityTier`: `critical|high|medium|low|none`
139+
- `isBlocker`: `true|false`
140+
- `reasoning`: short rationale explaining severity/blocker judgment
141+
142+
Example:
143+
```json
144+
{
145+
"assessments": {
146+
"2894": {
147+
"severityTier": "high",
148+
"isBlocker": false,
149+
"reasoning": "Frequent user impact in notifications flow; clear repro in comments; no confirmed workaround."
150+
}
151+
}
152+
}
153+
```
154+
155+
3. Run an agent content review for each highlighted issue using title, body, labels, and comments.
150156

151-
4. Copy output to team communication channel (Teams, email, wiki)
157+
4. Add annotation tags in report narrative: `[severity:critical|high|medium|low|none]`, `[blocker:yes|no]`, and optional `[confidence:XX]`.
158+
159+
5. Copy output to team communication channel (Teams, email, wiki)
152160

153161
### Workflow 2: Analyze a Specific Feature Area
154162

155163
1. Get area-specific issues:
156-
```powershell
157-
gh issue list --repo microsoft/WindowsAppSDK --label "area-Notification" --state open --json number,title,labels,reactionGroups,createdAt,comments
158-
```
164+
```powershell
165+
gh issue list --repo microsoft/WindowsAppSDK --label "area-Notifications" --state open --json number,title,body,labels,reactionGroups,createdAt,comments
166+
```
159167
160168
2. Check individual issue scores:
161169
```powershell
@@ -173,35 +181,93 @@ Retrieve or update the area-to-contact mapping configuration.
173181

174182
2. Update specific area contact:
175183
```powershell
176-
./scripts/Get-AreaContacts.ps1 -Area "area-Notification" -Update
184+
./scripts/Get-AreaContacts.ps1 -Area "area-Notifications" -Update
177185
```
178186

179187
## Highlight Scoring Algorithm
180188

181-
Issues are scored (0-100) based on multiple factors. See [scoring-algorithm.md](./references/scoring-algorithm.md) for complete details.
189+
Issues are scored with a normalized composite on a `0..100` scale. See [scoring-algorithm.md](./references/scoring-algorithm.md) for complete details.
190+
191+
PowerShell computes deterministic score factors and highlight labels. Severity and blocker are assessment-driven inputs.
192+
193+
Scripts load baseline assessments from:
194+
195+
- `./references/IssueAssessments.json`
196+
197+
They also load runtime agent assessments from:
198+
199+
- `./references/AgentAssessments.json`
200+
201+
If both files include the same issue number, `IssueAssessments.json` takes precedence.
202+
203+
If either file is missing or malformed, scripts emit status/warning output and continue with fallback behavior.
204+
205+
Implementation note: scripts load these files through a single `Read-Assessments` function in `./scripts/ReportLib.ps1` using `-AssessmentType Issue` or `-AssessmentType Agent`.
206+
207+
## Agent Content Review
208+
209+
After generating scores, review each highlighted issue and assign these annotations based on title, body, labels, and comments:
210+
211+
- `[severity:critical|high|medium|low|none]`
212+
- `[blocker:yes|no]`
213+
- `[confidence:XX]`
214+
215+
After assigning annotations, persist the same decision to `./references/AgentAssessments.json` and include `reasoning` for every updated issue entry.
216+
217+
Use this severity rubric:
218+
219+
| Tier | Meaning |
220+
|------|---------|
221+
| `critical` | Crash, data loss, severe regression, or broad user/system impact |
222+
| `high` | Serious functional break affecting key workflows |
223+
| `medium` | User-visible defect or limitation with practical workaround |
224+
| `low` | Minor issue, edge case, docs/polish impact |
225+
| `none` | No clear severity signal from issue content |
226+
227+
Mark `[blocker:yes]` only when issue content explicitly indicates dependency blocking (for example: "blocked by", "blocking release", "must be fixed before") and no workaround has been provided. Otherwise use `[blocker:no]`.
228+
229+
Use this confidence rubric:
230+
231+
| Score | Level | Meaning |
232+
|-------|-------|---------|
233+
| **80-100** | High | Multiple strong signals agree: issue content, labels, reactions, age, comments, and recent discussion all support highlighting it |
234+
| **60-79** | Medium-High | Strong support from the score breakdown and issue details, with only minor ambiguity |
235+
| **40-59** | Medium | Reasonable highlight candidate, but some evidence is weak, stale, or mixed |
236+
| **20-39** | Low | The numeric score is carrying most of the case; supporting context is limited or ambiguous |
237+
| **0-19** | Very Low | The issue surfaced mechanically, but the agent cannot defend highlighting it with the available evidence |
238+
239+
Confidence should consider:
240+
241+
- whether the issue body and comments clearly support the highlight label
242+
- whether the numeric score is driven by multiple meaningful factors instead of one outlier
243+
- whether the issue still appears relevant after reading recent discussion
244+
- whether the highlight reason would be easy to defend in a triage meeting
182245

183246
### Quick Reference: Score Factors
184247

185-
| Factor | Weight | Description |
248+
| Factor | Weight (between 0 and 1) | Description |
186249
|--------|--------|-------------|
187-
| **Reactions** | 30 | Total reactions (👍, ❤️, 🚀, etc.) indicate community interest |
188-
| **Age** | 25 | Older untriaged issues get higher priority |
189-
| **Comments** | 20 | Active discussion indicates importance |
190-
| **Severity** | 15 | Labels like `bug`, `regression`, `crash` increase score |
191-
| **Blockers** | 10 | Issues blocking other work get prioritized |
250+
| **Reactions** | `weights.reactions` | `round(min(1, totalReactions / rankingCeilings.reactions) * weight * 100, 1)` |
251+
| **Age** | `weights.age` | `round(min(1, issueAgeDays / rankingCeilings.ageDays) * weight * 100, 1)` |
252+
| **Comments** | `weights.comments` | `round(min(1, commentCount / rankingCeilings.comments) * weight * 100, 1)` |
253+
| **Severity** | `weights.severity` | `round(weight * severityMultipliers[tier] * 100, 1)` from assessments (`critical/high/medium/low/none`) |
254+
| **Blockers** | `weights.blockers` | Adds `round(weight * 100, 1)` when assessed `isBlocker=true` |
255+
256+
`Total = min(100, round(sum of factor points, 1))`.
257+
258+
`rankingCeilings` are independent per-factor scales and do not need to sum to any target.
259+
260+
`recommendationBands` are fixed score-ratio boundaries (`high`, `medium`, `normal`) used to classify recommendations. They are ratio cutoffs, not statistical percentiles.
192261

193262
### Highlight Labels (Output)
194263

195264
The report adds reason labels to highlighted issues:
196265

197266
| Label | Meaning |
198267
|-------|---------|
199-
| `🔥 Hot` | High reaction count (community demand) |
268+
| `🌟 Popular` | High reaction count (≥5 reactions) |
200269
| `⏰ Aging` | Open > 90 days without triage |
201-
| `🐛 Regression` | Marked as regression or recent breakage |
202-
| `🚧 Blocker` | Blocking other issues or teams |
203-
| `📈 Trending` | High comment activity recently |
204-
| ` Popular` | Feature proposal with significant support |
270+
| `📈 Trending` | High comment activity (≥10 comments) |
205271

206272
## Report Output Format
207273

@@ -210,44 +276,39 @@ The report adds reason labels to highlighted issues:
210276
```markdown
211277
| Feature Area | Area Contact | Open | Triage | Proposals | Closed | Highlights |
212278
|--------------|--------------|------|--------|-----------|--------|------------|
213-
| area-Notification | Notifications Owner | 34 | 8 | 11 | 0 | 🔥 [#2894](link) Hot, ⏰ [#3001](link) Aging |
214-
| area-Widgets | Widgets Owner | 21 | 10 | 4 | 0 | 📈 [#3958](link) Trending |
279+
| area-Notification | Contact Name | 34 | 8 | 11 | 0 | 🌟 [#2894](link), ⏰ [#3001](link) |
280+
| area-Widgets | Contact Name | 21 | 10 | 4 | 0 | 📈 [#3958](link) |
281+
```
282+
283+
### Agent-Reviewed Output
284+
285+
When producing the final narrative report, the agent should append content-review annotations:
286+
287+
```markdown
288+
| Feature Area | Area Contact | Open | Triage | Proposals | Closed | Highlights |
289+
|--------------|--------------|------|--------|-----------|--------|------------|
290+
| area-Notification | Contact Name | 34 | 8 | 11 | 0 | 🌟 [#2894](link) [severity:high] [blocker:no] [confidence:85], ⏰ [#3001](link) [severity:medium] [blocker:no] [confidence:72] |
291+
| area-Widgets | Contact Name | 21 | 10 | 4 | 0 | 📈 [#3958](link) [severity:low] [blocker:no] [confidence:68] |
215292
```
216293

217294
### Special Status Indicators
218295

219296
| Indicator | Meaning |
220297
|-----------|---------|
221298
| `0️⃣🐛🥳` | Zero bugs — celebrate! |
222-
| `🆕` | New area (no historical data) |
223299
| `-` | Data not applicable or unavailable |
224300

225301
## Configuration
226302

227303
### Area Contacts
228304

229-
Contact mappings are stored in [area-contacts.md](./references/area-contacts.md). Update this file when team assignments change.
305+
Contact mappings are stored in [area-contacts.json](./references/area-contacts.json). Update this file when team assignments change.
230306

231307
### Custom Scoring Weights
232308

233-
Modify scoring weights in `./scripts/ScoringConfig.json`:
234-
235-
```json
236-
{
237-
"weights": {
238-
"reactions": 30,
239-
"age": 25,
240-
"comments": 20,
241-
"severity": 15,
242-
"blockers": 10
243-
},
244-
"thresholds": {
245-
"hot_reactions": 10,
246-
"aging_days": 90,
247-
"trending_comments": 5
248-
}
249-
}
250-
```
309+
Modify scoring weights in `./scripts/ScoringConfig.json`.
310+
311+
`severityMultipliers` maps assessment tiers to the percentage of `weights.severity` that is applied.
251312

252313
## Troubleshooting
253314

@@ -257,13 +318,13 @@ Modify scoring weights in `./scripts/ScoringConfig.json`:
257318
| `authentication required` | Run `gh auth login` and follow prompts |
258319
| Rate limit exceeded | Wait or use `--limit` to reduce API calls |
259320
| Missing area label | Issue may use non-standard label; check label list |
260-
| Contact not found | Update [area-contacts.md](./references/area-contacts.md) |
321+
| Contact not found | Update [area-contacts.json](./references/area-contacts.json) |
261322

262323
## Common Commands Reference
263324

264325
```powershell
265-
# List all area labels
266-
gh label list --repo microsoft/WindowsAppSDK --search "area-" --json name
326+
# List all area labels (uses Get-RepositoryLabels.ps1 as the single source of truth)
327+
./.github/skills/triage-meeting-prep/scripts/Get-RepositoryLabels.ps1 -Filter "area-*" -OutputFormat table
267328
268329
# Get issue details with reactions
269330
gh issue view 4651 --repo microsoft/WindowsAppSDK --json number,title,labels,reactionGroups,createdAt,comments,author
@@ -278,5 +339,5 @@ gh issue list --repo microsoft/WindowsAppSDK --state open --limit 1000 --json nu
278339
## References
279340

280341
- [Scoring Algorithm Details](./references/scoring-algorithm.md) — Complete scoring methodology
281-
- [Area Contacts](./references/area-contacts.md) — Feature area ownership mapping
342+
- [Area Contacts](./references/area-contacts.json) — Feature area ownership mapping
282343
- [Report Template](./templates/report-template.md) — Customizable output template
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"assessments": {},
3+
"generatedAt": "2026-04-14T00:00:00Z",
4+
"assessedBy": "Copilot"
5+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"assessments": {
3+
"1234": {
4+
"severityTier": "high",
5+
"isBlocker": false,
6+
"reasoning": "Example entry. Update for your triage run."
7+
}
8+
},
9+
"generatedAt": "2026-04-14T00:00:00Z",
10+
"assessedBy": "Copilot"
11+
}

.github/skills/issue-triage-report/references/area-contacts.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"$schema": "https://json-schema.org/draft/2020-12/schema",
33
"$comment": "Area contacts configuration. Create your own copy at .user/issue-triage-report/area-contacts.json with actual team contacts.",
44
"areaContacts": {
5-
"area-ExampleFeature": { "primary": "Primary Contact Name", "secondary": null },
6-
"area-AnotherFeature": { "primary": "Primary Contact", "secondary": "Secondary Contact" },
7-
"area-FeatureWithNotes": { "primary": "Contact Name", "secondary": null, "notes": "Special handling notes" }
5+
"area-ExampleFeature": { "contact": "Contact Name" },
6+
"area-AnotherFeature": { "contact": "Contact Name", "notes": "Optional notes about this area" },
7+
"area-FeatureWithNotes": { "contact": "Contact Name", "notes": "Special handling notes" }
88
},
99
"specialAreas": {
1010
"triageOnly": ["area-TriageOnlyExample"],
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"title": "IssueAssessments",
4+
"type": "object",
5+
"additionalProperties": false,
6+
"properties": {
7+
"assessments": {
8+
"type": "object",
9+
"description": "Issue-number keyed assessments. Keys are issue numbers as strings.",
10+
"additionalProperties": {
11+
"type": "object",
12+
"additionalProperties": false,
13+
"properties": {
14+
"severityTier": {
15+
"type": "string",
16+
"enum": ["critical", "high", "medium", "low", "none"],
17+
"description": "Optional. Empty or missing value falls back to default behavior."
18+
},
19+
"isBlocker": {
20+
"type": "boolean",
21+
"description": "Optional. Empty or missing value falls back to default behavior."
22+
},
23+
"reasoning": {
24+
"type": "string",
25+
"description": "Optional human or agent notes."
26+
}
27+
}
28+
}
29+
},
30+
"generatedAt": {
31+
"type": "string",
32+
"description": "Optional ISO-8601 timestamp."
33+
},
34+
"assessedBy": {
35+
"type": "string",
36+
"description": "Optional source marker, e.g. Copilot or human alias."
37+
}
38+
},
39+
"required": ["assessments"]
40+
}

0 commit comments

Comments
 (0)