From f4780887976d76a37a49562dde7ff1cfc9727be9 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Mon, 1 Jun 2026 15:29:43 +0000 Subject: [PATCH] =?UTF-8?q?refactor(P06):=20rename=20milestone=20type=20sc?= =?UTF-8?q?hema-breaking=20=E2=86=92=20major,=20reinforce=20release=20flow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---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--- --- opencode/ci/references/branch-strategy.md | 46 ++++-- opencode/ci/workflows/run.md | 11 +- opencode/ci/workflows/ship.md | 164 +++++++++++++++++----- opencode/command/ci-ship.md | 4 +- src/cli/commands.ts | 8 +- src/core/ciagent-files.test.ts | 6 +- src/core/ciagent-files.ts | 2 +- src/core/git-branch.test.ts | 4 +- src/core/git-branch.ts | 2 +- src/core/git-context.test.ts | 4 +- src/core/git-context.ts | 2 +- src/types/config.ts | 2 +- 12 files changed, 187 insertions(+), 68 deletions(-) diff --git a/opencode/ci/references/branch-strategy.md b/opencode/ci/references/branch-strategy.md index 78d3246..250e549 100644 --- a/opencode/ci/references/branch-strategy.md +++ b/opencode/ci/references/branch-strategy.md @@ -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.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"`. +**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) + - 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): diff --git a/opencode/ci/workflows/run.md b/opencode/ci/workflows/run.md index e626393..c34be9a 100644 --- a/opencode/ci/workflows/run.md +++ b/opencode/ci/workflows/run.md @@ -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 diff --git a/opencode/ci/workflows/ship.md b/opencode/ci/workflows/ship.md index 5ac0ba8..743efe9 100644 --- a/opencode/ci/workflows/ship.md +++ b/opencode/ci/workflows/ship.md @@ -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.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 +**Tag rules (CRITICAL):** -**Usage:** `ciagent-ship [phase_number|milestone]` +- 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) + - 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 --head --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 --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] diff --git a/opencode/command/ci-ship.md b/opencode/command/ci-ship.md index bf827bb..b338539 100644 --- a/opencode/command/ci-ship.md +++ b/opencode/command/ci-ship.md @@ -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: --- -@__OPENCODE_DIR__/ci/workflows/ship.md +@/root/.config/opencode/ci/workflows/ship.md diff --git a/src/cli/commands.ts b/src/cli/commands.ts index 8ee1a23..ea03ed8 100644 --- a/src/cli/commands.ts +++ b/src/cli/commands.ts @@ -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 { diff --git a/src/core/ciagent-files.test.ts b/src/core/ciagent-files.test.ts index 31c0af4..54ec195 100644 --- a/src/core/ciagent-files.test.ts +++ b/src/core/ciagent-files.test.ts @@ -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"); }); }); diff --git a/src/core/ciagent-files.ts b/src/core/ciagent-files.ts index 73614c5..a1fcaa9 100644 --- a/src/core/ciagent-files.ts +++ b/src/core/ciagent-files.ts @@ -486,7 +486,7 @@ export class CIAgentFiles { } } - if (hasSchemaBreak) return "schema-breaking"; + if (hasSchemaBreak) return "major"; if (hasFeature) return "feature"; return "nfr"; } diff --git a/src/core/git-branch.test.ts b/src/core/git-branch.test.ts index f0606ca..45ceb9e 100644 --- a/src/core/git-branch.test.ts +++ b/src/core/git-branch.test.ts @@ -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"); }); diff --git a/src/core/git-branch.ts b/src/core/git-branch.ts index b2c49e0..046cee9 100644 --- a/src/core/git-branch.ts +++ b/src/core/git-branch.ts @@ -242,7 +242,7 @@ export class GitBranch { } } - if (milestoneType === "schema-breaking") { + if (milestoneType === "major") { return `v${major + 1}.0.0`; } diff --git a/src/core/git-context.test.ts b/src/core/git-context.test.ts index 1455868..b7542ac 100644 --- a/src/core/git-context.test.ts +++ b/src/core/git-context.test.ts @@ -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"); }); }); }); \ No newline at end of file diff --git a/src/core/git-context.ts b/src/core/git-context.ts index b636e8d..0fd804d 100644 --- a/src/core/git-context.ts +++ b/src/core/git-context.ts @@ -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"; diff --git a/src/types/config.ts b/src/types/config.ts index 02ffefa..96bb66c 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -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";