Formalize C0/C1/C2 change classification (#259)
## Summary - **C0 (Quick Fix):** Now explicitly allows direct-to-main commits with no PR required — for low-risk, fix-forward-safe changes - **C1 (Human Review):** New docs-first workflow with branch deployment (ArgoCD `--revision`, Ansible from checkout). Includes upgrade criteria for escalation to C2 - **C2 (Mikado Chain):** Introduces the **Mikado Branch Invariant** — strict commit ordering where card-introducing commits come first, followed by code progress, followed by card closures. Branch resets required when new prerequisites are discovered Updates CLAUDE.md rules (3, 4, 8, 9) to reflect that C0 bypasses branching/PR requirements. Also updates ai-assistance-guide, how-to index, and docs-mikado task description. ## Files changed - `CLAUDE.md` — rules and classification table - `docs/how-to/agent-change-process.md` — full process rewrite - `docs/tutorials/ai-assistance-guide.md` — branching and pitfalls sections - `docs/how-to/how-to.md` — index description - `mise-tasks/docs-mikado` — task description - `docs/changelog.d/formalize-change-classification.doc.md` — changelog fragment Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/259
This commit is contained in:
parent
f05e5cccdf
commit
66b5b32f1d
8 changed files with 728 additions and 68 deletions
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Agent Change Process
|
||||
modified: 2026-02-20
|
||||
last-reviewed: 2026-02-22
|
||||
modified: 2026-02-23
|
||||
last-reviewed: 2026-02-23
|
||||
tags:
|
||||
- how-to
|
||||
- ai
|
||||
|
|
@ -15,71 +15,202 @@ How to classify and execute infrastructure changes, especially when working with
|
|||
|
||||
Before starting work, classify the change:
|
||||
|
||||
| Class | Scope | Process |
|
||||
|-------|-------|---------|
|
||||
| **C0** | Quick fix, single-file, obvious | Read `ai-docs`, implement directly |
|
||||
| **C1** | Moderate, potential hidden complexity | Mikado method, single session, single PR |
|
||||
| **C2** | Complex, multi-session | Mikado method, documentation-driven, single PR |
|
||||
| Class | Name | When to use | Key trait |
|
||||
|-------|------|-------------|-----------|
|
||||
| **C0** | Quick Fix | Small, low-risk, fix-forward safe | Direct to main, no PR |
|
||||
| **C1** | Human Review | Moderate complexity or risk | Feature branch + PR, docs-first |
|
||||
| **C2** | Mikado Chain | Multi-phase, multi-session, high complexity | Mikado Branch Invariant |
|
||||
|
||||
When in doubt, start at C1. Upgrade to C2 if complexity spirals or the user requests it.
|
||||
|
||||
## C0 — Quick Fix
|
||||
|
||||
1. Run `mise run ai-docs` to load context
|
||||
2. Implement the change directly
|
||||
3. Commit, push, create PR
|
||||
|
||||
Examples: fix a typo, bump a version, add a simple config value.
|
||||
|
||||
## C1 — Guided Change (Single Session)
|
||||
|
||||
Use the [Mikado method](https://mikadomethod.info/) within a single session:
|
||||
A change where the risk is low enough that problems can be quickly fixed forward.
|
||||
|
||||
1. Run `mise run ai-docs` to load context
|
||||
2. Attempt the change on a feature branch, amending a single commit as you iterate
|
||||
3. **If it works:** push and create PR
|
||||
4. **If it fails:** revert the broken change (`git revert`), then:
|
||||
- Amend or add a commit with documentation updates noting what prerequisite was discovered
|
||||
- Update frontmatter: add `requires: [prerequisite-card]` to the goal card
|
||||
- Work the leaf nodes (prerequisites with no further dependencies) first
|
||||
- Repeat until the goal succeeds
|
||||
2. Implement the change directly on main
|
||||
3. Commit and push
|
||||
|
||||
Single feature branch, squash-merge when complete. GitOps may require pushing to test — if a pushed commit breaks, revert it promptly.
|
||||
No feature branch or PR required. If something goes wrong, fix forward with another commit.
|
||||
|
||||
## C2 — Documented Change (Multi-Session)
|
||||
Examples: fix a typo, bump a version, add a simple config value, update a doc.
|
||||
|
||||
Like C1 but designed to survive agent context loss across sessions:
|
||||
## C1 — Human Review
|
||||
|
||||
A change with enough complexity or risk that a human should review it, but not so much that a formal multi-phase approach is needed.
|
||||
|
||||
### Process
|
||||
|
||||
1. Run `mise run ai-docs` to load context
|
||||
2. **Search related docs** — read existing documentation and reference cards related to the change area
|
||||
3. **Create a feature branch** and open a PR early (draft is fine)
|
||||
4. **Documentation first** — commit doc changes reflecting the desired end state before writing code. This helps the reviewer understand intent and catches design issues early
|
||||
5. **Implement** — commit code changes, pushing as you go. The PR gets updated along the way and the user can review and comment at any point
|
||||
6. **Deploy from the branch** — do not wait for merge:
|
||||
- **ArgoCD:** `argocd app set <service> --revision <branch> && argocd app sync <service>`
|
||||
- **Ansible:** run playbooks directly from the branch checkout
|
||||
- **Workflows:** point workflow triggers at the branch if needed
|
||||
7. After user review and successful deployment, the user merges the PR
|
||||
8. **After merge:** reset ArgoCD revisions back to main, re-sync
|
||||
|
||||
### Upgrading to C2
|
||||
|
||||
Upgrade to C2 if any of these happen during a C1 change:
|
||||
|
||||
- You discover the change requires multiple prerequisite changes that must be sequenced
|
||||
- The change is spiraling in complexity beyond a single session
|
||||
- The user requests it
|
||||
- During planning you realize this is a multi-phase project
|
||||
|
||||
## C2 — Mikado Chain
|
||||
|
||||
A complex, multi-session change managed through the [Mikado method](https://mikadomethod.info/) with a strict branch discipline called the **Mikado Branch Invariant**.
|
||||
|
||||
### Planning and research
|
||||
|
||||
Before writing any code, invest in understanding the problem:
|
||||
|
||||
1. Run `mise run ai-docs` to load context
|
||||
2. Search related docs, reference cards, and existing how-to guides for the change area
|
||||
3. Think through the dependency graph — what prerequisites exist? What could go wrong?
|
||||
4. Create Mikado cards for everything you can anticipate (you'll discover more later — that's the point of the method)
|
||||
|
||||
This planning phase can span multiple sessions. Cards introduced during planning are merged to main and become the foundation for work cycles later.
|
||||
|
||||
### The Mikado Branch Invariant
|
||||
|
||||
The invariant governs how commits are ordered on a C2 feature branch. The branch must always have this structure:
|
||||
|
||||
```
|
||||
main ← [plan commits] ← [impl, close] ← [impl, close] ← ... ← [finalize]
|
||||
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Planning layer Repeating work cycles
|
||||
(cards only) (impl then close, one leaf at a time)
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
|
||||
1. The first N commits on the branch (after diverging from main) must ALL be commits that **only introduce or modify Mikado cards** — no code changes
|
||||
2. After the card layer, work proceeds in **cycles**: each cycle is one or more code commits followed by one or more commits closing leaf nodes
|
||||
3. A cycle should target a single leaf node (though closing multiple in one cycle is acceptable if the code supports it)
|
||||
4. Cycles repeat until the chain is complete
|
||||
|
||||
**The one rule:** No Mikado card may be introduced after any code or card-closing commit. New cards require a branch reset (see below).
|
||||
|
||||
**The length-zero case:** It is valid for the "planning layer" to have zero commits on the branch — this happens when all Mikado cards were introduced in earlier sessions and are already in main's history. The invariant is satisfied.
|
||||
|
||||
**Exception — finalize:** The terminal commit of a completed chain rewrites Mikado cards to historical documentation. This is a card modification after code commits, and is the only permitted violation of the one rule (see "Completing a chain" below).
|
||||
|
||||
### Conventions
|
||||
|
||||
#### Branch naming
|
||||
|
||||
C2 branches must be named `mikado/<chain-stem>`, where `<chain-stem>` is the filename stem of the goal card. Example: goal card `deploy-authentik.md` → branch `mikado/deploy-authentik`.
|
||||
|
||||
#### Goal card `branch:` frontmatter
|
||||
|
||||
The goal card of a C2 chain must include a `branch:` field once work begins:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Deploy Authentik
|
||||
status: active
|
||||
branch: mikado/deploy-authentik
|
||||
requires:
|
||||
- configure-postgres
|
||||
- setup-redis
|
||||
tags:
|
||||
- how-to
|
||||
---
|
||||
```
|
||||
|
||||
A goal card with `status: active` but no `branch:` field indicates a chain that has been planned but not yet started — the planning-phase cards exist but no implementation branch has been created.
|
||||
|
||||
#### Commit message convention
|
||||
|
||||
All commits on a `mikado/*` branch must use this format:
|
||||
|
||||
```
|
||||
C2(<chain-stem>): <verb> <short description>
|
||||
```
|
||||
|
||||
Verbs and their meanings:
|
||||
|
||||
| Verb | Phase | What it means |
|
||||
|------|-------|---------------|
|
||||
| `plan` | Planning layer | Introduces or modifies a Mikado card (no code changes) |
|
||||
| `impl` | Work cycle | Code progress toward closing a leaf node (no card changes) |
|
||||
| `close` | Work cycle | Closes a leaf node by removing `status: active` |
|
||||
| `finalize` | Terminal | Rewrites cards to historical docs, adds changelog |
|
||||
|
||||
Examples:
|
||||
```
|
||||
C2(deploy-authentik): plan add postgres and redis prerequisite cards
|
||||
C2(deploy-authentik): impl configure external-secrets for authentik
|
||||
C2(deploy-authentik): close configure-postgres
|
||||
C2(deploy-authentik): finalize rewrite cards as historical documentation
|
||||
```
|
||||
|
||||
The `mikado-branch-invariant-check` commit-msg hook validates this convention and the invariant ordering.
|
||||
|
||||
### Process
|
||||
|
||||
1. **Goal card:** Create a how-to doc in `docs/how-to/` describing the desired end state
|
||||
- Add `status: active` to frontmatter
|
||||
2. **Attempt the change** — GitOps may require pushing code to test (e.g., ArgoCD sync). When the attempt fails:
|
||||
- **First**, reset the failed code changes (the branch should not carry broken code forward)
|
||||
- **Then**, create/update prerequisite cards as how-to docs with `status: active`
|
||||
- Add `requires: [prerequisite-stem, ...]` to the goal card's frontmatter
|
||||
- Commit only the doc updates (the documentation IS the Mikado graph)
|
||||
3. **Work leaf nodes first** — cards with `status: active` and no unmet `requires`
|
||||
4. **Re-attempt the goal** after leaf nodes are resolved — code from the attempt comes back here
|
||||
5. **New agent sessions** pick up state by running `mise run docs-mikado`
|
||||
6. When a card's change succeeds, remove `status: active` (or the entire field) from its frontmatter
|
||||
- Add `status: active` and `branch: mikado/<chain-stem>` to frontmatter
|
||||
- Create prerequisite cards discovered during planning, each with `status: active`
|
||||
- Commit all cards together (or in a sequence of card-only commits) using `C2(<chain>): plan ...` messages
|
||||
2. **Open a PR** after the first card commits so the user can review the Mikado graph
|
||||
3. **Work leaf nodes** — pick a leaf (a card with `status: active` and no unmet `requires`):
|
||||
- Commit code changes (`C2(<chain>): impl ...`) that progress toward closing it
|
||||
- **Verify the change works** (deploy from branch, run tests, etc.) before closing
|
||||
- Commit the card closure (`C2(<chain>): close ...`) — remove `status: active`
|
||||
- Push to origin — this is the save point
|
||||
4. **Repeat** until the chain is complete
|
||||
5. **New agent sessions** pick up state by running `mise run docs-mikado --resume`
|
||||
|
||||
Documentation IS the Mikado graph. Each card captures what was learned from failed attempts, so the next agent session doesn't repeat mistakes.
|
||||
### Discovering new prerequisites
|
||||
|
||||
### Handling failed attempts
|
||||
When you discover a new prerequisite during code work, you must restore the Mikado Branch Invariant:
|
||||
|
||||
When an attempt fails and you discover prerequisites, the branch must be cleaned up before documenting what you learned:
|
||||
1. **Reset the branch** back to the top of the Mikado commit stack — the last `C2(<chain>): plan` or `C2(<chain>): close` commit before your current `impl` commits
|
||||
2. **Add a new commit** (`C2(<chain>): plan ...`) introducing the new prerequisite card (and updating `requires` on existing cards if needed)
|
||||
3. **Replay the Mikado process** from the new state of the card stack
|
||||
|
||||
1. Reset to before the code attempt (`git reset --hard`)
|
||||
2. Commit the new prerequisite cards and frontmatter updates
|
||||
3. If you already committed docs mixed with code, cherry-pick the doc commits onto a clean base rather than reverting (avoids noisy add/revert history)
|
||||
**Saving work across resets:** It is acceptable to cherry-pick or rebase code commits from before the reset back onto the branch after adding the new card. This is a pragmatic exception — use it only when you are confident the saved work is still valid given the new prerequisite. When in doubt, redo the work from scratch.
|
||||
|
||||
The branch between attempts should contain only documentation. Code returns when prerequisites are satisfied and the next attempt succeeds.
|
||||
### Completing a chain
|
||||
|
||||
When the final leaf node is closed and no `status: active` cards remain:
|
||||
|
||||
1. **Rewrite all Mikado cards** to reflect their nature as historical documentation:
|
||||
- Remove transient technical details (specific version numbers, temporary workarounds) that won't matter in the future
|
||||
- Frame the content as "what to do if someone wanted to repeat this process"
|
||||
- Add appropriate context about what was learned
|
||||
- Remove `branch:` from the goal card frontmatter
|
||||
2. **Add changelog information** in `docs/changelog.d/`
|
||||
3. Commit as `C2(<chain>): finalize ...` — this is the one permitted exception to the invariant's "no card changes after code" rule
|
||||
4. The user reviews and merges the PR
|
||||
|
||||
### Cold-start: resuming a chain in a new session
|
||||
|
||||
When starting a new session to continue C2 work:
|
||||
|
||||
1. Run `mise run ai-docs` to load context
|
||||
2. Run `mise run docs-mikado --resume` — this will:
|
||||
- Detect the current branch and match it to an active chain
|
||||
- Show the chain state, ready leaf nodes, and current position in the invariant
|
||||
- If on main, list active chains and suggest which to resume
|
||||
3. Check PR comments with `mise run pr-comments <pr_number>`
|
||||
4. Pick the next ready leaf node and continue with a work cycle
|
||||
|
||||
### Build artifacts
|
||||
|
||||
Mikado resets apply to branch code, not build artifacts. Container images in the registry are independent of branch lifecycle:
|
||||
|
||||
- **Registry images** are build outputs cached in zot — tagged with commit SHAs, so each build is unique and traceable.
|
||||
- **Automatic builds** trigger when container changes merge to main. Use `mise run container-build-and-release` for manual dispatch.
|
||||
- **If a build succeeds but deployment fails**, the image is fine; the problem is elsewhere. Document what you learned and try again.
|
||||
- **If a build fails in CI**, no image is pushed. Fix the nix/dockerfile and re-merge or re-dispatch.
|
||||
- **Registry images** are build outputs cached in zot — tagged with commit SHAs, so each build is unique and traceable
|
||||
- **Automatic builds** trigger when container changes merge to main. Use `mise run container-build-and-release` for manual dispatch
|
||||
- **If a build succeeds but deployment fails**, the image is fine; the problem is elsewhere. Document what you learned and try again
|
||||
- **If a build fails in CI**, no image is pushed. Fix the nix/dockerfile and re-merge or re-dispatch
|
||||
|
||||
## Card Conventions
|
||||
|
||||
|
|
@ -89,6 +220,7 @@ Mikado resets apply to branch code, not build artifacts. Container images in the
|
|||
---
|
||||
title: Deploy Authentik
|
||||
status: active # omit when complete
|
||||
branch: mikado/deploy-authentik # goal cards only; omit when complete
|
||||
requires: # explicit dependencies
|
||||
- configure-postgres
|
||||
- setup-redis
|
||||
|
|
@ -98,6 +230,7 @@ tags:
|
|||
```
|
||||
|
||||
- `status: active` marks in-progress work; remove when done (this is the ONLY way a card is marked complete)
|
||||
- `branch` is set on goal cards only, linking the card to its `mikado/<chain-stem>` branch. A goal card with `status: active` but no `branch` indicates a chain that is planned but not yet started. Remove `branch` when the chain is finalized.
|
||||
- `requires` lists card stems (filenames without `.md`) that must be completed first. **Keep `requires` permanently** even after prerequisites are done — it documents the dependency graph history
|
||||
- `required-by` is NOT stored — it's computed by `docs-mikado`
|
||||
|
||||
|
|
@ -111,20 +244,23 @@ tags:
|
|||
|
||||
### Git Discipline
|
||||
|
||||
- Single feature branch per C1/C2 change
|
||||
- **Create a PR early** — open a draft PR after the first doc commit so the user can review the Mikado graph as it evolves between iterations.
|
||||
- **Push after every iteration** — after completing a leaf node or documenting a failed attempt, push to origin. This is the save point for multi-session work.
|
||||
- Amend a single working commit as you iterate; keep the branch history clean
|
||||
- **C0:** Commit directly to main
|
||||
- **C1:** Single feature branch, PR early, push often
|
||||
- **C2:** Branch named `mikado/<chain-stem>`, Mikado Branch Invariant enforced, `C2()` commit convention, PR early, push after every leaf-node closure
|
||||
- **Deploy from branches** — C1 and C2 changes deploy from the unmerged branch (ArgoCD `--revision`, Ansible from checkout, etc.). Reset to main after merge.
|
||||
- GitOps requires pushing to test — if a pushed commit breaks, revert it promptly
|
||||
- Commit doc updates noting what was learned from failures
|
||||
|
||||
## Tools
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `mise run docs-mikado` | List all active Mikado chains |
|
||||
| `mise run docs-mikado` | List all active Mikado chains with branch status |
|
||||
| `mise run docs-mikado <card>` | Show dependency chain for a goal card |
|
||||
| `mise run docs-mikado <card> --all` | Include completed cards in full |
|
||||
| `mise run docs-mikado --resume` | Resume a chain: detect branch, show state and next steps |
|
||||
| `mise run docs-mikado --resume <chain>` | Resume a specific chain with branch consistency check |
|
||||
|
||||
The `mikado-branch-invariant-check` commit-msg hook runs automatically on `mikado/*` branches, validating commit message conventions and invariant ordering. Requires `uvx pre-commit install --hook-type commit-msg`.
|
||||
|
||||
## Related
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Task-oriented instructions for common BlumeOps operations. These guides assume y
|
|||
|-------|-------------|
|
||||
| [[review-documentation]] | Periodically review and maintain documentation |
|
||||
| [[review-services]] | Periodically review services for version freshness |
|
||||
| [[agent-change-process]] | C0/C1/C2 change classification and Mikado method for agents |
|
||||
| [[agent-change-process]] | C0/C1/C2 change classification and Mikado Branch Invariant |
|
||||
|
||||
## Operations
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue