@mutmutco/codex-plugin 4.3.4 → 4.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mmi",
3
- "version": "4.3.4",
3
+ "version": "4.3.6",
4
4
  "mmiCompat": "4.x",
5
5
  "description": "MMI workflow skills and org gates delivery.",
6
6
  "author": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/codex-plugin",
3
- "version": "4.3.4",
3
+ "version": "4.3.6",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -125,15 +125,18 @@ mmi-cli devops bootstrap verify "$OWNER/$REPO" --class content --json
125
125
  ```
126
126
 
127
127
  Run it again after Step 7. A repo is not ready for real developers until every check is green, or the report
128
- names an explicitly manual-only item that the master has accepted for that repo.
128
+ names an explicitly manual-only item that the master has accepted for that repo. For a deployable repo the
129
+ report ends with the train doctor verdict per lane (`release`; plus `rcand` on a full track) — the same
130
+ `mmi-cli devops train doctor` door `/release` and `/rcand` open (#6070); a `ready: false` there is an
131
+ unfinished repo.
129
132
 
130
- **Two verify FAILs are un-run manual steps or API lag, not code bugs — diagnose them as such, but never as
133
+ **Two verify FAILs are un-run apply steps or API lag, not code bugs — diagnose them as such, but never as
131
134
  acceptable end states (#2928):**
132
- - `branch protection exists` / `push allowlist configured` — **`bootstrap apply` does not apply branch
133
- protection.** That is **Step 2b**, and it is manual, so these FAIL until you run it. **Step 2b is
134
- mandatory**: these are security controls, and they must go green (or be an explicitly master-accepted
135
- manual item per the rule above) before the bootstrap is complete. A red branch-protection or
136
- push-allowlist check is an **unfinished repo**, never a known-benign FAIL to sign off around.
135
+ - `branch protection exists` / `push allowlist configured` — **`bootstrap apply --execute` applies the
136
+ train-branch push allowlist (Step 2b)**, so these FAIL until the live apply has run. They are security
137
+ controls and must go green (or be an explicitly master-accepted manual item per the rule above) before
138
+ the bootstrap is complete. A red branch-protection or push-allowlist check is an **unfinished repo**,
139
+ never a known-benign FAIL to sign off around.
137
140
  - `README has Agent context section — README.md not readable via API` on a README that demonstrably has the
138
141
  section — GitHub's contents API lags for a minute or so right after a merge. **Re-run before believing a
139
142
  content-read failure**; it clears on its own.
@@ -193,29 +196,21 @@ so a direct-track repo never gets a stray `rc` the `mmi-train-floor` ruleset can
193
196
  Ensure exactly the track's permanent branches exist and set the default branch — create only what the track
194
197
  uses; never create an `rc` for a direct-track repo.
195
198
 
196
- **Create `rc`/`main` server-side, not with `git push` (#3433).** The local **#1660 protected-branch push
197
- guard** fences every push to `main`/`master`/`rc`, including the legitimate *creation* of those refs on a
198
- brand-new repo so a `git push origin development rc main` cannot be run as written. Creating the refs
199
- through the API is not a force-push, so both the #1660 guard and the `mmi-train-floor` ruleset allow it, and
200
- it behaves the same on every machine. `development` (or `main`, for a content repo) already exists from
201
- Step 0b:
199
+ **`bootstrap apply --execute` creates `rc`/`main` server-side from the track's first branch (#6070).** The
200
+ local **#1660 protected-branch push guard** fences every push to `main`/`master`/`rc`, including the
201
+ legitimate *creation* of those refs on a brand-new repo (#3433); a ref created through the API is not a
202
+ force-push, so both the guard and the `mmi-train-floor` ruleset allow it. The apply's train-readiness plan
203
+ prints one `lane-branch` row per track branch `CREATE` (missing), `SKIP` (already exists), or `GAP`
204
+ (`bootstrap-gap`: the first branch from Step 0b is missing, so there is no source ref) — and the live apply
205
+ creates every `CREATE` row; a `422 Reference already exists` reply is the idempotent no-op, not a failure.
206
+ `development` (or `main`, for a content repo) already exists from Step 0b. Only the default branch stays a
207
+ `gh` write:
202
208
  ```bash
