# Open PR — forward mode

Forward pipeline's Stage 7. Invoked by `/muggle-do` after stages 1–6 of a fresh feature. Opens the change — a PR on GitHub (`gh pr create`) or an MR on GitLab (`glab mr create`), provider resolved in Step 5 — then seeds session state and dispatches the first watcher.

## Turn preamble

```
**Stage 7 — Create PR** — pushing the branch and opening the PR.
```

## Inputs

- Per-repo: name, path, branch.
- Requirements: goal, acceptance criteria.
- **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).

## Per repo

0. **`autoCreatePR` gate** — apply per [`../../muggle-preferences/preference-gates/autoCreatePR.md`](../../muggle-preferences/preference-gates/autoCreatePR.md). On skip, record the reason in `result.md` and move on.

1. **Sync with the base:** run [`../../_shared/sync-branch-with-base.md`](../../_shared/sync-branch-with-base.md) with `base` set to the PR target recorded in `state.md` — gated by [`autoRebase`](../../muggle-preferences/preference-gates/autoRebase.md), fires only when `behind > 0`. The branch is not on the remote yet, so the rebase lands without a force-push. Sync here rather than trusting stage 6: a `unit-only` or `skip` run never reaches the E2E stage's sync at all, and on a run that does, the base moves freely while stages 3–6 build and test. If the sync escalates — conflicts under `autoResolveConflicts=never`, or a resolution that fails the verify-or-rollback gate — stop and report; never open a PR on a tree that did not verify.

2. **Push:** Execute per [`../../_shared/vcs/common/push-to-branch.md`](../../_shared/vcs/common/push-to-branch.md) — the tool-agnostic instruction for pushing commits (handles the signing gate and directs to provider-specific recipes).

3. **Title** (under 70 chars):
   - E2E report exists and has failures → `[E2E FAILING] <goal>`
   - No E2E report (validation was `unit-only` or `skip`) → `[UNVERIFIED] <goal>` or `[UNIT-ONLY] <goal>` to match the validation strategy
   - Otherwise → `<goal>`

4. **Body** — assemble in order:
   - `## Goal` — from requirements.
   - `## Acceptance Criteria` — bulleted; omit if empty.
   - `## Changes` — summary of what changed in this repo.
   - `## Validation` — one line: link to E2E report, `unit-only`, or `skip — <reason>`.
   - The walkthrough does **not** go in the body. It settles the PR's designated walkthrough comment in Step 6, so a rerun updates one comment instead of rewriting the description.
   - **Signature** — write the assembled body to a file and sign it with `--command /muggle-do --mode editable` per [`../../_shared/vcs/post-signature.md`](../../_shared/vcs/post-signature.md). The signature lands last, after the walkthrough block; `editable` is the mode a description carries so later refreshes replace it instead of stacking.

5. **Create:** resolve the provider per [`../../_shared/vcs/detect-vcs.md`](../../_shared/vcs/detect-vcs.md).
   - `github` → `gh pr create --title "..." --body-file <signed-file> --head <branch>`, passing the file signed in Step 4. Capture the PR URL and number.
   - `gitlab` → open the change via [`../../_shared/vcs/gitlab/mr-create.md`](../../_shared/vcs/gitlab/mr-create.md): `glab mr create --source-branch <branch> --target-branch <base> --title "..." --description "..."`. Capture the MR URL and iid.

6. **Settle the designated walkthrough comment.** Creating the PR reserves one comment for the walkthrough, marked `muggle-pr-walkthrough` and empty until settled — the PR's walkthrough check fails while it stays that way.
   - E2E report exists → fire [`postPRVisualWalkthrough`](../../muggle-preferences/preference-gates/postPRVisualWalkthrough.md); on skip, leave the comment to the gate's own skip record. Otherwise invoke [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) Mode A with the PR number — it fills the reserved comment in place.
   - No E2E report (validation was `unit-only` or `skip`) → state the reason on the PR with `echo "MUGGLE_E2E_SKIP: <reason>"`, which settles the comment as a declared skip. A PR whose title says `[UNIT-ONLY]` still owes reviewers the why.

7. **Overflow comment:** if the walkthrough skill returned a non-null `comment`, post it once using the provider resolved in Step 5 — `github` per [`../../_shared/vcs/github/top-level-comment.md`](../../_shared/vcs/github/top-level-comment.md), `gitlab` per [`../../_shared/vcs/gitlab/mr-note.md`](../../_shared/vcs/gitlab/mr-note.md). End the posted body with the signature line (command `/muggle-do`) per [`../../_shared/vcs/post-signature.md`](../../_shared/vcs/post-signature.md). Never post when `comment` is `null`.

## Stage 7.5 gate

The E2E repair loop ([`../e2e-repair.md`](../e2e-repair.md)) runs once this stage has created the PR and posted the walkthrough, and before the handoff below. Proceed only on its `green`, `waived`, or `iteration-cap` clearance — handing a red run to a watcher puts it in front of reviewers with nobody looking at the failures. When Stage 6 recorded `PASS` or `SKIPPED` the loop clears in its own Step 0 at no cost, so there is never a reason to skip it.

## Stage 8 handoff

After every repo is processed and Stage 7.5 has cleared, build the watcher manifest and dispatch one watcher loop per opened PR. The dispatches are the LAST action this stage takes.

Write `~/.muggle-ai/muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#prsjson):

```json
[{ "repo": "owner/repo", "number": 142, "url": "...", "head_sha": "...", "state": "open" }]
```

Seed `~/.muggle-ai/muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty-watermark shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `lastBodyReviewId: 0`.

**Do not** seed `cycle.json` or `requirements.md`. The watcher is a dumb pipe; `/muggle-do` reads reviews off GitHub.

For each entry in `prs.json`, dispatch its watcher:
```
/loop 1m /muggle:muggle-pr-followup <slug> <pr-number>
```

If `prs.json` is empty, **do not dispatch** — record the reason in `result.md` and exit.

## Invariants

- Branch synced with its base before the push, never after; PR creation per non-skipped repo; designated walkthrough comment settled via Mode A, or its skip reason stated; `prs.json`+`last_seen.json` seeded (no `cycle.json`, no `requirements.md`); Stage 7.5 cleared before the dispatch; `/loop` dispatch is the last action.

## Output

**Synced with base:** repo → `rebased onto <base> (<n> behind)` | `already up to date` | `skipped (autoRebase)`
**PRs Created:** repo → URL
**Skipped:** repo → reason (when `autoCreatePR` short-circuited)
**Overflow comments posted:** repo → PR #
**Stage 7.5:** `green` | `waived — <reason>` | `iteration-cap`
**Stage 8:** `Watching <N> PR(s) — one /loop 1m /muggle:muggle-pr-followup <slug> <pr#> per PR` | `No PRs to watch — stage 8 not dispatched`
**Errors:** repo → message

## Post-merge cleanup

Gated by `autoCleanup`. Triggered when the watcher's terminal tick observes the merge and dispatches `/muggle-do`'s cleanup directive ([`../cleanup.md`](../cleanup.md)) — never from this stage. See [`../../_shared/post-merge-cleanup.md`](../../_shared/post-merge-cleanup.md).

Append one short reminder tied to the gate value:

- `always` → `Once merged, I'll run the cleanup sequence automatically.`
- `never` → omit.
- `ask` / absent → `Once merged, I'll check with you about cleanup.`

Regardless of the gate, also append: `Once it's merged or closed, I'll move to the next plan item — or ask where to go next if there's no plan.`
