@mutmutco/pi-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/pi-plugin",
3
- "version": "4.5.173",
3
+ "version": "4.5.175",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -5,11 +5,9 @@ description: Show the repo workboard and clear it in the fewest PRs.
5
5
 
6
6
  # /board — your workboard, and the fastest way through it
7
7
 
8
- Two halves. The first shows a dev their board for this repo — what they hold, what is free, what others
9
- took. The second is the reason this skill exists: plan the whole board into the **fewest pull requests**
10
- that can safely be opened, then run those lanes in parallel.
11
-
12
- Read-only until the dev says go. Rendering a board is not permission to take it.
8
+ Show the dev their board for this repo, then plan the whole board into the **fewest pull requests** that can
9
+ safely be opened and run those lanes in parallel. Read-only until the dev says go; rendering is not
10
+ permission to take anything.
13
11
 
14
12
  ## Step 1 — read the board
15
13
 
@@ -17,138 +15,71 @@ Read-only until the dev says go. Rendering a board is not permission to take it.
17
15
  mmi-cli oracle board read --json --out .jerv/tmp/board.json
18
16
  ```
19
17
 
20
- Prefer `--out` for a shell-independent UTF-8 receipt. Windows PowerShell 5.1's `>` writes
21
- UTF-16LE with a BOM (#5802); Bash redirects preserve the CLI's UTF-8 output.
22
-
23
- One call. Its JSON carries `viewer`, `repo` and the project title — do not spend extra calls on
24
- `gh api user` or `gh repo view`. Use `primary` for this repo and `secondary` for other repos on the same
25
- Project. Partial reads exit nonzero; pass `--allow-partial` only when the dev accepts an incomplete board.
26
-
27
- Partition, as the CLI computes it:
28
-
29
- - **Yours** — assignee includes the viewer, status in `Todo · In Progress · In Review`.
30
- - **Free to claim** — status `Todo`, unassigned, and the viewer has push on the repo. Also any item in
31
- any status whose claim stamp is stale: its session has done no work on it for 4 hours. A stale stamp
32
- holds nothing; `board claim` takes it over without `--force` and names the old stamp.
33
- - **Taken** — someone else's, any active status.
34
-
35
- Every stamped row names its session (`lane surface/session@host`), or `stale:<age>` when the stamp is
36
- stale. Work means the stamp, an issue comment, a commit on the issue's branch, or an update to an open
37
- PR that closes it. Any of these in the last 4 hours keeps the hold; a date that cannot be read counts as
38
- work. A takeover keeps the old branch and PR and names them, so the new session continues them.
18
+ One call; the JSON carries `viewer`, `repo` and the project title. Use `primary` for this repo and
19
+ `secondary` for other repos on the Project. Partial reads exit nonzero; `--allow-partial` only when the dev
20
+ accepts an incomplete board. The CLI partitions rows into **Yours**, **Free to claim** and **Taken**; stale
21
+ stamps (4 hours without work) hold nothing. Partition rules, stamp details and `--out` rationale:
22
+ [reference.md](reference.md).
39
23
 
40
24
  ## Step 2 — render it
41
25
 
42
26
  Plain markdown, never a fenced block. Flat `-` lists under bold heads, never `##` headings, never tables.
43
- Refs are `[RepoName#N](url) · short title` — no `owner/` prefix, no `[type]` brackets, title trimmed to
44
- its essence. **Taken** renders id · status · owner only, never the title. Skip empty sections silently.
45
- One screen.
46
-
47
- For a rendering example, read [examples.md](examples.md).
27
+ Refs are `[RepoName#N](url) · short title`, no `owner/` prefix, no `[type]` brackets. **Taken** renders
28
+ id · status · owner only, never the title. Skip empty sections. One screen. Example: [examples.md](examples.md).
48
29
 
49
- Status moves happen automatically as work flows — claim, PR open, merge. Never offer a status move.
30
+ Status moves happen automatically as work flows. Never offer a status move.
50
31
 
51
32
  ## Step 3 — plan the fewest PRs
52
33
 
53
- This is the aggressive half. Do not offer one item at a time and do not default to one PR per issue.
54
-
55
- Fetch the material you need to group by:
34
+ Never one item at a time, never one PR per issue. Fetch bodies:
56
35
 
57
36
  ```bash
58
37
  mmi-cli oracle board read --json --bodies --out .jerv/tmp/board-full.json
59
38
  ```
60
39
 
