From 41110652ef43cb198936dcb238dadca8137d2c01 Mon Sep 17 00:00:00 2001 From: ilml Date: Mon, 17 Aug 2026 21:31:16 +0000 Subject: [PATCH 1/4] Update split-PR skill with the real CI-driven stacking workflow The skill's stacking guidance predated actually running a stacked series through Megatron-LM's CI and was wrong or incomplete in ways that bite: - It said to CREATE dependent PRs with base pull-request/; that ref does not exist until a vetter runs /ok to test, so creation fails. Correct flow: create everything on main, vet, then retarget. - Its only merge warning was the auto-close hazard. The worse failure is merging while mirror-based: GitHub merges into the bot's scratch ref, nothing lands on main, and the MERGED PR cannot be reopened. Rule: retarget to main before merging, always. - It did not explain the copy-pr-bot trust model that stacking piggybacks on (vetted-snapshot refs, staleness on push, /ok to test ), the squash-merge rebase cascade children need after each parent lands, the lint job checking touched core/tests files against main's formatter pins, or how to linearize a PR with two dependencies. Adds a CI-model section, splits the workflow into create -> stack for review -> merge bottom-up phases, and folds the failure modes into the constraints. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: ilml --- skills/mcore-split-pr/SKILL.md | 92 +++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 12 deletions(-) diff --git a/skills/mcore-split-pr/SKILL.md b/skills/mcore-split-pr/SKILL.md index 28c86f9a172..6baafd7b497 100644 --- a/skills/mcore-split-pr/SKILL.md +++ b/skills/mcore-split-pr/SKILL.md @@ -1,8 +1,8 @@ --- name: mcore-split-pr -description: Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups. +description: Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups, and manage the resulting stack through review and merge. license: Apache-2.0 -when_to_use: User asks to split a PR, reduce reviewer groups, or break up a large PR; 'too many CODEOWNERS', 'split this PR', 'break up PR', 'reduce reviewers needed'. +when_to_use: User asks to split a PR, reduce reviewer groups, break up a large PR, or stack dependent PRs; 'too many CODEOWNERS', 'split this PR', 'break up PR', 'reduce reviewers needed', 'stacked PRs', 'clean per-PR diffs'. user_invocable: true argument: "PR URL or number" metadata: @@ -28,16 +28,45 @@ workflow: separate PR just to reduce reviewer groups. - If PR B depends on symbols renamed in PR A, call out the dependency and put backward-compatible aliases, re-exports, or shims in PR A when needed. -- When creating dependent PRs, set the dependent PR's GitHub base/diffbase to - `pull-request/`, not the base PR author's branch. -- Before merging a base PR, retarget each dependent PR back to `main` and - refresh it against `main`; otherwise GitHub may automatically close the - dependent PR, losing approvals and review discussion. +- **Create every PR with base `main`.** Stacked bases come later: the + `pull-request/` mirror refs used for stacking do not exist until a vetter + runs `/ok to test`, so creating a PR with such a base fails. +- **Never merge a PR whose base is a `pull-request/*` ref.** GitHub merges into + the base branch: merging while mirror-based writes the commits into the + bot's scratch ref (which gets force-pushed away), lands nothing on `main`, + and leaves an unreopenable MERGED PR. Retarget to `main` first, then merge. - Wait for user approval before execution. -- Execution creates draft PRs from the right base, applies file-scoped diffs - with `git diff upstream/main.. -- | git apply`, pushes +- Execution creates draft PRs, applies file-scoped diffs with + `git diff upstream/main.. -- | git apply`, pushes to the user's fork, and never pushes directly to upstream. +## How Megatron-LM's CI shapes stacked PRs + +Understand this model before touching PR bases; every stacking step below +derives from it. + +- CI runs on self-hosted runners, so fork PRs get **no CI** until a trusted + vetter comments `/ok to test ` (copy-pr-bot). The bot then copies + the vetted SHA into a real upstream branch, `refs/heads/pull-request/`, + and workflows run against that trusted copy — never against the fork ref. +- That mirror branch is the **only** upstream ref containing a fork PR's + commits, and GitHub requires a PR's base to be an upstream branch — which is + why `pull-request/` is the one legal way to get stacked + (per-layer) diffs in a fork-only repo. +- The mirror is a **vetted snapshot, not a live mirror**: it refreshes only on + the next `/ok to test`. After pushing to a parent, child diffs go slightly + stale until the parent is re-vetted. This is the security model working as + intended, not a bug. +- The `linting` job checks the PR **merged with current main**, using main's + tool pins (e.g. black version from main's `pyproject.toml`), over changed + `.py` files under `megatron/core` and `tests/` only. A touched file must be + fully clean under main's formatter version — pre-existing lines can fail + after a formatter bump on main, and a local older formatter will not + reproduce the complaint. +- Merges are **squash** merges: a child's diff does not collapse automatically + when its parent merges. The child must be rebased onto the new `main` + (the parent's commits drop out as already-applied) and force-pushed. + ## Workflow ### 1. Analyze the PR @@ -58,6 +87,11 @@ Strategy: 3. Remaining files form one or more additional PRs, each ideally requiring only one or two reviewer groups. 4. If a split creates a dependency (e.g., PR B uses symbols renamed in PR A), the dependent PR must be merged after the first. Note this explicitly. 5. Each PR must be independently mergeable to main — no broken imports, no missing symbols. Backward-compatible aliases and re-export stubs in the first PR can make this possible. +6. A PR with **two dependencies** cannot have a clean stacked diff (a git branch + has one parent). Linearize: stack it on one parent's branch and cherry-pick a + copy of the other parent's commit beneath it. Its diff shows the copied + commit until that other parent merges to `main`, after which the next rebase + drops the copy and the diff collapses — note this in the PR body. Present the proposed split as a table: - PR name/description @@ -72,17 +106,51 @@ Wait for user approval before proceeding. For each new PR: 1. Create a new branch from the appropriate local base (`main`, or a dependency PR's branch). 2. Extract the relevant changes: `git diff upstream/main.. -- | git apply`. -3. Stage, commit with a clear message, and push to the user's fork. -4. Create the PR as a **draft** (per repo contributing guidelines). For dependent PRs, set the GitHub base/diffbase to `pull-request/`. +3. Stage, commit with `-s -S` and a clear message, and push to the user's fork. +4. Create the PR as a **draft** with base `main` (per repo contributing + guidelines; the mirror refs for stacking do not exist yet). 5. If the original PR needs to be narrowed in scope, confirm with the user before force-pushing. 6. Report all PR URLs when done. +### 4. Stack for review (once a vetter is available) + +1. Have a vetter comment `/ok to test ` on every PR in the series — + this both unblocks CI and creates the `pull-request/` mirrors. +2. Confirm the refs exist: `git ls-remote origin 'refs/heads/pull-request/'`. +3. Retarget each child onto its parent's mirror: + `gh pr edit --base pull-request/`. + Roots keep base `main`. +4. Each PR's Files-changed now shows only its own layer. Reviews proceed in + parallel across the whole stack. +5. While reviewing: pushes to a child require rebasing its descendants + (cascade + force-push). Do **not** use GitHub's "Update branch" button on + stacked branches — it injects merge commits that fight the rebase cascade. + +### 5. Merge (bottom-up through the dependency DAG) + +Reviews are parallel; merges are strictly parents-before-children. For each +PR whose dependencies have all merged: + +1. **Retarget to `main`:** `gh pr edit --base main`. Never click merge + while the header says "into `pull-request/...`". +2. Rebase the branch onto latest `origin/main` if needed; push; re-vet for CI. +3. Squash-merge into `main`. +4. Immediately rebase every descendant onto the new `main` and force-push + (the merged parent's commits drop out as already-applied). +5. The next child's diff has now collapsed to its own layer; retarget it to + `main` when its turn comes, and repeat. + +Independent roots can merge at any time, in any order — the ordering +constraint is the dependency DAG, not the PR-number sequence. + ## Important guidelines - Always create PRs as **drafts** and push to the user's fork, never directly to upstream. - Backward-compatible changes (aliases, re-exports, deprecation shims) should go in the first PR so subsequent PRs can depend on them. -- Dependent PRs should target `pull-request/` while stacked, then be retargeted and refreshed to `main` before the base PR is merged. - Test files should go with the production code they test, not in a separate PR. - Prefer a single clean commit per split PR over replaying the original commit history. - If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in. - If the current GitHub user is not the author of the original PR, each new PR's description must explicitly credit the original author (e.g., "Original changes by @ in #"). +- Consider a watchdog for the two stacking failure modes: a PR reaching + approved state while still mirror-based (merge hazard), and a parent merging + (a rebase cascade is now due). From e89c8e89b8cbdf4959039c3f6eb48059b0885481 Mon Sep 17 00:00:00 2001 From: ilml Date: Tue, 18 Aug 2026 16:42:22 +0000 Subject: [PATCH 2/4] Retarget stacked children to main on parent approval, not at merge time copy-pr-bot deletes the pull-request/ mirror when PR N merges or closes, and GitHub then auto-closes every PR based on that ref; such a PR cannot be reopened while the ref is missing, so a single parent merge can domino-close the rest of the stack faster than anyone can react. Move the un-stacking step to the moment the parent is approved -- the last point at which the child can safely leave the mirror -- and extend the suggested watchdog to flag an approved parent that still has mirror-based children. Co-Authored-By: Claude Fable 5 Signed-off-by: ilml --- skills/mcore-split-pr/SKILL.md | 42 ++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/skills/mcore-split-pr/SKILL.md b/skills/mcore-split-pr/SKILL.md index 6baafd7b497..49fd87aa86e 100644 --- a/skills/mcore-split-pr/SKILL.md +++ b/skills/mcore-split-pr/SKILL.md @@ -35,6 +35,11 @@ workflow: the base branch: merging while mirror-based writes the commits into the bot's scratch ref (which gets force-pushed away), lands nothing on `main`, and leaves an unreopenable MERGED PR. Retarget to `main` first, then merge. +- **Un-stack children the moment their parent is approved.** copy-pr-bot + deletes `pull-request/` when PR N merges or closes, and GitHub then + auto-closes (unreopenably) every PR based on that ref — one merge can + domino-close the rest of the stack. Retarget the child to `main` as soon as + the parent is approved, before the parent becomes mergeable. - Wait for user approval before execution. - Execution creates draft PRs, applies file-scoped diffs with `git diff upstream/main.. -- | git apply`, pushes @@ -128,17 +133,34 @@ For each new PR: ### 5. Merge (bottom-up through the dependency DAG) -Reviews are parallel; merges are strictly parents-before-children. For each -PR whose dependencies have all merged: +Reviews are parallel; merges are strictly parents-before-children. -1. **Retarget to `main`:** `gh pr edit --base main`. Never click merge - while the header says "into `pull-request/...`". +**Un-stack on approval, not at merge time.** When copy-pr-bot's mirror ref +`pull-request/` is deleted — which the bot does automatically the moment +PR N merges *or* closes — GitHub instantly auto-closes every PR based on +that ref, and a PR closed by base-branch deletion cannot be reopened while +the ref is gone. One merge can therefore domino-close the entire remaining +stack before you can react. The only safe window to leave the mirror is +*before* the parent becomes mergeable: + +- The moment a parent PR is **approved**, retarget its direct child to + `main` (`gh pr edit --base main`). The child's diff temporarily + shows the parent's layer too; that is cosmetic and resolves when the + parent merges and the child is rebased. +- Never let any PR merge or close while another PR still bases on its + mirror. + +For each PR whose dependencies have all merged: + +1. **Retarget to `main`:** `gh pr edit --base main` (already done if the + approval rule above was followed). Never click merge while the header + says "into `pull-request/...`". 2. Rebase the branch onto latest `origin/main` if needed; push; re-vet for CI. 3. Squash-merge into `main`. 4. Immediately rebase every descendant onto the new `main` and force-push (the merged parent's commits drop out as already-applied). -5. The next child's diff has now collapsed to its own layer; retarget it to - `main` when its turn comes, and repeat. +5. The next child's diff has now collapsed to its own layer; re-vet its + descendants' mirrors and re-stack them on the refreshed refs. Independent roots can merge at any time, in any order — the ordering constraint is the dependency DAG, not the PR-number sequence. @@ -151,6 +173,8 @@ constraint is the dependency DAG, not the PR-number sequence. - Prefer a single clean commit per split PR over replaying the original commit history. - If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in. - If the current GitHub user is not the author of the original PR, each new PR's description must explicitly credit the original author (e.g., "Original changes by @ in #"). -- Consider a watchdog for the two stacking failure modes: a PR reaching - approved state while still mirror-based (merge hazard), and a parent merging - (a rebase cascade is now due). +- Consider a watchdog for the three stacking failure modes: a PR reaching + approved state while still mirror-based (merge hazard), a *parent* reaching + approved state while a child still bases on its mirror (auto-close hazard — + retarget the child to `main` now), and a parent merging (a rebase cascade + is now due). From be9de0a96289bac7fcde09e01c36bd0d80eb3f41 Mon Sep 17 00:00:00 2001 From: ilml Date: Tue, 18 Aug 2026 17:17:11 +0000 Subject: [PATCH 3/4] Correct the split-PR skill's stacking rules for copy-pr-bot CI The pull-request/ mirror refs only exist after a vetter's /ok to test, are merged into if a mirror-based PR is merged, and are deleted (auto-closing dependents) when the base PR merges or closes. Create PRs on main, stack after vetting, never merge mirror-based, and retarget dependents to main on base-PR approval. Co-Authored-By: Claude Fable 5 Signed-off-by: ilml --- skills/mcore-split-pr/SKILL.md | 123 +++++---------------------------- 1 file changed, 19 insertions(+), 104 deletions(-) diff --git a/skills/mcore-split-pr/SKILL.md b/skills/mcore-split-pr/SKILL.md index 49fd87aa86e..c316c66e82c 100644 --- a/skills/mcore-split-pr/SKILL.md +++ b/skills/mcore-split-pr/SKILL.md @@ -1,8 +1,8 @@ --- name: mcore-split-pr -description: Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups, and manage the resulting stack through review and merge. +description: Split a PR into multiple PRs to reduce the number of required CODEOWNERS reviewer groups. license: Apache-2.0 -when_to_use: User asks to split a PR, reduce reviewer groups, break up a large PR, or stack dependent PRs; 'too many CODEOWNERS', 'split this PR', 'break up PR', 'reduce reviewers needed', 'stacked PRs', 'clean per-PR diffs'. +when_to_use: User asks to split a PR, reduce reviewer groups, or break up a large PR; 'too many CODEOWNERS', 'split this PR', 'break up PR', 'reduce reviewers needed'. user_invocable: true argument: "PR URL or number" metadata: @@ -28,50 +28,23 @@ workflow: separate PR just to reduce reviewer groups. - If PR B depends on symbols renamed in PR A, call out the dependency and put backward-compatible aliases, re-exports, or shims in PR A when needed. -- **Create every PR with base `main`.** Stacked bases come later: the - `pull-request/` mirror refs used for stacking do not exist until a vetter - runs `/ok to test`, so creating a PR with such a base fails. -- **Never merge a PR whose base is a `pull-request/*` ref.** GitHub merges into - the base branch: merging while mirror-based writes the commits into the - bot's scratch ref (which gets force-pushed away), lands nothing on `main`, - and leaves an unreopenable MERGED PR. Retarget to `main` first, then merge. -- **Un-stack children the moment their parent is approved.** copy-pr-bot - deletes `pull-request/` when PR N merges or closes, and GitHub then - auto-closes (unreopenably) every PR based on that ref — one merge can - domino-close the rest of the stack. Retarget the child to `main` as soon as - the parent is approved, before the parent becomes mergeable. +- Create every PR with base `main`; the `pull-request/` mirror refs do not + exist until a vetter comments `/ok to test ` (copy-pr-bot). Once + the mirror exists, stack a dependent PR with + `gh pr edit --base pull-request/`. +- Never merge a PR while its base is a `pull-request/*` ref: the squash lands + in the bot's scratch ref, not `main`, and the PR ends up MERGED and + unreopenable. Retarget to `main` first. +- Retarget each dependent PR back to `main` as soon as its base PR is + approved: copy-pr-bot deletes `pull-request/` when PR N merges or + closes, and GitHub then auto-closes (unreopenably) every PR based on that + ref. After the base PR squash-merges, rebase dependents onto the new `main` + and force-push. - Wait for user approval before execution. -- Execution creates draft PRs, applies file-scoped diffs with - `git diff upstream/main.. -- | git apply`, pushes +- Execution creates draft PRs from the right base, applies file-scoped diffs + with `git diff upstream/main.. -- | git apply`, pushes to the user's fork, and never pushes directly to upstream. -## How Megatron-LM's CI shapes stacked PRs - -Understand this model before touching PR bases; every stacking step below -derives from it. - -- CI runs on self-hosted runners, so fork PRs get **no CI** until a trusted - vetter comments `/ok to test ` (copy-pr-bot). The bot then copies - the vetted SHA into a real upstream branch, `refs/heads/pull-request/`, - and workflows run against that trusted copy — never against the fork ref. -- That mirror branch is the **only** upstream ref containing a fork PR's - commits, and GitHub requires a PR's base to be an upstream branch — which is - why `pull-request/` is the one legal way to get stacked - (per-layer) diffs in a fork-only repo. -- The mirror is a **vetted snapshot, not a live mirror**: it refreshes only on - the next `/ok to test`. After pushing to a parent, child diffs go slightly - stale until the parent is re-vetted. This is the security model working as - intended, not a bug. -- The `linting` job checks the PR **merged with current main**, using main's - tool pins (e.g. black version from main's `pyproject.toml`), over changed - `.py` files under `megatron/core` and `tests/` only. A touched file must be - fully clean under main's formatter version — pre-existing lines can fail - after a formatter bump on main, and a local older formatter will not - reproduce the complaint. -- Merges are **squash** merges: a child's diff does not collapse automatically - when its parent merges. The child must be rebased onto the new `main` - (the parent's commits drop out as already-applied) and force-pushed. - ## Workflow ### 1. Analyze the PR @@ -92,11 +65,6 @@ Strategy: 3. Remaining files form one or more additional PRs, each ideally requiring only one or two reviewer groups. 4. If a split creates a dependency (e.g., PR B uses symbols renamed in PR A), the dependent PR must be merged after the first. Note this explicitly. 5. Each PR must be independently mergeable to main — no broken imports, no missing symbols. Backward-compatible aliases and re-export stubs in the first PR can make this possible. -6. A PR with **two dependencies** cannot have a clean stacked diff (a git branch - has one parent). Linearize: stack it on one parent's branch and cherry-pick a - copy of the other parent's commit beneath it. Its diff shows the copied - commit until that other parent merges to `main`, after which the next rebase - drops the copy and the diff collapses — note this in the PR body. Present the proposed split as a table: - PR name/description @@ -111,70 +79,17 @@ Wait for user approval before proceeding. For each new PR: 1. Create a new branch from the appropriate local base (`main`, or a dependency PR's branch). 2. Extract the relevant changes: `git diff upstream/main.. -- | git apply`. -3. Stage, commit with `-s -S` and a clear message, and push to the user's fork. -4. Create the PR as a **draft** with base `main` (per repo contributing - guidelines; the mirror refs for stacking do not exist yet). +3. Stage, commit with a clear message, and push to the user's fork. +4. Create the PR as a **draft** with base `main` (per repo contributing guidelines). Retarget dependent PRs to `pull-request/` only after a vetter's `/ok to test` has created that mirror ref. 5. If the original PR needs to be narrowed in scope, confirm with the user before force-pushing. 6. Report all PR URLs when done. -### 4. Stack for review (once a vetter is available) - -1. Have a vetter comment `/ok to test ` on every PR in the series — - this both unblocks CI and creates the `pull-request/` mirrors. -2. Confirm the refs exist: `git ls-remote origin 'refs/heads/pull-request/'`. -3. Retarget each child onto its parent's mirror: - `gh pr edit --base pull-request/`. - Roots keep base `main`. -4. Each PR's Files-changed now shows only its own layer. Reviews proceed in - parallel across the whole stack. -5. While reviewing: pushes to a child require rebasing its descendants - (cascade + force-push). Do **not** use GitHub's "Update branch" button on - stacked branches — it injects merge commits that fight the rebase cascade. - -### 5. Merge (bottom-up through the dependency DAG) - -Reviews are parallel; merges are strictly parents-before-children. - -**Un-stack on approval, not at merge time.** When copy-pr-bot's mirror ref -`pull-request/` is deleted — which the bot does automatically the moment -PR N merges *or* closes — GitHub instantly auto-closes every PR based on -that ref, and a PR closed by base-branch deletion cannot be reopened while -the ref is gone. One merge can therefore domino-close the entire remaining -stack before you can react. The only safe window to leave the mirror is -*before* the parent becomes mergeable: - -- The moment a parent PR is **approved**, retarget its direct child to - `main` (`gh pr edit --base main`). The child's diff temporarily - shows the parent's layer too; that is cosmetic and resolves when the - parent merges and the child is rebased. -- Never let any PR merge or close while another PR still bases on its - mirror. - -For each PR whose dependencies have all merged: - -1. **Retarget to `main`:** `gh pr edit --base main` (already done if the - approval rule above was followed). Never click merge while the header - says "into `pull-request/...`". -2. Rebase the branch onto latest `origin/main` if needed; push; re-vet for CI. -3. Squash-merge into `main`. -4. Immediately rebase every descendant onto the new `main` and force-push - (the merged parent's commits drop out as already-applied). -5. The next child's diff has now collapsed to its own layer; re-vet its - descendants' mirrors and re-stack them on the refreshed refs. - -Independent roots can merge at any time, in any order — the ordering -constraint is the dependency DAG, not the PR-number sequence. - ## Important guidelines - Always create PRs as **drafts** and push to the user's fork, never directly to upstream. - Backward-compatible changes (aliases, re-exports, deprecation shims) should go in the first PR so subsequent PRs can depend on them. +- Dependent PRs target `pull-request/` while stacked, and must be retargeted to `main` as soon as the base PR is approved — before it can merge or close and take the mirror ref (and every PR based on it) down with it. - Test files should go with the production code they test, not in a separate PR. - Prefer a single clean commit per split PR over replaying the original commit history. - If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in. - If the current GitHub user is not the author of the original PR, each new PR's description must explicitly credit the original author (e.g., "Original changes by @ in #"). -- Consider a watchdog for the three stacking failure modes: a PR reaching - approved state while still mirror-based (merge hazard), a *parent* reaching - approved state while a child still bases on its mirror (auto-close hazard — - retarget the child to `main` now), and a parent merging (a rebase cascade - is now due). From a0a24c88c18f0894de803199ecd916a6bd3fd7a1 Mon Sep 17 00:00:00 2001 From: ilml Date: Tue, 18 Aug 2026 17:45:15 +0000 Subject: [PATCH 4/4] Explain why GitHub's standard stacked-PR flow is unavailable Contributors cannot push branches to NVIDIA/Megatron-LM, and a PR's base must be an upstream branch, so the documented stacked-PR flow of basing each PR on the previous feature branch does not apply; the copy-pr-bot pull-request/ mirrors are the only usable stack bases. Also drop the Important-guidelines bullet on retargeting, which duplicated the answer-first constraint (review feedback). Co-Authored-By: Claude Fable 5 Signed-off-by: ilml --- skills/mcore-split-pr/SKILL.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/skills/mcore-split-pr/SKILL.md b/skills/mcore-split-pr/SKILL.md index c316c66e82c..38dd13760ff 100644 --- a/skills/mcore-split-pr/SKILL.md +++ b/skills/mcore-split-pr/SKILL.md @@ -28,6 +28,12 @@ workflow: separate PR just to reduce reviewer groups. - If PR B depends on symbols renamed in PR A, call out the dependency and put backward-compatible aliases, re-exports, or shims in PR A when needed. +- [GitHub's standard stacked-PR flow](https://docs.github.com/en/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests) + — push each branch to the upstream repo and base each PR on the previous + branch — does not work here: contributors cannot push branches to + `NVIDIA/Megatron-LM`, and a PR's base must be an upstream branch. The only + upstream refs containing a fork PR's commits are the `pull-request/` + mirrors that copy-pr-bot creates, so stacking goes through them. - Create every PR with base `main`; the `pull-request/` mirror refs do not exist until a vetter comments `/ok to test ` (copy-pr-bot). Once the mirror exists, stack a dependent PR with @@ -88,7 +94,6 @@ For each new PR: - Always create PRs as **drafts** and push to the user's fork, never directly to upstream. - Backward-compatible changes (aliases, re-exports, deprecation shims) should go in the first PR so subsequent PRs can depend on them. -- Dependent PRs target `pull-request/` while stacked, and must be retargeted to `main` as soon as the base PR is approved — before it can merge or close and take the mirror ref (and every PR based on it) down with it. - Test files should go with the production code they test, not in a separate PR. - Prefer a single clean commit per split PR over replaying the original commit history. - If a file is hard to categorize (e.g., it touches two groups), ask the user which PR it should go in.