refactor(P06): rename milestone type schema-breaking → major, reinforce release flow

---ci---
phase: 6
milestone: v0.10
status: execute
decisions:
  - id: D-001
    decision: Rename MilestoneType schema-breaking to major for clarity
    rationale: Major better describes the semver impact (major version bump) and aligns with standard semver terminology
    confidence: 0.95
    alternatives: [schema-breaking, breaking, major-change]
  - id: D-002
    decision: Add autopilot rules, PR+QA gates, and merge validation to ship workflow
    rationale: Release flow was documented but not enforced in the workflow. Zero-HITL rules, branch hierarchy validation, and coreci packaging steps ensure consistent releases
    confidence: 0.90
    alternatives: [keep-as-documentation-only, add-to-AGENTS.md-only]
---/ci---
This commit is contained in:
Jon Chery
2026-06-01 15:29:43 +00:00
parent e2b749d42e
commit f478088797
12 changed files with 187 additions and 68 deletions
+32 -14
View File
@@ -106,20 +106,27 @@ Phase branches can be deleted after merge if desired.
**Every merge to main creates a release. No exceptions.** Versioning follows a 3-tier model based on milestone type:
### 3-Tier Versioning Model
### Milestone Type and Versioning
The milestone type is determined **before any development work** and governs all versioning for the entire milestone.
**Define semver at milestone start:** establish the version and milestone type before writing code.
Determine milestone type via `getMilestoneType()` which returns `"nfr" | "feature" | "major"`:
| Milestone Type | Condition | Phase release | Milestone release |
|---------------|-----------|---------------|-------------------|
| **NFR** | All phases: fix/chore/docs/perf/refactor/test | Patch (`vX.Y.Z`) | None |
| **Feature** | Any phase is `feat`, no schema break | Patch (`vX.Y.Z`) | Minor — `vX.(Y+1).0` |
| **Schema-breaking** | Refactor/schema break/new direction | Minor — `vX.(Y+N).0` per phase | Major — `v(X+1).0.0` |
| **NFR** | All phases are fix/chore/docs/perf/refactor/test | Patch `v1.8.1`, `v1.8.2`, ... | None — final patch IS the deliverable |
| **Feature** | At least one phase has new features (`feat`) | Patch `v1.8.1`, `v1.8.2`, ... | Next minor — `v1.9.0` |
| **Major** | Breaking schema changes or complete refactor | Minor — `v2.1.0`, `v2.2.0`, ... | Major — `v3.0.0` |
**IMPORTANT:** Milestone tags are always the NEXT version, never the base:
- Feature: patches v0.5.1v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
- Schema-breaking: minors v0.3.0, v0.4.0, v0.5.0 → milestone tag is v1.0.0
- NFR: no milestone tag — the milestone is implicit from the patch sequence
Determine milestone type via `getMilestoneType()` which returns `"nfr" | "feature" | "schema-breaking"`.
**Tag rules (CRITICAL):**
- Milestone tags are always the NEXT version, never the base:
- Feature: patches v0.5.1v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
- Major: minors v0.3.0, v0.4.0, v0.5.0 → milestone tag is v1.0.0
- NFR: no milestone tag — the final patch release IS the deliverable
- Tags must be strictly greater than all existing tags on the same major.minor line
- NEVER create a milestone tag that is semantically below existing phase tags
### Phase completion
@@ -135,7 +142,7 @@ git push origin main --tags
Phase number within the milestone determines the patch version (1st phase = .1, 2nd phase = .2, etc.)
**Schema-breaking (minor release per phase):**
**Major (minor release per phase):**
```bash
git checkout milestone/v0.5-schema-rewrite
git merge --squash phase/01-core-refactor
@@ -145,7 +152,7 @@ git push origin main --tags
# Create Gitea release for v0.5.0
```
Each schema-breaking phase bumps the minor. 1st phase = next available minor, 2nd = minor+1, etc.
Each major phase bumps the minor. 1st phase = next available minor, 2nd = minor+1, etc.
### Milestone completion
@@ -160,7 +167,7 @@ git push origin main --tags
# Create Gitea release for v0.6.0 with full milestone summary
```
**Schema-breaking (major release):**
**Major (major release):**
```bash
# All phases already merged into milestone branch
git checkout main
@@ -177,9 +184,20 @@ git push origin main --tags
Before creating any tag:
1. Tag must be strictly greater than all existing tags on the same major.minor line
2. Milestone completion tag must be next minor (feature) or next major (schema-breaking)
2. Milestone completion tag must be next minor (feature) or next major (major)
3. NEVER create a tag that is semantically below existing phase tags
### Merge Validation Gates
The branch hierarchy `main > milestone/vX.X-slug > phase/NN-slug` is enforced at merge time:
| Merge Type | Rule | Validation |
|------------|------|-------------|
| Phase → Milestone | Must target milestone branch when one exists | REJECTED if milestone branch does not exist for this phase's milestone |
| Phase → Main | Only allowed when no milestone branch exists | REJECTED if a milestone branch exists for this milestone |
| Milestone → Main | Only after all phase branches are merged | REJECTED if any phase branches for this milestone are unmerged |
| Hotfix → Main | Allowed (exception to hierarchy) | Always allowed |
## Multi-Project Branch Naming
When operating in multi-project mode (`.ciagent/config.json` has `projects[]` with length > 0):
+6 -5
View File
@@ -101,7 +101,7 @@ For each stage in order (starting from current or from `specify`):
- Update `.ciagent/ROADMAP.md` phase status
- Commit: `docs(P##): complete [phase-name] phase`
Versioning: Major = project-level refactor/schema change, Minor = milestone completion, Patch = every phase.
Versioning: Major milestone = breaking schema changes, Feature milestone = milestone completion (minor), Patch = every phase.
## Phase Boundary Checkpoint
@@ -113,12 +113,13 @@ Between phases, perform a context reset:
4. Reset context: spawn fresh agent (opencode) or re-read git context (platforms without subagents)
5. Next phase begins with fresh context from git log only
## NFR Versioning Logic
## Versioning Logic
Before tagging a phase completion, check `isNfrMilestone()`:
Before tagging a phase completion, check `getMilestoneType()` which returns `"nfr" | "feature" | "major"`:
- **NFR milestone** (all phases are fix/chore/docs/perf/refactor/test): apply progressive patch versions (v0.1.1, v0.1.2, v0.1.3). No separate milestone tag.
- **Feature milestone** (any feat phase): apply progressive patch versions per phase, then tag minor milestone version on completion (e.g., v0.2.0).
- **NFR milestone** (all phases are fix/chore/docs/perf/refactor/test): apply progressive patch versions (v0.1.1, v0.1.2, v0.1.3). No separate milestone tag — the final patch IS the deliverable.
- **Feature milestone** (at least one feat phase): apply progressive patch versions per phase, then tag next minor milestone version on completion (e.g., v0.6.0, NOT v0.5.0).
- **Major milestone** (breaking schema changes or complete refactor): apply progressive minor versions per phase (v0.3.0, v0.4.0), then tag next major on completion (e.g., v1.0.0).
## Step 4: Error Recovery
+132 -32
View File
@@ -1,25 +1,45 @@
---
description: Ship CIAgent phase or milestone — test, tag, release. Every phase and milestone gets a release. Full autopilot.
description: Ship CIAgent phase or milestone — Full autopilot release: validate, test, merge, tag, push, release. Zero HITL
---
# CIAgent Ship
Ship a CIAgent phase or milestone. Every ship creates a release — no exceptions.
**3-Tier Versioning Model:**
**Usage:** `ciagent-ship [phase_number|milestone]`
## Autopilot Rules
These rules are **non-negotiable**. The ship workflow runs in full autopilot mode:
- **Zero HITL** — no confirmation prompts, no approval gates, no requests for human input. The agent executes the entire release flow autonomously.
- **No Shortcuts** — deep validation, testing, and merge checks must all run in full. The lack of HITL is not an excuse to skip steps.
- **Notification Only** — status updates are informational, not requests for approval. Report outcomes, never ask permission.
- **Autonomous Loop on Failure** — if any step fails (tests, pipeline, merge conflicts), iterate autonomously until success. Do NOT ask the user for guidance on how to fix a failing test or pipeline.
- **Branch Hierarchy Enforced** — `main > milestone/vX.X-slug > phase/NN-slug`. Phase merges into milestone, milestone merges into main. This is validated, not assumed.
## Milestone Type and Versioning
The milestone type is determined **before any development work** and governs all versioning for the entire milestone.
**Define semver at milestone start:** establish the version and milestone type before writing code.
Determine milestone type by calling `getMilestoneType()` which returns `"nfr" | "feature" | "major"`:
| Milestone Type | Condition | Phase release | Milestone release |
|---------------|-----------|---------------|-------------------|
| **NFR** | All phases: fix/chore/docs/perf/refactor/test | Patch (`vX.Y.Z`) | None |
| **Feature** | Any phase is `feat`, no schema break | Patch (`vX.Y.Z`) | Minor — `vX.(Y+1).0` |
| **Schema-breaking** | Refactor/schema break/new direction | Minor — `vX.(Y+N).0` per phase | Major — `v(X+1).0.0` |
| **NFR** | All phases are fix/chore/docs/perf/refactor/test | Patch `v1.8.1`, `v1.8.2`, ... | None — final patch IS the deliverable |
| **Feature** | At least one phase has new features (`feat`) | Patch `v1.8.1`, `v1.8.2`, ... | Next minor — `v1.9.0` |
| **Major** | Breaking schema changes or complete refactor | Minor — `v2.1.0`, `v2.2.0`, ... | Major — `v3.0.0` |
**CRITICAL:** Milestone tags are always the NEXT version, never the base:
- Feature: patches v0.5.1v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
- Schema-breaking: minors v0.3.0, v0.4.0, v0.5.0 → milestone tag is v1.0.0
- NFR: no milestone tag — the milestone is implicit from the patch sequence
**Tag rules (CRITICAL):**
**Usage:** `ciagent-ship [phase_number|milestone]`
- Milestone tags are always the NEXT version, never the base:
- Feature: patches v0.5.1v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
- Major: minors v0.3.0, v0.4.0, v0.5.0 → milestone tag is v1.0.0
- NFR: no milestone tag — the final patch release IS the deliverable
- Tags must be strictly greater than all existing tags on the same major.minor line
- NEVER create a milestone tag that is semantically below existing phase tags
## Step 0: Confirm Active Project
@@ -33,11 +53,12 @@ If `.ciagent/config.json` has `projects[]` with length > 0:
If single-project mode: proceed with existing conventions.
## Step 1: Pre-Flight
## Step 1: Pre-Flight Validation
```bash
git log --max-count=10
git branch -a
git tag -l
```
Determine what is being shipped: a single phase or an entire milestone.
@@ -49,6 +70,16 @@ Read `.ciagent/ROADMAP.md` to determine:
Read `.ciagent/config.json` for autonomy level.
**Validation gates — all must pass before proceeding:**
1. **Milestone type resolved**`getMilestoneType()` must return `"nfr" | "feature" | "major"`. Stop if undefined.
2. **Branch hierarchy correct** — phase branch exists and targets the correct parent (milestone branch, or main if no milestone branch exists).
3. **No unmerged phase branches** — if shipping a milestone, all phase branches for this milestone must be merged into the milestone branch.
4. **Tag sequence valid** — the computed tag must be strictly greater than all existing tags on the same major.minor line. Check with `git tag -l`.
5. **Autonomy confirmed**`.ciagent/config.json` autonomy level must be `full`. This is the zero-HITL enforcement point.
If any validation fails: stop and report. Do NOT proceed past a failed gate.
## Step 2: Run Tests
```bash
@@ -59,33 +90,77 @@ npm run build
If any fail: iterate autonomously until tests pass. Do NOT ask the user for guidance — debug and fix.
## Step 3: Compute Version
## Step 3: Create PR and Quality Assurance
Determine milestone type by calling `getMilestoneType()` which returns `"nfr" | "feature" | "schema-breaking"`:
**Open a Pull Request for the merge target:**
```bash
tea pr create --base <target-branch> --head <source-branch> --title "ship: [phase-name or milestone-name]"
```
- For a phase ship: PR from `phase/NN-slug` into `milestone/vX.Y-slug` (or `main` if no milestone branch).
- For a milestone ship: PR from `milestone/vX.Y-slug` into `main`.
**Auto-merge configuration:**
Set the PR to auto-merge upon pipeline success:
```bash
tea pr merge <pr-number> --auto --squash
```
**Review:**
Conduct a thorough autonomous review of the PR diff. Check:
- All expected files are included
- No unintended changes slipped in
- No secrets or credentials in the diff
- All `---ci---` blocks have correct metadata
**Finalization:**
- **On pipeline success:** the PR auto-merges. Proceed to Step 4.
- **On pipeline failure:** iterate autonomously until the pipeline passes. Do NOT merge a PR with a failing pipeline. Do NOT ask for guidance.
**Strict rule:** Never merge a PR with a failed pipeline. No exceptions.
## Step 4: Compute Version
| What's shipping | Milestone Type | Phase release | Milestone release | Example |
|----------------|---------------|-------------|------------|---------|
|----------------|---------------|---------------|-------------------|---------|
| Single phase | NFR | Patch `vX.Y.Z` | N/A | v0.1.3 (3rd NFR phase) |
| Single phase | Feature | Patch `vX.Y.Z` | N/A | v0.2.3 (3rd feature phase) |
| Single phase | Schema-breaking | Minor `vX.(Y+N).0` | N/A | v0.4.0 (2nd schema-breaking phase) |
| Single phase | Major | Minor `vX.(Y+N).0` | N/A | v0.4.0 (2nd major phase) |
| Milestone completion | NFR | Patch (last phase) | None | v0.1.3 (no milestone tag) |
| Milestone completion | Feature | Last patch | Minor `vX.(Y+1).0` | v0.3.0 (NOT v0.2.0) |
| Milestone completion | Schema-breaking | Last minor | Major `v(X+1).0.0` | v1.0.0 |
| Milestone completion | Major | Last minor | Major `v(X+1).0.0` | v1.0.0 |
Phase number within the milestone determines the increment:
- NFR/Feature: 1st phase = .1, 2nd = .2, etc. (v0.5.1, v0.5.2)
- Schema-breaking: 1st phase = next minor, 2nd = minor+1, etc. (v0.3.0, v0.4.0)
- Major: 1st phase = next minor, 2nd = minor+1, etc. (v0.3.0, v0.4.0)
**Before creating ANY tag, validate:**
1. The tag must be strictly greater than all existing tags on the same major.minor line
2. Milestone completion tag must be the next minor (feature) or next major (schema-breaking)
**Tag validation (before creating ANY tag):**
1. Tag must be strictly greater than all existing tags on the same major.minor line
2. Milestone completion tag must be next minor (feature) or next major (major)
3. NEVER create a milestone tag that is semantically below existing phase tags (e.g., v0.5.0 when v0.5.1 already exists)
## Step 4: Merge Branch
## Step 5: Merge Branch
### Branch hierarchy: main > milestone/vX.X-slug > phase/NN-slug
Phases MUST merge into their milestone branch (or to main if no milestone branch exists). Milestones merge into main only after all phases are complete.
### Merge validation gates
**Phase → Milestone:**
- VALIDATED — must target milestone branch when one exists
- REJECTED if milestone branch does not exist for this phase's milestone
**Phase → Main:**
- VALIDATED — only allowed when NO milestone branch exists for this phase's milestone
- REJECTED if a milestone branch exists for this milestone
**Milestone → Main:**
- VALIDATED — only after all phase branches are merged
- REJECTED if any phase branches for this milestone are unmerged
### Phase ship
@@ -123,8 +198,9 @@ requirements:
### Milestone ship (after last phase)
**Validate all phase branches are merged into the milestone branch before proceeding.**
```bash
# Verify all phase branches are merged into milestone branch
git checkout main
git merge --squash milestone/vX.Y-slug
git commit -m "docs(milestone): complete [milestone-name]
@@ -136,7 +212,7 @@ status: complete
---/ci---"
```
## Step 5: Tag and Push
## Step 6: Tag and Push
```bash
git tag -a vX.Y.Z -m "vX.Y.Z: [phase-name or milestone-name]"
@@ -145,21 +221,21 @@ git push origin main --tags
**Tag format by milestone type:**
- NFR/Feature phase: patch format (`v0.5.1`, `v0.5.2`)
- Schema-breaking phase: minor format (`v0.3.0`, `v0.4.0`)
- Major phase: minor format (`v0.3.0`, `v0.4.0`)
- Feature milestone: next minor (`v0.6.0`, NOT `v0.5.0`)
- Schema-breaking milestone: next major (`v1.0.0`)
- Major milestone: next major (`v1.0.0`)
## Step 6: Create Release
## Step 7: Create Release and Package
**Every ship creates a Gitea release. No exceptions.**
Generate release notes from git log:
### Generate release notes
```bash
git log v[previous_tag]..vX.Y.Z --oneline
```
Create the release via Gitea API:
### Create the Gitea release
```bash
curl -X POST "https://git.cloudinit.dev/api/v1/repos/continuous-intelligence/ci/releases" \
@@ -170,14 +246,37 @@ curl -X POST "https://git.cloudinit.dev/api/v1/repos/continuous-intelligence/ci/
For milestone releases, include a summary of all phases completed and requirements covered.
## Step 7: Update .ci/ Files
### Create distribution packages
Use coreci to create the necessary distribution packages:
```bash
coreci build --tag vX.Y.Z
coreci package --tag vX.Y.Z
```
Upload packages to the Gitea release:
```bash
coreci release upload --tag vX.Y.Z --files [built-artifacts]
```
### Generate documentation
Include release notes in the Gitea release body with:
- Summary of changes
- Requirements covered
- Known issues (if any)
- Migration notes (for major milestones)
## Step 8: Update .ci/ Files
- Update `.ciagent/REQUIREMENTS.md` — mark shipped requirements as complete
- Update `.ciagent/ROADMAP.md` — mark shipped phase as complete
Commit the file updates.
## Step 8: Report
## Step 9: Report
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -185,7 +284,7 @@ Commit the file updates.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase [N]: [name]
Milestone: [vX.Y] ([nfr|feature|schema-breaking])
Milestone: [vX.Y] ([nfr|feature|major])
Version: vX.Y.Z
Release: https://git.cloudinit.dev/continuous-intelligence/ci/releases/tag/vX.Y.Z
Status: complete
@@ -193,6 +292,7 @@ Status: complete
Tests: PASS
Typecheck: PASS
Build: PASS
Pipeline: PASS
Requirements covered: [N]
Commits: [N]
+2 -2
View File
@@ -1,5 +1,5 @@
---
description: Ship CIAgent phase or milestone — test, commit, tag, push, release. Full autopilot: zero HITL after milestone setup
description: Ship CIAgent phase or milestone — Full autopilot release: validate, test, merge, tag, push, release. Zero HITL
argument-hint: "[phase_number|milestone]"
tools:
read: true
@@ -12,7 +12,7 @@ tools:
---
<execution_context>
@__OPENCODE_DIR__/ci/workflows/ship.md
@/root/.config/opencode/ci/workflows/ship.md
</execution_context>
<context>