From 74753fd6a358cb7bf2d8574c3657951f861b268d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= <54936225+sourcehawk@users.noreply.github.com> Date: Sat, 4 Jul 2026 05:32:31 +0200 Subject: [PATCH 1/3] feat(skills/opening-a-pull-request): document keyword and linkage semantics for stacked retargeted PRs --- skills/opening-a-pull-request/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skills/opening-a-pull-request/SKILL.md b/skills/opening-a-pull-request/SKILL.md index 07dc04d..9656d96 100644 --- a/skills/opening-a-pull-request/SKILL.md +++ b/skills/opening-a-pull-request/SKILL.md @@ -47,6 +47,7 @@ Which keyword belongs depends on **which branch the PR targets**: - **PR targets `main` (the default branch)** — use `Fixes` / `Closes` if the merge should close the issue; use `Towards` if the issue should stay open. This includes sub-PRs in the `sub_pr_target: main` model (see `feature-dev-workflow:fanning-out-with-worktrees`): each sub-PR targets main directly with the type-appropriate closing keyword (`Fixes #` for a bug sub-issue, `Closes #` otherwise); the epic is closed manually by the orchestrator after all sub-PRs merge. - **PR targets a feature branch** (`feature/` in the multi-PR feature-branch model — see `feature-dev-workflow:developing-a-feature`) — use `Towards #`. `Fixes` / `Closes` keywords only auto-trigger on merges to the default branch, so writing them on a feature-branch-bound PR creates a misleading promise that nothing will fulfill. The sub-issue is closed manually by the orchestrator after the self-merge. The integration PR (feature → main) gets `Closes #` because that PR does merge to main. +- **PR temporarily targets a sibling branch and will be retargeted to `main`** (stacked sub-PRs in the `sub_pr_target: main` model: each draft opens against its parent branch so its diff shows only its own commits, then retargets to `main` when the parent merges) — use the type-appropriate closing keyword (`Fixes` / `Closes`) from the start. It describes the merge that will eventually happen on `main`, and it survives the retarget with no body edit; a `Towards` placed "because the base isn't main yet" has to be remembered and upgraded at every retarget, and a forgotten upgrade means the sub-issue never auto-closes. Know what the keyword does NOT do while the base is a sibling branch: GitHub only creates the issue's linked-PR association (and only auto-closes) for closing keywords on default-branch-base PRs, so until the retarget the sub-issue shows a plain timeline mention and **no linked PR** — deferred, not broken. At each retarget, verify the linkage materialized (`gh pr view --json closingIssuesReferences` lists the sub-issue); if it stays empty, re-save the body so GitHub re-evaluates the keyword against the new base. If there is no tracking issue, drop the line entirely and open the section with prose. @@ -104,5 +105,6 @@ These thoughts mean the PR isn't actually ready to publish or flip: | "The user said yes a turn ago, this is the same thing" | Bodies change between turns. Confirm the exact body about to land. | | "I'll just append a note and they can edit later if needed" | They shouldn't have to clean up after the agent. Confirm first. | | "The PR's already open/ready, the stale body isn't worth re-editing" | The body is what the reviewer reads first; once the diff moves past it, it misleads. Reconcile the body to match the diff — body only, no comment (§Reconciling an open PR's body with reality). | +| "The sub-issue shows no linked PR, the keyword must be wrong" | Closing-keyword linkage only materializes while the PR's base is the default branch. On a stacked draft it's deferred until retarget — verify with `gh pr view --json closingIssuesReferences` then, not before. | All of these mean: rewrite the body from the right template, paste it inline in chat, and wait for an explicit yes. From 56d3a6d13815980d4ecf21138b7ee1f8714bd838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= <54936225+sourcehawk@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:58:55 +0200 Subject: [PATCH 2/3] fix(skills/opening-a-pull-request): include the PR number placeholder in the red-flag row's verification command The row's command omitted while the body text includes it; without the number the command depends on the checked-out branch. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01J1vgUwZZpzavETACT3fXPM --- skills/opening-a-pull-request/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/opening-a-pull-request/SKILL.md b/skills/opening-a-pull-request/SKILL.md index 9656d96..bc49819 100644 --- a/skills/opening-a-pull-request/SKILL.md +++ b/skills/opening-a-pull-request/SKILL.md @@ -105,6 +105,6 @@ These thoughts mean the PR isn't actually ready to publish or flip: | "The user said yes a turn ago, this is the same thing" | Bodies change between turns. Confirm the exact body about to land. | | "I'll just append a note and they can edit later if needed" | They shouldn't have to clean up after the agent. Confirm first. | | "The PR's already open/ready, the stale body isn't worth re-editing" | The body is what the reviewer reads first; once the diff moves past it, it misleads. Reconcile the body to match the diff — body only, no comment (§Reconciling an open PR's body with reality). | -| "The sub-issue shows no linked PR, the keyword must be wrong" | Closing-keyword linkage only materializes while the PR's base is the default branch. On a stacked draft it's deferred until retarget — verify with `gh pr view --json closingIssuesReferences` then, not before. | +| "The sub-issue shows no linked PR, the keyword must be wrong" | Closing-keyword linkage only materializes while the PR's base is the default branch. On a stacked draft it's deferred until retarget — verify with `gh pr view --json closingIssuesReferences` then, not before. | All of these mean: rewrite the body from the right template, paste it inline in chat, and wait for an explicit yes. From 5f204457f3e4ba9c47953363e828c2d23d0d19f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= <54936225+sourcehawk@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:04:34 +0200 Subject: [PATCH 3/3] fix(skills/opening-a-pull-request): spell out the keyword placeholders in the stacked-PR bullet Matches the placeholder form the main-target bullet uses. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01J1vgUwZZpzavETACT3fXPM --- skills/opening-a-pull-request/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/opening-a-pull-request/SKILL.md b/skills/opening-a-pull-request/SKILL.md index bc49819..95058f9 100644 --- a/skills/opening-a-pull-request/SKILL.md +++ b/skills/opening-a-pull-request/SKILL.md @@ -47,7 +47,7 @@ Which keyword belongs depends on **which branch the PR targets**: - **PR targets `main` (the default branch)** — use `Fixes` / `Closes` if the merge should close the issue; use `Towards` if the issue should stay open. This includes sub-PRs in the `sub_pr_target: main` model (see `feature-dev-workflow:fanning-out-with-worktrees`): each sub-PR targets main directly with the type-appropriate closing keyword (`Fixes #` for a bug sub-issue, `Closes #` otherwise); the epic is closed manually by the orchestrator after all sub-PRs merge. - **PR targets a feature branch** (`feature/` in the multi-PR feature-branch model — see `feature-dev-workflow:developing-a-feature`) — use `Towards #`. `Fixes` / `Closes` keywords only auto-trigger on merges to the default branch, so writing them on a feature-branch-bound PR creates a misleading promise that nothing will fulfill. The sub-issue is closed manually by the orchestrator after the self-merge. The integration PR (feature → main) gets `Closes #` because that PR does merge to main. -- **PR temporarily targets a sibling branch and will be retargeted to `main`** (stacked sub-PRs in the `sub_pr_target: main` model: each draft opens against its parent branch so its diff shows only its own commits, then retargets to `main` when the parent merges) — use the type-appropriate closing keyword (`Fixes` / `Closes`) from the start. It describes the merge that will eventually happen on `main`, and it survives the retarget with no body edit; a `Towards` placed "because the base isn't main yet" has to be remembered and upgraded at every retarget, and a forgotten upgrade means the sub-issue never auto-closes. Know what the keyword does NOT do while the base is a sibling branch: GitHub only creates the issue's linked-PR association (and only auto-closes) for closing keywords on default-branch-base PRs, so until the retarget the sub-issue shows a plain timeline mention and **no linked PR** — deferred, not broken. At each retarget, verify the linkage materialized (`gh pr view --json closingIssuesReferences` lists the sub-issue); if it stays empty, re-save the body so GitHub re-evaluates the keyword against the new base. +- **PR temporarily targets a sibling branch and will be retargeted to `main`** (stacked sub-PRs in the `sub_pr_target: main` model: each draft opens against its parent branch so its diff shows only its own commits, then retargets to `main` when the parent merges) — use the type-appropriate closing keyword (`Fixes #` for a bug sub-issue, `Closes #` otherwise) from the start. It describes the merge that will eventually happen on `main`, and it survives the retarget with no body edit; a `Towards` placed "because the base isn't main yet" has to be remembered and upgraded at every retarget, and a forgotten upgrade means the sub-issue never auto-closes. Know what the keyword does NOT do while the base is a sibling branch: GitHub only creates the issue's linked-PR association (and only auto-closes) for closing keywords on default-branch-base PRs, so until the retarget the sub-issue shows a plain timeline mention and **no linked PR** — deferred, not broken. At each retarget, verify the linkage materialized (`gh pr view --json closingIssuesReferences` lists the sub-issue); if it stays empty, re-save the body so GitHub re-evaluates the keyword against the new base. If there is no tracking issue, drop the line entirely and open the section with prose.