Skip to content

Commit dc14609

Browse files
authored
feat: pre-flight PR deduplication protocol to cut Copilot retry waste (#28843)
1 parent 885ab32 commit dc14609

4 files changed

Lines changed: 151 additions & 26 deletions

File tree

.github/agents/developer.instructions.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ This document consolidates development guidelines, architectural patterns, and i
2222
- [Hierarchical Agent Management](#hierarchical-agent-management)
2323
- [Release Management](#release-management)
2424
- [Scope Hints for Complex Workflows](#scope-hints-for-complex-workflows)
25+
- [PR Deduplication Protocol](#pr-deduplication-protocol)
2526
- [Quick Reference](#quick-reference)
2627

2728
---
@@ -700,7 +701,63 @@ Before submitting a complex workflow request, confirm you have specified:
700701
701702
---
702703
703-
## Quick Reference
704+
## PR Deduplication Protocol
705+
706+
Repeated closed PR attempts on the same topic waste CI resources and agent context. Follow this protocol every time you are about to create a pull request.
707+
708+
### Pre-flight Duplicate PR Check
709+
710+
Before opening a PR, search for existing closed PRs with a similar topic using the GitHub MCP `search_pull_requests` tool:
711+
712+
1. Extract 2–4 keywords from the feature/fix title.
713+
2. Run a search such as:
714+
- `is:pr is:closed head:copilot/ <keywords>`
715+
- `is:pr is:closed <keywords>`
716+
3. If **no** closed PR is found, proceed normally.
717+
4. If **one or more** closed PRs are found, move to the [Prior Failure Analysis](#prior-failure-analysis) step before writing any code.
718+
719+
### Prior Failure Analysis
720+
721+
When a closed PR exists on the same topic, perform this analysis at the start of the session — before any code exploration or implementation:
722+
723+
1. Read the closed PR description, review comments, and timeline.
724+
2. Identify the **root cause of closure**:
725+
- Reviewer requested changes → list them explicitly
726+
- CI/test failures → identify failing checks and root cause
727+
- Scope mismatch → clarify what was actually requested
728+
- Duplicate of another fix → link to that fix
729+
3. Verify that the root cause will be addressed in the new implementation.
730+
4. Include a "## Prior Attempts" section in the new PR description that summarizes:
731+
- Link(s) to prior closed PR(s)
732+
- Why each was closed
733+
- What is different this time
734+
735+
**Example PR description section:**
736+
737+
```markdown
738+
## Prior Attempts
739+
740+
- #1234 (closed): CI failed on `TestFoo` due to missing nil check — fixed in this PR
741+
- #1189 (closed): Reviewer requested scope reduction — this PR limits change to X only
742+
```
743+
744+
### Retry Limit Circuit Breaker
745+
746+
If **two or more** closed PRs already exist on the same topic:
747+
748+
1. **Do not open a third PR** without explicit human review.
749+
2. Post a comment on the originating issue that:
750+
- Lists all prior closed PRs and their close reasons
751+
- Explains what changed (if anything) in the new approach
752+
- Requests explicit maintainer approval to proceed
753+
3. Label the issue `copilot-retry-blocked` to signal that human review is required.
754+
4. Wait for a maintainer to remove the label or leave an approving comment before creating the new PR.
755+
756+
**Rationale:** Two consecutive failed PR attempts indicate a systemic problem (unclear requirements, missing context, fundamental design issue) that code changes alone cannot resolve.
757+
758+
---
759+
760+
704761

705762
### File Locations
706763

@@ -792,4 +849,4 @@ For detailed specifications, see individual files in `scratchpad/`:
792849

793850
---
794851

795-
**Last Updated**: 2026-01-31
852+
**Last Updated**: 2026-04-28

.github/workflows/copilot-opt.lock.yml

Lines changed: 15 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/copilot-opt.md

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ safe-outputs:
3434
max: 3
3535
labels: [copilot-opt, optimization, cookie]
3636
title-prefix: "[copilot-opt] "
37+
close-older-issues: true
3738
imports:
3839
- shared/jqschema.md
3940
- shared/copilot-session-data-fetch.md
@@ -59,7 +60,7 @@ Pre-fetched data is available from shared imports:
5960

6061
- `/tmp/gh-aw/session-data/sessions-list.json`
6162
- `/tmp/gh-aw/session-data/logs/` (conversation logs and/or fallback logs)
62-
- `/tmp/gh-aw/pr-data/copilot-prs.json` (optional cross-analysis source)
63+
- `/tmp/gh-aw/pr-data/copilot-prs.json` (cross-analysis source — always present)
6364

6465
These paths are populated by imported setup components:
6566
- `shared/copilot-session-data-fetch.md` writes the session files under `/tmp/gh-aw/session-data/`
@@ -77,12 +78,13 @@ These paths are populated by imported setup components:
7778
- large initial instruction/context payload
7879
- inefficient orchestration/model-loading patterns
7980
- prompt drift / instruction adherence degradation
80-
4. Optionally correlate findings with Copilot PR patterns from `/tmp/gh-aw/pr-data/copilot-prs.json` when useful.
81-
5. Generate **exactly three** recommendations:
81+
4. **Always** correlate findings with Copilot PR patterns from `/tmp/gh-aw/pr-data/copilot-prs.json`.
82+
5. **Always** perform duplicate PR pattern detection (see Phase 3) and surface retry-blocked topics.
83+
6. Generate **exactly three** recommendations:
8284
- each recommendation must target a distinct root cause
8385
- each recommendation must be concrete and actionable
8486
- each recommendation must include expected impact
85-
6. Create **exactly three GitHub issues** (one per recommendation).
87+
7. Create **exactly three GitHub issues** (one per recommendation).
8688

8789
If data is incomplete, proceed with available evidence and clearly state data quality limitations.
8890

@@ -127,15 +129,53 @@ For each session summary:
127129

128130
Aggregate across all sessions to identify recurring systemic patterns.
129131

130-
## Phase 3 — Optional PR Cross-Analysis
132+
## Phase 3 — PR Cross-Analysis and Duplicate Pattern Detection
131133

132-
If `/tmp/gh-aw/pr-data/copilot-prs.json` is present and non-empty:
134+
This phase is **mandatory**. `/tmp/gh-aw/pr-data/copilot-prs.json` is always present from the imported `shared/copilot-pr-data-fetch.md` step.
135+
136+
### 3a — General PR Failure Signals
133137

134138
1. Extract recurring failure/friction signals from recent Copilot PRs.
135-
2. Correlate with session-derived patterns.
139+
2. Correlate with session-derived patterns from Phase 2.
136140
3. Increase priority for overlapping problem areas.
137141

138-
If PR data is unavailable, continue without this phase and note that in evidence.
142+
### 3b — Duplicate PR Pattern Detection
143+
144+
Identify topics where Copilot PRs were closed without merging and then re-attempted. This is the costliest waste pattern because each retry consumes a full agent session.
145+
146+
**Detection procedure:**
147+
148+
```bash
149+
# Find closed (not merged) PRs grouped by normalized title
150+
jq '[.[] | select(.state == "CLOSED" and .mergedAt == null)]
151+
| group_by(.title)
152+
| map({title: .[0].title, count: length, prs: [.[] | {number, url, closedAt}]})
153+
| map(select(.count >= 2))
154+
| sort_by(-.count)' /tmp/gh-aw/pr-data/copilot-prs.json
155+
```
156+
157+
For each topic with **two or more** closed-without-merge PRs (retry-blocked topics):
158+
159+
1. Record the PR numbers, titles, and close dates.
160+
2. Use the GitHub MCP `get_pull_request` or `search_pull_requests` tool to read the most recent closed PR and identify the close reason (review comments, CI failures, or reviewer request).
161+
3. Classify the close reason into one of:
162+
- `ci-failure` — tests or lint failed
163+
- `reviewer-rejected` — maintainer closed without merging and left a reason
164+
- `scope-mismatch` — implementation did not match what was requested
165+
- `duplicate` — a separate fix was merged that covers the same change
166+
- `unknown` — no clear close reason found
167+
4. Build a **retry-blocked topics table**:
168+
169+
| Topic (PR title keywords) | Closed PRs | Close reason | Retry count |
170+
|---------------------------|------------|--------------|-------------|
171+
|| #N, #M | ci-failure | 2 |
172+
173+
### 3c — Retry Count Threshold
174+
175+
- Topics with **exactly two** closed PRs: flag as **high-risk retry**. Include in recommendations if the close reason is actionable.
176+
- Topics with **three or more** closed PRs: flag as **retry-blocked**. These must produce a recommendation that explicitly calls for human review before any further agent attempt.
177+
178+
If PR data is unexpectedly unavailable (file missing or empty), skip Phase 3 and note that in all three issue bodies.
139179

140180
## Phase 4 — Recommendation Selection
141181

@@ -145,6 +185,7 @@ Selection rules:
145185

146186
- cover distinct root causes (no overlap)
147187
- prioritize high-frequency and high-severity patterns
188+
- **retry-blocked topics (≥2 closed PRs) are automatically elevated to high priority** — if any exist, at least one recommendation must address them unless all three slots are taken by higher-impact findings from Phase 2
148189
- include evidence (counts, rates, or representative examples)
149190
- include expected impact and a concrete change proposal
150191

@@ -155,6 +196,7 @@ Possible recommendation domains:
155196
- tool payload/latency optimization
156197
- earlier/stronger validation strategy
157198
- prompt design corrections to reduce drift
199+
- **duplicate-PR / retry waste reduction** (use when Phase 3b finds retry-blocked topics)
158200

159201
## Phase 5 — Issue Creation (Exactly Three)
160202

@@ -192,6 +234,28 @@ Use this template:
192234
- Data quality caveats (if any)
193235
```
194236

237+
### Retry-Blocked Topic Addendum
238+
239+
When an issue covers a retry-blocked topic (from Phase 3b), **append** the following section to the body:
240+
241+
```markdown
242+
### Prior Failed Attempts
243+
244+
The following Copilot PRs on this topic were closed without merging before this issue was created:
245+
246+
| PR | Closed (YYYY-MM-DD) | Close reason |
247+
|----|---------------------|--------------|
248+
| #N | YYYY-MM-DD | [reason] |
249+
| #M | YYYY-MM-DD | [reason] |
250+
251+
**Retry count: [N] — human review required before a new implementation attempt.**
252+
Any agent attempting to implement this recommendation MUST read this section and the linked PRs, address all close reasons, and post a plan comment on this issue before opening a new PR.
253+
```
254+
255+
### Labels for Retry-Blocked Issues
256+
257+
When creating an issue that covers a retry-blocked topic, add `copilot-retry-blocked` to the labels list in the `create_issue` safe-output call alongside the standard labels.
258+
195259
## Items That Should Not Be Addressed
196260

197261
The following items are out of scope because they are not actionable by repository users:
@@ -215,8 +279,12 @@ Before creating issues, verify:
215279
- [ ] last-14-day filtering was applied
216280
- [ ] `events.jsonl` parsing was attempted across all in-scope sessions
217281
- [ ] tool latency/payload, validation timing, context size, orchestration, and prompt drift were analyzed
282+
- [ ] Phase 3 PR cross-analysis was performed (not skipped)
283+
- [ ] duplicate PR pattern detection was run and retry-blocked topics table was built
284+
- [ ] retry-blocked topics (≥2 closed PRs) are reflected in at least one recommendation when present
218285
- [ ] exactly three recommendations selected
219286
- [ ] each recommendation has evidence + proposed change + expected impact
287+
- [ ] retry-blocked issues include the "Prior Failed Attempts" addendum and `copilot-retry-blocked` label
220288
- [ ] exactly three issue outputs will be created
221289

222290
## Usage

0 commit comments

Comments
 (0)