Formalize C0/C1/C2 change classification process

Redefine the three change classes with clearer boundaries:
- C0: direct-to-main commits for low-risk, fix-forward-safe changes
- C1: feature branch + PR with docs-first workflow and branch deployment
- C2: Mikado Branch Invariant enforcing strict commit ordering (card
  commits first, code progress, card closures) with branch resets on
  new prerequisite discovery

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-02-23 15:33:18 -08:00
commit 9e39087a0a
6 changed files with 127 additions and 64 deletions

View file

@ -15,25 +15,31 @@ blumeops is Erich Blume's GitOps repository for personal infrastructure, orchest
1. **Always run `mise run ai-docs -- --style=header --color=never --decorations=always` at session start**
This will refresh your context with important information you will be assumed to know and follow.
2. **Always use `--context=minikube-indri` with kubectl** (or `--context=k3s-ringtail` for ringtail services) - work contexts must never be touched
3. **Feature branches only** - checkout main, pull, create branch, commit often
4. **Create PRs via `tea pr create`** - user reviews before deploy, merges after
3. **Classify the change as C0/C1/C2 before starting** (see below) — this determines branching and PR requirements
4. **Feature branches + PRs for C1/C2** - checkout main, pull, create branch, open PR via `tea pr create`. C0 goes direct to main.
5. **Check PR comments with `mise run pr-comments <pr_number>`** before proceeding
6. **Add changelog fragments** - `docs/changelog.d/<branch>.<type>.md`
Types: `feature`, `bugfix`, `infra`, `doc`, `ai`, `misc`
7. **Test before applying** - dry runs (`--check --diff`), syntax checks, `ssh indri '...'`
8. **Wait for user review before deploying**
9. **Never merge PRs or push to main without explicit request**
8. **Wait for user review before deploying** (C1/C2)
9. **Never merge PRs or push to main without explicit request** (C0 commits to main are fine)
10. **Verify deployments** - `mise run services-check`
## Change Classification
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 |
**C0** — commit directly to main. No branch or PR needed. Fix forward if problems arise.
**C1** — feature branch with early PR. Search related docs first, write documentation changes before code, deploy from the unmerged branch (ArgoCD `--revision`, Ansible from checkout). Upgrade to C2 if complexity spirals.
**C2** — feature branch governed by the Mikado Branch Invariant: all Mikado card commits come first, then code progress commits, then card-closing commits. Reset the branch when new prerequisites are discovered.
See [[agent-change-process]] for the full methodology.

View file

@ -0,0 +1 @@
Formalize C0/C1/C2 change classification: C0 allows direct-to-main commits, C1 adds docs-first workflow with branch deployment, C2 introduces the Mikado Branch Invariant for strict commit ordering on multi-phase changes.

View file

@ -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,125 @@ 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, reference cards, and prior Mikado chains 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**.
### The Mikado Branch Invariant
The invariant governs how commits are ordered on a C2 feature branch. The branch must always have this structure:
```
main ← [Mikado card commits] ← [code commits] ← [card-closing commits]
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
Planning layer Implementation Resolution
(cards only) (code only) (close leaf nodes)
```
**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 commits, a series of commits (preferably just one) make **code progress toward closing a leaf node** — these commits must NOT introduce or change Mikado cards
3. The code commits must be followed by one or more commits that **close Mikado leaf nodes** based on the work done
4. This pattern (code → close) repeats until the chain is complete
**What is NOT allowed:**
- Introducing a Mikado card in a commit that comes after code progress commits
- Closing a Mikado card before all cards it depends on have been introduced
**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.
### 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
- Create prerequisite cards discovered during planning, each with `status: active`
- Commit all cards together (or in a sequence of card-only commits)
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 that progress toward closing it
- Commit the card closure (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`
6. When a card's change succeeds, remove `status: active` (or the entire field) from its frontmatter
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 point where all card-introducing commits end and code commits begin
2. **Add a new commit** 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
2. **Add changelog information** in `docs/changelog.d/`
3. The user reviews and merges the PR
### 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
@ -111,12 +165,11 @@ 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:** Single feature branch, Mikado Branch Invariant enforced, 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

View file

@ -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

View file

@ -1,6 +1,6 @@
---
title: AI Assistance Guide
modified: 2026-02-09
modified: 2026-02-23
tags:
- tutorials
- ai
@ -22,13 +22,16 @@ These are non-negotiable for AI agents working in this repo:
4. **Wait for user review before deploying** - Create PRs, don't auto-deploy
5. **Never merge PRs without explicit request** - The user merges after review
Full rules are in the repo's `CLAUDE.md`. See [[agent-change-process]] for the C0/C1/C2 change classification methodology.
Full rules are in the repo's `CLAUDE.md`. See [[agent-change-process]] for the C0/C1/C2 change classification methodology — C0 (direct to main), C1 (feature branch + PR), C2 (Mikado Branch Invariant).
## Workflow Conventions
### Feature Branches
### Branching
All work happens on feature branches:
Branching depends on change classification (see [[agent-change-process]]):
- **C0 (Quick Fix):** Commit directly to main — no branch or PR needed
- **C1/C2:** Feature branch required:
```bash
git checkout main && git pull
git checkout -b feature/descriptive-name
@ -85,7 +88,7 @@ BlumeOps operations are driven by mise tasks. Run `mise tasks` to list all avail
| Task | When to Use |
|------|-------------|
| `ai-docs` | At session start - review infrastructure documentation |
| `docs-mikado` | View active Mikado dependency chains for C1/C2 changes |
| `docs-mikado` | View active Mikado dependency chains for C2 changes |
| `provision-indri` | Deploy changes to [[indri]]-hosted services via Ansible |
| `services-check` | After deployments - verify all services are healthy |
| `pr-comments` | Check unresolved PR comments during review |
@ -131,5 +134,5 @@ Credentials live in 1Password. Never retrieve them directly - use existing patte
| Missing kubectl context | Always add `--context=minikube-indri` |
| Deploying without review | Create PR first, wait for user approval |
| Re-explaining reference material | Link to reference cards instead |
| Committing to main | Use feature branches |
| Committing to main without classifying | Classify as C0/C1/C2 first — only C0 goes to main |
| Guessing at credentials | Ask user or check 1Password patterns |

View file

@ -3,10 +3,10 @@
# requires-python = ">=3.12"
# dependencies = ["pyyaml>=6.0", "rich>=13.0.0", "typer>=0.15.0"]
# ///
#MISE description="View active Mikado dependency chains for C1/C2 changes"
#MISE description="View active Mikado dependency chains for C2 changes"
#USAGE arg "[card]" help="Card stem to show chain for"
#USAGE flag "--all" help="Show all cards in full, including complete ones"
"""View active Mikado dependency chains for C1/C2 changes.
"""View active Mikado dependency chains for C2 changes.
Scans all markdown files in docs/ for YAML frontmatter with ``status: active``
and ``requires`` fields, then builds and displays the Mikado dependency graph.