---
name: rcand
description: Promote development to a release candidate.
---

**Host-native invocation:** Claude `/mmi:rcand` · Codex `$mmi:rcand` · jervcode `/rcand` · Hermes skill_view.

**Argument:** `/rcand minor|major|patch` — a bare bump word, never a flag or env var; none → `patch`.

# /rcand — promote development to release-candidate

Merge `development → rc`, tag `vX.Y.0-rc.N`, push the tag, wait for required checks, push the protected `rc`, start the rc deploy. `rc` is ephemeral: `/release` ships exactly what is on it and retires it. Needs train authority (project-admin or master). The board needs no touch.

## Lane

MM-Work suite lead or member: read [suite.md](suite.md) first. Name the lane from META:

```bash
mmi-cli oracle org project get {owner}/{repo} --json
```

`releaseTrack: direct` (product repos with explicit META, plus MMI-Hub) has no `rc`: run `/release` from `development`. Full-track may skip rc with `/release --dev`. On `deployModel: vercel` nothing is dispatched; `--watch` waits for the non-Production Vercel deployment, then probes its URL. Unreadable META → stop; never infer the lane.

## Preflight

```bash
mmi-cli devops train doctor --lane rcand --heal --json
```

Parse stdout only (never `2>&1`). `ready` false → stop and quote every blocker's `code` and `remedy`; an unread origin is never green. Findings carry `code`, `severity`, `source`, `remedy`, `anchor`. `--apply` re-runs the doctor.

## Apply

From the primary checkout on `development`, export `MMI_BUMP_INTENT=minor|major|patch` once and keep it through the following `/release`; `MMI_RELEASE_VERSION=X.Y.Z` only when tag math cannot derive it.

```bash
mkdir -p .jerv/tmp && r=$(mktemp .jerv/tmp/rcand-receipt.XXXXXX)
mmi-cli devops rcand --apply --json --out "$r"
```

`--watch` blocks on the deploy. Version-manifest merge conflicts take `development` (any other refuses); the `-rc.N` tag is re-run-safe. Deploy by model: `tenant-deploy.yml` for tenant-container; serverless, registry-publish and solo-container deploy via their push-triggered workflow. Never push, force or commit to `rc` by hand.

## Verify

Read the receipt at `$r`, never the exit code (`1` = deploy failed after promotion; unresolved exits `0`):

- `promoted` is `true` even when the deploy failed; `tag` is the minted `vX.Y.0-rc.N` (`resumeNote`: resumed).
- `deployStatus`: `pending` is never terminal. Watch each non-success run in `workflowRuns`: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`.
- `releaseVerdict`: `followUpStatus` (`complete` · `pending` · `failed`); a failed `legs` row carries its error.
- `checkout.status: returned` to `development` and `localSync`/`ledger` green, or the named reason.

Then confirm `git rev-list --count origin/rc..origin/development` is `0` and the rc tag is on origin (no GitHub Release at rc). A red deploy after green promotion is a deploy retry, never a re-tag or re-merge.

## Recovery

On any failure or interruption, read [recovery.md](recovery.md).

## Merge floor

- **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag, so tag-anchored checks mis-read. Any merge that carries an already-tagged commit — the `main → development` roll-forward, an alignment PR, a hotfix fold PR — lands as a true merge: `mmi-cli devops pr merge <number> --auto --merge` (or `--wait --merge`); `--wait` alone still squashes. The hotfix main-base PR itself may squash: its tag lands after, on the merged `main` HEAD, and the `-x` trailer must survive the squash message.
- **A refused train is a stop, never a license to finish by hand.** Every fail-closed halt — doctor blocker, authority probe, coverage guard, untolerated conflict, required checks, stray tag, ledger — ends the run. Fix the cause on `development` through a normal PR and rerun the train; never hand-resolve on `main`, hand-cherry-pick, bare-push a train branch, ack to save time, or bypass a check.
- **Version probes anchor on the latest Release tag, not a branch (#2734).** A branch manifest or a stale local tag is not a version source; a surviving local tag silently mints the next version.
- **One train at a time on a repo (#5380).** Two overlapping runs race the shared tag namespace; the ledger refuses the second — never start one to help the first.
- **Tag and Release deletion need Jervaise's yes (principle 12),** named in the guide entry that prescribes it.

## Report

Verdict first: the resolved tag (never a placeholder like `vX.Y.0`), Release URL, `releaseStatus`, `followUpStatus`, `deployStatus`, `promoted`, each run's conclusion and URL (or the no-run-URL note), which run is red (deploy/publish verdict or ordinary CI), `announceNote`, the alignment note (`devRollForward`, `rcAlignment` or the fold PR), `checkout`, the dispatch used. Pending is unverified, never success. Product names only when releasing that product's repo.

## Retro

Before the final report: did this skill misfire? Process only. If yes, file one lesson (hard cap: one per run); a clean run is silent; if the call fails, note it and continue. Lessons are deduplicated on the owning board and change the skill only by reviewed PR, never live; no issue references outside Merge floor.

```bash
mmi-cli learning skill-lesson --skill rcand --title "<what misfired>" --body "<what; evidence; proposed amendment>"
```
