@mutmutco/claude-plugin 4.5.173 → 4.5.175
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/.claude-plugin/plugin.json +1 -1
- package/cli/dist/main.cjs +481 -268
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/skills/board/SKILL.md +36 -105
- package/skills/board/reference.md +66 -0
- package/skills/bootstrap/SKILL.md +34 -120
- package/skills/bootstrap/reference.md +65 -0
- package/skills/epic/SKILL.md +33 -78
- package/skills/hotfix/SKILL.md +22 -42
- package/skills/hotfix/recovery.md +10 -0
- package/skills/rcand/SKILL.md +18 -24
- package/skills/rcand/recovery.md +8 -0
- package/skills/release/SKILL.md +11 -73
- package/skills/release/verification.md +71 -0
- package/skills/secrets/SKILL.md +18 -80
- package/skills/secrets/reference.md +41 -0
- package/skills/stage/SKILL.md +20 -74
- package/skills/stage/reference.md +49 -0
package/skills/epic/SKILL.md
CHANGED
|
@@ -5,66 +5,48 @@ description: Split a vision or umbrella issue into linked child issues in one ba
|
|
|
5
5
|
|
|
6
6
|
# /epic — decompose an umbrella into children
|
|
7
7
|
|
|
8
|
-
Turn one large item
|
|
9
|
-
single pre-validated batch, each already linked to its parent. This is the slice-and-fan-out act done by
|
|
10
|
-
hand today: draft the children, validate them all, create them, confirm the tree.
|
|
8
|
+
Turn one large item (vision, epic, umbrella issue) into native sub-issues in one pre-validated batch, each linked to its parent: draft the children, validate all, create, confirm the tree.
|
|
11
9
|
|
|
12
|
-
## Opening branch —
|
|
10
|
+
## Opening branch — no umbrella yet
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
repo's live issue templates, draft the umbrella from the matching feature/task template, and show that
|
|
16
|
-
draft for the user's go. Only then create one issue with the `epic` label and an explicit Priority field;
|
|
17
|
-
re-read it from the board to prove the body, label, and priority landed. Stop there unless the user also
|
|
18
|
-
asked for and approved child decomposition.
|
|
12
|
+
For a product intent rather than an existing issue: gather the intent, read the repo's live issue templates, draft the umbrella from the matching feature/task template and show the draft for the user's go. Then create one issue with the `epic` label and an explicit Priority field; re-read it from the board to prove body, label and priority landed. Stop there unless child decomposition was also asked for and approved.
|
|
19
13
|
|
|
20
14
|
## Step 0 — load the umbrella whole
|
|
21
15
|
|
|
22
|
-
Read the
|
|
23
|
-
superseding:
|
|
16
|
+
Read the body **and every comment** (later comments supersede):
|
|
24
17
|
|
|
25
18
|
```bash
|
|
26
|
-
mmi-cli oracle board show <owner/repo#N>
|
|
19
|
+
mmi-cli oracle board show <owner/repo#N>
|
|
27
20
|
```
|
|
28
21
|
|
|
29
|
-
Slice by deliverable, not
|
|
30
|
-
Keep the parent as the umbrella — do not close it until the last child merges.
|
|
22
|
+
Slice by deliverable, not phase: each child is independently claimable and lands in its own PR. The parent stays open until the last child merges.
|
|
31
23
|
|
|
32
24
|
## Step 1 — draft the batch file
|
|
33
25
|
|
|
34
|
-
|
|
26
|
+
Inspect existing children first:
|
|
35
27
|
|
|
36
28
|
```bash
|
|
37
|
-
mmi-cli oracle issue children <owner/repo#N>
|
|
29
|
+
mmi-cli oracle issue children <owner/repo#N>
|
|
38
30
|
```
|
|
39
31
|
|
|
40
|
-
Write a JSON array
|
|
41
|
-
epic — `.jerv/tmp/epic-<parentNumber>-children.json` (never reuse the file between epics: a previous
|
|
42
|
-
epic's leftover batch collides with the new rows, silently on an unguarded host). Each row:
|
|
32
|
+
Write a JSON array, one object per child, to `.jerv/tmp/epic-<parentNumber>-children.json` (unique per epic; a leftover batch from another epic collides with the new rows):
|
|
43
33
|
|
|
44
34
|
```json
|
|
45
35
|
[
|
|
46
36
|
{ "type": "task", "title": "C1: extract the shared frame", "body": "…", "priority": "high",
|
|
47
37
|
"surface": "cli", "parent": "owner/repo#42" },
|
|
48
|
-
{ "type": "feature", "title": "C2: wire the new command", "body": "…", "
|
|
49
|
-
"parent": "owner/repo#42" }
|
|
38
|
+
{ "type": "feature", "title": "C2: wire the new command", "body": "…", "parent": "owner/repo#42" }
|
|
50
39
|
]
|
|
51
40
|
```
|
|
52
41
|
|
|
53
|
-
- `type` — `bug` · `feature` · `task
|
|
54
|
-
- `title` — required,
|
|
55
|
-
- `parent` — the umbrella
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- `
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- `surface` — required when the target repo uses `surface:*` taxonomy; accepts the value with or without
|
|
62
|
-
the prefix. A top-level `--surface <value>` may supply the default for every applicable row.
|
|
63
|
-
|
|
64
|
-
The batch **pre-validates every row before creating any** — one bad row fails the whole set with an
|
|
65
|
-
aggregate error, so you fix all of them once. It warns when a row title closely matches an existing open
|
|
66
|
-
child of the same parent; inspect that warning before creating a duplicate. Get the user's go on the drafted
|
|
67
|
-
set before writing.
|
|
42
|
+
- `type` — required: `bug` · `feature` · `task`.
|
|
43
|
+
- `title` — required, a short greppable deliverable.
|
|
44
|
+
- `parent` — the umbrella (`N`, `#N`, a bare number, `owner/repo#N` or URL); links the child as a native sub-issue on create, so no `link-child` pass. Cross-repo is fine.
|
|
45
|
+
- `priority` — `urgent|high|medium|low` (default `medium`); sets the board Priority field.
|
|
46
|
+
- `repo` — optional per-row `owner/repo`; defaults to `--repo`, then the current repo.
|
|
47
|
+
- `surface` — required when the target repo uses `surface:*` taxonomy, with or without the prefix; top-level `--surface <value>` sets the default.
|
|
48
|
+
|
|
49
|
+
The batch pre-validates every row before creating any; one bad row fails the set with an aggregate error. A warning that a title closely matches an open child of the same parent must be inspected before creating a duplicate. Get the user's go on the drafted set before writing.
|
|
68
50
|
|
|
69
51
|
## Step 2 — create the children
|
|
70
52
|
|
|
@@ -72,57 +54,30 @@ set before writing.
|
|
|
72
54
|
mmi-cli oracle issue create --type task --batch .jerv/tmp/epic-42-children.json --surface cli
|
|
73
55
|
```
|
|
74
56
|
|
|
75
|
-
`--type` is required
|
|
76
|
-
placeholder. It prints per-row `{number,url}` results and fails loud on any misfire. Add
|
|
77
|
-
`--idempotency-key <key>` when a retried loop must not duplicate.
|
|
78
|
-
|
|
79
|
-
When creating through `mmi-cli vault secrets use GH_TOKEN -- …`, the `GH_TOKEN` environment override can
|
|
80
|
-
disrupt Hub session discovery and print `board attach skipped — no Hub session token` for batch rows. That
|
|
81
|
-
warning can appear when placement is correct, but it is not harmless or proof of placement: final verification
|
|
82
|
-
must prove every intended child is linked and on the board as Todo with `mmi-cli oracle issue children
|
|
83
|
-
<owner/repo#N> --json`. `boardStatus: null` is **inconclusive** (the children walk can miss org-board
|
|
84
|
-
Status that `board show` still sees) — it is not proof the child is off the board. A non-null Status
|
|
85
|
-
(Todo / In Progress / …) is the placement proof; if Status stays null after this command, investigate
|
|
86
|
-
with `board show` rather than treating null as "not on board".
|
|
57
|
+
`--type` is required but each row's own `type` governs. It prints per-row `{number,url}` and fails loud. Add `--idempotency-key <key>` when a retried loop must not duplicate. The lookup is find-before-create, not atomic: one batch writer at a time, never concurrent creates with the same key. Size the command's wall-clock budget for the whole sequential batch; on timeout the outcome is unknown, so confirm the process ended, wait for writes to quiesce, inspect the children, then retry the missing rows with the same key.
|
|
87
58
|
|
|
88
|
-
|
|
89
|
-
never submit concurrent creates with the same key. Size the calling command's wall-clock budget for the
|
|
90
|
-
whole sequential batch. If the command times out, its outcome is unknown — confirm the process has ended,
|
|
91
|
-
wait for writes to quiesce, inspect the children, then retry the missing rows with the same key.
|
|
59
|
+
Under `mmi-cli vault secrets use GH_TOKEN -- …` the `GH_TOKEN` override can break Hub session discovery and print `board attach skipped — no Hub session token`; that is not proof of placement either way, so verify in Step 3.
|
|
92
60
|
|
|
93
61
|
## Step 3 — confirm the tree
|
|
94
62
|
|
|
95
63
|
```bash
|
|
96
|
-
mmi-cli oracle issue children <owner/repo#N> --json
|
|
64
|
+
mmi-cli oracle issue children <owner/repo#N> --json
|
|
97
65
|
```
|
|
98
66
|
|
|
99
|
-
This JSON is the
|
|
100
|
-
(`boardStatus` names Todo). `boardStatus: null` is inconclusive, not "not on board".
|
|
101
|
-
If it does not prove that placement, investigate and correct the misfire. To link a child that already existed (not
|
|
102
|
-
part of the batch), use the inverse-friendly single link:
|
|
67
|
+
This JSON is the placement authority: every intended child must be linked and on the board as Todo (`boardStatus` names it). `boardStatus: null` is inconclusive (the walk can miss org-board Status that `board show` still sees); investigate with `board show`. If placement is not proven, correct the misfire. Link a pre-existing child with:
|
|
103
68
|
|
|
104
69
|
```bash
|
|
105
70
|
mmi-cli oracle issue link-child <parent> <child>
|
|
106
71
|
```
|
|
107
72
|
|
|
108
|
-
Each child is now a parallel item
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
and structured output.
|
|
120
|
-
|
|
121
|
-
## Retro — one check before you finish
|
|
122
|
-
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
123
|
-
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
124
|
-
about? (Process only — never the user's code or task; e.g. a batch schema that rejected a valid row, or a
|
|
125
|
-
link that attached to the wrong parent.) If yes, file **one** lesson and move on; a clean run is silent
|
|
126
|
-
(hard cap: one per run). It lands on the owning board (deduped) and is fixed only via a reviewed PR — never
|
|
127
|
-
edit the skill live; the retro is advisory, so if the call fails, note it and continue. File through MMI:
|
|
128
|
-
`mmi-cli learning skill-lesson --skill epic --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
73
|
+
Each child is now a parallel item: one worktree + PR each. On Windows set `git config core.longpaths true` on the main checkout before the first `git worktree add`. When linked worktrees share a clone, serialize `git branch -m` and other ref renames (or retry serially on `.tmp-renamed-log`). **When the last child merges, close the umbrella** (board `Done` follows).
|
|
74
|
+
|
|
75
|
+
Never free-type children with raw `gh issue create`: the batch path carries validation, board attach and structured output.
|
|
76
|
+
|
|
77
|
+
## Retro
|
|
78
|
+
|
|
79
|
+
Before the final report, ask once: did this skill's own instructions 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. Never edit the skill live.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mmi-cli learning skill-lesson --skill epic --title "<what misfired>" --body "<what; evidence; proposed amendment>"
|
|
83
|
+
```
|
package/skills/hotfix/SKILL.md
CHANGED
|
@@ -3,25 +3,23 @@ name: hotfix
|
|
|
3
3
|
description: Promote a merged development fix to main and production via the Hub train.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
**Host-native invocation:** Claude `/mmi:hotfix` · Codex `$mmi:hotfix` · jervcode `/hotfix` · Hermes skill_view.
|
|
6
|
+
**Host-native invocation:** Claude `/mmi:hotfix` · Codex `$mmi:hotfix` · jervcode `/hotfix` · Hermes skill_view.
|
|
7
7
|
|
|
8
|
-
**Argument:** none
|
|
8
|
+
**Argument:** none; PATCH-only (leave `MMI_BUMP_INTENT`, `MMI_RELEASE_VERSION` unset).
|
|
9
9
|
|
|
10
10
|
# /hotfix — promote a development fix to main + prod
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
The fix lands on `development` first; Hub ports that merged PR or SHA onto a main-base branch (cherry-pick with `-x`) and releases the PATCH. Never author the fix on a branch off `main`. The fix is NOT a back-merge (`rc` absorbs it next `/rcand`; the hotfix-coverage guard blocks a candidate omitting it).
|
|
13
13
|
|
|
14
14
|
## Lane
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Read META and name the lane before describing or executing anything:
|
|
16
|
+
MM-Work suite seats: read [suite.md](suite.md). Lane from META:
|
|
19
17
|
|
|
20
18
|
```bash
|
|
21
19
|
mmi-cli oracle org project get {owner}/{repo} --json
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
A hotfix
|
|
22
|
+
A hotfix skips rc on every track; `deployModel: vercel` waits for the Production Deployment, then probes it. Unreadable META → stop; never infer the lane.
|
|
25
23
|
|
|
26
24
|
## Preflight
|
|
27
25
|
|
|
@@ -29,59 +27,41 @@ A hotfix always skips rc on every track: it cherry-picks `development → main`
|
|
|
29
27
|
mmi-cli devops train doctor --lane hotfix --heal --json
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
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`.
|
|
33
31
|
|
|
34
32
|
## Apply
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
From the primary checkout.
|
|
37
35
|
|
|
38
|
-
1. Start from the
|
|
36
|
+
1. Start (derives PATCH from the latest `origin/main` Release tag, branches `hotfix/vX.Y.Z`, folds the version, opens the PR; never repeat by hand):
|
|
39
37
|
|
|
40
38
|
```bash
|
|
41
39
|
mkdir -p .jerv/tmp && r1=$(mktemp .jerv/tmp/hotfix-start.XXXXXX)
|
|
42
40
|
mmi-cli devops hotfix start --from <pr|sha>[,<pr|sha>…] --json --out "$r1"
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
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 merge through Hub — it waits for required CI and demands the review verdict itself; the PR may squash, and the `-x` trailer must survive in the squash message:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
mmi-cli devops pr merge <number> --squash
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
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.
|
|
43
|
+
2. Verify: local gate, required review, acceptance criteria. Merge with `mmi-cli devops pr merge <number> --squash` (waits for CI and review; keep the `-x` trailer). Because Hub's default branch is `development`, it closes no issue; no raw GitHub issue operations.
|
|
54
44
|
|
|
55
|
-
3. Release
|
|
45
|
+
3. Release:
|
|
56
46
|
|
|
57
47
|
```bash
|
|
58
|
-
|
|
48
|
+
r2=$(mktemp .jerv/tmp/hotfix-release.XXXXXX)
|
|
59
49
|
mmi-cli devops hotfix status --json
|
|
60
50
|
mmi-cli devops hotfix release vX.Y.Z --carries <pr|sha>[,<pr|sha>…] --json --out "$r2"
|
|
61
51
|
```
|
|
62
52
|
|
|
63
|
-
MMI-Hub adds `--announce-summary-file "$f"
|
|
53
|
+
MMI-Hub adds `--announce-summary-file "$f"`: a fresh 3–6 line neutral summary, no product or brand name, never a product's board (`mutmutco/MMI-Hub` only). It tags, publishes, watches, announces, verifies, opens the `hotfix-fold/<tag>` PR. Do not hand-dispatch a second publish or deploy.
|
|
64
54
|
|
|
65
55
|
## Verify
|
|
66
56
|
|
|
67
|
-
|
|
68
|
-
Developers need no local AWS tools, AWS identity, or shared Slack key. Preserve a failed summary
|
|
69
|
-
for the supported continuation; never replay a delivery whose result is uncertain.
|
|
57
|
+
Read receipts, not the exit code (`1` = follow-up failed after tag; pending exits `0`):
|
|
70
58
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- `
|
|
74
|
-
- `
|
|
75
|
-
- `announceNote` (Hub), `verifyNote`, `checkout`, `localSync`, `ledger` — the durable phase legs; a pending or failed leg is unresolved, never done.
|
|
76
|
-
- `localInstall` (MMI-Hub) — the train installs the release on this machine via `mmi-hub update`; never run `npm i -g`.
|
|
77
|
-
|
|
78
|
-
`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:
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
gh api repos/{owner}/{repo}/releases/latest --jq '{tagName:.tag_name,targetCommitish:.target_commitish,publishedAt:.published_at,url:.html_url}'
|
|
82
|
-
```
|
|
59
|
+
- `runs[]`: watch each non-success: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`. `deploy.yml`, `publish.yml`, `tenant-deploy.yml`, `jerv-gateway` are deploy/publish verdicts; a `gate` run is ordinary CI.
|
|
60
|
+
- `foldStatus`/`foldNote`: land the fold PR by true merge (Merge floor).
|
|
61
|
+
- `announceNote`, `verifyNote`, `checkout`, `localSync`, `ledger`: pending or failed = unresolved.
|
|
62
|
+
- `localInstall` (MMI-Hub): via `mmi-hub update`, never `npm i -g`.
|
|
83
63
|
|
|
84
|
-
|
|
64
|
+
`gh api repos/{owner}/{repo}/releases/latest --jq .tag_name` must equal the tag, on `origin/main`.
|
|
85
65
|
|
|
86
66
|
## Recovery
|
|
87
67
|
|
|
@@ -89,19 +69,19 @@ On any failure or interruption, read [recovery.md](recovery.md).
|
|
|
89
69
|
|
|
90
70
|
## Merge floor
|
|
91
71
|
|
|
92
|
-
- **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag
|
|
72
|
+
- **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.
|
|
93
73
|
- **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.
|
|
94
74
|
- **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.
|
|
95
75
|
- **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.
|
|
96
|
-
- **Tag and Release deletion
|
|
76
|
+
- **Tag and Release deletion need Jervaise's yes (principle 12),** named in the guide entry that prescribes it.
|
|
97
77
|
|
|
98
78
|
## Report
|
|
99
79
|
|
|
100
|
-
|
|
80
|
+
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.
|
|
101
81
|
|
|
102
82
|
## Retro
|
|
103
83
|
|
|
104
|
-
Before the final report
|
|
84
|
+
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.
|
|
105
85
|
|
|
106
86
|
```bash
|
|
107
87
|
mmi-cli learning skill-lesson --skill hotfix --title "<what misfired>" --body "<what; evidence; proposed amendment>"
|
|
@@ -2,3 +2,13 @@ Every refusal and every doctor blocker names its `code` and `anchor`: open `docs
|
|
|
2
2
|
|
|
3
3
|
A prior release's unresolved ledger also blocks this lane — and when its only unresolved leg is a content-caused failed deploy on the already-published tag, this lane is the fix's carrier: close that leg first with the master-approved `mmi-cli devops release --supersede-deploy --apply` (the cause fix must already be merged on `development`), then run the hotfix; the gate archives the closed ledger aside on its own.
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
The `jerv-gateway` release leg has no run id: read `deployNote` / `ledger.phases.deploy`; `pending` means production was never deployed and blocks the next train run. Keep a failed announce summary for the supported continuation; never replay a delivery whose result is uncertain.
|
|
7
|
+
|
|
8
|
+
## Field reference (moved from SKILL.md)
|
|
9
|
+
|
|
10
|
+
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; on `vercel` nothing is dispatched — Vercel builds `main` on the push and the hotfix waits for its Production Deployment and probes the URL, same as `/release --watch`; a leg left pending settles on the next doctor `--heal`. Unreadable META → stop; never infer the lane from branch names, tags or release history.
|
|
11
|
+
|
|
12
|
+
The JSON is on stdout alone; a stale CLI first prints its self-update notice on stderr and re-runs itself, so parse stdout only, never `2>&1`. 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.
|
|
13
|
+
|
|
14
|
+
`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:
|
package/skills/rcand/SKILL.md
CHANGED
|
@@ -3,27 +3,23 @@ name: rcand
|
|
|
3
3
|
description: Promote development to a release candidate.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
**Host-native invocation:** Claude `/mmi:rcand` · Codex `$mmi:rcand` · jervcode `/rcand` · Hermes skill_view.
|
|
6
|
+
**Host-native invocation:** Claude `/mmi:rcand` · Codex `$mmi:rcand` · jervcode `/rcand` · Hermes skill_view.
|
|
7
7
|
|
|
8
|
-
**Argument:** `/rcand minor
|
|
8
|
+
**Argument:** `/rcand minor|major|patch` — a bare bump word, never a flag or env var; none → `patch`.
|
|
9
9
|
|
|
10
10
|
# /rcand — promote development to release-candidate
|
|
11
11
|
|
|
12
|
-
Merge `development → rc`, tag `vX.Y.0-rc.N`, push the tag
|
|
12
|
+
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.
|
|
13
13
|
|
|
14
14
|
## Lane
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Read META and name the lane before describing or executing anything:
|
|
16
|
+
MM-Work suite lead or member: read [suite.md](suite.md) first. Name the lane from META:
|
|
19
17
|
|
|
20
18
|
```bash
|
|
21
19
|
mmi-cli oracle org project get {owner}/{repo} --json
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
`releaseTrack: direct` (product repos with explicit META, plus MMI-Hub) has no `rc`:
|
|
25
|
-
|
|
26
|
-
Authority is structural and server-checked: the doctor asks the Hub, and the protected `rc` push allowlist carries the same people (master + that repo's project-admins). Gate ordering: the tag lands the rc SHA for checks, and every deploy side-effect waits until the protected `rc` push accepts that checked SHA.
|
|
22
|
+
`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.
|
|
27
23
|
|
|
28
24
|
## Preflight
|
|
29
25
|
|
|
@@ -31,31 +27,29 @@ Authority is structural and server-checked: the doctor asks the Hub, and the pro
|
|
|
31
27
|
mmi-cli devops train doctor --lane rcand --heal --json
|
|
32
28
|
```
|
|
33
29
|
|
|
34
|
-
|
|
30
|
+
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.
|
|
35
31
|
|
|
36
32
|
## Apply
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
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.
|
|
39
35
|
|
|
40
36
|
```bash
|
|
41
37
|
mkdir -p .jerv/tmp && r=$(mktemp .jerv/tmp/rcand-receipt.XXXXXX)
|
|
42
38
|
mmi-cli devops rcand --apply --json --out "$r"
|
|
43
39
|
```
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
collected in Verify — verification is never skipped, only un-blocked. The one command fetches, merges `development → rc` (version-manifest conflicts resolve to the `development` side; any other conflicted path refuses), tags the next `-rc.N` (re-run-safe), pushes the tag first, discovers and waits for the required contexts on `rc`, pushes `rc`, and starts the deploy by model — `tenant-deploy.yml` centrally (keyless) for tenant-container; nothing for serverless, registry-publish or solo-container, whose own push-triggered workflow deploys. Never `git push` rc by hand, never force, never commit to `rc` outside that merge.
|
|
41
|
+
`--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.
|
|
47
42
|
|
|
48
43
|
## Verify
|
|
49
44
|
|
|
50
|
-
Read the receipt at `$r`, never the exit code (
|
|
45
|
+
Read the receipt at `$r`, never the exit code (`1` = deploy failed after promotion; unresolved exits `0`):
|
|
51
46
|
|
|
52
|
-
- `promoted`
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
55
|
-
- `
|
|
56
|
-
- `checkout`, `localSync`, `ledger` — `checkout.status: returned` to `development` and phases-green, or the named reason it is not.
|
|
47
|
+
- `promoted` is `true` even when the deploy failed; `tag` is the minted `vX.Y.0-rc.N` (`resumeNote`: resumed).
|
|
48
|
+
- `deployStatus`: `pending` is never terminal. Watch each non-success run in `workflowRuns`: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`.
|
|
49
|
+
- `releaseVerdict`: `followUpStatus` (`complete` · `pending` · `failed`); a failed `legs` row carries its error.
|
|
50
|
+
- `checkout.status: returned` to `development` and `localSync`/`ledger` green, or the named reason.
|
|
57
51
|
|
|
58
|
-
Then confirm
|
|
52
|
+
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.
|
|
59
53
|
|
|
60
54
|
## Recovery
|
|
61
55
|
|
|
@@ -63,19 +57,19 @@ On any failure or interruption, read [recovery.md](recovery.md).
|
|
|
63
57
|
|
|
64
58
|
## Merge floor
|
|
65
59
|
|
|
66
|
-
- **Never squash-merge a tagged commit (#3167).** A squash re-mints the SHA and orphans the tag
|
|
60
|
+
- **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.
|
|
67
61
|
- **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.
|
|
68
62
|
- **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.
|
|
69
63
|
- **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.
|
|
70
|
-
- **Tag and Release deletion
|
|
64
|
+
- **Tag and Release deletion need Jervaise's yes (principle 12),** named in the guide entry that prescribes it.
|
|
71
65
|
|
|
72
66
|
## Report
|
|
73
67
|
|
|
74
|
-
|
|
68
|
+
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.
|
|
75
69
|
|
|
76
70
|
## Retro
|
|
77
71
|
|
|
78
|
-
Before the final report
|
|
72
|
+
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.
|
|
79
73
|
|
|
80
74
|
```bash
|
|
81
75
|
mmi-cli learning skill-lesson --skill rcand --title "<what misfired>" --body "<what; evidence; proposed amendment>"
|
package/skills/rcand/recovery.md
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
Every refusal and every doctor blocker names its `code` and `anchor`: open `docs/Guides/train-troubleshooting.md#<code>` and follow that entry, nothing else. That guide is test-parsed, never free text — the infra drift and plugin-set suites validate every anchor cited here and assert policy from its wording — so an edit to it re-runs the infra suite (`npm --prefix infra test`) in the same PR: a heading or slug change is a code change. A candidate whose immutable rc tag passed policy but whose `origin/rc` was not pushed continues with `mmi-cli devops rcand --resume --watch --json --out <fresh-receipt>` — the only continuation form: `--resume` never re-tags, and `--apply` mints the next `-rc.N` for a new cut only. A promoted candidate whose rc deploy failed retries it, once the cause is fixed, with `mmi-cli devops rcand --retry-deploy --watch --json --out <fresh-receipt>` — same tag and SHA, never re-cut or re-pushed; `--resume` only re-reads that failed leg. Supersede is the last resort, with the authorized human's fresh approval. A refused train is a stop (Merge floor): fix the cause on `development` through a normal PR, then rerun; a rejected protected push leaves the local tag for an authorized rerun, never a force.
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## Field reference (moved from SKILL.md)
|
|
5
|
+
|
|
6
|
+
**Argument:** `/rcand minor`, `/rcand major`, or `/rcand patch` — a bare bump word, never a `--flag` or env var. No argument → `patch`; declare `minor` or `major` for a planned feature cycle.
|
|
7
|
+
|
|
8
|
+
The JSON is on stdout alone; a stale CLI first prints its self-update notice on stderr and re-runs itself, so parse stdout only, never `2>&1`. 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. `--apply` re-runs this doctor as its step 0 with heal on.
|
|
9
|
+
|
|
10
|
+
- `deployStatus` — `pending` is never terminal. `runId` / `runUrl` / `workflowRuns` name the run: the dispatched `tenant-deploy.yml` for tenant-container, the auto-fired `deploy.yml` for serverless. Watch each non-success entry to conclusion: `gh run watch <run-id> --repo {owner}/{repo} --exit-status --interval 30`.
|