@mutmutco/codex-plugin 4.3.5 → 4.3.7
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.
- package/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/bootstrap/SKILL.md +57 -68
- package/skills/hotfix/SKILL.md +51 -126
- package/skills/rcand/SKILL.md +40 -188
- package/skills/release/SKILL.md +38 -919
- package/scripts/edit-tool-paths.mjs +0 -115
package/package.json
CHANGED
|
@@ -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
|
|
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`
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
197
|
-
guard** fences every push to `main`/`master`/`rc`, including the
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
218
|
-
|
|
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*.
|
|
233
|
-
`development`/`rc`/`main` for deployable repos, or just `main` for content
|
|
234
|
-
push"** = the
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
gate
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
product ruleset
|
|
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,
|
|
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
|
package/skills/hotfix/SKILL.md
CHANGED
|
@@ -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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
|
53
|
-
mmi-cli doctor --no-repo-writes
|
|
27
|
+
mmi-cli devops train doctor --lane hotfix --heal --json
|
|
54
28
|
```
|
|
55
29
|
|
|
56
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
+
Run from the primary checkout. One cycle carries as many merged fixes as you name, in pick order.
|
|
68
35
|
|
|
69
|
-
|
|
36
|
+
1. Start from the merged development fix(es):
|
|
70
37
|
|
|
71
38
|
```bash
|
|
72
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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 <
|
|
48
|
+
mmi-cli devops pr checks-wait <number>
|
|
112
49
|
mmi-cli devops pr merge <number> --squash
|
|
113
50
|
```
|
|
114
51
|
|
|
115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
mmi-cli devops hotfix
|
|
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
|
-
|
|
131
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
+
## Merge floor
|
|
160
85
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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`), and every workflow run row with its conclusion and evidence — use its URL when emitted, otherwise the receipt's explicit no-run-URL note — 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
|
-
|
|
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>"
|