# Release Handoff Profile

```yaml
roles: []
```

- Record the handoff shape in `releaseHandoff.handoffScope`: `mode` always, plus `stages`
  and `collectorBranch` in stage-group mode. The report is the only place a reader learns
  which stages shipped — the collector branch name does not say.
- Purpose: take an `accepted` final-verification verdict for an already-committed implementation branch and turn it into a delivered push and/or pull request, with explicit user selection at every mutating step. Two modes: **whole-task** (default — the verified task branch becomes one PR) and **stage-group** (a user-selected subset of verified stages is merged into a collector branch and becomes one PR).
- **Execution model: single-lead, no worker dispatch.** This phase is a thin orchestrator over `git` / `gh`; it does NOT dispatch teammates, does NOT dispatch analysis or drafter sub-agents, and does NOT run convergence. The host-native Okstra lead performs every step inline (drafting PR text, asking the user, running git / gh, writing the final report) — see "Lead-only contract" below.
- Worker roster: none — this profile intentionally has no `- Required workers:` block; the run is executed entirely by the Okstra lead.
- Lead-only contract (replaces the shared team contract for this phase):
  - The host-native Okstra lead is the sole agent for this run. No worker dispatch, no teammates, no parallel sub-agents, no convergence loop.
  - The lead drafts the PR title and PR body **inline** by reading the run brief, the cited final-verification report, `git log --oneline <base>..HEAD`, and `git diff <base>..HEAD --stat`. No drafter worker is dispatched.
  - The lead authors the final-report file directly (no `Report writer worker` dispatch). The report still conforms to the standard `templates/reports/final-report-v2.template.md` structure, including the `## 5.6 Release Handoff Deliverables` section.
  - The shared anti-escalation rule from the common contract still applies: do not start any other lifecycle phase from inside this run.
  - The shared "authority & permissions assumption" rule from the common contract still applies: assume the user holds every permission needed; do not block on hypothetical approvals.
- Pre-handoff entry gate (mandatory — refuse to start if any item fails):
  - the run's input document (`release-handoff-input.md`, generated by prepare in place of a task brief — briefs belong to entry phases only) carries a `## Source Verification Report` section with `Mode`, `Stages`, and one table row per cited `final-verification` final-report. The run context exposes the same selection as `HANDOFF_MODE` (`whole-task` | `stage-group`) and `HANDOFF_STAGES` (csv, empty for whole-task).
  - **whole-task mode** (`HANDOFF_MODE=whole-task`): the lead opens the cited report and confirms its `verificationScope` is `whole-task` and its verdict is release-ready — `Verdict Token` exactly `accepted`, or exactly `conditional-accept` with every **Conditional Acceptance Condition** row declaring `blocksReleaseHandoff: false`. The rule lives in `okstra_ctl.release_gate.release_handoff_allowed`; the lead reads the report against it and does not invent a third case.
  - **stage-group mode** (`HANDOFF_MODE=stage-group`): the lead opens each cited single-stage report and confirms every verdict is release-ready by the same rule as whole-task mode. Eligibility was already enforced at prepare time (`okstra_ctl.handoff.compute_eligibility`) and is re-enforced by `okstra handoff assemble` — the lead never hand-computes it.
  - if the verdict is `blocked`, a `conditional-accept` carrying any condition that blocks release, or any other token (including ambiguous phrasing like "looks good"), the run MUST end immediately with status `blocked` and a routing recommendation back to `error-analysis` or `implementation-planning`. Do NOT prompt the user; Do NOT run any git command.
  - when the cited verdict is `conditional-accept`, the lead MUST carry every **Conditional Acceptance Condition** row into the PR body under a heading naming them as unresolved — id, condition, and the evidence the reviewer would need. These conditions are the whole reason a non-`accepted` verdict was allowed through; a PR body that drops them turns a recorded condition into a silent one.
  - the lead MUST capture `git status --short` and confirm the working tree is clean. Dirty state aborts the run; release-handoff packages the commits produced by `implementation`, it does not stage or commit changes.
  - the lead MUST capture `git rev-parse --abbrev-ref HEAD` and record it as the **feature branch**. If the current branch is itself `main`, `master`, `prod`, `preprod`, `staging`, or `dev`, the run MUST end immediately — release-handoff never operates on a base branch.
  - the lead MUST confirm `git log --oneline <base>..HEAD` contains at least one implementation commit. If it is empty, the run MUST end with status `blocked` and route back to `implementation`.