203
- sha=$(gh api "repos/$OWNER/$REPO/git/ref/heads/development" --jq '.object.sha')
204
-
205
- # full — development (Step 0b) + rc + main
206
- gh api "repos/$OWNER/$REPO/git/refs" -f ref=refs/heads/rc -f sha="$sha"
207
- gh api "repos/$OWNER/$REPO/git/refs" -f ref=refs/heads/main -f sha="$sha"
208
- gh repo edit "$OWNER/$REPO" --default-branch development
209
-
210
- # direct — development (Step 0b) + main, NO rc
211
- gh api "repos/$OWNER/$REPO/git/refs" -f ref=refs/heads/main -f sha="$sha"
212
- gh repo edit "$OWNER/$REPO" --default-branch development
213
-
214
- # trunk (content) — main only; Step 0b already created it with `-b main`
215
- gh repo edit "$OWNER/$REPO" --default-branch main
209
+ gh repo edit "$OWNER/$REPO" --default-branch development # full / direct
210
+ gh repo edit "$OWNER/$REPO" --default-branch main # trunk (content)
216
211
  ```
217
- Re-running a create on a ref that already exists returns `422 Reference already exists` that is the
218
- idempotent no-op, not a failure. Verify with `gh api "repos/$OWNER/$REPO/branches" --jq '.[].name'`.
212
+ Verify with `gh api "repos/$OWNER/$REPO/branches" --jq '.[].name'`, or read the `lane-branch` rows of the
213
+ next dry-run `bootstrap apply`.
219
214
 
220
215
  ## Step 2 — authority (org Ruleset)
221
216
 
@@ -229,39 +224,19 @@ apply those contexts org-wide unless every target repo exposes them.
229
224
 
230
225
  ## Step 2b — lock the train branches (who can push)
231
226
 
232
- The ruleset says *a PR is required*; this says *who may merge it*. Apply classic branch protection on
233
- `development`/`rc`/`main` for deployable repos, or just `main` for content repos, with **"Restrict who can
234
- push"** = the master + the App (the repo's full-write people get added at Step 4b). Everyone else is
235
- `write`-locked on protected branches: they push feature branches and open PRs but cannot merge there. Run per
236
- protected branch (App token):
227
+ The ruleset says *a PR is required*; this says *who may merge it*. `bootstrap apply --execute` applies the
228
+ classic branch protection on `development`/`rc`/`main` for deployable repos, or just `main` for content
229
+ repos, with **"Restrict who can push"** = the org owners + the App (#6070): the owners are resolved live
230
+ from the GitHub org admins (`orgs/$OWNER/members?role=admin`), never a hard-coded user list an empty
231
+ resolution refuses to write an empty allowlist — and the App is `mmi-github-app`. The repo's full-write
232
+ people get added at Step 4b. Everyone else is `write`-locked on protected branches: they push feature
233
+ branches and open PRs but cannot merge there.
237
234
 
238
- ```bash
239
- BRANCHES="development rc main" # full
240
- BRANCHES="development main" # direct (no rc)
241
- BRANCHES="main" # trunk / content
242
-
243
- mapfile -t MASTER_USERS < <(gh api --paginate "orgs/$OWNER/members?role=admin" --jq '.[].login')
244
- if [ "${#MASTER_USERS[@]}" -eq 0 ]; then
245
- echo "No org owners resolved for $OWNER; stop before writing branch protection." >&2
246
- exit 1
247
- fi
248
- USERS_JSON=$(printf '%s\n' "${MASTER_USERS[@]}" | node -e "const fs=require('fs'); const users=fs.readFileSync(0,'utf8').trim().split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(users));")
249
-
250
- for b in $BRANCHES; do
251
- node - "$USERS_JSON" <<'NODE' | gh api --method PUT repos/$OWNER/$REPO/branches/$b/protection --input -
252
- const users = JSON.parse(process.argv[2]);
253
- process.stdout.write(JSON.stringify({
254
- required_status_checks: null,
255
- enforce_admins: false,
256
- required_pull_request_reviews: null,
257
- restrictions: { users, teams: [], apps: ['mmi-github-app'] },
258
- }, null, 2));
259
- NODE
260
- done
261
- ```
262
-
263
- Only the master (sole repo `admin`) can change this afterward. Full grant/lock mechanics + inspect commands:
264
- `docs/Guides/repo-access.md`.
235
+ The plan prints one `push-allowlist` row per track branch — `UPDATE` (preserve every existing
236
+ review/status/admin/force-push bit and replace only the push restriction), `SKIP` (exact owners + App
237
+ already present), or `GAP` (`bootstrap-gap`: the protection read failed; zero writes are performed while any
238
+ control-plane read is unverified). Only the master (sole repo `admin`) can change this afterward. Full
239
+ grant/lock mechanics + inspect commands: `docs/Guides/repo-access.md`.
265
240
 
266
241
  ## Step 3 — attach to the repo's Project (one board per repo; confirm)
267
242
 
@@ -336,6 +311,9 @@ box assignment** — the `sshHost` (and the loopback port) per stage — then wr
336
311
  `mmi-cli oracle org project set-deploy <owner/repo> --stage <dev|rc|main> --ssh-host <host> [--port <p>]` (defaults:
337
312
  `substrate: hetzner-ssh`, deploy path `/opt/mmi/<slug>/<stage>`, service = slug, ssh-user `root`). Without those
338
313
  rows the tenant cannot deploy (`tenant-deploy.yml` errors on missing `DEPLOY#` coords), so do not skip this.
