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:
|
||||
|
||||
### 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:
|
||||
**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)
|
||||
- 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"`.
|
||||
- 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):
|
||||
|
||||
@@ -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
@@ -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:
|
||||
**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)
|
||||
- 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
|
||||
|
||||
**Usage:** `ciagent-ship [phase_number|milestone]`
|
||||
- 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]
|
||||
|
||||
@@ -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>
|
||||
|
||||
+4
-4
@@ -1002,7 +1002,7 @@ function computeShipVersion(
|
||||
projectPath: string,
|
||||
phaseNum: number,
|
||||
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" })
|
||||
.split("\n")
|
||||
.map((t) => t.trim())
|
||||
@@ -1029,7 +1029,7 @@ function computeShipVersion(
|
||||
const milestoneType = inferMilestoneType(projectPath);
|
||||
|
||||
let tag: string;
|
||||
if (milestoneType === "schema-breaking") {
|
||||
if (milestoneType === "major") {
|
||||
tag = `v${major}.${minor + phaseNum}.0`;
|
||||
} else {
|
||||
tag = `v${major}.${minor}.${phaseNum}`;
|
||||
@@ -1038,10 +1038,10 @@ function computeShipVersion(
|
||||
return { tag, milestoneType };
|
||||
}
|
||||
|
||||
function inferMilestoneType(projectPath: string): "nfr" | "feature" | "schema-breaking" {
|
||||
function inferMilestoneType(projectPath: string): "nfr" | "feature" | "major" {
|
||||
try {
|
||||
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";
|
||||
return "nfr";
|
||||
} catch {
|
||||
|
||||
@@ -329,7 +329,7 @@ describe("CIAgentFiles", () => {
|
||||
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");
|
||||
ciFiles.ensureProjectDir();
|
||||
fs.writeFileSync(path.join(dir, ".ciagent", "config.json"), JSON.stringify({
|
||||
@@ -337,13 +337,13 @@ describe("CIAgentFiles", () => {
|
||||
active_project: "schema-proj",
|
||||
}));
|
||||
const roadmap: RoadmapMd = {
|
||||
overview: "schema-breaking",
|
||||
overview: "major",
|
||||
phases: [
|
||||
{ number: 1, name: "refactor-core", description: "Refactor core", status: "in_progress", dependsOn: [], requirements: [], successCriteria: [] },
|
||||
],
|
||||
};
|
||||
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";
|
||||
return "nfr";
|
||||
}
|
||||
|
||||
@@ -192,11 +192,11 @@ describe("GitBranch", () => {
|
||||
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" });
|
||||
|
||||
const gitBranch = new GitBranch(repoDir);
|
||||
const tag = gitBranch.computeMilestoneTag("schema-breaking");
|
||||
const tag = gitBranch.computeMilestoneTag("major");
|
||||
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`;
|
||||
}
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ status: execute
|
||||
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
|
||||
|
||||
---ci---
|
||||
@@ -317,7 +317,7 @@ status: execute
|
||||
---/ci---`);
|
||||
|
||||
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;
|
||||
hasAnyCiCommit = true;
|
||||
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";
|
||||
return "nfr";
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export type ModelProfile = "quality" | "speed" | "balanced";
|
||||
|
||||
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";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user