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:
@@ -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:
|
**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 |
|
| Milestone Type | Condition | Phase release | Milestone release |
|
||||||
|---------------|-----------|---------------|-------------------|
|
|---------------|-----------|---------------|-------------------|
|
||||||
| **NFR** | All phases: fix/chore/docs/perf/refactor/test | Patch (`vX.Y.Z`) | None |
|
| **NFR** | All phases are fix/chore/docs/perf/refactor/test | Patch — `v1.8.1`, `v1.8.2`, ... | None — final patch IS the deliverable |
|
||||||
| **Feature** | Any phase is `feat`, no schema break | Patch (`vX.Y.Z`) | Minor — `vX.(Y+1).0` |
|
| **Feature** | At least one phase has new features (`feat`) | Patch — `v1.8.1`, `v1.8.2`, ... | Next minor — `v1.9.0` |
|
||||||
| **Schema-breaking** | Refactor/schema break/new direction | Minor — `vX.(Y+N).0` per phase | Major — `v(X+1).0.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:
|
**Tag rules (CRITICAL):**
|
||||||
|
- Milestone tags are always the NEXT version, never the base:
|
||||||
- Feature: patches v0.5.1–v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
|
- Feature: patches v0.5.1–v0.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
|
- Major: 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
|
- 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
|
||||||
Determine milestone type via `getMilestoneType()` which returns `"nfr" | "feature" | "schema-breaking"`.
|
- NEVER create a milestone tag that is semantically below existing phase tags
|
||||||
|
|
||||||
### Phase completion
|
### 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.)
|
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
|
```bash
|
||||||
git checkout milestone/v0.5-schema-rewrite
|
git checkout milestone/v0.5-schema-rewrite
|
||||||
git merge --squash phase/01-core-refactor
|
git merge --squash phase/01-core-refactor
|
||||||
@@ -145,7 +152,7 @@ git push origin main --tags
|
|||||||
# Create Gitea release for v0.5.0
|
# 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
|
### Milestone completion
|
||||||
|
|
||||||
@@ -160,7 +167,7 @@ git push origin main --tags
|
|||||||
# Create Gitea release for v0.6.0 with full milestone summary
|
# Create Gitea release for v0.6.0 with full milestone summary
|
||||||
```
|
```
|
||||||
|
|
||||||
**Schema-breaking (major release):**
|
**Major (major release):**
|
||||||
```bash
|
```bash
|
||||||
# All phases already merged into milestone branch
|
# All phases already merged into milestone branch
|
||||||
git checkout main
|
git checkout main
|
||||||
@@ -177,9 +184,20 @@ git push origin main --tags
|
|||||||
|
|
||||||
Before creating any tag:
|
Before creating any tag:
|
||||||
1. Tag must be strictly greater than all existing tags on the same major.minor line
|
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
|
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
|
## Multi-Project Branch Naming
|
||||||
|
|
||||||
When operating in multi-project mode (`.ciagent/config.json` has `projects[]` with length > 0):
|
When operating in multi-project mode (`.ciagent/config.json` has `projects[]` with length > 0):
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ For each stage in order (starting from current or from `specify`):
|
|||||||
- Update `.ciagent/ROADMAP.md` phase status
|
- Update `.ciagent/ROADMAP.md` phase status
|
||||||
- Commit: `docs(P##): complete [phase-name] phase`
|
- 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
|
## 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)
|
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
|
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.
|
- **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** (any feat phase): apply progressive patch versions per phase, then tag minor milestone version on completion (e.g., v0.2.0).
|
- **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
|
## Step 4: Error Recovery
|
||||||
|
|
||||||
|
|||||||
+132
-32
@@ -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
|
# CIAgent Ship
|
||||||
|
|
||||||
Ship a CIAgent phase or milestone. Every ship creates a release — no exceptions.
|
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 |
|
| Milestone Type | Condition | Phase release | Milestone release |
|
||||||
|---------------|-----------|---------------|-------------------|
|
|---------------|-----------|---------------|-------------------|
|
||||||
| **NFR** | All phases: fix/chore/docs/perf/refactor/test | Patch (`vX.Y.Z`) | None |
|
| **NFR** | All phases are fix/chore/docs/perf/refactor/test | Patch — `v1.8.1`, `v1.8.2`, ... | None — final patch IS the deliverable |
|
||||||
| **Feature** | Any phase is `feat`, no schema break | Patch (`vX.Y.Z`) | Minor — `vX.(Y+1).0` |
|
| **Feature** | At least one phase has new features (`feat`) | Patch — `v1.8.1`, `v1.8.2`, ... | Next minor — `v1.9.0` |
|
||||||
| **Schema-breaking** | Refactor/schema break/new direction | Minor — `vX.(Y+N).0` per phase | Major — `v(X+1).0.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:
|
**Tag rules (CRITICAL):**
|
||||||
|
|
||||||
|
- Milestone tags are always the NEXT version, never the base:
|
||||||
- Feature: patches v0.5.1–v0.5.5 → milestone tag is v0.6.0 (NOT v0.5.0)
|
- Feature: patches v0.5.1–v0.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
|
- Major: 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
|
- 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
|
||||||
**Usage:** `ciagent-ship [phase_number|milestone]`
|
- NEVER create a milestone tag that is semantically below existing phase tags
|
||||||
|
|
||||||
## Step 0: Confirm Active Project
|
## 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.
|
If single-project mode: proceed with existing conventions.
|
||||||
|
|
||||||
## Step 1: Pre-Flight
|
## Step 1: Pre-Flight Validation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git log --max-count=10
|
git log --max-count=10
|
||||||
git branch -a
|
git branch -a
|
||||||
|
git tag -l
|
||||||
```
|
```
|
||||||
|
|
||||||
Determine what is being shipped: a single phase or an entire milestone.
|
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.
|
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
|
## Step 2: Run Tests
|
||||||
|
|
||||||
```bash
|
```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.
|
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 |
|
| 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 | 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 | 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 | 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 | 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:
|
Phase number within the milestone determines the increment:
|
||||||
- NFR/Feature: 1st phase = .1, 2nd = .2, etc. (v0.5.1, v0.5.2)
|
- 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:**
|
**Tag validation (before creating ANY tag):**
|
||||||
1. The tag must be strictly greater than all existing tags on the same major.minor line
|
1. 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)
|
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)
|
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
|
### 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
|
### Phase ship
|
||||||
|
|
||||||
@@ -123,8 +198,9 @@ requirements:
|
|||||||
|
|
||||||
### Milestone ship (after last phase)
|
### Milestone ship (after last phase)
|
||||||
|
|
||||||
|
**Validate all phase branches are merged into the milestone branch before proceeding.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verify all phase branches are merged into milestone branch
|
|
||||||
git checkout main
|
git checkout main
|
||||||
git merge --squash milestone/vX.Y-slug
|
git merge --squash milestone/vX.Y-slug
|
||||||
git commit -m "docs(milestone): complete [milestone-name]
|
git commit -m "docs(milestone): complete [milestone-name]
|
||||||
@@ -136,7 +212,7 @@ status: complete
|
|||||||
---/ci---"
|
---/ci---"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 5: Tag and Push
|
## Step 6: Tag and Push
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git tag -a vX.Y.Z -m "vX.Y.Z: [phase-name or milestone-name]"
|
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:**
|
**Tag format by milestone type:**
|
||||||
- NFR/Feature phase: patch format (`v0.5.1`, `v0.5.2`)
|
- 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`)
|
- 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.**
|
**Every ship creates a Gitea release. No exceptions.**
|
||||||
|
|
||||||
Generate release notes from git log:
|
### Generate release notes
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git log v[previous_tag]..vX.Y.Z --oneline
|
git log v[previous_tag]..vX.Y.Z --oneline
|
||||||
```
|
```
|
||||||
|
|
||||||
Create the release via Gitea API:
|
### Create the Gitea release
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST "https://git.cloudinit.dev/api/v1/repos/continuous-intelligence/ci/releases" \
|
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.
|
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/REQUIREMENTS.md` — mark shipped requirements as complete
|
||||||
- Update `.ciagent/ROADMAP.md` — mark shipped phase as complete
|
- Update `.ciagent/ROADMAP.md` — mark shipped phase as complete
|
||||||
|
|
||||||
Commit the file updates.
|
Commit the file updates.
|
||||||
|
|
||||||
## Step 8: Report
|
## Step 9: Report
|
||||||
|
|
||||||
```
|
```
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
@@ -185,7 +284,7 @@ Commit the file updates.
|
|||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
Phase [N]: [name]
|
Phase [N]: [name]
|
||||||
Milestone: [vX.Y] ([nfr|feature|schema-breaking])
|
Milestone: [vX.Y] ([nfr|feature|major])
|
||||||
Version: vX.Y.Z
|
Version: vX.Y.Z
|
||||||
Release: https://git.cloudinit.dev/continuous-intelligence/ci/releases/tag/vX.Y.Z
|
Release: https://git.cloudinit.dev/continuous-intelligence/ci/releases/tag/vX.Y.Z
|
||||||
Status: complete
|
Status: complete
|
||||||
@@ -193,6 +292,7 @@ Status: complete
|
|||||||
Tests: PASS
|
Tests: PASS
|
||||||
Typecheck: PASS
|
Typecheck: PASS
|
||||||
Build: PASS
|
Build: PASS
|
||||||
|
Pipeline: PASS
|
||||||
|
|
||||||
Requirements covered: [N]
|
Requirements covered: [N]
|
||||||
Commits: [N]
|
Commits: [N]
|
||||||
|
|||||||
@@ -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]"
|
argument-hint: "[phase_number|milestone]"
|
||||||
tools:
|
tools:
|
||||||
read: true
|
read: true
|
||||||
@@ -12,7 +12,7 @@ tools:
|
|||||||
---
|
---
|
||||||
|
|
||||||
<execution_context>
|
<execution_context>
|
||||||
@__OPENCODE_DIR__/ci/workflows/ship.md
|
@/root/.config/opencode/ci/workflows/ship.md
|
||||||
</execution_context>
|
</execution_context>
|
||||||
|
|
||||||
<context>
|
<context>
|
||||||
|
|||||||
+4
-4
@@ -1002,7 +1002,7 @@ function computeShipVersion(
|
|||||||
projectPath: string,
|
projectPath: string,
|
||||||
phaseNum: number,
|
phaseNum: number,
|
||||||
config: CIAgentConfig
|
config: CIAgentConfig
|
||||||
): { tag: string; milestoneType: "nfr" | "feature" | "schema-breaking" } {
|
): { tag: string; milestoneType: "nfr" | "feature" | "major" } {
|
||||||
const tags = execSync("git tag -l", { cwd: projectPath, encoding: "utf-8" })
|
const tags = execSync("git tag -l", { cwd: projectPath, encoding: "utf-8" })
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map((t) => t.trim())
|
.map((t) => t.trim())
|
||||||
@@ -1029,7 +1029,7 @@ function computeShipVersion(
|
|||||||
const milestoneType = inferMilestoneType(projectPath);
|
const milestoneType = inferMilestoneType(projectPath);
|
||||||
|
|
||||||
let tag: string;
|
let tag: string;
|
||||||
if (milestoneType === "schema-breaking") {
|
if (milestoneType === "major") {
|
||||||
tag = `v${major}.${minor + phaseNum}.0`;
|
tag = `v${major}.${minor + phaseNum}.0`;
|
||||||
} else {
|
} else {
|
||||||
tag = `v${major}.${minor}.${phaseNum}`;
|
tag = `v${major}.${minor}.${phaseNum}`;
|
||||||
@@ -1038,10 +1038,10 @@ function computeShipVersion(
|
|||||||
return { tag, milestoneType };
|
return { tag, milestoneType };
|
||||||
}
|
}
|
||||||
|
|
||||||
function inferMilestoneType(projectPath: string): "nfr" | "feature" | "schema-breaking" {
|
function inferMilestoneType(projectPath: string): "nfr" | "feature" | "major" {
|
||||||
try {
|
try {
|
||||||
const log = execSync("git log --oneline -50", { cwd: projectPath, encoding: "utf-8" });
|
const log = execSync("git log --oneline -50", { cwd: projectPath, encoding: "utf-8" });
|
||||||
if (log.match(/\brefactor\b|\brewrite\b|\bmigrate\b|\brestructure\b/i)) return "schema-breaking";
|
if (log.match(/\brefactor\b|\brewrite\b|\bmigrate\b|\brestructure\b/i)) return "major";
|
||||||
if (log.match(/\bfeat\b/)) return "feature";
|
if (log.match(/\bfeat\b/)) return "feature";
|
||||||
return "nfr";
|
return "nfr";
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ describe("CIAgentFiles", () => {
|
|||||||
expect(ciFiles.getMilestoneType()).toBe("feature");
|
expect(ciFiles.getMilestoneType()).toBe("feature");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns schema-breaking when phases include refactor/rewrite/migrate", () => {
|
it("returns major when phases include refactor/rewrite/migrate", () => {
|
||||||
const ciFiles = new CIAgentFiles(dir, "schema-proj");
|
const ciFiles = new CIAgentFiles(dir, "schema-proj");
|
||||||
ciFiles.ensureProjectDir();
|
ciFiles.ensureProjectDir();
|
||||||
fs.writeFileSync(path.join(dir, ".ciagent", "config.json"), JSON.stringify({
|
fs.writeFileSync(path.join(dir, ".ciagent", "config.json"), JSON.stringify({
|
||||||
@@ -337,13 +337,13 @@ describe("CIAgentFiles", () => {
|
|||||||
active_project: "schema-proj",
|
active_project: "schema-proj",
|
||||||
}));
|
}));
|
||||||
const roadmap: RoadmapMd = {
|
const roadmap: RoadmapMd = {
|
||||||
overview: "schema-breaking",
|
overview: "major",
|
||||||
phases: [
|
phases: [
|
||||||
{ number: 1, name: "refactor-core", description: "Refactor core", status: "in_progress", dependsOn: [], requirements: [], successCriteria: [] },
|
{ number: 1, name: "refactor-core", description: "Refactor core", status: "in_progress", dependsOn: [], requirements: [], successCriteria: [] },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
ciFiles.writeRoadmapMd(roadmap);
|
ciFiles.writeRoadmapMd(roadmap);
|
||||||
expect(ciFiles.getMilestoneType()).toBe("schema-breaking");
|
expect(ciFiles.getMilestoneType()).toBe("major");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ export class CIAgentFiles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSchemaBreak) return "schema-breaking";
|
if (hasSchemaBreak) return "major";
|
||||||
if (hasFeature) return "feature";
|
if (hasFeature) return "feature";
|
||||||
return "nfr";
|
return "nfr";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,11 +192,11 @@ describe("GitBranch", () => {
|
|||||||
expect(tag).toBe("v0.6.0");
|
expect(tag).toBe("v0.6.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("computes next major for schema-breaking milestone", () => {
|
it("computes next major for major milestone", () => {
|
||||||
execSync(`git tag -a v0.5.1 -m "v0.5.1"`, { cwd: repoDir, stdio: "pipe" });
|
execSync(`git tag -a v0.5.1 -m "v0.5.1"`, { cwd: repoDir, stdio: "pipe" });
|
||||||
|
|
||||||
const gitBranch = new GitBranch(repoDir);
|
const gitBranch = new GitBranch(repoDir);
|
||||||
const tag = gitBranch.computeMilestoneTag("schema-breaking");
|
const tag = gitBranch.computeMilestoneTag("major");
|
||||||
expect(tag).toBe("v1.0.0");
|
expect(tag).toBe("v1.0.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ export class GitBranch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (milestoneType === "schema-breaking") {
|
if (milestoneType === "major") {
|
||||||
return `v${major + 1}.0.0`;
|
return `v${major + 1}.0.0`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ status: execute
|
|||||||
expect(ctx.getMilestoneType()).toBe("feature");
|
expect(ctx.getMilestoneType()).toBe("feature");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns schema-breaking when refactor commits exist", () => {
|
it("returns major when refactor commits exist", () => {
|
||||||
commit(repoDir, `refactor(P01): rewrite core
|
commit(repoDir, `refactor(P01): rewrite core
|
||||||
|
|
||||||
---ci---
|
---ci---
|
||||||
@@ -317,7 +317,7 @@ status: execute
|
|||||||
---/ci---`);
|
---/ci---`);
|
||||||
|
|
||||||
const ctx = new GitContext(repoDir);
|
const ctx = new GitContext(repoDir);
|
||||||
expect(ctx.getMilestoneType()).toBe("schema-breaking");
|
expect(ctx.getMilestoneType()).toBe("major");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -333,7 +333,7 @@ export class GitContext {
|
|||||||
if (!commit.ci) continue;
|
if (!commit.ci) continue;
|
||||||
hasAnyCiCommit = true;
|
hasAnyCiCommit = true;
|
||||||
if (commit.type === "feat") return "feature";
|
if (commit.type === "feat") return "feature";
|
||||||
if (commit.type === "refactor" || commit.scope === "init") return "schema-breaking";
|
if (commit.type === "refactor" || commit.scope === "init") return "major";
|
||||||
}
|
}
|
||||||
if (!hasAnyCiCommit) return "nfr";
|
if (!hasAnyCiCommit) return "nfr";
|
||||||
return "nfr";
|
return "nfr";
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ export type ModelProfile = "quality" | "speed" | "balanced";
|
|||||||
|
|
||||||
export type BranchingStrategy = "phase" | "feature" | "trunk";
|
export type BranchingStrategy = "phase" | "feature" | "trunk";
|
||||||
|
|
||||||
export type MilestoneType = "nfr" | "feature" | "schema-breaking";
|
export type MilestoneType = "nfr" | "feature" | "major";
|
||||||
|
|
||||||
export type PhaseName = "research" | "plan" | "execute" | "verify" | "complete";
|
export type PhaseName = "research" | "plan" | "execute" | "verify" | "complete";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user