314
+ `bootstrap apply` prints one `deploy-row` row per track stage for container models (#6070): `SKIP` when the
315
+ registry row exists, `GAP` (`bootstrap-gap`) with the exact `set-deploy` command otherwise — a box
316
+ assignment cannot be invented, so this row is the one train-readiness fact the apply never writes itself.
339
317
  Keep every runtime config value in the vault; never paste secret values into logs.
340
318
 
341
319
  Only an AWS `tenant-container` (the exception) provisions the reusable tenant stack: release bucket,
@@ -390,13 +368,15 @@ collaborator list + the per-branch allowlist are the record — no separate rost
390
368
  under the org **wall-clock budget** (#3178): the render pins `run-with-budget` to the CLI's blessed SHA
391
369
  with `--var GATE_MAX_SECONDS=` (300s onboarding default — tighten once the gate is measured, via
392
370
  `--var` or `org project set <repo> --var gate={"maxSeconds":N}`); `ci audit` and the release train
393
- both enforce the step, so do not remove it. After apply,
394
- master-admin must **activate** that JSON as a repository ruleset (GitHub Settings Rules Rulesets
395
- Import/create from the committed reference) so the `gate` context is required on train branches. Once the
396
- gate is green on `development`, `mmi-cli devops ci reconcile --apply --repo $OWNER/$REPO` should flip enforcement
397
- to **Active**; if it does not, use the Step 5 PUT fallback and confirm with `bootstrap verify` before
398
- reporting bootstrap complete. MMI-Hub keeps its own three-job gate (`cli`/`infra`/`docs`) never apply the
399
- product ruleset there.
371
+ both enforce the step, so do not remove it. `bootstrap apply --execute` installs that JSON as the
372
+ repository ruleset itself (#6070) and reports one `product-ruleset` row: `PARK` (the gate file is not on
373
+ the base branch yet — installed disabled), `WAIT` (the gate exists but has not emitted a proven-green
374
+ `gate` context kept disabled; re-run apply after the gate passes), `ACTIVATE` (gate green enforcement
375
+ active), or `SKIP` (already exact). The activation boundary is fail-closed on purpose: a required context
376
+ that cannot pass yet would lock the seed PR behind itself. `mmi-cli devops ci reconcile --apply --repo
377
+ $OWNER/$REPO` remains the supported fallback; confirm `product required-check ruleset enforcement active`
378
+ with `bootstrap verify` before reporting bootstrap complete. MMI-Hub keeps its own three-job gate
379
+ (`cli`/`infra`/`docs`) — never apply the product ruleset there.
400
380
  - **A brand-new repo cannot pass the gate you just installed — its first commit must carry a real project
401
381
  (#2928).** The seeded `gate.yml` runs `GATE_INSTALL_CMD` + `GATE_CMD` (`npm ci` + `npm run check` by
402
382
  default) **unconditionally**. An empty repo has no `package.json`, so the gate **fails on the seed PR
@@ -552,7 +532,16 @@ Repo, default branch, ruleset applied, train branches locked (push allowlist), r
552
532
  provisioned per track (plan-gated protections named in apply output), project attached/created
553
533
  (+ info seeded, Status lanes and Labels field verified), secrets set (names only), developer access, plugin
554
534
  installed, docs seeded, registry META written, issue templates committed, org App credentials registered,
555
- org-managed `.gitignore` block seeded, and the final `mmi-cli devops bootstrap verify "$OWNER/$REPO" --class ... --json` result.
535
+ org-managed `.gitignore` block seeded, the final `mmi-cli devops bootstrap verify "$OWNER/$REPO" --class ... --json` result,
536
+ and — for a deployable repo — the train door itself, run from the repo's own checkout on `development`:
537
+
538
+ ```bash
539
+ mmi-cli devops train doctor --lane release --repo "$OWNER/$REPO" --json
540
+ ```
541
+
542
+ `ready: true` is the bootstrap's train-readiness proof; every finding carries `code`, `severity`, `source`,
543
+ `remedy` and a `docs/Guides/train-troubleshooting.md#<code>` anchor. A full-track repo runs
544
+ `--lane rcand` as well. A `bootstrap-gap` blocker names the apply row still missing.
556
545
 
557
546
  ## Retro — one check before you finish
558
547
  Before your final report, answer one question honestly: did **this skill's own instructions** misfire
@@ -5,172 +5,97 @@ description: Promote an already-merged development fix to main and production th
5
5
 
6
6
  **Host-native invocation:** Claude `/mmi:hotfix` · Codex `$mmi:hotfix` · Cursor `/hotfix` · jervcode `/hotfix` · Hermes skill_view. A backticked `/name` in this doc names the matching workflow (this skill or a sibling), not a literal command.
7
7
 
8
+ **Argument:** none. A hotfix is PATCH-only; leave `MMI_BUMP_INTENT` and `MMI_RELEASE_VERSION` unset — a non-patch declaration refuses.
9
+
8
10
  # /hotfix — promote a development fix to main + prod
9
11
 
10
- A hotfix is promotion, not authoring. The fix must land on `development` through a normal issue,
11
- worktree, PR, review, and CI gate first. Hub then ports that merged PR or SHA to a main-base hotfix PR,
12
- preserves the cherry-pick audit trail, and performs the PATCH release. Never author directly from `main`.
13
- Never author the fix on a branch off `main`. The main-base branch is only the orchestrated port of a fix
14
- that is already merged to `development`.
15
-
16
- The FIX is never back-merged: `development` already contains it, and `rc` absorbs it at the next
17
- `/rcand`. The release hotfix-coverage guard blocks a later candidate that omits the production fix.
18
-
19
- The VERSION FOLD is different, and `hotfix release` ports it for you (#4410). `hotfix start` commits the
20
- fold onto the main-base branch, so after the tag `main` declares the new version while `development`
21
- still declares the old one. The Hub's catalogs now pin exact npm packages (#4948), so there is no
22
- branch/content lockstep red; the fold still must land so the next release starts from production's real
23
- version, BOM, and package pins. Step 3 opens that development-base fold PR automatically; land it.
24
-
25
- ## Merge floor (#3167 — non-negotiable)
26
-
27
- - **Never squash-merge a tagged commit.** The hotfix PR itself may squash (step 2 — the tag lands *after*,
28
- on the merged `main` HEAD, and the `-x` trailer must survive the squash message). But any merge that
29
- carries an already-tagged commit — an alignment PR, a later `main → development` roll-forward — lands as a
30
- true merge, never squash: a squash re-mints the SHA and orphans the tag from the branch lineage.
31
- - **A refused release train is a stop, never a license to finish by hand.** A conflict on the port, a red
32
- authority probe, a failed required check, a refused `hotfix release` — each ends the run. Fix the cause on
33
- `development` through a normal PR and re-run the orchestrator; never hand-cherry-pick, bare-push, or
34
- bypass the gate to finish.
35
- - **Version probes anchor on the latest Release tag, not a branch.** `hotfix status` derives the PATCH from
36
- the latest Release tag; branch manifests and stale local tags are not version sources.
37
-
38
- ## Authority and preflight
39
-
40
- Production changes require the authorized human's explicit approval in the current turn. Before describing
41
- or executing any hotfix lane, read the project META and name the lane (#5244 — same gate as `/release`):
12
+ A hotfix is promotion, not authoring. The fix lands on `development` first through a normal issue, worktree, PR, review and CI gate; Hub then ports that merged PR or SHA onto a main-base branch as a cherry-pick with `-x`, keeps the audit trail, and performs the PATCH release. Never author the fix on a branch off `main`. The FIX is never back-merged: `development` already has it, `rc` absorbs it at the next `/rcand`, and the release hotfix-coverage guard blocks a later candidate that omits it. The VERSION FOLD is different: `hotfix release` ports it to `development` as a fold PR — NOT a back-merge, nothing from `main` is merged into `development`.
13
+
14
+ ## Lane
15
+
16
+ Read META and name the lane before describing or executing anything:
17
+
42
18
  ```bash
43
19
  mmi-cli oracle org project get {owner}/{repo} --json
44
20
  ```
45
- `releaseTrack: direct` means `development → main` only — **no `rc` branch** (MMI-Hub included via the
46
- Hub-control special case). Stop on an unreadable META record; never infer the lane from branch names or
47
- release history.
48
21
 
49
- Verify authority and CLI health before starting:
22
+ A hotfix always skips rc on every track: it cherry-picks `development → main` directly, MMI-Hub included. `deployModel` decides the release-triggered runs the train watches. Unreadable META → stop; never infer the lane from branch names, tags or release history.
23
+
24
+ ## Preflight
50
25
 
51
26
  ```bash
52
- mmi-cli oracle org access role <owner/repo> --json
53
- mmi-cli doctor --no-repo-writes
27
+ mmi-cli devops train doctor --lane hotfix --heal --json
54
28
  ```
55
29
 
56
- Stop on a red authority or CLI-version result. Hub hotfix release runs the same distribution fold as
57
- `/release`; its hook-contract verifier executes adapter commands as a native argv without a shell
58
- (#5605), so a checkout path containing spaces is supported.
30
+ Read `ready`, then `findings[]`: each carries `code`, `severity` (`blocker` · `warning` · `healed` · `info`), `source` (`local` · `origin`), `remedy` and `anchor`. `ready: false` → stop and quote every blocker's `code` and `remedy`; an unread origin is never green. `hotfix start` and `hotfix release` re-run this doctor as their step 0 with heal on.
59
31
 
60
- The worktree must be clean; move scratch into `tmp/` or
61
- gitignore it rather than widening the hotfix diff. A TRACKED path named in a `working tree must be clean
62
- before …` refusal is not scratch: read both `git status --porcelain` columns, treat every state except
63
- exactly ` M` as real work to commit or stash, and for ` M` discard only when
64
- `git diff HEAD --numstat -- <paths>` is empty, and only with `git checkout -- <paths>`. Plain
65
- `git diff --numstat` prints nothing for a merely staged change, so it cannot make that call (#4004).
32
+ ## Apply
66
33
 
67
- ## 1. Start from the merged development fix
34
+ Run from the primary checkout. One cycle carries as many merged fixes as you name, in pick order.
68
35
 
69
- Use the orchestrator with an explicit source every time:
36
+ 1. Start from the merged development fix(es):
70
37
 
71
38
  ```bash
72
- mmi-cli devops hotfix start --from <development-pr-or-sha>[,<development-pr-or-sha>...] --json
39
+ r1=$(mktemp tmp/hotfix-start.XXXXXX)
40
+ mmi-cli devops hotfix start --from <pr|sha>[,<pr|sha>…] --json --out "$r1"
73
41
  ```
74
42
 
75
- **One hotfix cycle carries as many merged fixes as you name.** `--from` takes a comma-separated list in
76
- pick order, and every sha it picks goes into the PR's carries marker, so the release proves each one
77
- present before tagging. Do not open one hotfix per fix: batch everything ready for production into the
78
- single PATCH. A fix that only becomes ready mid-cycle rides the same tag — cherry-pick it with `-x` onto
79
- a `hotfix/<tag>-<n>` continuation branch, merge that PR, and rerun `hotfix release` with the full
80
- `--carries` list; the release pins the newest merged SHA (#1025).
81
-
82
- `hotfix start` resolves the PATCH version, branches from `origin/main`, performs the cherry-pick with `-x`,
83
- prepares Hub distribution artifacts when applicable (stamping BOM `sourceCommit` at the durable
84
- `origin/main` merge-base so a squash merge cannot orphan it — #4361; and for `registry-publish`
85
- consumers, folds the package version so upgrade probes observe the PATCH), pushes the branch, and opens
86
- the main-base PR. Do not duplicate those steps with raw branch commands, manual cherry-picks, or raw
87
- GitHub PR creation.
88
-
89
- Conflicts confined to regenerable distribution / version-fold paths (e.g. Hub `distribution-bom.json`,
90
- locked plugin manifests, consumer `package.json`) — and, for hub-serverless + registry-publish, the
91
- canonical skill root `skills/` (#4363 / #4471) — are auto-resolved (take the picked side) and regenerated
92
- by the bump/fold step. Source TS under `src/` / `cli/src/` is never auto-resolved.
93
-
94
- Before cutting the hotfix branch, `hotfix start` preflights every `--from` pick on an accumulating
95
- `origin/main` tree (#4472). If any pick would hard-stop, it refuses with every failing pick and path and
96
- prescribes **one** development-based cite-only synthesis PR for the whole batch (#4643; the old
97
- "cut from origin/main" pattern #4467 wording is retired — a main-parented branch must never merge
98
- into development, #4365/#4371): cut from `origin/development`, regenerate the conflicting content so
99
- it cherry-picks cleanly onto `origin/main`, land it with the cite-only marker (the #5096 flow) — not N
100
- serial ports. Behavior changes still land on `development` first through a normal PR, then rerun hotfix
101
- start from the port merge SHA(s) — never hand-resolve onto main.
102
-
103
- ## 2. Verify the hotfix PR
104
-
105
- Run the repo's local gate against the hotfix branch, then obtain the independent reviewer required by the
106
- active agent doctrine. Review the actual main-base diff and the original issue acceptance criteria.
107
-
108
- Wait for required CI through Hub:
43
+ `hotfix start` derives the PATCH from the latest Release tag on `origin/main`, branches `hotfix/vX.Y.Z` from `origin/main`, cherry-picks with `-x`, folds the version, pushes, and opens the main-base PR with its carries marker. Never duplicate those steps with raw branch, cherry-pick or PR commands.
44
+
45
+ 2. Verify the main-base PR: the repo's local gate on the hotfix branch, the independent review the active agent doctrine requires, and the original issue's acceptance criteria. Then wait for required CI and merge through Hub — the PR may squash, and the `-x` trailer must survive in the squash message:
109
46
 
110
47
  ```bash
111
- mmi-cli devops pr checks-wait <hotfix-pr-number>
48
+ mmi-cli devops pr checks-wait <number>
112
49
  mmi-cli devops pr merge <number> --squash
113
50
  ```
114
51
 
115
- The main-base PR is the production gate. Do not bypass checks or protected-branch authority. After the
116
- authorized merge, verify the merged main commit still carries the cherry-pick provenance; if the PR was
117
- squashed, the source trailer must survive in the squash message so future coverage checks remain exact.
118
- Because Hub's default branch is `development`, the main-base hotfix PR does not close a separate tracking
119
- issue. The development PR should already have closed the work item; do not add raw GitHub issue operations.
52
+ Because Hub's default branch is `development`, the main-base PR closes no tracking issue — the development PR already did; add no raw GitHub issue operations.
120
53
 
121
- ## 3. Run the gated release
122
-
123
- Derive the tag from `mmi-cli devops hotfix status`, then release with the same declared source:
54
+ 3. Release, naming every fix the cycle carries (each is proven an ancestor of the tagged SHA before tagging):
124
55
 
125
56
  ```bash
126
- mmi-cli devops hotfix status
127
- mmi-cli devops hotfix release <vX.Y.Z> --carries <development-pr-or-sha>[,<development-pr-or-sha>...]
57
+ r2=$(mktemp tmp/hotfix-release.XXXXXX)
58
+ mmi-cli devops hotfix status --json
59
+ mmi-cli devops hotfix release vX.Y.Z --carries <pr|sha>[,<pr|sha>…] --json --out "$r2"
128
60
  ```
129
61
 
130
- Name **every** fix the cycle carries. Each is proven an ancestor of the tagged SHA before tagging; a
131
- missing one refuses the release and names the continuation path.
62
+ MMI-Hub adds `--announce-summary-file "$f"` with a fresh 3–6 line neutral summary — never a product or brand name; Hub scope is only `mutmutco/MMI-Hub`, never a product's board or `ds-propagate.yml`. `hotfix release` tags, publishes the Release, watches the release-triggered runs, verifies distribution, announces (Hub), and opens the `hotfix-fold/<tag>` development fold PR. Do not hand-dispatch a second publish or deploy path: duplicate release events race or double-publish.
63
+
64
+ ## Verify
65
+
66
+ Read the receipts, never the exit code (exit `2` = a follow-up pending; exit `1` = a follow-up failed after the tag):
132
67
 
133
- For MMI-Hub, pass a fresh 2-4 line neutral summary file with `--announce-summary-file`; never reuse a
134
- stale file and never put a product or brand name in the summary. Hub release scope never includes another
135
- repo's board or `ds-propagate.yml`. The orchestrator creates the tag and GitHub Release, selects the
136
- registry-declared deploy path, watches the release-triggered or central deployment, verifies distribution,
137
- and announces best-effort. Do not hand-dispatch a second publish/deploy path: duplicate release events can
138
- race or double-publish.
68
+ - `runs[]` — the release-triggered runs on the tagged SHA (workflow, conclusion, url). Watch each non-success entry to conclusion: `gh run watch <run-id> --repo {owner}/{repo} --exit-status`. Name which run is red: `deploy.yml` / `publish.yml` / `tenant-deploy.yml` is a deploy or publish verdict; a `gate` push run is ordinary CI sharing the SHA.
69
+ - `foldStatus` + `foldNote` the `hotfix-fold/<tag>` development PR; land it by true merge (Merge floor) and say whether it landed.
70
+ - `announceNote` (Hub), `verifyNote`, `checkout`, `localSync`, `ledger` the durable phase legs; a pending or failed leg is unresolved, never done.
139
71
 
140
- For a private package, trust the authenticated publish job and its logged package/version result; a bare
141
- unauthenticated `npm view` cannot distinguish private from missing.
72
+ `mmi-cli devops hotfix status vX.Y.Z --json` re-derives the whole pipeline from live reads (`state`, `tagPushed`, `releaseExists`, `runs`, `alignmentStatus`, `npmVersion`, `next`). Then the bounded Latest Release read; its `tagName` must equal the tag:
142
73
 
143
- ## 4. Verify and report
74
+ ```bash
75
+ gh api repos/{owner}/{repo}/releases/latest --jq '{tagName:.tag_name,targetCommitish:.target_commitish,publishedAt:.published_at,url:.html_url}'
76
+ ```
144
77
 
145
- Report the tag and Release URL, production run and URL, source development PR/SHA, hotfix PR, and these
146
- branch facts:
78
+ Branch facts close the verdict: the tag commit is on `origin/main`; `development` already had the fix before the hotfix began; `rc` is untouched by design; the fold PR landed or is named as pending.
147
79
 
148
- - `main`: the tag commit is on `origin/main`.
149
- - `development`: the source fix was already merged before the hotfix began.
150
- - `rc`: intentionally untouched; the next release coverage gate prevents regression.
151
- - the development fold PR the release opened (`hotfix-fold/<tag>`), and whether it landed.
80
+ ## Recovery
152
81
 
153
- Do not hand-open a manifest-alignment PR: the version fold is already ported by `hotfix release` — land
154
- its PR instead of authoring one. That port is explicitly NOT a back-merge — nothing from `main` is
155
- merged into `development`; the fold is regenerated on a branch cut from `development` itself. If the run
156
- reported `development fold port FAILED`, follow the manual remedy it named; never improvise a merge from
157
- `main`.
82
+ Every refusal and every doctor blocker names its `code` and `anchor`: open `docs/Guides/train-troubleshooting.md#<code>` and follow that entry, nothing else. The hotfix subcommands are idempotent, so after an interruption rerun the identical `mmi-cli devops hotfix release vX.Y.Z --carries …` — each effect is checked before it is re-attempted, and the ledger names that rerun as this lane's continuation; `--resume --watch --json` is the release and rcand ledgers' only continuation form and never a hotfix one. A refused pick, a port conflict, a red authority probe, a failed check, a missing carry, or `development fold port FAILED` each ends the run (Merge floor): fix the cause on `development` through a normal PR, then rerun from the port merge SHA never improvise a merge from `main`.
158
83
 
159
- ### Development fold after a hotfix (#4517 / #4948)
84
+ ## Merge floor
160
85
 
161
- The Hub's thin catalogs now pin exact npm packages, so the old main-anchored catalog-lockstep gate is
162
- retired: an unreleased branch cannot deliver a package version the release train has not published.
163
- Hotfix versioning still belongs on the main-base train, never in an improvised development prepare PR:
86
+ - **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag from the branch lineage, so every tag-anchored check mis-reads forever after. 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.
87
+ - **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.
88
+ - **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.
89
+ - **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.
90
+ - **Tag and Release deletion are deletion-class:** the authorized human's explicit per-turn go, named in the guide entry that prescribes it.
164
91
 
165
- 1. `mmi-cli devops hotfix start --from <merged-dev-pr-or-sha>` (prepare + distribution bump on `hotfix/vX.Y.Z` from `main`)
166
- 2. merge the hotfix PR → `mmi-cli devops hotfix release vX.Y.Z` (publish)
167
- 3. land the automatic `hotfix-fold/<tag>` development fold PR (or follow its printed remedy)
92
+ ## Report
168
93
 
169
- The fold is now required for version/BOM/package-pin continuity, not to clear a branch-content gate.
94
+ Title first, verdict first. Name the resolved tag (never a placeholder like `vX.Y.0`) and the Release URL, the receipt's status fields (`releaseStatus`, `followUpStatus`, `deployStatus`, `promoted`), every `workflowRuns` entry with its conclusion and URL — saying which run is red, and whether it is a deploy/publish verdict or ordinary CI — `announceNote`, the alignment note (`devRollForward`, `rcAlignment`, or the hotfix fold PR and whether it landed), the `checkout` clause, and the sanctioned dispatch mechanism you used. A pending follow-up is reported as unverified, never as success. Product names appear only when releasing that product's repo.
170
95
 
171
96
  ## Retro
172
97
 
173
- If this skill's instructions themselves misfired, file one deduplicated lesson and continue:
98
+ Before the final report, answer one question honestly: did this skill's own instructions misfire this run — ambiguous wording, a misleading message, or an environment failure it should have warned about? Process only, never the user's code or task. If yes, file one lesson and move on; a clean run is silent (hard cap: one per run). It lands on the Hub board, deduplicated, and is fixed only through a reviewed PR — never edit the skill live. The retro is advisory: if the call fails, note it and continue.
174
99
 
175
100
  ```bash
176
101
  mmi-cli learning skill-lesson --skill hotfix --title "<what misfired>" --body "<what; evidence; proposed amendment>"