Contribution Workflow#
How a change travels from a branch to a review-ready pull request. The workflow puts an automated Copilot review before human review: the author iterates with Copilot on a draft pull request until it has no more feedback, then opens the pull request for people.
This is the operational "how" for a repository-delivery Task or Bug. The conventions it builds on live in the ways of working — Issue Lifecycle, PR Format, Branching and Merging, and Review Etiquette. Epic and PBI aggregates stay in planning and coordination rather than entering this branch-and-pull-request flow.
The flow#
flowchart TD
A[Branch and implement] --> B[Open PR as draft]
B --> C[Request Copilot review]
C --> D{New comments?}
D -- in scope --> E[Fix in this PR]
D -- out of scope --> F[File an issue]
E --> C
F --> C
D -- none --> G[Mark ready for review]
G --> AM[Enable auto-merge]
AM --> H[Human review]
H --> M[Auto-merge lands it on approval + green checks]
- Branch and implement. Pull one ready, unblocked Task or Bug into work on a
<type>/<issue>-<description>branch. Keep per-change implementation detail in that delivery issue and the pull request, not in the spec, design, or parent aggregate. - Open the pull request as a draft. A draft attaches CI and keeps the change out of people's review queues while you iterate.
- Run the Copilot review loop (below) until Copilot reports a clean round — no changes requested and no new inline comments.
- Mark the pull request ready for review once it meets the Definition of Ready for Review.
- Enable auto-merge so the change lands automatically when human review approves and the required checks stay green. Human review takes over from there.
Why draft first#
- Copilot is the first pass. It catches the obvious issues quickly, so the cheap feedback is spent before a person's time is (AI-First Development).
- People review a self-reviewed change. By the time someone is asked, the pull request has already survived an automated pass and the author's responses — review starts from a higher baseline.
- The draft is a safe workspace. Force-pushes, rewrites, and rapid iteration are fine while it is a draft; readiness is a deliberate signal.
The Copilot review loop#
Each round is the same: request a review, wait for Copilot, triage what it says,
and repeat until it is clean. The waiting is deterministic, so it is scripted —
.github/scripts/Wait-CopilotReview.ps1 explicitly requests a Copilot review
and polls until Copilot submits one, then reports whether it left inline comments:
- exit
0— a clean round: Copilot requested no changes and left no new inline comments; - exit
2— Copilot has feedback (a new inline comment or a changes-requested review); - exit
1— no review arrived before the timeout.
# one round: request Copilot and wait for its verdict (-Verbose logs each step)
./.github/scripts/Wait-CopilotReview.ps1 -Repository MSXOrg/<repo> -PullRequest <n> -Verbose
Always request the review explicitly — never assume a ruleset or other
automation will do it. The script checks whether Copilot is already processing a
request (from the timeline) and requests one only if not; a review "requested
automatically" on push or on marking ready is not guaranteed to fire. Run a round
after each push; the loop ends on a clean round (exit 0). Copilot re-reviews the
diff from scratch each round, so a genuine false positive can recur — do not
change correct code to silence it; dismiss it with a reason and treat the loop as
converged on substance.
Triage: fix in scope, file an issue for the rest#
For each piece of feedback, decide:
- In scope — it concerns the change under review. Address it in this pull request and push; the next round re-checks it.
- Out of scope — it points at a pre-existing gap or an adjacent improvement. Route a follow-up through the Issue Hierarchy and reference it; do not grow the pull request to cover it.
- Not actionable — a false positive, or a matter of taste you disagree with. Reply with the reason and resolve the thread; a documented dismissal counts as handled (Review Etiquette).
Keeping out-of-scope work in its own issue is what stops a focused change from sprawling — the pull request stays reviewable, and the gap is recorded rather than lost.
Marking ready#
Mark the pull request ready for review only when it meets every item in the Definition of Ready for Review — that gate is the single checklist, and nothing in it is left open. Readiness is a deliberate signal that the change has passed the automated pass and is ready for people — see Review Etiquette for what a reviewer is accountable for.
Anyone who can verify that gate — a human contributor, or an agent acting on their behalf — may mark the pull request ready. The gate, not the actor, is what makes it ready.
Enable auto-merge#
Once the pull request is ready, enable auto-merge (squash). The change then lands automatically the moment human review approves and the required checks are green — no one has to watch the pull request to click merge. Auto-merge waits on all of the branch's protection requirements — required checks, required approvals, and anything else the ruleset enforces — so nothing lands early. See Branching and Merging for the approval identity that satisfies the gate.
Where this connects#
- Workflow — the spec-led loop this operates within.
- Issue Lifecycle — why only ready Task and Bug leaves enter this flow.
- PR Format — the pull request title, description, and labels.
- Definition of Ready and Done — the readiness gate this hands off at.
- Branching and Merging — the branch model a pull request builds on.
- Review Etiquette — how human review proceeds once the pull request is ready.