diff --git a/CLAUDE.md b/CLAUDE.md index aaa0749..34c29ff 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,7 +38,7 @@ plugins// - **slide-studio** — `/slides` skill: presentation decks as one HTML file from `skills/slides/assets/deck.html` (19 layouts as `data-layout`, 3 themes — `ink`, `paper`, `kaizen` (washi/sumi/vermilion, ensō + hanko drawn by the runtime) — + BRAND tokens, presenter runtime with steps/notes/overview); `scripts/slides.mjs` lists layouts, previews themes (`themes`), scaffolds (`new --layouts`), audits each slide in Chromium (`check`: overflow, collisions, safe area, contrast, density) and exports PDF/PNG/contact sheet. Self-sufficient: `scripts/setup.mjs`/`deps.mjs` reuse or auto-install playwright-core + Chrome Headless Shell into `${CLAUDE_PLUGIN_DATA}` (check/export only). Tests `node --test plugins/slide-studio/tests/*.test.mjs` (browser tests need `SLIDE_STUDIO_HOME` with a ready `env.json`); CI in `.github/workflows/slide-studio.yml`. -- **kaizen** (4.3.0, self-sufficient since the other plugins left; production commands in kaizen-ops since 4.0; English since #17; French plans/constitutions from 2.x still parsed) — AI-assisted SDLC built on Every's Compound Engineering loop (MIT, see `plugins/kaizen/LICENSE`) plus Spec Kit's constitution. 20 skills invoked `/kaizen:` (the 4.0 stubs of `deploy`, `monitor`, `postmortem` were removed in 4.1.0; changelogs keep the old names, other docs only as `old → /kaizen-ops:` migration notes, enforced by the contracts) — newcomers get a four-command path, `setup` → `plan` → `work` → `ship` (README "Start here", `help`, `setup`, `status` next step; constitution optional, after the next step): `help` (orientation, reads `kaizen.mjs status`), the production CLI behind kaizen-ops' `deploy` and `monitor` (team-declared deploy/rollback/flag commands and production signals in `.kaizen/config.json`; protected envs need a user-typed `kaizen deploy `; annotated tags `deploy//…`/`rollback//…` feed real DORA in `metrics` and postmortem timelines; `scripts/deploy.mjs`, `scripts/monitor.mjs`; `monitor patrol` (scheduled confirmed check; a blind signal — broken metric command — never rolls back nor opens an incident, unlike an unreachable HTTP health-check) and `monitor alert` (Alertmanager/PagerDuty/Datadog/generic payloads) open dated incidents as `incident//…` tags (resolved by rollback or `resolve//…`), feeding DORA failure rate and time to restore; `deploy detect|configure` in `scripts/deploydetect.mjs` recognizes the platform — Vercel, Netlify, Fly, Heroku, Kamal, Capistrano, Helm, Kustomize, Serverless, SAM, Firebase, GitHub Actions, Makefile/npm, Compose, Terraform), `constitution`, `ideate`, `brainstorm`, `decide` (ADR), `plan`, `doc-review`, `work`, `debug`, `polish`, `review`, `ship`, `address-feedback`, `watch-pr`, `release`, `learn`, `prune-learnings`, `metrics`, `autopilot`, `setup`. 22 read-only agents (5 research, 6 plan reviewers sharing `references/doc-review-contract.md`, 11 code reviewers (incl. `rendering-reviewer`, which opens before/after captures) sharing `references/review-contract.md`). Artifacts live in the target repo: `CONSTITUTION.md` (articles each with a **Check:**, enforced by `plan check`, doc-review and standards-reviewer; hierarchy constitution > packs > learnings; written headless it is a `status: draft` that informs but never blocks until ratified), one unified plan per topic in `docs/plans/` (`kaizen-plan/v1`, `` markers incl. constitution/threats/rollout, R/AE/KTD/U IDs, PR-sized slices), learnings `docs/learnings/`, `docs/adr/`, `docs/postmortems/`. `scripts/kaizen.mjs` is a zero-dependency CLI for all deterministic work (verify, plan check, size, learnings, packs, constitution, PR snapshot/watch via `pr.mjs`, dev server, DORA metrics, ADR, release notes); `scripts/quality-gate.mjs` is a Stop hook blocking while verify is red during work/autopilot (scoped to the session that ran `gate on` via a PostToolUse `--claim`, time-budgeted under the hook timeout); `scripts/secret-gate.mjs` is a PreToolUse hook refusing a `git commit` that adds a key or token (~30 patterns in `scripts/secrets.mjs`, also `kaizen.mjs secrets scan` and the `audit fix secret_scanning` PR workflow; refuses `--no-verify`; active in every repo, `secrets.scan`/`secrets.ignore` in config); `.mcp.json` bundles the Playwright MCP server (pinned) used by polish/work/autopilot; `scripts/review-gate.mjs` is a PreToolUse hook refusing `git push` of a branch until `/kaizen:review` recorded the pushed tree (`review record`, which requires evidence that Kaizen code reviewers actually ran — logged by `review-hooks.mjs --evidence`, a PostToolUse hook on Agent — except light reviews ≤ 20 lines or post-fix updates; `review waive --reason` only issues a code the user must type as `kaizen waive `, confirmed by the `review-hooks.mjs --confirm` UserPromptSubmit hook; state in `review-state.mjs`, direct writes blocked; a PreToolUse `--launch` hook logs each reviewer as launched, and `review record --run` refuses a run where one left no `[-].json`, a gap only accepted by a user-typed code). `kaizen upgrade [--apply]` (`scripts/upgrade.mjs`, plan `docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md`) lists the migrations a repository still needs after a Kaizen update — `learnings-folder` 2.0.0, `marketplace-dojo` 3.1.0, `profile-names` 3.4.0, `kaizen-ops` 4.0.0, `hook-lookup` 4.1.2 — each detected from the repo's state (never a stored version), and `--apply` runs the automatable ones (targeted edits, team lines kept, files to commit listed; folder renames stay manual). Guard rails beyond the plugin: `kaizen doctor` (`scripts/doctor.mjs`; SessionStart heartbeat `hooks-seen.json`, `.claude/settings.json` declaring `kaizen@dojo`, git hooks wired, branch or upstream unreviewed) run first by help/work/setup; `audit fix git_hooks` (`scripts/githooks.mjs`, `templates/githooks/`) installs fail-closed pre-push/pre-commit hooks resolving a pinned CLI (`git config kaizen.cli`, `$KAIZEN_CLI`, or `cache/dojo/kaizen/` only; each must be Kaizen core by its `plugin.json`, a wrong explicit pointer is refused — same lookup as the kaizen-ops resolver, held by `plugins/kaizen-ops/tests/parity.test.mjs`; `doctor`/`audit` warn on a Kaizen hook whose lookup line is not the template's, and `audit fix git_hooks` refreshes that line only, keeping team additions) and `audit fix claude_settings` declares the plugin. Plans: `plan amend` (append-only R IDs, `amended:` frontmatter, `scripts/planamend.mjs`), `plan reviewed` (`reviewed: " "`, plan check warns when absent or stale), `visual: ` evidence warned for rendering units. `kaizen perf` (`scripts/perf.mjs`, `perf` config: pass/fail/blind). `/kaizen:learn harvest`. `profile: prototype|product|critical` (named by stakes; former `lean|standard|full` still read, reported deprecated) in `.kaizen/config.json` scales ceremony, never the deterministic gates; it is a floor: `scripts/risk.mjs` raises it one step for a cycle whose files touch a risk surface (auth, payment, sensitive data, migration, public API, dependencies, team `risk.paths`), `kaizen.mjs profile [--plan|--files]` gives the effective one and skills pass it to `models --profile`. `review estimate` (`scripts/estimate.mjs`) prices a review before launch — tokens and relative cost per model, from the repo's cycle history (agents counted per role) or a diff heuristic; `/kaizen:review` asks above `review.confirm_above_cost`. Cycles record tokens per model family (`usage.by_model`); `metrics dashboard` (`scripts/dashboard.mjs`) writes a self-contained HTML cost dashboard to `.kaizen/state/cost-dashboard.html`. Every gate stop and what lifts it (review recorded, waiver) is appended to `.kaizen/state/friction.jsonl` (`logFriction` in lib, never changes a decision); `metrics` → `friction` reports refusals, time blocked on push, waiver share and blocking checks. A second Stop hook (`scripts/ledger-hook.mjs` → `ledger.mjs`) charges every turn's new tokens (transcript byte offsets) to the work item — branch Jira key, else plan `jira:`/`plan:`, else branch, else `unattributed` — in `.kaizen/state/ledger.jsonl`; `kaizen cost [item|current]` and `metrics` → `work_items` give the cost of each feature or fix end to end. `scripts/models.mjs` maps every agent to a role and every role to a model per profile (`models.roles` / `models.agents` overrides, `kaizen.mjs models`); skills pass that `model` to each Agent call and review evidence records it. `scripts/audit.mjs` (`kaizen.mjs audit`, `/kaizen:setup audit`) scores SDLC maturity in five areas and scaffolds ci/pr_template/dependabot/codeowners/gitignore_env without overwriting. The Stop hook also records token usage from the transcript, main session plus subagents (`/subagents/agent-*.jsonl`, attributed to a role via launches logged by the Agent hook in `scripts/cycle-agents.mjs`); verify commands run through `scripts/run-bounded.mjs`, which kills the whole process tree on timeout; `gate off` appends the cycle to `.kaizen/state/cycles.jsonl` (`metrics` → `cycle_cost`); `gate.targeted` runs `{files}`-scoped checks. `plan check` warns on rollout without rollback/signal/threshold, `release notes` extracts rollout of shipped plans; constitution `approvers` require an approved amendment per version. Tests: `node --test plugins/kaizen/tests/*.test.mjs` (unit, CLI, gate, PR with fake `gh`, contracts — run after any skill/agent/CLI/doc change; contracts require the README to list every CLI command and hook, `docs/README.md` to list every guide, and every relative doc link to resolve; `tests/diagrams.test.mjs` holds the SVGs to `docs/media/source/diagrams.mjs` (edit the generator, then run it — never the SVGs), to `hooks.json` and `agents/`, draws kaizen-ops commands only in the `ops` style, and checks every counted claim — reviewers, researchers, hook registrations, skills, agents). User docs: `plugins/kaizen/docs/` (getting-started, configuration, packs, troubleshooting, positioning, one guide per skill); end-to-end evals: `node plugins/kaizen/evals/run.mjs` (real `claude -p`, costly); CI in `.github/workflows/kaizen.yml`. +- **kaizen** (4.4.0, self-sufficient since the other plugins left; production commands in kaizen-ops since 4.0; English since #17; French plans/constitutions from 2.x still parsed) — AI-assisted SDLC built on Every's Compound Engineering loop (MIT, see `plugins/kaizen/LICENSE`) plus Spec Kit's constitution. 20 skills invoked `/kaizen:` (the 4.0 stubs of `deploy`, `monitor`, `postmortem` were removed in 4.1.0; changelogs keep the old names, other docs only as `old → /kaizen-ops:` migration notes, enforced by the contracts) — newcomers get a four-command path, `setup` → `plan` → `work` → `ship` (README "Start here", `help`, `setup`, `status` next step; constitution optional, after the next step): `help` (orientation, reads `kaizen.mjs status`), the production CLI behind kaizen-ops' `deploy` and `monitor` (team-declared deploy/rollback/flag commands and production signals in `.kaizen/config.json`; protected envs need a user-typed `kaizen deploy `; annotated tags `deploy//…`/`rollback//…` feed real DORA in `metrics` and postmortem timelines; `scripts/deploy.mjs`, `scripts/monitor.mjs`; `monitor patrol` (scheduled confirmed check; a blind signal — broken metric command — never rolls back nor opens an incident, unlike an unreachable HTTP health-check) and `monitor alert` (Alertmanager/PagerDuty/Datadog/generic payloads) open dated incidents as `incident//…` tags (resolved by rollback or `resolve//…`), feeding DORA failure rate and time to restore; `deploy detect|configure` in `scripts/deploydetect.mjs` recognizes the platform — Vercel, Netlify, Fly, Heroku, Kamal, Capistrano, Helm, Kustomize, Serverless, SAM, Firebase, GitHub Actions, Makefile/npm, Compose, Terraform), `constitution`, `ideate`, `brainstorm`, `decide` (ADR), `plan`, `doc-review`, `work`, `debug`, `polish`, `review`, `ship`, `address-feedback`, `watch-pr`, `release`, `learn`, `prune-learnings`, `metrics`, `autopilot`, `setup`. 22 read-only agents (5 research, 6 plan reviewers sharing `references/doc-review-contract.md`, 11 code reviewers (incl. `rendering-reviewer`, which opens before/after captures) sharing `references/review-contract.md`). Artifacts live in the target repo: `CONSTITUTION.md` (articles each with a **Check:**, enforced by `plan check`, doc-review and standards-reviewer; hierarchy constitution > packs > learnings; written headless it is a `status: draft` that informs but never blocks until ratified), one unified plan per topic in `docs/plans/` (`kaizen-plan/v1`, `` markers incl. constitution/threats/rollout, R/AE/KTD/U IDs, PR-sized slices), learnings `docs/learnings/`, `docs/adr/`, `docs/postmortems/`. `scripts/kaizen.mjs` is a zero-dependency CLI for all deterministic work (verify, plan check, size, learnings, packs, constitution, PR snapshot/watch via `pr.mjs`, dev server, DORA metrics, ADR, release notes); `scripts/quality-gate.mjs` is a Stop hook blocking while verify is red during work/autopilot (scoped to the session that ran `gate on` via a PostToolUse `--claim`, time-budgeted under the hook timeout); `scripts/secret-gate.mjs` is a PreToolUse hook refusing a `git commit` that adds a key or token (~30 patterns in `scripts/secrets.mjs`, also `kaizen.mjs secrets scan` and the `audit fix secret_scanning` PR workflow; refuses `--no-verify`; active in every repo, `secrets.scan`/`secrets.ignore` in config); `.mcp.json` bundles the Playwright MCP server (pinned) used by polish/work/autopilot; `scripts/review-gate.mjs` is a PreToolUse hook refusing `git push` of a branch until `/kaizen:review` recorded the pushed tree (`review record`, which requires evidence that Kaizen code reviewers actually ran — logged by `review-hooks.mjs --evidence`, a PostToolUse hook on Agent — except light reviews ≤ 20 lines or post-fix updates; `review waive --reason` only issues a code the user must type as `kaizen waive `, confirmed by the `review-hooks.mjs --confirm` UserPromptSubmit hook; state in `review-state.mjs`, direct writes blocked; a PreToolUse `--launch` hook logs each reviewer as launched, and `review record --run` refuses a run where one left no `[-].json`, a gap only accepted by a user-typed code). `kaizen upgrade [--apply]` (`scripts/upgrade.mjs`, plan `docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md`) lists the migrations a repository still needs after a Kaizen update — `learnings-folder` 2.0.0, `marketplace-dojo` 3.1.0, `profile-names` 3.4.0, `kaizen-ops` 4.0.0, `hook-lookup` 4.1.2 — each detected from the repo's state (never a stored version), and `--apply` runs the automatable ones (targeted edits, team lines kept, files to commit listed; folder renames stay manual); `doctor` reports pending ones (check `upgrade`, relayed by help/work/setup), and `tests/upgrade.test.mjs` requires every CHANGELOG release ≥ 4.3.0 with a Breaking or Deprecated section to register a migration with that `since` or a `NO_MIGRATION` reason. Guard rails beyond the plugin: `kaizen doctor` (`scripts/doctor.mjs`; SessionStart heartbeat `hooks-seen.json`, `.claude/settings.json` declaring `kaizen@dojo`, git hooks wired, branch or upstream unreviewed) run first by help/work/setup; `audit fix git_hooks` (`scripts/githooks.mjs`, `templates/githooks/`) installs fail-closed pre-push/pre-commit hooks resolving a pinned CLI (`git config kaizen.cli`, `$KAIZEN_CLI`, or `cache/dojo/kaizen/` only; each must be Kaizen core by its `plugin.json`, a wrong explicit pointer is refused — same lookup as the kaizen-ops resolver, held by `plugins/kaizen-ops/tests/parity.test.mjs`; `doctor`/`audit` warn on a Kaizen hook whose lookup line is not the template's, and `audit fix git_hooks` refreshes that line only, keeping team additions) and `audit fix claude_settings` declares the plugin. Plans: `plan amend` (append-only R IDs, `amended:` frontmatter, `scripts/planamend.mjs`), `plan reviewed` (`reviewed: " "`, plan check warns when absent or stale), `visual: ` evidence warned for rendering units. `kaizen perf` (`scripts/perf.mjs`, `perf` config: pass/fail/blind). `/kaizen:learn harvest`. `profile: prototype|product|critical` (named by stakes; former `lean|standard|full` still read, reported deprecated) in `.kaizen/config.json` scales ceremony, never the deterministic gates; it is a floor: `scripts/risk.mjs` raises it one step for a cycle whose files touch a risk surface (auth, payment, sensitive data, migration, public API, dependencies, team `risk.paths`), `kaizen.mjs profile [--plan|--files]` gives the effective one and skills pass it to `models --profile`. `review estimate` (`scripts/estimate.mjs`) prices a review before launch — tokens and relative cost per model, from the repo's cycle history (agents counted per role) or a diff heuristic; `/kaizen:review` asks above `review.confirm_above_cost`. Cycles record tokens per model family (`usage.by_model`); `metrics dashboard` (`scripts/dashboard.mjs`) writes a self-contained HTML cost dashboard to `.kaizen/state/cost-dashboard.html`. Every gate stop and what lifts it (review recorded, waiver) is appended to `.kaizen/state/friction.jsonl` (`logFriction` in lib, never changes a decision); `metrics` → `friction` reports refusals, time blocked on push, waiver share and blocking checks. A second Stop hook (`scripts/ledger-hook.mjs` → `ledger.mjs`) charges every turn's new tokens (transcript byte offsets) to the work item — branch Jira key, else plan `jira:`/`plan:`, else branch, else `unattributed` — in `.kaizen/state/ledger.jsonl`; `kaizen cost [item|current]` and `metrics` → `work_items` give the cost of each feature or fix end to end. `scripts/models.mjs` maps every agent to a role and every role to a model per profile (`models.roles` / `models.agents` overrides, `kaizen.mjs models`); skills pass that `model` to each Agent call and review evidence records it. `scripts/audit.mjs` (`kaizen.mjs audit`, `/kaizen:setup audit`) scores SDLC maturity in five areas and scaffolds ci/pr_template/dependabot/codeowners/gitignore_env without overwriting. The Stop hook also records token usage from the transcript, main session plus subagents (`/subagents/agent-*.jsonl`, attributed to a role via launches logged by the Agent hook in `scripts/cycle-agents.mjs`); verify commands run through `scripts/run-bounded.mjs`, which kills the whole process tree on timeout; `gate off` appends the cycle to `.kaizen/state/cycles.jsonl` (`metrics` → `cycle_cost`); `gate.targeted` runs `{files}`-scoped checks. `plan check` warns on rollout without rollback/signal/threshold, `release notes` extracts rollout of shipped plans; constitution `approvers` require an approved amendment per version. Tests: `node --test plugins/kaizen/tests/*.test.mjs` (unit, CLI, gate, PR with fake `gh`, contracts — run after any skill/agent/CLI/doc change; contracts require the README to list every CLI command and hook, `docs/README.md` to list every guide, and every relative doc link to resolve; `tests/diagrams.test.mjs` holds the SVGs to `docs/media/source/diagrams.mjs` (edit the generator, then run it — never the SVGs), to `hooks.json` and `agents/`, draws kaizen-ops commands only in the `ops` style, and checks every counted claim — reviewers, researchers, hook registrations, skills, agents). User docs: `plugins/kaizen/docs/` (getting-started, configuration, packs, troubleshooting, positioning, one guide per skill); end-to-end evals: `node plugins/kaizen/evals/run.mjs` (real `claude -p`, costly); CI in `.github/workflows/kaizen.yml`. - **kaizen-ops** (1.0.1, requires Kaizen ≥ 4.0.0; plan `docs/plans/2026-10-20-1515-refactor-kaizen-core-ops-split-plan.md`) — Kaizen's production skills `/kaizen-ops:deploy`, `/kaizen-ops:monitor`, `/kaizen-ops:postmortem`, plus their guides and the postmortem template; skills and docs only — the CLI, hooks, config and every gate stay in core, so nothing is weaker without it (a core contract test forbids core scripts and hooks from loading or resolving a path into kaizen-ops — naming its plugin id or `/kaizen-ops:` commands is fine). `scripts/kaizen.mjs` is a resolver that finds Kaizen core (`git config kaizen.cli`, `$KAIZEN_CLI`, sibling `../kaizen`, newest `cache/dojo/kaizen/`), refuses a core older than `scripts/requires.json` and forwards the call; answers `core-root` (the skills read core's `references/` and `docs/configuration.md` through it) and `--version`. `kaizen doctor` warns (`ops_plugin`) when a repo declares deployments or signals, or has postmortems or deploy/incident tags, without `kaizen-ops@dojo` enabled (`audit` scores it under `claude_settings`); `audit fix claude_settings` enables it. Evals load both plugins (`--plugin-dir` twice). Tests `node --test plugins/kaizen-ops/tests/*.test.mjs` (run by `.github/workflows/kaizen.yml`). diff --git a/docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md b/docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md index ad2393f..2bdc928 100644 --- a/docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md +++ b/docs/plans/2026-10-21-0700-feat-kaizen-upgrade-plan.md @@ -233,7 +233,8 @@ release adds its signal at all. ## Definition of done -- [ ] S1 (Kaizen 4.3.0) and S2 (4.4.0) merged. -- [ ] Every R covered by its tests above; CI green on the matrix for each slice. -- [ ] The five migrations of the Problem table detected and, where automatable, applied. -- [ ] `doctor`, `help` and `setup` point to `upgrade` when something is pending. +- [x] S1 (Kaizen 4.3.0, #44) merged; S2 (4.4.0) in review. +- [x] Every R covered by its tests above (`tests/upgrade.test.mjs`: AE1–AE5); CI green on the matrix for S1. +- [x] The five migrations of the Problem table detected and, where automatable, applied. +- [x] `doctor` reports pending migrations; `help`, `work` and `setup` relay them through the + conventions' guard rails, and `setup check` runs `upgrade`. diff --git a/plugins/kaizen/.claude-plugin/plugin.json b/plugins/kaizen/.claude-plugin/plugin.json index b4afda7..9170bb0 100644 --- a/plugins/kaizen/.claude-plugin/plugin.json +++ b/plugins/kaizen/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "kaizen", "description": "High-quality AI SDLC adapted from the Compound Engineering loop: engineering constitution enforced as gates, brainstorm, plan (traceability, threats, rollout, PR-sized slices) with independent doc review, test-first work with a Stop-hook quality gate, multi-agent code review, ship and PR watching, UI polish, learnings in docs/learnings/ read back by every cycle, ADRs, blameless postmortems, DORA metrics and releases; production commands (deploy, monitor, postmortem) in kaizen-ops", - "version": "4.3.0", + "version": "4.4.0", "author": { "name": "Angelo LIMA", "email": "contact@example.com" diff --git a/plugins/kaizen/CHANGELOG.md b/plugins/kaizen/CHANGELOG.md index 1f05a0c..c6a2530 100644 --- a/plugins/kaizen/CHANGELOG.md +++ b/plugins/kaizen/CHANGELOG.md @@ -2,6 +2,19 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions: [SemVer](https://semver.org/). +## [4.4.0] - 2026-10-21 + +### Added +- **`kaizen doctor` reports pending migrations** (check `upgrade`): "3 Kaizen migration(s) pending + (profile-names, kaizen-ops, hook-lookup)", with how many must be done by hand, and + `node "$K" upgrade` as the fix. `help`, `work` and `setup` relay it (conventions, "Guard rails"): + they show the list, offer `upgrade --apply` before touching versioned files, and give the manual + steps; `setup check` runs `upgrade` too. +- **No breaking release without its migration.** From 4.3.0 on, a CHANGELOG release with a + **Breaking** or **Deprecated** section must register a migration with that version in + `scripts/upgrade.mjs`, or say in `NO_MIGRATION` why the repository has nothing to change; a contract + test fails otherwise. + ## [4.3.0] - 2026-10-21 ### Added diff --git a/plugins/kaizen/docs/guides/help.md b/plugins/kaizen/docs/guides/help.md index b74a4f3..fce39c9 100644 --- a/plugins/kaizen/docs/guides/help.md +++ b/plugins/kaizen/docs/guides/help.md @@ -59,8 +59,9 @@ Order of the inference: ## Guard rails `help` runs `kaizen doctor` first and tells you when the guard rails are off: the plugin not declared -for the repository, hooks not firing in this session, git hooks not wired, or a branch pushed without a -review — each with the command that fixes it. +for the repository, hooks not firing in this session, git hooks not wired, a branch pushed without a +review, or migrations a Kaizen update still asks of the repo (`kaizen upgrade` lists them, `--apply` +fixes the automatable ones) — each with the command that fixes it. ## See also diff --git a/plugins/kaizen/docs/guides/setup.md b/plugins/kaizen/docs/guides/setup.md index 443e27c..63b69b9 100644 --- a/plugins/kaizen/docs/guides/setup.md +++ b/plugins/kaizen/docs/guides/setup.md @@ -72,7 +72,9 @@ Config, detected checks, learnings, packs, constitution, gate, review state and ## Guard rails without the plugin -Setup starts with `kaizen doctor`. It offers, with your consent: `audit fix claude_settings` +Setup starts with `kaizen doctor`. After a Kaizen update, it lists what the repository still has to +change (`kaizen upgrade`: renamed profile, kaizen-ops to enable, git hooks to refresh, a folder to rename +by hand) and offers `kaizen upgrade --apply` for the automatable ones; `setup check` runs it too. It offers, with your consent: `audit fix claude_settings` (declares `kaizen@dojo` in the versioned `.claude/settings.json`, so every clone loads Kaizen) and `audit fix git_hooks` (git hooks that refuse an unreviewed push and a staged secret even when the plugin is not loaded; they refuse when the Kaizen CLI cannot be found — set `git config kaizen.cli diff --git a/plugins/kaizen/docs/reference/cli.md b/plugins/kaizen/docs/reference/cli.md index 3f54177..62cf521 100644 --- a/plugins/kaizen/docs/reference/cli.md +++ b/plugins/kaizen/docs/reference/cli.md @@ -36,8 +36,9 @@ the versioned `.claude/settings.json` declares the `dojo` marketplace and enable fresh clone or a cloud session runs without Kaizen); Claude Code hooks firing (heartbeat written by the SessionStart hook — absent means "not verified" from a terminal, "off" with `--in-skill`, which the entry skills pass); git hooks in `.githooks/` wired through `core.hooksPath`; verification commands -detected; the branch's review state, and whether its upstream was pushed without a review. Exit 0, or 1 -with `--strict` when anything needs attention. +detected; Kaizen migrations pending after an update (`upgrade`, below); the branch's review state, and +whether its upstream was pushed without a review. Exit 0, or 1 with `--strict` when anything needs +attention. ### `upgrade [--apply] [--json]` @@ -56,7 +57,11 @@ touches, and — when it cannot be automated — the steps to run by hand. `--apply` runs the automatable ones that still apply, writes only what each owns (formatting and team lines kept), and ends with the files to commit; run twice, it changes nothing. Nothing pending outside -a Kaizen repo (no `.kaizen/config.json`). +a Kaizen repo (no `.kaizen/config.json`). `kaizen doctor` reports the pending ones (check `upgrade`), +so `help`, `work` and `setup` relay them. + +A release that breaks or deprecates something declares its migration here, or why it needs none +(`NO_MIGRATION` in `scripts/upgrade.mjs`): a contract test fails otherwise, from 4.3.0 on. ### `root` diff --git a/plugins/kaizen/references/conventions.md b/plugins/kaizen/references/conventions.md index 9f3da4f..06192c7 100644 --- a/plugins/kaizen/references/conventions.md +++ b/plugins/kaizen/references/conventions.md @@ -83,6 +83,10 @@ before anything else: - **production commands moved (`ops_plugin`)** → the repo deploys or watches signals with Kaizen: say the commands are now `/kaizen-ops:deploy`, `/kaizen-ops:monitor`, `/kaizen-ops:postmortem`, and offer `node "$K" audit fix claude_settings`, which enables `kaizen-ops@dojo` (ask first); +- **Kaizen migrations pending (`upgrade`)** → Kaizen was updated and the repo still has changes to make: + run `node "$K" upgrade`, show the list (each migration's version, why, files), offer + `node "$K" upgrade --apply` for the automatable ones (versioned files: ask first, then name the files to + commit), and relay the steps to run by hand; - **branch pushed without a review** → `/kaizen:review` before anything else is pushed. No ⚠ → say nothing. The doctor never blocks: it informs. diff --git a/plugins/kaizen/scripts/doctor.mjs b/plugins/kaizen/scripts/doctor.mjs index 74ad6bd..b49440a 100644 --- a/plugins/kaizen/scripts/doctor.mjs +++ b/plugins/kaizen/scripts/doctor.mjs @@ -13,6 +13,7 @@ import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { docsRoot, git, loadConfig, verifyCommands } from './lib.mjs'; import { checkPush, currentBranch } from './review-state.mjs'; +import { pending as pendingMigrations } from './upgrade.mjs'; export const MARKETPLACE = 'dojo'; export const PLUGIN_ID = `kaizen@${MARKETPLACE}`; @@ -117,6 +118,13 @@ export function doctor(root, { inSkill = false, now = Date.now() } = {}) { '/kaizen:setup', ); + // What a Kaizen update still asks of this repo, detected from its state (kaizen upgrade). + const migrations = pendingMigrations(root, config); + if (migrations.length) { + const auto = migrations.filter((m) => m.auto).length; + add('upgrade', 'Kaizen migrations', 'warn', `${migrations.length} Kaizen migration(s) pending (${migrations.map((m) => m.id).join(', ')})${auto < migrations.length ? `, ${migrations.length - auto} by hand` : ''}`, 'node "$K" upgrade (lists them), then node "$K" upgrade --apply'); + } else if (existsSync(join(root, '.kaizen', 'config.json'))) add('upgrade', 'Kaizen migrations', 'ok', 'nothing to migrate'); + const decl = pluginDeclared(root); add( 'plugin_declared', diff --git a/plugins/kaizen/scripts/upgrade.mjs b/plugins/kaizen/scripts/upgrade.mjs index ce23fed..92309f1 100644 --- a/plugins/kaizen/scripts/upgrade.mjs +++ b/plugins/kaizen/scripts/upgrade.mjs @@ -10,7 +10,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs'; import { join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; import { docsRoot, loadConfig, PROFILE_ALIASES } from './lib.mjs'; -import { MARKETPLACE, PLUGIN_ID, gitHooksState, opsDeclared, opsNeeded } from './doctor.mjs'; +import { PLUGIN_ID, gitHooksState, opsDeclared, opsNeeded } from './doctor.mjs'; import { declarePlugin, refreshHookLookups } from './githooks.mjs'; export const KAIZEN_VERSION = JSON.parse(readFileSync(fileURLToPath(new URL('../.claude-plugin/plugin.json', import.meta.url)), 'utf8')).version; @@ -54,6 +54,10 @@ function declare(root) { } } +// Releases with a Breaking or Deprecated section that ask nothing of a repository, with the reason +// (tests/upgrade.test.mjs requires one or the other from 4.3.0 on). +export const NO_MIGRATION = {}; + export const MIGRATIONS = [ { id: 'learnings-folder', @@ -71,7 +75,8 @@ export const MIGRATIONS = [ { id: 'marketplace-dojo', since: '3.1.0', - title: `the marketplace is "${MARKETPLACE}": plugins are enabled as ${PLUGIN_ID}`, + // Plain text: doctor imports this module, which must not read doctor's exports while it loads. + title: 'the marketplace is "dojo": plugins are enabled as kaizen@dojo', applies(root) { const old = oldMarketplaceIds(root); const plugins = readJson(join(root, '.claude', 'settings.json'))?.enabledPlugins || {}; diff --git a/plugins/kaizen/skills/setup/SKILL.md b/plugins/kaizen/skills/setup/SKILL.md index 7a3a550..6a5a926 100644 --- a/plugins/kaizen/skills/setup/SKILL.md +++ b/plugins/kaizen/skills/setup/SKILL.md @@ -19,7 +19,8 @@ of what setup fixes. `node "$K" doctor`, `node "$K" root`, `node "$K" config`, `node "$K" detect`, `node "$K" learnings validate`, `node "$K" packs`, `node "$K" constitution check`, `node "$K" gate status`, `node "$K" review status`, -`node "$K" models` (warnings) → report: ✔/⚠ per point, with the proposed fix. +`node "$K" models` (warnings), `node "$K" upgrade` (migrations pending after a Kaizen update) → report: +✔/⚠ per point, with the proposed fix. A gate left active without work in progress (`gate status` active) → propose `gate off`. ## `audit` — set up the SDLC, in order diff --git a/plugins/kaizen/tests/upgrade.test.mjs b/plugins/kaizen/tests/upgrade.test.mjs index df1360e..53209d4 100644 --- a/plugins/kaizen/tests/upgrade.test.mjs +++ b/plugins/kaizen/tests/upgrade.test.mjs @@ -123,3 +123,44 @@ test('each migration: does not apply once fixed by hand, nor when its trigger is assert.deepEqual(run(foreign, ['upgrade', '--json']).json.pending, []); for (const d of [dir, ops, foreign]) cleanup(d); }); + +test('AE4: doctor reports pending migrations with their count, ids and the fix', () => { + const dir = oldRepo(); + const check = (d) => run(d, ['doctor', '--json']).json.checks.find((c) => c.id === 'upgrade'); + const before = check(dir); + assert.equal(before.status, 'warn'); + assert.equal(before.evidence, '3 Kaizen migration(s) pending (profile-names, kaizen-ops, hook-lookup)'); + assert.match(before.fix, /node "\$K" upgrade/); + run(dir, ['upgrade', '--apply']); + assert.deepEqual([check(dir).status, check(dir).evidence], ['ok', 'nothing to migrate']); + // A manual one is counted as such; outside a Kaizen repo, no check at all. + const manual = tempRepo({ '.kaizen/config.json': {}, 'docs/solutions/a.md': '# a\n' }); + assert.match(check(manual).evidence, /1 Kaizen migration\(s\) pending \(learnings-folder\), 1 by hand/); + const bare = tempRepo({ 'a.txt': 'a\n' }); + assert.equal(check(bare), undefined); + for (const d of [dir, manual, bare]) cleanup(d); +}); + +// AE5: every release from 4.3.0 on that breaks or deprecates something declares its migration, or says +// why there is none — so the next one cannot fall back into a corner of the doctor. +const semver = (v) => v.split('.').map(Number); +const atLeast = (v, min) => { const [a, b] = [semver(v), semver(min)]; for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i]; return true; }; +function undeclared(changelog, migrations, exempt) { + const out = []; + for (const [, version, body] of changelog.matchAll(/^## \[(\d+\.\d+\.\d+)\][^\n]*\n([\s\S]*?)(?=^## \[|(?![\s\S]))/gm)) { + if (!atLeast(version, '4.3.0') || !/^### (Breaking|Deprecated)/m.test(body)) continue; + if (!migrations.some((m) => m.since === version) && !exempt[version]) out.push(version); + } + return out; +} + +test('AE5: a Breaking or Deprecated release from 4.3.0 on declares its migration or why there is none', async () => { + const { MIGRATIONS, NO_MIGRATION } = await import('../scripts/upgrade.mjs'); + assert.deepEqual(undeclared(readFileSync(join(PLUGIN, 'CHANGELOG.md'), 'utf8'), MIGRATIONS, NO_MIGRATION), []); + // The check itself: a breaking 9.9.0 with nothing declared fails; a migration or an exemption lifts it; + // older releases are covered by the migrations of 4.3.0. + const fixture = '# Changelog\n\n## [9.9.0] - 2030-01-01\n\n### Breaking\n- renamed a key\n\n## [9.8.0] - 2030-01-01\n\n### Added\n- x\n\n## [4.0.0] - 2026-10-20\n\n### Breaking\n- moved\n'; + assert.deepEqual(undeclared(fixture, MIGRATIONS, NO_MIGRATION), ['9.9.0']); + assert.deepEqual(undeclared(fixture, [...MIGRATIONS, { since: '9.9.0' }], NO_MIGRATION), []); + assert.deepEqual(undeclared(fixture, MIGRATIONS, { '9.9.0': 'the key is still read' }), []); +});