- User interaction protocol (Okstra lead — performed in order, using the selected runtime adapter's interactive prompt):
  1. **Action selection** — present three choices and capture exactly one:
     - `local checkout` — bring a verified branch into the MAIN worktree for local testing (no push, no PR). Two targets: the whole-task branch (whole-task mode only), or a single stage's stack branch (`--stage N`, available in both modes since stage branches survive verification). See step 1c. When `HANDOFF_MODE` is `stage-group`, offer only the per-stage target.
     - `push + PR` — push the feature branch, then open or reuse a pull request.
     - `skip` — cancel delivery actions for now: record that release-handoff was intentionally skipped and end the run without any git command.
     If the user picks `skip`, route directly to the final-report self-review pass.
  1c. **Local checkout execution** (only when the user picked `local checkout`) — first ask which target — when `HANDOFF_MODE` is `whole-task`, offer both the whole-task branch and one stage's stack branch; when it is `stage-group`, offer only the per-stage target — listing the selectable stage numbers (from the approved plan's Stage Map, since the run input document carries no Stage Map). Then confirm with the user that okstra will remove the corresponding okstra worktree (when it still exists) and `git checkout <branch>` in the MAIN worktree, and that the base branch is never modified. On confirmation run:
      `okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t>` — append `--stage <N>` for the per-stage target.
      Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra worktree for that target no longer exists — if the lead's cwd was inside it, EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
  - **stage-group mode step order** (overrides the default Q1→Q3 sequence): after Q1 picks `push + PR`, run (1) base-branch selection first — identical to Q2 below, because the dependency-closure check needs `origin/<base>`; (2) G2 stage confirmation (step 1g); (3) assemble (step 2g); then Q2b and Q3 as usual, with the collector branch as the PR head.
  1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR target stage: <csv> — proceeding`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
  2g. **assemble**: run `okstra handoff assemble --plan-run-root <...> --approved-plan <...> --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --work-category <c> --stages <csv> --base <chosen-base>`. Exit 2 means a stage-vs-stage merge conflict: show the `conflicts` paths and stop (route: reshape the group or resolve manually). Exit 1 means an eligibility/closure violation: show the error verbatim and re-ask G2. On success the returned `branch` is the PR head branch for every subsequent step.
  2. **PR base branch** (only when the user picked `push + PR`) — present four options and capture exactly one:
     - `preprod`
     - `main`
     - `direct input` (free-form branch name; lead validates the name exists on origin via `git ls-remote --heads origin <name>` and re-asks on failure)
     The chosen base MUST NOT equal the feature branch. If it does, re-ask.
  2b. **Pre-merge conflict probe** (only when the user picked `push + PR`) — before the push/PR step, the lead MUST refresh the base ref and probe for merge conflicts against it:
     - run `git fetch origin <chosen-base>` (read-only on the local working tree).
     - run `git merge-tree --write-tree --merge-base origin/<chosen-base> HEAD origin/<chosen-base>`. A non-zero exit code OR conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in the output indicate a merge conflict against the chosen base.
     - If no conflict is detected, proceed silently to Q3 (do NOT add a confirmation prompt — keep the happy path frictionless).
     - If a conflict IS detected, present the conflicting paths (parsed from the `merge-tree` output) and capture exactly one:
       - `proceed anyway` — continue to Q3; the PR will be opened with conflicts and the final report MUST flag this in `Merge Conflict Probe`.
       - `change base branch` — return to Q2 and re-ask the base selection.
       - `cancel` — end the run without push or PR; record the cancellation in the final report.
     - The probe is read-only. It MUST NOT run `git merge`, `git rebase`, `git pull`, or any command that mutates the working tree or local refs.
  3. **PR title + PR body confirmation** — show the lead's inline draft verbatim, together with the filled-body self-check result (either `body self-check: clean` or the list of hits with their lines, per the drafting rules below), and capture one of:
     - `use as-is` — proceed with the drafted text.
     - `edit then proceed` — accept inline edits from the user, then proceed with the edited text.
     - `cancel` — end the run without executing push or PR commands; record the cancellation in the final report.
- Inline drafting rules (Okstra lead):
  - read the run brief, the cited final-verification report, `git log --oneline <base>..HEAD`, and `git diff <base>..HEAD --stat` to ground the drafted text in actual committed changes. In stage-group mode the draft is grounded on `git log <implementation_base_commit>..<collector HEAD>` / `git diff <implementation_base_commit>..<collector HEAD> --stat`, with source material = each selected stage's implementation report + its single-stage verification report.
  - **PR body template** — the run context exposes `PR_TEMPLATE_PATH` and `PR_TEMPLATE_SOURCE`. The path MUST be an okstra-owned project artifact under `<PROJECT_ROOT>/.okstra/**`, or a file the prepare step already materialised into this run's artifact directory. If the resolved file is missing or outside that boundary at draft time, abort with a clear error — do NOT invent a structure. Otherwise the lead MUST `Read` it verbatim, strip HTML comments, and fill in the placeholders, treating the template (never a hard-coded section list) as the source of truth for the structure.
  - produce **two artifacts** before showing them to the user:
    1. **PR title** — by default the subject of the most recent implementation commit, or a concise Conventional Commits-style summary of the committed range.
    2. **PR body** — markdown filled from `PR_TEMPLATE_PATH`. The user-confirmation step's diff (Q3 `edit then proceed`) is computed against the filled template, not against the raw template file.
  - **Filled-body self-check (runs on the drafted body, before Q3 shows it).** "Fill in the placeholders" is only observable if someone checks that they were filled, so scan the drafted body for these and carry the result into Q3: a residual HTML comment or template marker (`<!-- … -->`, `_Describe your changes…_`, a bare `TODO` / `FIXME` the diff did not introduce), an unchecked `- [ ]` box with no inline N/A justification, a section heading whose body is empty, and a whole body short enough to carry no substance. Each hit is reported to the user with its line — never silently left in, and never auto-filled with invented content. The user remains free to accept it; the point is that they see it before choosing `use as-is`.
- Allowed actions during the run (Okstra lead only):
  - read-only inspection: `git status`, `git status --short`, `git diff`, `git log`, `git rev-parse`, `git ls-remote --heads origin <name>`, `gh pr list --head <branch>`, `gh pr view <url>`.
  - merge-conflict probe (only when the user picked `push + PR`): `git fetch origin <chosen-base>` and `git merge-tree --write-tree --merge-base origin/<chosen-base> HEAD origin/<chosen-base>`. Both are non-mutating with respect to the working tree.
  - feature-branch push (only when the user picked `push + PR`): `git push -u origin <current-branch>`. The pushed ref MUST be the feature branch — never the chosen base branch. (stage-group mode: the collector branch returned by assemble)
  - PR creation (only when the user picked `push + PR` AND no PR with the same head already exists on origin): `gh pr create --base <chosen-base> --head <current-branch> --title "<title>" --body "<body>"`. The title and body are the user-confirmed PR draft.
  - PR reuse: if `gh pr list --head <branch> --state open --json url --jq '.[0].url'` returns a URL, treat that PR as already existing — record the URL in the final report and SKIP `gh pr create`.
  - after `gh pr create` succeeds (or an existing PR is reused), the lead MUST run `okstra handoff record-pr --plan-run-root <...> --stages <csv> --branch <head branch> --url <pr url>` and quote the command + exit code in the final report. This applies to BOTH modes — whole-task runs record `--stages` as the full Stage Map list — so duplicate-PR prevention for both modes converges on a single consumers ledger.
  - stage-group helpers: `okstra handoff eligible`, `okstra handoff assemble`, `okstra handoff record-pr`. The assemble step is the ONLY path that may create commits (merge commits on the collector branch) in this phase.
- Forbidden actions (any occurrence → terminal status `contract-violated`):
{{PHASE_FORBIDDEN_ACTIONS}}
- Required deliverable shape (final report, in addition to the standard sections):
  - **Source Verification Report**: relative path of the originating `final-verification` final-report file plus the literal quoted `Verdict Token` row, and — when that token is `conditional-accept` — every Conditional Acceptance Condition row quoted with its `blocksReleaseHandoff` value.
  - **Feature Branch & Working-Tree State**: branch name from `git rev-parse --abbrev-ref HEAD`, output of `git status --short` at run start.
  - **User Selections**: a block recording each prompt and the user's verbatim answer.
    - Q1 action: `local checkout` | `push + PR` | `skip`.
    - Q1c checkout target (only when Q1 is `local checkout`): `whole-task branch` | `stage <N> stack branch`, plus the `--stage <N>` value this answer produced (or `no --stage` for the whole-task branch). Record it in the `User Selections` row `H1c` (`userSelections.h1c`); omit the row entirely when Q1 was not `local checkout`.
    - Q2 PR base (if applicable): the chosen branch and how it was selected (menu pick vs free-form input).
    - Q2b merge-conflict probe (if applicable): `not-run` | `clean` (no conflict, no prompt shown) | `proceed anyway` | `change base branch` | `cancel`. Record it in both the `User Selections` row `H2b` and the `Merge Conflict Probe` deliverable. When a conflict was detected, list the conflicting paths.
    - Q3 title/body: `use as-is` | `edit then proceed` (with a diff between the lead's draft and the final text) | `cancel`.
  - **Executed Commands**: every git / gh command the lead actually ran, with its exit code and a one-line stdout/stderr summary. Read-only inspection commands MAY be summarised; mutating commands MUST be listed verbatim.
  - **Commit List**: each existing implementation commit in `git log <base>..HEAD`, with short/full SHA, subject line, and touched files. Release-handoff MUST NOT create new commits.
  - **Merge Conflict Probe**: one of
    - `- Not run (user picked local checkout or skip).`
    - `- Clean — no conflicts against <base> at <origin/base SHA>.`
    - `- Conflicts detected against <base> at <origin/base SHA>; user chose <proceed anyway | change base branch | cancel>. Conflicting paths: <list>.`
  - **Pull Request Outcome**: one of
    - `- No PR action requested.` (user picked `local checkout` or `skip`)
    - `- PR created: <url>` with title and base branch
    - `- PR reused: <url>` when an existing PR was found via `gh pr list`
    - `- PR creation skipped: <reason>` for any user-driven cancellation
  - **Local Checkout Outcome**: one of
    - `- Not run (user picked push + PR or skip).`
    - `- Checked out <branch> into <main worktree path>; okstra worktree <path> removed. Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
    - `- Checked out <branch> into <main worktree path>; no okstra worktree removed (already torn down — the branch survived). Next: to run a local test and then open a PR, re-enter release-handoff via okstra-run → push + PR.`
    - Pick between the two `Checked out` variants by the command's `removedWorktree` field: a non-empty path takes the first, an empty string takes the second. Never write a removal that did not happen.
  - **Stage Group** (stage-group mode only): selected stages, each stage's single-stage verification report path + quoted `Verdict Token` row, collector branch name, merge commit SHAs from assemble, and the dependency-closure verdict (from the assemble output / error).
  - **Routing recommendation**: explicit `done` token, since release-handoff is the terminal lifecycle phase. If the run ended in `skip` or `cancel`, the recommendation MUST also state whether re-entry into release-handoff is appropriate.
- Self-review pass before finalising the report (the Okstra lead runs this):
  1. **Entry-gate audit** — section 2 cites the originating final-verification report path and the literal `Verdict Token` row with a release-ready value. If either is missing, or a `conditional-accept` run's PR body omits the conditions, the run is invalid and MUST be re-routed to `final-verification`.
  2. **User-selection traceability** — every executed mutating command maps to a user selection captured in the report. Any mutating command without a corresponding user answer is a contract violation.
  3. **Forbidden-action audit** — scan the run's session transcripts (`git`, `gh` invocations) for every entry in the Forbidden actions list above. Any occurrence means the run has crossed into unsafe territory and MUST be flagged as `contract-violated`.
  4. **Push-target audit** — for every `git push` recorded, confirm the refspec resolves to the feature branch, not the base branch.
  5. **Idempotency check** — if a PR with the same head already existed at run start, confirm the report records `PR reused` rather than a fresh `gh pr create` invocation.
  6. **Merge-conflict probe audit** — for any `push + PR` run, confirm the report's `Merge Conflict Probe` section is present and either records `Clean` or records `Conflicts detected` with the user's verbatim choice. A missing or unparseable probe entry on a `push + PR` run is a contract violation.
- Non-goals:
  - re-litigating the final-verification verdict — release-handoff trusts the cited release-ready verdict and does not reopen acceptance checks. Carrying a conditional-accept's conditions into the PR body is transcription, not verification: the lead does not check whether a condition has been satisfied.
  - creating, amending, squashing, or rewriting commits. Commit production belongs to `implementation`.
  - opening additional PRs, releases, or deployments beyond the single PR the user chose to create.
  - merging the PR. Merging is a separate, manual step performed by the user (or by repo automation) after release-handoff ends; the lead MUST NOT call `gh pr merge`.
  - escalating beyond the menu choices on user phrasing — every mutating action requires an explicit menu selection.