61
- `--bodies` fetches body and comments for every scoped issue. In the JSON, read them at
62
- `row.details.body` and `row.details.comments` — not `row.body` or `row.comments`. `--bundle-details` is
63
- the cheaper variant that covers only `userOwned` and `claimable` — prefer it when the plan is limited
64
- to claimable work. `taken` stays metadata-only either way. Do not fetch Done items.
65
-
66
- Then build the plan:
67
-
68
- 1. **Derive each issue's touch-set** — the files and directories it will change, read from the body,
69
- its comments and its `surface:*` label. An issue whose touch-set you cannot name is not plannable;
70
- leave it out of the batch and say so.
71
- 2. **Join issues whose touch-sets overlap.** Follow the overlap transitively: if A and B share a file and
72
- B and C share another, all three are one group. Each resulting group is one worktree and **one PR**.
73
- 3. **Groups are disjoint by construction**, so every group runs in parallel with no worktree contention.
74
- That is the whole trick — the number of groups is the number of PRs, and it is the smallest number
75
- reachable without two PRs fighting over the same file.
76
-
77
- Forced splits — these override the grouping and each takes its own PR:
78
-
79
- - **Another repo.** Never bundle across repos. Board advance is per-repo and deliberately refuses to move
80
- another repo's issue, so a cross-repo bundle lands the code and leaves those issues stranded open.
81
- - **Irreversible or gated work** — migrations, secret rotation, release-train changes. Bundling hides them.
82
- - **An issue that must stay open** (HOLD, prep, partial delivery).
83
- - **Review size.** A PR no one can review is not cheap. When a group grows past roughly ten issues or
84
- spans unrelated subsystems, cut it at its weakest overlap and take two PRs.
40
+ (Bodies and comments are at `row.details.body` and `row.details.comments`. Skip Done.)
85
41
 
86
- Present the plan before touching anything — batch count, issue count, and one line per batch naming its
87
- shared surface. Then stop and wait.
42
+ 1. **Derive each issue's touch-set** from body, comments and `surface:*` label. If you cannot name it, leave
43
+ the issue out and say so.
44
+ 2. **Join overlapping touch-sets**, transitively. Each group is one worktree and **one PR**; groups are
45
+ disjoint, so all run in parallel.
88
46
 
89
- > Nine claimable, three PRs: **A** #6395–#6397 board routing · **B** #6398–#6401 train doctor heal ·
90
- > **C** #6402–#6403 CLI flag validation. Say go and I'll run all three in parallel.
47
+ Forced splits, each its own PR: another repo; irreversible or gated work (migrations, secret rotation,
48
+ release-train changes; principle 12); an issue that must stay open; a group past roughly ten issues or
49
+ spanning unrelated subsystems. Reasons: [reference.md](reference.md).
91
50
 
92
- ## Step 4 — on the dev's go, claim and run
51
+ Present the plan — batch count, issue count, one line per batch naming its shared surface — then wait for go.
93
52
 
94
- Claim a whole batch in one call — it shares setup cost and returns per-item results:
53
+ ## Step 4 — on go, claim and run
95
54
 
96
55
  ```bash
97
56
  mmi-cli oracle board claim <ref> <ref> <ref> --json
98
57
  ```
99
58
 
100
- Claiming takes a card that is unassigned or assigned to the viewer, in `Todo`, `In Progress` or
101
- `In Review`, unless another session still shows work on it in the last 4 hours (then it refuses). It assigns the viewer, moves Status to
102
- `In Progress`, and stamps a lane-identity comment so other agents can attribute the hold. Any per-item failure exits nonzero — read
103
- the per-item results rather than assuming the batch took. **Route is `oracle board claim` only**; there is
104
- no `oracle issue claim` and no flat `board claim` — both refuse. Guessing either burns a call.
59
+ Say the size first: how many issues, how many PRs. Read per-item results; any failure exits nonzero. **Route
60
+ is `oracle board claim` only**; `oracle issue claim` and flat `board claim` refuse.
105
61
 
106
- Then one worktree per batch, all batches concurrently. The host owns worktree mechanics; MMI owns board
107
- and PR facts. For worktree setup on Windows or concurrent ref renames, read [reference.md](reference.md).
62
+ The claim prints the issue's recorded owner rulings; follow them. Record a new one with `mmi-cli oracle issue decision`.
108
63
 
109
- ## Step 5 — land one PR per batch
110
-
111
- There is no `--issues` or `--closes` flag. A bundled PR is expressed in the **body**:
64
+ One worktree per batch, all concurrently. Windows setup and ref renames: [reference.md](reference.md).
112
65
 
113
- ```
114
- Closes #6395, #6396, #6397
115
- ```
66
+ ## Step 5 — land one PR per batch
116
67
 
117
- `pr create` normalizes multiple closing directives, and after the merge the board advance walks GitHub's
118
- full `closingIssuesReferences` list and moves **each** issue to Done, verifying every one and naming any
119
- that did not move. So a bundle is a first-class landing, not a trick.
68
+ No `--issues` or `--closes` flag; put `Closes #6395, #6396, #6397` in the **body**. After merge, board
69
+ advance moves each closed issue to Done.
120
70
 
121
71
  ```bash
122
72
  mmi-cli devops pr create --body-file .jerv/tmp/pr-batch-a.md
123
73
  mmi-cli devops pr land <pr> --json
124
74
  ```
125
75
 
