@mutmutco/claude-plugin 4.6.41 → 4.6.43
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 +56 -19
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/skills/bootstrap/seeds/gate.template.yml +3 -2
- package/skills/bootstrap/seeds/manifest.json +2 -2
- package/skills/bootstrap/seeds/readme-mmi-developer-environment.block.md +1 -1
- package/skills/bootstrap/seeds/runbook-unaffected.json +6 -6
- package/skills/hotfix/SKILL.md +1 -1
- package/skills/hotfix/suite.md +1 -2
- package/skills/org-guide/references/work-and-releases.md +6 -5
- package/skills/rcand/SKILL.md +1 -1
- package/skills/rcand/suite.md +1 -4
- package/skills/release/SKILL.md +1 -1
- package/skills/release/suite.md +2 -6
- package/skills/release/verification.md +1 -1
package/cli/dist/main.cjs
CHANGED
|
@@ -25273,6 +25273,31 @@ function missingPlaceholders(rendered) {
|
|
|
25273
25273
|
for (const m of rendered.matchAll(PLACEHOLDER_RE)) out.add(m[1]);
|
|
25274
25274
|
return [...out];
|
|
25275
25275
|
}
|
|
25276
|
+
function seedMatchesReleaseTrack(seed, releaseTrack) {
|
|
25277
|
+
if (!seed.releaseTracks?.length) return true;
|
|
25278
|
+
return releaseTrack != null && seed.releaseTracks.includes(releaseTrack);
|
|
25279
|
+
}
|
|
25280
|
+
var TRAIN_ONLY_BEGIN = "mmi-train-only:start";
|
|
25281
|
+
var TRAIN_ONLY_END = "mmi-train-only:end";
|
|
25282
|
+
function renderSelfSeedForTrack(content, releaseTrack) {
|
|
25283
|
+
if (releaseTrack !== "single") return content;
|
|
25284
|
+
const lines2 = content.split(/(?<=\n)/);
|
|
25285
|
+
const out = [];
|
|
25286
|
+
let skipping = false;
|
|
25287
|
+
for (const line of lines2) {
|
|
25288
|
+
if (!skipping && line.includes(TRAIN_ONLY_BEGIN)) {
|
|
25289
|
+
skipping = true;
|
|
25290
|
+
continue;
|
|
25291
|
+
}
|
|
25292
|
+
if (skipping) {
|
|
25293
|
+
if (line.includes(TRAIN_ONLY_END)) skipping = false;
|
|
25294
|
+
continue;
|
|
25295
|
+
}
|
|
25296
|
+
out.push(line);
|
|
25297
|
+
}
|
|
25298
|
+
if (skipping) throw new Error(`unterminated ${TRAIN_ONLY_BEGIN} region`);
|
|
25299
|
+
return out.join("");
|
|
25300
|
+
}
|
|
25276
25301
|
function isPropagatableSeed(seed) {
|
|
25277
25302
|
return seed.ownership === "org" && seed.source === "self" || seed.managedBlock != null;
|
|
25278
25303
|
}
|
|
@@ -26639,6 +26664,7 @@ function withDerivedRepoVars(vars, parsed, cls, releaseTrack, requiredCheckBranc
|
|
|
26639
26664
|
out.CLASS ??= cls;
|
|
26640
26665
|
out.PROJECT_OWNER ??= parsed.owner;
|
|
26641
26666
|
const track = releaseTrack ?? resolveBootstrapReleaseTrack(cls);
|
|
26667
|
+
out.RELEASE_TRACK ??= track;
|
|
26642
26668
|
const runtime = out.GATE_RUNTIME === "python" ? "python" : "node";
|
|
26643
26669
|
for (const [key, value] of Object.entries(gateSeedVars(cls, track, runtime, requiredCheckBranches, requiredChecks))) {
|
|
26644
26670
|
out[key] ??= value;
|
|
@@ -26998,7 +27024,10 @@ function renderBootstrapAncillaryPlan(labels, environments, exceptions = []) {
|
|
|
26998
27024
|
].join("\n");
|
|
26999
27025
|
}
|
|
27000
27026
|
function resolveSeedContent(seed, vars, readFile11) {
|
|
27001
|
-
if (seed.source === "self")
|
|
27027
|
+
if (seed.source === "self") {
|
|
27028
|
+
const own = readFile11(seed.target);
|
|
27029
|
+
return own == null ? null : renderSelfSeedForTrack(own, vars.RELEASE_TRACK);
|
|
27030
|
+
}
|
|
27002
27031
|
if (seed.source.startsWith("seed:")) {
|
|
27003
27032
|
const tmpl = readFile11(`skills/bootstrap/seeds/${seed.source.slice("seed:".length)}`);
|
|
27004
27033
|
return tmpl == null ? null : renderSeed(tmpl, vars);
|
|
@@ -28527,10 +28556,10 @@ var rollout_plan_default = {
|
|
|
28527
28556
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
28528
28557
|
},
|
|
28529
28558
|
baseline: {
|
|
28530
|
-
version: "4.6.
|
|
28531
|
-
tag: "v4.6.
|
|
28532
|
-
commit: "
|
|
28533
|
-
npm: "@mutmutco/cli@4.6.
|
|
28559
|
+
version: "4.6.43",
|
|
28560
|
+
tag: "v4.6.43",
|
|
28561
|
+
commit: "856f4651277d",
|
|
28562
|
+
npm: "@mutmutco/cli@4.6.43"
|
|
28534
28563
|
},
|
|
28535
28564
|
exitCriterion: "fleet-n-of-n",
|
|
28536
28565
|
hubOnlyShortcut: "forbidden",
|
|
@@ -28547,14 +28576,14 @@ var rollout_plan_default = {
|
|
|
28547
28576
|
repo: "mutmutco/mmi-hub",
|
|
28548
28577
|
role: "canary",
|
|
28549
28578
|
schedule: "train",
|
|
28550
|
-
v3Target: "v4.6.
|
|
28579
|
+
v3Target: "v4.6.43"
|
|
28551
28580
|
}
|
|
28552
28581
|
],
|
|
28553
28582
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
28554
28583
|
rollback: {
|
|
28555
28584
|
independent: true,
|
|
28556
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
28557
|
-
v3Target: "v4.6.
|
|
28585
|
+
mechanism: "npm dist-tag latest -> 4.6.43 and redeploy the Hub Lambda from tag v4.6.43 (856f4651277d); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
28586
|
+
v3Target: "v4.6.43 (@mutmutco/cli@4.6.43, tag commit 856f4651277d \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
28558
28587
|
}
|
|
28559
28588
|
},
|
|
28560
28589
|
{
|
|
@@ -31670,17 +31699,17 @@ function isBundleOnlySuiteMember(repo, suite) {
|
|
|
31670
31699
|
if (!suite) return false;
|
|
31671
31700
|
return repo.split("/")[1]?.toLowerCase() !== suite.toLowerCase();
|
|
31672
31701
|
}
|
|
31702
|
+
var MM_GOES_LIVE = "MM-Work and its modules merge to development and it goes live; there is no release, rc or candidate stage.";
|
|
31673
31703
|
function suiteMemberRefusal(repo, meta, lane, solo = false, cut) {
|
|
31674
31704
|
const suite = meta?.suite;
|
|
31675
31705
|
if (!suite) return null;
|
|
31676
31706
|
if (!isBundleOnlySuiteMember(repo, suite)) {
|
|
31677
31707
|
if (solo || cut?.token === SUITE_LEAD_TOKEN && cut.repo.toLowerCase() === repo.toLowerCase()) return null;
|
|
31678
|
-
|
|
31679
|
-
return `${repo} is the ${suite} suite lead; a plain ${lane} would cut it without its members: ${route}. A lead-only ${lane} needs --suite-solo --owner-go.`;
|
|
31708
|
+
return `${repo} is the ${suite} suite lead; ${MM_GOES_LIVE} There is no ${lane} to run: land the change through a normal PR to development and state what landed.`;
|
|
31680
31709
|
}
|
|
31681
31710
|
if (authorisedSuiteCut(repo, meta, cut)) return null;
|
|
31682
31711
|
if (lane !== "rcand" && solo) return null;
|
|
31683
|
-
return `${repo} is part of the ${suite} suite;
|
|
31712
|
+
return `${repo} is part of the ${suite} suite; ${MM_GOES_LIVE} A suite member never asks for, proposes or prompts an rc, release or hotfix: there is none, so state what landed and stop.`;
|
|
31684
31713
|
}
|
|
31685
31714
|
|
|
31686
31715
|
// src/tenant-control-parse.ts
|
|
@@ -51008,7 +51037,7 @@ async function verifyBootstrap(repo, repoClass, deps, releaseTrack) {
|
|
|
51008
51037
|
detail: `expected: ${requiredProductRulesetRef} (apply as an active repo ruleset after bootstrap)`
|
|
51009
51038
|
});
|
|
51010
51039
|
}
|
|
51011
|
-
if (repoClass === "deployable") {
|
|
51040
|
+
if (repoClass === "deployable" && effectiveTrack !== "single") {
|
|
51012
51041
|
const trainScript = "scripts/next-version.mjs";
|
|
51013
51042
|
checks.push({ ok: await contentExists2(deps, repo, baseBranch, trainScript), label: `train tooling script exists: ${trainScript}` });
|
|
51014
51043
|
}
|
|
@@ -51734,7 +51763,9 @@ function registerBootstrapCommands(program3) {
|
|
|
51734
51763
|
for (const repo of targets) {
|
|
51735
51764
|
const cls = classOf(repo);
|
|
51736
51765
|
const meta = metaOf(repo);
|
|
51737
|
-
const
|
|
51766
|
+
const track = resolveReleaseTrack(metaWithDeclaredClass(meta, cls), void 0, repo);
|
|
51767
|
+
const seeds = byteComparableSeeds(manifest, cls).filter((s) => seedMatchesReleaseTrack(s, track));
|
|
51768
|
+
const trackHubContents = new Map([...hubContents].map(([t, c]) => [t, c == null ? c : renderSelfSeedForTrack(c, track)]));
|
|
51738
51769
|
seedsPerRepo = Math.max(seedsPerRepo, seeds.length);
|
|
51739
51770
|
const baseBranch = cls === "content" ? "main" : "development";
|
|
51740
51771
|
const reads = [];
|
|
@@ -51749,9 +51780,8 @@ function registerBootstrapCommands(program3) {
|
|
|
51749
51780
|
}
|
|
51750
51781
|
reads.push({ target: seed.target, content });
|
|
51751
51782
|
}
|
|
51752
|
-
findings.push(...auditRepoSeedDrift(repo, seeds,
|
|
51783
|
+
findings.push(...auditRepoSeedDrift(repo, seeds, trackHubContents, reads));
|
|
51753
51784
|
findings.push(...declaredRenderWaivers(manifest, repo));
|
|
51754
|
-
const track = resolveReleaseTrack(metaWithDeclaredClass(meta, cls), void 0, repo);
|
|
51755
51785
|
const github = await readBootstrapGitHubFacts(repo, track, controlClient);
|
|
51756
51786
|
const deployFacts = await fetchDeployFactsBySlug((repo.split("/").pop() ?? repo).toLowerCase(), registryClientDeps(await loadConfig()));
|
|
51757
51787
|
const controlRows = planBootstrapControlPlane({
|
|
@@ -52176,6 +52206,7 @@ function registerBootstrapCommands(program3) {
|
|
|
52176
52206
|
if (!seed.classes.includes(o.class)) continue;
|
|
52177
52207
|
if (!seedMatchesDeployModel(seed, applyDeployModel)) continue;
|
|
52178
52208
|
if (!seedMatchesProjectType(seed, applyProjectType)) continue;
|
|
52209
|
+
if (!seedMatchesReleaseTrack(seed, vars.RELEASE_TRACK)) continue;
|
|
52179
52210
|
const waiver = seed.waivers?.[slug];
|
|
52180
52211
|
if (waiver) {
|
|
52181
52212
|
actions.push({ action: "skip", target: seed.target, ownership: seed.ownership, reason: `waived: ${waiver}` });
|
|
@@ -52670,7 +52701,12 @@ LIVE apply to ${repo}:
|
|
|
52670
52701
|
const readSeedFile2 = (path2) => (0, import_node_fs40.existsSync)(path2) ? (0, import_node_fs40.readFileSync)(path2, "utf8") : null;
|
|
52671
52702
|
const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
|
|
52672
52703
|
const { projects, classOf, inClassRepos, canarySlug, sourcePilot } = await propagationScope(seed.classes, `target '${seed.target}'`);
|
|
52673
|
-
const
|
|
52704
|
+
const trackOf = (repo) => resolveReleaseTrack(
|
|
52705
|
+
projects.find((p) => (p.repos ?? []).some((r) => r.toLowerCase() === repo.toLowerCase())),
|
|
52706
|
+
void 0,
|
|
52707
|
+
repo
|
|
52708
|
+
);
|
|
52709
|
+
const repos = inClassRepos.filter((repo) => seedMatchesReleaseTrack(seed, trackOf(repo))).map((repo) => {
|
|
52674
52710
|
const slug = repo.split("/").pop().toLowerCase();
|
|
52675
52711
|
const waiver = seed.waivers?.[slug];
|
|
52676
52712
|
return { repo, slug, waiver };
|
|
@@ -52718,7 +52754,7 @@ LIVE apply to ${repo}:
|
|
|
52718
52754
|
}
|
|
52719
52755
|
desired = resolved.content;
|
|
52720
52756
|
} else {
|
|
52721
|
-
desired = hubContent;
|
|
52757
|
+
desired = renderSelfSeedForTrack(hubContent, trackOf(r.repo));
|
|
52722
52758
|
}
|
|
52723
52759
|
desiredByRepo.set(r.repo, desired);
|
|
52724
52760
|
const drift = compareSeedBytes(desired, content);
|
|
@@ -59669,7 +59705,7 @@ function branchRulesReadHint(path2) {
|
|
|
59669
59705
|
const match = new RegExp(`^repos/(${NAME})/(${NAME})/(?:rules/branches/[^/?#]+|branches/[^/?#]+/protection(?:/|$)|rulesets(?:/|$))`).exec(path2.split("?")[0]);
|
|
59670
59706
|
if (!match) return "";
|
|
59671
59707
|
const slug = `${match[1]}/${match[2]}`;
|
|
59672
|
-
return ` No raw rules, rulesets or branch-protection read is on the App allowlist, so retrying path or query variants cannot work \u2014 inspect a PR's required status contexts with \`MMI_ACTOR=app mmi-cli devops pr checks-required <pr> --repo ${slug} --json\`, or verify repository ruleset and branch-protection health with \`mmi-cli devops bootstrap verify --repo ${slug} --json\` and \`mmi-cli devops ci audit --repo ${slug} --json
|
|
59708
|
+
return ` No raw rules, rulesets or branch-protection read is on the App allowlist, so retrying path or query variants cannot work \u2014 inspect a PR's required status contexts with \`MMI_ACTOR=app mmi-cli devops pr checks-required <pr> --repo ${slug} --json\`, or verify repository ruleset and branch-protection health with \`mmi-cli devops bootstrap verify --repo ${slug} --json\` and \`mmi-cli devops ci audit --repo ${slug} --json\`. Stepping around it with a raw \`gh api repos/${slug}/rulesets/<id> > file\` is not a substitute \u2014 when that read fails it leaves an EMPTY file, and a later require/JSON.parse throws 'Unexpected end of JSON input' that looks like corrupt data while the real refusal is only on stderr; check the exit code and file size, or ask a human token holder for the raw ruleset body.`;
|
|
59673
59709
|
}
|
|
59674
59710
|
function commitsReadHint(path2) {
|
|
59675
59711
|
const clean4 = path2.split("?")[0];
|
|
@@ -61643,7 +61679,8 @@ async function observePrCreateClaims(body, repoOption, deps = {}) {
|
|
|
61643
61679
|
continue;
|
|
61644
61680
|
}
|
|
61645
61681
|
const holder = contest.marker ? `lane ${describeClaimMarker(contest.marker)} (claim marker read from ${commentsPath}${posted})` : `an unreadable lane (its claim-marker comments could not be read${throttledPaths.has(commentsPath) ? " \u2014 GitHub rate-limited the read (HTTP 403) and the bounded reset-aware retry could not clear it" : ""}; the holder may be this very lane)`;
|
|
61646
|
-
|
|
61682
|
+
const localLive = contest.marker && contest.live.some((l) => l.endsWith("has recent local transcript activity")) ? ` The holder ${describeClaimMarker(contest.marker)} is running on THIS host (marker ${Number.isFinite(postedMs) ? `${formatClaimAge(now() - postedMs)} old` : "age unknown"}), so --force would race it: if it is this lane's own earlier incarnation (same task, same branch this PR lands), reclaim with \`mmi-cli oracle board claim ${ref} --force\`; otherwise stop and leave ${ref} to it.` : "";
|
|
61683
|
+
findings.push(`pr create: REFUSED \u2014 ${ref} is held by ${holder} with ${kinds} work evidence (${why}); run \`mmi-cli oracle board claim ${ref} --force\` (move it to In Progress first if it sits In Review) or drop the closing line before creating this PR;${localLive} ${requester}`);
|
|
61647
61684
|
}
|
|
61648
61685
|
let attempted = false;
|
|
61649
61686
|
return {
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
name: gate
|
|
2
2
|
# Org-standard green-before-merge gate for product repos (#1333). Runs on PRs, train-branch pushes,
|
|
3
|
-
# and v* tags so /release and /hotfix can discover required contexts on the tagged SHA
|
|
3
|
+
# and v* tags so /release and /hotfix can discover required contexts on the tagged SHA (repos with a
|
|
4
|
+
# release train only; MM-Work and its modules have none — they merge to development and it goes live).
|
|
4
5
|
#
|
|
5
6
|
# Runner (#9248, owner 29 Oct 2026): included GitHub-hosted capacity is FIRST CHOICE for CI — this gate
|
|
6
7
|
# runs on `ubuntu-latest`, which costs included Enterprise minutes, not spend. Self-hosted lanes
|
|
@@ -196,7 +197,7 @@ jobs:
|
|
|
196
197
|
- run: {{GATE_INSTALL_CMD}}
|
|
197
198
|
if: ${{ steps.development-gate.outputs.reuse != 'true' }}{{GATE_JEV_FETCH_YAML}}{{GATE_CHECK_POLICY_STEP_YAML}}
|
|
198
199
|
# #3178: the check runs under the org wall-clock budget — a hung suite dies at the ceiling instead
|
|
199
|
-
# of squatting a runner lane for GitHub's 6h default. ci-audit
|
|
200
|
+
# of squatting a runner lane for GitHub's 6h default. ci-audit (and, on repos that have one, the release train) enforce this step.
|
|
200
201
|
# #9293: PRs fail fast, merge_group and tags run everything. pytest reads PYTEST_ADDOPTS natively; a
|
|
201
202
|
# Node check script opts in with MMI_FAIL_FAST (`vitest run ${MMI_FAIL_FAST:+--bail=1}`, or
|
|
202
203
|
# `--fail-fast` on the org node runner). #9295: on PRs the Jev plan step exports JEV_PYTEST_ARGS
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "Bootstrap seed manifest (#201) — the machine-readable contract of what /bootstrap and `mmi-cli devops bootstrap --apply` (#202) stamp into a target repo. Consumed by the CLI (loadBootstrapSeeds). ownership: 'org' = org-delivered, OVERWRITTEN on upgrade (the org owns it); 'repo' = created ONCE on a fresh bootstrap, never clobbered on upgrade (the repo owns its content). source: 'self' = copy MMI-Hub's own current file verbatim; 'seed:<file>' = render the named template in this dir with {{PLACEHOLDERS}}; 'managed-block' = merge the legacy org-managed .gitignore block in place. managedBlock declares a separately sourced, exact-marker-bounded Hub-owned region inside a repo-owned containing file; apply/propagate reconcile only that region and refuse malformed markers. NOTE: this manifest seeds org-managed PRODUCT assets only — it never seeds AGENTS.md / CLAUDE.md / .claude/settings.json (personal agent guides) or a legacy repo-local control-plane marker. classes: which repo classes receive this seed.",
|
|
2
|
+
"_comment": "Bootstrap seed manifest (#201) — the machine-readable contract of what /bootstrap and `mmi-cli devops bootstrap --apply` (#202) stamp into a target repo. Consumed by the CLI (loadBootstrapSeeds). ownership: 'org' = org-delivered, OVERWRITTEN on upgrade (the org owns it); 'repo' = created ONCE on a fresh bootstrap, never clobbered on upgrade (the repo owns its content). source: 'self' = copy MMI-Hub's own current file verbatim; 'seed:<file>' = render the named template in this dir with {{PLACEHOLDERS}}; 'managed-block' = merge the legacy org-managed .gitignore block in place. managedBlock declares a separately sourced, exact-marker-bounded Hub-owned region inside a repo-owned containing file; apply/propagate reconcile only that region and refuse malformed markers. NOTE: this manifest seeds org-managed PRODUCT assets only — it never seeds AGENTS.md / CLAUDE.md / .claude/settings.json (personal agent guides) or a legacy repo-local control-plane marker. classes: which repo classes receive this seed. releaseTracks (#10076): when set, only repos on those registry release tracks receive it; a 'self' seed's '# mmi-train-only:start' ... ':end' line regions are dropped for single-track repos.",
|
|
3
3
|
"placeholders": ["OWNER", "REPO", "REPO_SLUG", "REPO_NAME", "CLASS", "GATE_CMD", "GATE_PUSH_BRANCHES_YAML", "GATE_FULL_RUN_BRANCH", "GATE_RULESET_BRANCH_REFS_JSON", "GATE_RULESET_CONTEXTS_JSON", "PROJECT_OWNER", "PROJECT_NUMBER", "PROJECT_ID", "STATUS_FIELD_ID", "STATUS_TODO", "STATUS_IN_PROGRESS", "STATUS_IN_REVIEW", "STATUS_DONE", "STACK", "REGION"],
|
|
4
4
|
"seeds": [
|
|
5
5
|
{ "target": ".github/ISSUE_TEMPLATE/bug.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
6
6
|
{ "target": ".github/ISSUE_TEMPLATE/feature.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
7
7
|
{ "target": ".github/ISSUE_TEMPLATE/task.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
8
8
|
{ "target": ".github/ISSUE_TEMPLATE/config.yml", "source": "self", "ownership": "repo", "classes": ["deployable", "content"] },
|
|
9
|
-
{ "target": "scripts/next-version.mjs", "source": "self", "ownership": "org", "classes": ["deployable"] },
|
|
9
|
+
{ "target": "scripts/next-version.mjs", "source": "self", "ownership": "org", "classes": ["deployable"], "releaseTracks": ["full", "direct", "trunk"] },
|
|
10
10
|
{ "target": ".github/workflows/gate.yml", "source": "seed:gate.template.yml", "ownership": "repo", "classes": ["deployable"], "waivers": { "mmi-katip": "gates through py-gate and web-gate (in-job path filters, #3836) and its registry requiredChecks name exactly those two; a generic Node gate.yml here is red noise on every PR and would be re-created by every apply (#6333)." } },
|
|
11
11
|
{ "target": ".github/workflows/agent-pr.yml", "source": "self", "ownership": "org", "classes": ["deployable"], "waivers": { "jerv-jervcode": "pins this workflow's EXACT step shapes in its own scripts/workflow-boundary-core.mjs — a literal repositories: Jerv-JervCode token scope, and whole-step equality for the surface and verdict legs. #4040 widened the org seed to the same hardened boundary (pull_request_target off the trusted base, an immutable BASE..HEAD compare with a file-count equality wall, a per-repo App token scope, and a certified-head merge), so the two now agree on substance. They cannot agree on bytes: a seed serving 16 repos resolves its token scope and its required contexts at run time, which exact-step equality rejects by construction. The waiver is permanent by design, not a deferral — lifting it would mean weakening the strictest repo to match a fleet file." } },
|
|
12
12
|
{ "target": ".github/rulesets/mmi-product-required-checks.json", "source": "seed:mmi-product-required-checks.template.json", "ownership": "org", "classes": ["deployable"] },
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
Use the [canonical MMI developer-environment guide](https://github.com/mutmutco/MMI-Hub/blob/main/docs/Architecture/agentic-dev-environment.md) for shared setup and daily agent work.
|
|
5
5
|
|
|
6
6
|
Daily loop: `mmi-cli oracle issue create` → `mmi-cli oracle board claim <n>` (stamps the mmi-claim lease) → `mmi-cli devops pr create` → `mmi-cli devops pr land <pr>`.
|
|
7
|
-
Any org member with repository write (developer) or repository admin (project admin) can run it, with no vault access; release trains stay org-owner only.
|
|
7
|
+
Any org member with repository write (developer) or repository admin (project admin) can run it, with no vault access; Hub release trains (repos that have one) stay org-owner only; MM-Work and its modules have none — merge and go live.
|
|
8
8
|
<!-- mmi-developer-environment:end -->
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
".github/workflows/agent-pr.yml": {
|
|
3
|
-
"blob": "
|
|
4
|
-
"reason": "
|
|
3
|
+
"blob": "a99d0be49e66423dfbafb9db6273a6b841752972",
|
|
4
|
+
"reason": "train-only markers around the release-align replay and its comment, stripped for single-track repos (#10076); the #7717 note says it applies only on repos with a release train (#10071); guarded paths, permissions and operator responsibilities unchanged"
|
|
5
5
|
},
|
|
6
6
|
"scripts/next-version.mjs": {
|
|
7
|
-
"blob": "
|
|
8
|
-
"reason": "comment-only
|
|
7
|
+
"blob": "7faba0bb3ee48074702da48d149657820d74de1a",
|
|
8
|
+
"reason": "comment-only header: the train applies only to repos with a release lane; MM-Work and its modules merge to development and it goes live with no release, rc or candidate stage (#10071); no runtime or operator behaviour change"
|
|
9
9
|
},
|
|
10
10
|
"README.md": {
|
|
11
|
-
"blob": "
|
|
12
|
-
"reason": "the developer-environment seed block now
|
|
11
|
+
"blob": "46f5e07288931eee1c26362219b9d4271a5ed49e",
|
|
12
|
+
"reason": "the developer-environment seed block now says Hub release trains (repos that have one) stay org-owner only and MM-Work and its modules have none — merge and go live (#10071); no runbook step changes"
|
|
13
13
|
}
|
|
14
14
|
}
|
package/skills/hotfix/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ Pushing to `main` and production needs Jervaise's yes unless a standing authoriz
|
|
|
15
15
|
|
|
16
16
|
## Lane
|
|
17
17
|
|
|
18
|
-
MM-Work
|
|
18
|
+
MM-Work and its modules have no hotfix: a fix merges to development and it goes live ([suite.md](suite.md)). Every other repo, lane from META:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
mmi-cli oracle org project get {owner}/{repo} --json
|
package/skills/hotfix/suite.md
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
MM-Work and its modules (MM-Account, MM-Chat, MM-Inspo, MM-Moments, MM-PM, MM-Strategy, MMI-Junior, MMI-Katip, MMI-Pulse, MMI-Scout, MM-Talent) merge to development and it goes live. No release, rc or candidate stage (owner ruling 2026-11-05): `development` is their only branch, and a merged change is live once its deploy is green. There is no suite rcand, suite release or suite hotfix for them and no `--suite-solo` path: never run `/release`, `/rcand` or `/hotfix` in these repos (the CLI refuses), and never tell the owner a landed change waits on a release. An urgent fix is a normal PR to development. A suite member never asks for, proposes or prompts an rc, release or hotfix — there is none; state what landed and stop.
|
|
@@ -27,8 +27,8 @@ mmi-cli devops pr land <pr-number>
|
|
|
27
27
|
|
|
28
28
|
Board writes (attach, claim stamp, status move) gate on org owner, repo admin or repository write, so
|
|
29
29
|
these roles pass. Where the GitHub App route is absent the writes go as the person's own GitHub login
|
|
30
|
-
(one note says so); an agent host with the App route writes as the App. MMI-Hub's own merges and
|
|
31
|
-
release trains stay org-owner only.
|
|
30
|
+
(one note says so); an agent host with the App route writes as the App. MMI-Hub's own merges and the Hub
|
|
31
|
+
release trains (repos that have one) stay org-owner only; MM-Work and its modules have none: merge and go live.
|
|
32
32
|
|
|
33
33
|
Start with `mmi-cli onboard` and the [board skill](../../board/SKILL.md).
|
|
34
34
|
Reading or discussing the board is read-only until the developer authorizes work.
|
|
@@ -169,8 +169,9 @@ development. A trunk repository follows its single branch and declared workflow
|
|
|
169
169
|
No box stage.
|
|
170
170
|
- Trunk track: one main branch, without an rc/development promotion train. Follow the repository's
|
|
171
171
|
declared publishing workflow rather than manufacturing train branches.
|
|
172
|
-
-
|
|
173
|
-
|
|
172
|
+
- MM-Work and its modules (registry `releaseTrack: single`) are not on any of these trains: MM-Work and
|
|
173
|
+
its modules merge to development and it goes live. No release, rc or candidate stage; `development`
|
|
174
|
+
is their only branch, and release, rcand and hotfix refuse. The Hub's own release train never applies to them.
|
|
174
175
|
- Urgent already-merged fixes: use [hotfix](../../hotfix/SKILL.md), which carries selected development
|
|
175
176
|
fixes directly to main on either track.
|
|
176
177
|
|
|
@@ -199,7 +200,7 @@ refresh tags with `git fetch origin --tags --force` (or `git fetch origin '+refs
|
|
|
199
200
|
never chain a plain tag fetch with `&&` ahead of a read-only `git log <tag>..origin/<branch>` range (#9517).
|
|
200
201
|
A Hub summary never mentions a Jerv-side project; the train
|
|
201
202
|
refuses such a line.
|
|
202
|
-
|
|
203
|
+
MM-Work and its modules never cut a release, so they write no release summary: MM-Work and its modules merge to development and it goes live. No release, rc or candidate stage, no suite cut and no `--suite-solo` path (owner ruling 2026-11-05). Details: the release skill's suite.md.
|
|
203
204
|
|
|
204
205
|
Announcement delivery uses the developer's GitHub-authenticated Hub session. The Hub checks project
|
|
205
206
|
authority, resolves the registered channel, and reads the MMI Future Slack key inside its vault boundary.
|
package/skills/rcand/SKILL.md
CHANGED
|
@@ -13,7 +13,7 @@ Merge `development → rc`, tag `vX.Y.0-rc.N`, push the tag, wait for required c
|
|
|
13
13
|
|
|
14
14
|
## Lane
|
|
15
15
|
|
|
16
|
-
MM-Work
|
|
16
|
+
MM-Work and its modules have no rcand: they merge to development and it goes live ([suite.md](suite.md)). Every other repo: Name the lane from META:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
mmi-cli oracle org project get {owner}/{repo} --json
|
package/skills/rcand/suite.md
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Support sessions (MMI-Hub, Jerv-Hub, Jerv-JervCode) are not suite members and hold standing owner authorization (2026-10-25) to cut and ship releases at their discretion during suite runs without repeated per-release approval, and under the owner's 2026-11-01 ruling each support session strives during a suite run to finish its own board and cut a patch release for landed-but-unreleased merges so suite members pick the update up in that run instead of waiting for a later cut, keeping all standard release preflight, gate, and verification checks.
|
|
4
|
-
|
|
1
|
+
MM-Work and its modules (MM-Account, MM-Chat, MM-Inspo, MM-Moments, MM-PM, MM-Strategy, MMI-Junior, MMI-Katip, MMI-Pulse, MMI-Scout, MM-Talent) merge to development and it goes live. No release, rc or candidate stage (owner ruling 2026-11-05): `development` is their only branch, and a merged change is live once its deploy is green. There is no suite rcand, suite release or suite hotfix for them and no `--suite-solo` path: never run `/release`, `/rcand` or `/hotfix` in these repos (the CLI refuses), and never tell the owner a landed change waits on a release. An urgent fix is a normal PR to development. A suite member never asks for, proposes or prompts an rc, release or hotfix — there is none; state what landed and stop.
|
package/skills/release/SKILL.md
CHANGED
|
@@ -11,7 +11,7 @@ Bare `minor|major|patch` (default `patch`), never a flag. A production release n
|
|
|
11
11
|
|
|
12
12
|
## Lane
|
|
13
13
|
|
|
14
|
-
Read `mmi-cli oracle org project get {owner}/{repo} --json` and name the lane ([verification.md](verification.md) Lane rules); unreadable META → stop.
|
|
14
|
+
Read `mmi-cli oracle org project get {owner}/{repo} --json` and name the lane ([verification.md](verification.md) Lane rules); unreadable META → stop. MM-Work and its modules merge to development and it goes live. No release, rc or candidate stage: release, rcand and hotfix refuse there, and a merged change is live once its deploy is green ([suite.md](suite.md)). A `trunk` repo has no release lane either and follows its own declared publishing workflow. Never tell the owner a landed change waits on a release. [vercel.md](vercel.md) for Vercel.
|
|
15
15
|
|
|
16
16
|
## Preflight
|
|
17
17
|
|
package/skills/release/suite.md
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
MM-Work and
|
|
1
|
+
MM-Work and its modules (MM-Account, MM-Chat, MM-Inspo, MM-Moments, MM-PM, MM-Strategy, MMI-Junior, MMI-Katip, MMI-Pulse, MMI-Scout, MM-Talent) merge to development and it goes live. No release, rc or candidate stage (owner ruling 2026-11-05): `development` is their only branch, and a merged change is live once its deploy is green. There is no suite rcand, suite release or suite hotfix for them and no `--suite-solo` path: never run `/release`, `/rcand` or `/hotfix` in these repos (the CLI refuses), and never tell the owner a landed change waits on a release. An urgent fix is a normal PR to development. A suite member never asks for, proposes or prompts an rc, release or hotfix — there is none; state what landed and stop.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Hub's own release train (MMI-Hub, Jerv-Hub, Jerv-JervCode and other non-MM repos with a release lane) is unchanged and never applies to MM-Work or its modules.
|
|
4
4
|
|
|
5
5
|
Support sessions (MMI-Hub, Jerv-Hub, Jerv-JervCode) are not suite members and hold standing owner authorization (2026-10-25) to cut and ship releases at their discretion during suite runs without repeated per-release approval, and under the owner's 2026-11-01 ruling each support session strives during a suite run to finish its own board and cut a patch release for landed-but-unreleased merges so suite members pick the update up in that run instead of waiting for a later cut, keeping all standard release preflight, gate, and verification checks.
|
|
6
|
-
|
|
7
|
-
Every new mm-work suite Release (including solo and hotfix releases) requires both `--announce-summary-file <path>` (English) and `--announce-summary-file-tr <path>` (Turkish, "sen" form) in the update-notes template. The canonical wording lives in the [MM-Work GUIDE, "Update notes"](https://github.com/mutmutco/MM-Work/blob/development/packages/mmwork-ds/GUIDE.md#update-notes); this repo links it and never copies it. Each file has the section word `Fixed` / `Düzeldi` (what works now, never the problem: "Drive: Scans of large drives now finish without timing out."; a line without now / again / no longer, or artık / yeniden / tekrar / yine, is refused) and/or `New` / `Yeni` (what you can now do) on its own line, Fixed first, each only when it has lines. Under them go 1–8 lines of `<Area>: <sentence>.`, each at most 120 characters, with no issue numbers, versions or commit prefixes. Off-template or missing files refuse before tagging. Do not write the head (app · date · time) or the thanks line: MM-Work renders both from the Release date and credits. Suite release also requires a valid `--member-summary-file <owner/repo=path>` and `--member-summary-file-tr <owner/repo=path>` for every member being released, before promoting any member. Carried, held and already-released members need none, and existing Releases can resume without new files.
|
|
8
|
-
The `/user-releases` feed serves template notes as `updateNotes: {en?, tr?: {fixed[], new[]}}`. Older title-and-notes bodies keep `plainWords` and get `updateNotes: null`.
|
|
9
|
-
|
|
@@ -8,7 +8,7 @@ Do not use a `--jq` formatter, raw `gh` reads (`gh run list`, `gh run list --com
|
|
|
8
8
|
|
|
9
9
|
## Release summary file
|
|
10
10
|
|
|
11
|
-
Required for MMI-Hub and any product whose META carries `releaseChannel
|
|
11
|
+
Required for MMI-Hub and any product whose META carries `releaseChannel`. MM-Work and its modules never cut a release, so they never write one ([suite.md](suite.md)). Run `mkdir -p .jerv/tmp` and write 3–6 lines to a file made by `mktemp .jerv/tmp/release-summary.XXXXXX` (scratch lives under `.jerv/tmp` in every repo; a repo-root `tmp/` may not exist and a host guards root writes).
|
|
12
12
|
|
|
13
13
|
- MMI-Hub: neutral Hub-subsystem terms, never a product or brand name or a Jerv-side project (the train refuses one). Build every line from `git log --stat --format='%h %s%n%b' origin/main..origin/development`; a line you cannot point to there stays out, and every cited `#N` must appear there.
|
|
14
14
|
- Product: in `releaseLanguage` (default `en`), plain words on what changed and why it matters; no prefixes, issue/PR numbers, file names or jargon.
|