On Windows set `git config core.longpaths true` on the main checkout before the first
`git worktree add` (#5499). Linked worktrees share one `.git`, so serialize `git branch -m` and other ref
renames across them, or retry serially when the error names `.tmp-renamed-log` (#5485).

A repo running a guidance-learning gate also needs the body's learning line PLANNED here, not patched in
after a red check: when the batch's touch-set intersects that repo's guidance files (Jerv-JervCode:
`product/soul.md`, `product/runbooks/**`, `packages/*/skills/**/SKILL.md`), the body must carry a
standalone `learning: none — <reason>` line unless a closing learning issue's `promote.globs` names a
changed file. The line must stand alone on its own newline — a literal `\n` inside an inline edit fails
the gate again.


## Detail moved from SKILL.md

Prefer `--out` for a shell-independent UTF-8 receipt. Windows PowerShell 5.1's `>` writes
UTF-16LE with a BOM (#5802); Bash redirects preserve the CLI's UTF-8 output.

One call. Its JSON carries `viewer`, `repo` and the project title — do not spend extra calls on
`gh api user` or `gh repo view`. Use `primary` for this repo and `secondary` for other repos on the same
Project. Partial reads exit nonzero; pass `--allow-partial` only when the dev accepts an incomplete board.

Partition, as the CLI computes it:

- **Yours** — assignee includes the viewer, status in `Todo · In Progress · In Review`, or stamped by this
  seat (same login, host, and surface, including a prior session on this host whose transcript is dead).
- **Free to claim** — status `Todo`, unassigned, and the viewer has push on the repo. Also any item in
  any status whose foreign claim stamp is stale: its session has done no work on it for 4 hours. A stale stamp
  holds nothing; `board claim` takes it over without `--force` and names the old stamp.
- **Taken** — someone else's, any active status.

Every stamped row names its session (`lane surface/session@host`), or `stale:<age>` when the stamp is
stale. Work means the stamp, an issue comment, a commit on the issue's branch, or an update to an open
PR that closes it. Any of these in the last 4 hours keeps the hold; a date that cannot be read counts as
work. A takeover keeps the old branch and PR and names them, so the new session continues them.

`--bodies` fetches body and comments for every scoped issue. In the JSON, read them at
`row.details.body` and `row.details.comments` — not `row.body` or `row.comments`. `--bundle-details` is
the cheaper variant that covers only `userOwned` and `claimable` — prefer it when the plan is limited
to claimable work. `taken` stays metadata-only either way. Do not fetch Done items.

3. **Groups are disjoint by construction**, so every group runs in parallel with no worktree contention.
   That is the whole trick — the number of groups is the number of PRs, and it is the smallest number
   reachable without two PRs fighting over the same file.

Forced splits — these override the grouping and each takes its own PR:

- **Another repo.** Never bundle across repos. Board advance is per-repo and deliberately refuses to move
  another repo's issue, so a cross-repo bundle lands the code and leaves those issues stranded open.
- **Irreversible or gated work** — migrations, secret rotation, release-train changes. Bundling hides them.
- **An issue that must stay open** (HOLD, prep, partial delivery).
- **Review size.** A PR no one can review is not cheap. When a group grows past roughly ten issues or
  spans unrelated subsystems, cut it at its weakest overlap and take two PRs.

> Nine claimable, three PRs: **A** #6395–#6397 board routing · **B** #6398–#6401 train doctor heal ·
> **C** #6402–#6403 CLI flag validation. Say go and I'll run all three in parallel.

Claiming takes a card that is unassigned or assigned to the viewer, in `Todo`, `In Progress` or
`In Review`, unless another session still shows work on it in the last 4 hours (then it refuses). It assigns the viewer, sets
`In Progress` and stamps a lane-identity comment.

Then one worktree per batch, all batches concurrently. The host owns worktree mechanics; MMI owns board
and PR facts.

`pr create` normalizes multiple closing directives, and after the merge the board advance walks GitHub's
full `closingIssuesReferences` list and moves **each** issue to Done, verifying every one and naming any
that did not move. So a bundle is a first-class landing, not a trick.

Materialize the body as a real UTF-8 file and pass its path; do not pipe it to `--body-file -`. Read
`mmi-cli explain devops pr create --json` before the write — flags change.

When an issue must stay open, write `Part of #N` or `Refs #N`. **Never** write `Does not close #N` —
GitHub closes it anyway (JC#495).

Landing requires a merged receipt before any cleanup: `state` `MERGED`, the head ref and OID matching the
local task branch, and a clean worktree. Anything else means retain and report, never clean.

Retro: the lesson lands on the owning board (deduped) and is fixed only via a reviewed PR — never edit the skill live; the retro is advisory. A misfire is ambiguous wording, a misleading message, or an environment failure the skill should have warned about (e.g. a grouping rule that bundled two issues which turned out to conflict, or a board read that misreported what was claimable). Hard cap: one lesson per run.