126
- Materialize the body as a real UTF-8 file and pass its path; do not pipe it to `--body-file -`. Read
127
- `mmi-cli explain devops pr create --json` before the write — flags change.
128
-
129
- When an issue must stay open, write `Part of #N` or `Refs #N`. **Never** write `Does not close #N` —
130
- GitHub closes it anyway (JC#495).
131
-
132
- When the repo runs a guidance-learning gate, read [reference.md](reference.md) before preparing the PR body.
133
-
134
- Landing requires a merged receipt before any cleanup: `state` `MERGED`, the head ref and OID matching the
135
- local task branch, and a clean worktree. Anything else means retain and report, never clean.
136
-
137
- ## Guardrails
138
-
139
- - **No go, no write.** The board render and the plan are free. Claims, branches, PRs are not.
140
- - **Say the size out loud** before claiming: how many issues, how many PRs.
141
- - **Same repo only** inside one PR.
142
- - A batch is justified by a shared code surface, never by convenience. Unrelated changes in one PR make a
143
- worse PR, not a cheaper one.
144
- - Surface any `gh` / `mmi-cli` error verbatim.
76
+ Write the body as a UTF-8 file; run `mmi-cli explain devops pr create --json` first. An issue that stays
77
+ open: `Part of #N` or `Refs #N`, never `Does not close #N`. Guidance-learning gate: read
78
+ [reference.md](reference.md) first. Clean up only after a merged receipt (`state` `MERGED`, matching head
79
+ ref and OID, clean worktree); otherwise retain and report. Show any `gh` / `mmi-cli` error verbatim.
145
80
 
146
81
  ## Retro — one check before you finish
147
- Before your final report, answer one question honestly: did **this skill's own instructions** misfire this
148
- run — ambiguous wording, a misleading message, or an environment failure it should have warned about?
149
- (Process only — never the user's code or task; e.g. a grouping rule that bundled two issues which turned
150
- out to conflict, or a board read that misreported what was claimable.) If yes, file **one** lesson and
151
- move on; a clean run is silent (hard cap: one per run). It lands on the owning board (deduped) and is
152
- fixed only via a reviewed PR — never edit the skill live; the retro is advisory, so if the call fails,
153
- note it and continue. File through MMI:
82
+
83
+ Did this skill's own instructions misfire this run (process only, never the user's code)? If yes, file one:
154
84
  `mmi-cli learning skill-lesson --skill board --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
85
+ File one per run; a clean run is silent; if the call fails, note it and continue.
@@ -9,3 +9,69 @@ standalone `learning: none — <reason>` line unless a closing learning issue's
9
9
  changed file. The line must stand alone on its own newline — a literal `\n` inside an inline edit fails
10
10
  the gate again.
11
11
 
12
+
13
+ ## Detail moved from SKILL.md
14
+
15
+ Prefer `--out` for a shell-independent UTF-8 receipt. Windows PowerShell 5.1's `>` writes
16
+ UTF-16LE with a BOM (#5802); Bash redirects preserve the CLI's UTF-8 output.
17
+
18
+ One call. Its JSON carries `viewer`, `repo` and the project title — do not spend extra calls on
19
+ `gh api user` or `gh repo view`. Use `primary` for this repo and `secondary` for other repos on the same
20
+ Project. Partial reads exit nonzero; pass `--allow-partial` only when the dev accepts an incomplete board.
21
+
22
+ Partition, as the CLI computes it:
23
+
24
+ - **Yours** — assignee includes the viewer, status in `Todo · In Progress · In Review`, or stamped by this
25
+ seat (same login, host, and surface, including a prior session on this host whose transcript is dead).
26
+ - **Free to claim** — status `Todo`, unassigned, and the viewer has push on the repo. Also any item in
27
+ any status whose foreign claim stamp is stale: its session has done no work on it for 4 hours. A stale stamp
28
+ holds nothing; `board claim` takes it over without `--force` and names the old stamp.
29
+ - **Taken** — someone else's, any active status.
30
+
31
+ Every stamped row names its session (`lane surface/session@host`), or `stale:<age>` when the stamp is
32
+ stale. Work means the stamp, an issue comment, a commit on the issue's branch, or an update to an open
33
+ PR that closes it. Any of these in the last 4 hours keeps the hold; a date that cannot be read counts as
34
+ work. A takeover keeps the old branch and PR and names them, so the new session continues them.
35
+
36
+ `--bodies` fetches body and comments for every scoped issue. In the JSON, read them at
37
+ `row.details.body` and `row.details.comments` — not `row.body` or `row.comments`. `--bundle-details` is
38
+ the cheaper variant that covers only `userOwned` and `claimable` — prefer it when the plan is limited
39
+ to claimable work. `taken` stays metadata-only either way. Do not fetch Done items.
40
+
41
+ 3. **Groups are disjoint by construction**, so every group runs in parallel with no worktree contention.
42
+ That is the whole trick — the number of groups is the number of PRs, and it is the smallest number
43
+ reachable without two PRs fighting over the same file.
44
+
45
+ Forced splits — these override the grouping and each takes its own PR:
46
+
47
+ - **Another repo.** Never bundle across repos. Board advance is per-repo and deliberately refuses to move
48
+ another repo's issue, so a cross-repo bundle lands the code and leaves those issues stranded open.
49
+ - **Irreversible or gated work** — migrations, secret rotation, release-train changes. Bundling hides them.
50
+ - **An issue that must stay open** (HOLD, prep, partial delivery).
51
+ - **Review size.** A PR no one can review is not cheap. When a group grows past roughly ten issues or
52
+ spans unrelated subsystems, cut it at its weakest overlap and take two PRs.
53
+
54
+ > Nine claimable, three PRs: **A** #6395–#6397 board routing · **B** #6398–#6401 train doctor heal ·
55
+ > **C** #6402–#6403 CLI flag validation. Say go and I'll run all three in parallel.
56
+
57
+ Claiming takes a card that is unassigned or assigned to the viewer, in `Todo`, `In Progress` or
58
+ `In Review`, unless another session still shows work on it in the last 4 hours (then it refuses). It assigns the viewer, sets
59
+ `In Progress` and stamps a lane-identity comment.
60
+
61
+ Then one worktree per batch, all batches concurrently. The host owns worktree mechanics; MMI owns board
62
+ and PR facts.
63
+
64
+ `pr create` normalizes multiple closing directives, and after the merge the board advance walks GitHub's
65
+ full `closingIssuesReferences` list and moves **each** issue to Done, verifying every one and naming any
66
+ that did not move. So a bundle is a first-class landing, not a trick.
67
+
68
+ Materialize the body as a real UTF-8 file and pass its path; do not pipe it to `--body-file -`. Read
69
+ `mmi-cli explain devops pr create --json` before the write — flags change.
70
+
71
+ When an issue must stay open, write `Part of #N` or `Refs #N`. **Never** write `Does not close #N` —
72
+ GitHub closes it anyway (JC#495).
73
+
74
+ Landing requires a merged receipt before any cleanup: `state` `MERGED`, the head ref and OID matching the
75
+ local task branch, and a clean worktree. Anything else means retain and report, never clean.
76
+
77
+ Retro: the lesson lands on the owning board (deduped) and is fixed only via a reviewed PR — never edit the skill live; the retro is advisory. A misfire is ambiguous wording, a misleading message, or an environment failure the skill should have warned about (e.g. a grouping rule that bundled two issues which turned out to conflict, or a board read that misreported what was claimable). Hard cap: one lesson per run.
@@ -7,157 +7,71 @@ description: Provision an org repo with board, registry, rules, and plugin setup
7
7
 
8
8
  # /bootstrap — provision a repo into the org
9
9
 
10
- The one-time onboarding that turns a repo into a first-class org citizen. **Master-admin only, run from
11
- `MMI-Hub` (the hub).** Every step operates org-level resources (Project, Ruleset, org secrets, member
12
- access) **through the GitHub App's installation token** — not a human credential — so the gate is who may
13
- invoke the skill (the master holds the App key), not the caller's GitHub role.
10
+ One-time onboarding, run from `MMI-Hub` by the master (who holds the GitHub App key). It uses the App installation token, no per-repo checkout. The repo must already be named `<CATEGORY>-<PascalName>`.
14
11
 
15
- Bootstrap operates on the target repo entirely through the App — **no per-repo checkout**. The repo must
16
- already be named on the taxonomy `<CATEGORY>-<PascalName>`.
12
+ Read [reference.md](reference.md) for create vs upgrade, seed refresh, propagation rollback, or new topology values.
17
13
 
18
- Read [reference.md](reference.md) when choosing create vs upgrade, refreshing seeds, rolling back propagation, or using newly released topology values.
14
+ ## Step 0 — confirm the four axes before any mutation
19
15
 
20
- ## Step 0 — capability shape (confirm the four axes before any mutation)
16
+ Before Step 0a, state a recommended default per axis and confirm all four with Jervaise through the orchestrator; never default silently.
21
17
 
22
- Bootstrap is **destructive to undo**: a wrong shape means converting in place later — deleting protected
23
- branches, temporarily disabling the org-wide `mmi-train-floor` ruleset (which affects every repo for that
24
- window), and tearing down train artifacts (#1450). So **before Step 0a touches anything**,
25
- surface and **confirm all four topology axes with the master** — present the recommended default for each,
26
- never apply it silently. Use the structured-question UI; one question per axis (or one grouped confirm).
18
+ - **`class`** — `deployable` (full or direct train) · `content` (trunk, `main` only); sets the branch model.
19
+ - **`project-type`** — `web-app`, `cli-tool`, `worker`, `desktop-app`, `desktop-game`, `mobile-app`, `content`…; sets Hub services.
20
+ - **`deploy-model`** — `tenant-container`, `none`, `content`…; sets the deploy path.
21
+ - **`release-track`** — `full` (development·rc·main) · `direct` (development·main) · `trunk` (`main`); sets the branch set.
27
22
 
28
- - **`class`** — `deployable` (ships an app/service; full or direct train) · `content` (docs/content;
29
- trunk, `main`-only). *Controls the branch model.* Recommend from what the repo **is**, not a fixed default.
30
- - **`project-type`** — e.g. `web-app`, `cli-tool`, `worker`, `desktop-app`, `desktop-game`, `mobile-app`, `content`. *Controls which Hub
31
- services attach.*
32
- - **`deploy-model`** — e.g. `tenant-container`, `none`, `content`. *Controls the deploy path.*
33
- - **`release-track`** — `full` (development·rc·main) · `direct` (development·main, skips rc) · `trunk`
34
- (`main` only). *The branch set follows the track, not just the class (#1097).*
23
+ A **deployable** repo also needs gate runtime (`node` default, `python` for a Python app), check command and working directory: `--var GATE_RUNTIME=`, `GATE_CMD=`, `GATE_WORKDIR=`, and `GATE_CACHE_DEP_PATH=` for a non-root Node lockfile.
35
24
 
25
+ **Content/trunk**: `main` only, no `rc`, no `gate.yml`, no product required-check ruleset, `projects.json` entry with `branch: main`.
36
26
 
37
- For a **deployable** repo, also capture the **gate runtime** (`node` | `python`), the **check command**, and
38
- the **working directory** — these feed the product gate (`--var GATE_RUNTIME=`, `--var GATE_CMD=`,
39
- `--var GATE_WORKDIR=`, and `--var GATE_CACHE_DEP_PATH=` for a non-root Node lockfile; see Step 5 / the
40
- "Product gate + required checks" note below). Default to `node` at the repo root; recommend `python` when the
41
- repo's app is Python.
42
-
43
- A **content/trunk** choice provisions: `main`-only (no `rc`), **no** `.github/workflows/gate.yml` and **no**
44
- product required-check ruleset, and a `projects.json` entry with `branch: main` (which marks it a content-class
45
- repo). A clean content repo then verifies green — `bootstrap verify --class content` no longer reports
46
- the deployable gate checks as FAIL (#1450).
47
-
48
- Record the confirmed axes; Step 0a runs `verify --class <confirmed>`, Step 0b creates the repo on the
49
- track's default branch, and the apply flags (`--project-type` / `--deploy-model` / `--release-track`) carry
50
- the confirmed values — no silent defaulting.
27
+ Apply flags carry the confirmed values; Step 0b creates the repo on the track's default branch.
51
28
 
52
29
  ## Step 0a — no-mutation verifier
53
30
 
54
- Before mutating anything, run the verifier so the current gaps are concrete:
55
31
  ```bash
56
- mmi-cli devops bootstrap verify "$OWNER/$REPO" --class deployable --json
57
- # or for content repos:
58
- mmi-cli devops bootstrap verify "$OWNER/$REPO" --class content --json
32
+ mmi-cli devops bootstrap verify "$OWNER/$REPO" --class deployable --json # or --class content
59
33
  ```
60
34
 
61
- Run it again after Step 7. A repo is not ready for real developers until every check is green, or the report
62
- names an explicitly manual-only item that the master has accepted for that repo. For a deployable repo the
63
- report ends with the train doctor verdict per lane (`release`; plus `rcand` on a full track) — the same
64
- `mmi-cli devops train doctor` door `/release` and `/rcand` open (#6070); a `ready: false` there is an
65
- unfinished repo, **with one expected exception**: a full track's two lanes start from different branches
66
- (`release` from `rc`, `rcand` from `development`) and one checkout stands on one branch, so the lane you
67
- are not standing on reports the never-healed `branch-mismatch` blocker (#6432). Verify is read-only and
68
- does not check the other branch out: a lane whose ONLY finding is that mismatch is printed `NOT EVALUATED
69
- from this branch` and does not fail the verify (#6677). That is the finished state, not a gap — run
70
- `mmi-cli devops train doctor --lane <lane> --json` from that lane's own branch for its verdict. Any other
71
- blocker in that lane, or an unread origin, still makes the report red.
72
-
73
- **Two verify FAILs are un-run apply steps or API lag, not code bugs — diagnose them as such, but never as
74
- acceptable end states (#2928):**
75
- - `branch protection exists` / `push allowlist configured` — **`bootstrap apply --execute` applies the
76
- train-branch push allowlist (Step 2b)**, so these FAIL until the live apply has run. They are security
77
- controls and must go green (or be an explicitly master-accepted manual item per the rule above) before
78
- the bootstrap is complete. A red branch-protection or push-allowlist check is an **unfinished repo**,
79
- never a known-benign FAIL to sign off around.
80
- - `README has Agent context section — README.md not readable via API` on a README that demonstrably has the
81
- section — GitHub's contents API lags for a minute or so right after a merge. **Re-run before believing a
82
- content-read failure**; it clears on its own.
83
-
84
- For a new repo, board selection/creation, access, gate setup, or manual provisioning, read [reference.md](reference.md) Steps 0b–5 before applying; upgrades can use the apply path below.
35
+ Re-run after Step 7. Ready = all green, or a named manual-only item Jervaise accepted. A deployable report ends with the train doctor verdict per lane (`release`, plus `rcand` on full track); the lane you are not standing on reports `branch-mismatch`; if that is its ONLY finding, verify prints `NOT EVALUATED from this branch` and passes: run `mmi-cli devops train doctor --lane <lane> --json` from that lane's branch. Any other blocker, or an unread origin, is red.
85
36
 
86
- ## Step 6 — register Hub META
37
+ Two FAILs are unrun steps or API lag, never acceptable end states:
38
+ - `branch protection exists` / `push allowlist configured` — `bootstrap apply --execute` applies the allowlist (Step 2b). Security controls: green, or an accepted manual item, before the bootstrap is complete.
39
+ - `README has Agent context section — README.md not readable via API` on a README that has it — API lag after a merge; re-run.
87
40
 
88
- Do not seed a product repo control-plane config file. `mmi-cli` carries the Hub API endpoint and resolves board,
89
- deploy, secret, and project state from the Hub registry at runtime.
41
+ For board selection/creation, access, gate setup or manual provisioning of a new repo, read [reference.md](reference.md) Steps 0b–5; upgrades use the apply path below.
90
42
 
91
- For project-type/deploy-model flag combinations or an MM-Work module, read [reference.md](reference.md) before choosing the apply flags.
43
+ ## Step 6 — register Hub META
92
44
 
93
- Run the apply path with the board variables discovered above, or register the same values with
94
- `mmi-cli oracle org project set` from the Hub or from the target project checkout:
45
+ No product repo control-plane file; `mmi-cli` resolves state from the Hub registry. For flag combinations or an MM-Work module, read [reference.md](reference.md) first. Apply with the board variables discovered earlier (or `mmi-cli oracle org project set`):
95
46
 
96
47
  ```bash
97
48
  mmi-cli devops bootstrap apply "$OWNER/$REPO" --class deployable \
98
49
  --project-type web-app --deploy-model tenant-container --execute \
99
- --var PROJECT_OWNER="$PROJECT_OWNER" \
100
- --var PROJECT_NUMBER="$PROJECT_NUMBER" \
101
- --var PROJECT_ID="$PROJECT_ID" \
102
- --var STATUS_FIELD_ID="$STATUS_FIELD_ID" \
103
- --var STATUS_TODO="$STATUS_TODO" \
104
- --var STATUS_IN_PROGRESS="$STATUS_IN_PROGRESS" \
105
- --var STATUS_IN_REVIEW="$STATUS_IN_REVIEW" \
106
- --var STATUS_DONE="$STATUS_DONE"
50
+ --var PROJECT_OWNER="$PROJECT_OWNER" --var PROJECT_NUMBER="$PROJECT_NUMBER" \
51
+ --var PROJECT_ID="$PROJECT_ID" --var STATUS_FIELD_ID="$STATUS_FIELD_ID" \
52
+ --var STATUS_TODO="$STATUS_TODO" --var STATUS_IN_PROGRESS="$STATUS_IN_PROGRESS" \
53
+ --var STATUS_IN_REVIEW="$STATUS_IN_REVIEW" --var STATUS_DONE="$STATUS_DONE"
107
54
  ```
108
55
 
109
- Tenant-container repos must carry a `docker-compose.yml` and Dockerfile that build from the shipped source
110
- archive; the train does not ship a prebuilt `dist/`. **Bootstrap seeds both files** for
111
- `deployModel: tenant-container` from `skills/bootstrap/seeds/` (rendered from
112
- the bootstrap seed Dockerfile and compose templates). The seeded compose is fileless: its service carries
113
- `labels: { mmi.runtime-env: "true" }`, no `env_file`, and a loopback-only port; the deploy injects the stage's
114
- vault values at runtime (`DEPLOY#<stage>.noEnvFile: true`) and the app reads plain env vars — it must **not** self-load SSM and must **not** ship a committed `.env`.
56
+ `tenant-container` repos need a `docker-compose.yml` and Dockerfile building from the shipped source archive (no prebuilt `dist/`); bootstrap seeds both from `skills/bootstrap/seeds/`. The seeded compose is fileless: label `mmi.runtime-env: "true"`, no `env_file`, loopback-only port; deploy injects the stage's vault values (`DEPLOY#<stage>.noEnvFile: true`), so the app reads plain env vars, never self-loads SSM, never ships a `.env`. For an MM-Work module or non-suite web-app with OAuth META, read [reference.md](reference.md) before the first CI/deploy or OAuth provisioning.
115
57
 
116
- For an MM-Work module or non-suite web-app with OAuth META, read [reference.md](reference.md) before the first CI/deploy or OAuth provisioning.
58
+ **Stage port block:** `tenant-container` and `solo-container` need Hub registry `portRange` (`bootstrap verify` fails without it). `bootstrap apply --execute` assigns it; for older META run `mmi-cli stage port-range <Repo>` (idempotent). Use `$STAGE_PORT` in `stage.up`/`healthUrl`.
117
59
 
118
- Local `/stage` is optional product-owned configuration. A repo that wants `/stage` may carry a local
119
- `stage` block, but that file must not contain board, deploy, or secret registry facts.
60
+ ## Step 7 — org-managed .gitignore block
120
61
 
121
- **Stage port block (required for central-container):** run `mmi-cli stage port-range <Repo>` to assign
122
- (idempotently) the repo's local port block from the central registry. `tenant-container` and
123
- `solo-container` **must** have Hub registry `portRange` — `mmi-cli devops bootstrap verify` fails without
124
- it (#5539), and `mmi-cli stage` cannot derive a local preview until the block exists. `bootstrap apply
125
- --execute` assigns the block automatically after DDB register for those models; for older META holes,
126
- run `stage port-range` explicitly. Use `$STAGE_PORT` in `stage.up` / `healthUrl`; `/stage` then picks a
127
- free port inside the block so a dev can run several projects/versions locally without collisions.
128
-
129
- ## Step 7 — seed the org-managed .gitignore block
130
-
131
- The org-managed `.gitignore` block is delivered by the `managed-block` bootstrap seed (`skills/bootstrap/seeds/manifest.json`),
132
- which merges the canonical block into the repo's `.gitignore` in place, preserving the repo's own ignore lines.
133
- The independent CLI/user-settings resume path may run doctor thereafter. The block carries **only** org-universal ignores —
134
- never agent guides or a spine. The fanout pipeline that used to push this block via App-token PRs is retired
135
- (Hub#3010), and the whole-spine fanout was retired earlier (hub-v3 WS4.2 #2219).
62
+ The `managed-block` seed (`skills/bootstrap/seeds/manifest.json`) merges org-universal ignores into `.gitignore` in place, keeping the repo's own lines.
136
63
 
137
64
  ## Step 8 — report
138
65
 
139
- Repo, default branch, ruleset applied, train branches locked (push allowlist), repository Environments
140
- provisioned per track (plan-gated protections named in apply output), project attached/created
141
- (+ info seeded, Status lanes and Labels field verified), secrets set (names only), developer access, plugin
142
- installed, docs seeded, registry META written, issue templates committed, org App credentials registered,
143
- org-managed `.gitignore` block seeded, the final `mmi-cli devops bootstrap verify "$OWNER/$REPO" --class ... --json` result,
144
- and — for a deployable repo — the train door itself, run from the repo's own checkout on `development`:
66
+ Repo, default branch, ruleset, push allowlist, Environments per track, project (info, Status lanes, Labels field verified), secrets set (names only), access, plugin, docs, registry META, issue templates, org App credentials, `.gitignore` block, the final `bootstrap verify` result, and for a deployable repo the train door from the repo's checkout on `development`:
145
67
 
146
68
  ```bash
147
- mmi-cli devops train doctor --lane release --repo "$OWNER/$REPO" --json
69
+ mmi-cli devops train doctor --lane release --repo "$OWNER/$REPO" --json # full track: also --lane rcand
148
70
  ```
149
71
 
150
- `ready: true` is the bootstrap's train-readiness proof; every finding carries `code`, `severity`, `source`,
151
- `remedy` and a `docs/Guides/train-troubleshooting.md#<code>` anchor. A full-track repo runs
152
- `--lane rcand` as well. A `bootstrap-gap` finding names the apply row still missing — a blocker for a
153
- train branch absent on origin, a warning for a stage with no required status check (#6136): read the
154
- warnings too, `ready: true` alone does not prove the product ruleset is active.
155
-
156
- ## Retro — one check before you finish
157
- Before your final report, answer one question honestly: did **this skill's own instructions** misfire
158
- this run — ambiguous wording, a misleading message, or an environment failure it should have warned
159
- about? (Process only — never the user's code or task; e.g. an ambiguous seed, registry, or OIDC step, or
160
- a guard that fired on a healthy repo.) If yes, file **one** lesson and move on; a clean run is silent
161
- (hard cap: one per run). It lands on the owning board (deduped) and is fixed only via a reviewed PR — never
162
- edit the skill live; the retro is advisory, so if the call fails, note it and continue. File through MMI:
72
+ `ready: true` is the train-readiness proof (findings: `docs/Guides/train-troubleshooting.md#<code>`). A `bootstrap-gap` finding names the missing apply row (blocker: train branch absent on origin; warning: stage with no required status check). Read warnings too: `ready: true` alone does not prove the product ruleset is active.
73
+
74
+ ## Retro
75
+
76
+ If this skill's instructions misfired (process only), file one lesson (one per run; if the call fails, note it and continue):
163
77
  `mmi-cli learning skill-lesson --skill bootstrap --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
@@ -419,3 +419,68 @@ The keys are the one stageless pair `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`
419
419
  stage reads it (#2244/#2528). Never a staged `{dev,rc,main}/GOOGLE_*`, `GOOGLE_OAUTH_CLIENT_*`, or `prod/`
420
420
  variant; the runtime reads only the canonical names and declare-first rejects the rest.
421
421
 
422
+
423
+
424
+ ## Detail moved from SKILL.md (verbatim)
425
+
426
+ For a **deployable** repo, also capture the **gate runtime** (`node` | `python`), the **check command**, and
427
+ the **working directory** — these feed the product gate (`--var GATE_RUNTIME=`, `--var GATE_CMD=`,
428
+ `--var GATE_WORKDIR=`, and `--var GATE_CACHE_DEP_PATH=` for a non-root Node lockfile; see Step 5 / the
429
+ "Product gate + required checks" note below). Default to `node` at the repo root; recommend `python` when the
430
+ repo's app is Python.
431
+
432
+ A **content/trunk** choice provisions: `main`-only (no `rc`), **no** `.github/workflows/gate.yml` and **no**
433
+ product required-check ruleset, and a `projects.json` entry with `branch: main` (which marks it a content-class
434
+ repo). A clean content repo then verifies green — `bootstrap verify --class content` no longer reports
435
+ the deployable gate checks as FAIL (#1450).
436
+
437
+ Record the confirmed axes; Step 0a runs `verify --class <confirmed>`, Step 0b creates the repo on the
438
+ track's default branch, and the apply flags (`--project-type` / `--deploy-model` / `--release-track`) carry
439
+ the confirmed values — no silent defaulting.
440
+
441
+ Run it again after Step 7. A repo is not ready for real developers until every check is green, or the report
442
+ names an explicitly manual-only item that the master has accepted for that repo. For a deployable repo the
443
+ report ends with the train doctor verdict per lane (`release`; plus `rcand` on a full track) — the same
444
+ `mmi-cli devops train doctor` door `/release` and `/rcand` open (#6070); a `ready: false` there is an
445
+ unfinished repo, **with one expected exception**: a full track's two lanes start from different branches
446
+ (`release` from `rc`, `rcand` from `development`) and one checkout stands on one branch, so the lane you
447
+ are not standing on reports the never-healed `branch-mismatch` blocker (#6432). Verify is read-only and
448
+ does not check the other branch out: a lane whose ONLY finding is that mismatch is printed `NOT EVALUATED
449
+ from this branch` and does not fail the verify (#6677). That is the finished state, not a gap — run
450
+ `mmi-cli devops train doctor --lane <lane> --json` from that lane's own branch for its verdict. Any other
451
+ blocker in that lane, or an unread origin, still makes the report red.
452
+
453
+ Tenant-container repos must carry a `docker-compose.yml` and Dockerfile that build from the shipped source
454
+ archive; the train does not ship a prebuilt `dist/`. **Bootstrap seeds both files** for
455
+ `deployModel: tenant-container` from `skills/bootstrap/seeds/` (rendered from
456
+ the bootstrap seed Dockerfile and compose templates). The seeded compose is fileless: its service carries
457
+ `labels: { mmi.runtime-env: "true" }`, no `env_file`, and a loopback-only port; the deploy injects the stage's
458
+ vault values at runtime (`DEPLOY#<stage>.noEnvFile: true`) and the app reads plain env vars — it must **not** self-load SSM and must **not** ship a committed `.env`.
459
+
460
+ Local `/stage` is optional product-owned configuration. A repo that wants `/stage` may carry a local
461
+ `stage` block, but that file must not contain board, deploy, or secret registry facts.
462
+
463
+ **Stage port block (required for central-container):** run `mmi-cli stage port-range <Repo>` to assign
464
+ (idempotently) the repo's local port block from the central registry. `tenant-container` and
465
+ `solo-container` **must** have Hub registry `portRange` — `mmi-cli devops bootstrap verify` fails without
466
+ it (#5539), and `mmi-cli stage` cannot derive a local preview until the block exists. `bootstrap apply
467
+ --execute` assigns the block automatically after DDB register for those models; for older META holes,
468
+ run `stage port-range` explicitly. Use `$STAGE_PORT` in `stage.up` / `healthUrl`; `/stage` then picks a
469
+ free port inside the block so a dev can run several projects/versions locally without collisions.
470
+
471
+ Repo, default branch, ruleset applied, train branches locked (push allowlist), repository Environments
472
+ provisioned per track (plan-gated protections named in apply output), project attached/created
473
+ (+ info seeded, Status lanes and Labels field verified), secrets set (names only), developer access, plugin
474
+ installed, docs seeded, registry META written, issue templates committed, org App credentials registered,
475
+ org-managed `.gitignore` block seeded, the final `mmi-cli devops bootstrap verify "$OWNER/$REPO" --class ... --json` result,
476
+ and — for a deployable repo — the train door itself, run from the repo's own checkout on `development`:
477
+
478
+ ```bash
479
+ mmi-cli devops train doctor --lane release --repo "$OWNER/$REPO" --json
480
+ ```
481
+
482
+ `ready: true` is the bootstrap's train-readiness proof; every finding carries `code`, `severity`, `source`,
483
+ `remedy` and a `docs/Guides/train-troubleshooting.md#<code>` anchor. A full-track repo runs
484
+ `--lane rcand` as well. A `bootstrap-gap` finding names the apply row still missing — a blocker for a
485
+ train branch absent on origin, a warning for a stage with no required status check (#6136): read the
486
+ warnings too, `ready: true` alone does not prove the product ruleset is active.