feat(P06): 3-tier versioning, branch hierarchy enforcement, ARCHITECTURE-PLAN synthesis
---ci---
phase: 6
milestone: v0.5
status: complete
decisions:
- id: D-006
decision: Research as intermediate work product
rationale: Conclusions update .ci/ files; full research doc intentionally not preserved
confidence: 0.90
- id: D-007
decision: Branch hierarchy enforcement: main > milestone > phase
rationale: Prevents out-of-order merges and semantically wrong tags
confidence: 0.92
- id: D-008
decision: 3-tier versioning: NFR/feature/schema-breaking
rationale: Patch per phase (NFR/feature) or minor per phase (schema-breaking); milestone gets minor (feature) or major (schema-breaking)
confidence: 0.95
requirements:
covered: [VER-06, BRANCH-01, BRANCH-02, ARCH-01]
---/ci---
- Synthesize ARCHITECTURE-PLAN.md into .ci/ci/ARCHITECTURE.md (expanded 51→230 lines)
- Add D-006/D-007/D-008 to .ci/ci/PROJECT.md key decisions table
- Delete ARCHITECTURE-PLAN.md after synthesis
- Rewrite ship.md with 3-tier versioning model + branch hierarchy merge flows
- Rewrite branch-strategy.md with 3-tier versioning + branch hierarchy + version validation
- Add MilestoneType to config types
- Replace isNfrMilestone() with getMilestoneType() returning nfr|feature|schema-breaking
- Add validateMergeOrder(), mergeMilestoneBranch(), computeMilestoneTag() to GitBranch
- Add computeShipVersion(), validateVersionOrder(), resolveMergeTarget() to ship command
- Remove hardcoded v0.5. from error-recovery rollback
- Create .githooks/pre-push for semver ordering + branch hierarchy validation
- Add 15 new tests (370 total, all passing)
This commit is contained in:
+19
-6
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { writeFile, readFile, ensureDir, fileExists } from "../utils/file.js";
|
||||
import { PipelineStage } from "../types/pipeline.js";
|
||||
import { MilestoneType } from "../types/config.js";
|
||||
|
||||
const CI_DIR = ".ci";
|
||||
|
||||
@@ -467,19 +468,31 @@ export class CiFiles {
|
||||
this.writeRoadmapMd(roadmap);
|
||||
}
|
||||
|
||||
isNfrMilestone(): boolean {
|
||||
getMilestoneType(): MilestoneType {
|
||||
const roadmap = this.readRoadmapMd();
|
||||
if (!roadmap) return true;
|
||||
if (!roadmap) return "nfr";
|
||||
|
||||
const nfrTypes: string[] = ["fix", "chore", "docs", "perf", "refactor", "test"];
|
||||
const schemaBreakKeywords: string[] = ["refactor", "rewrite", "rearchitecture", "migrate", "restructure"];
|
||||
let hasFeature = false;
|
||||
let hasSchemaBreak = false;
|
||||
|
||||
for (const phase of roadmap.phases) {
|
||||
if (phase.status === "in_progress" || phase.status === "not_started") {
|
||||
if (phase.status === "in_progress" || phase.status === "not_started" || phase.status === "complete") {
|
||||
const phaseName = phase.name.toLowerCase();
|
||||
const hasFeature = !nfrTypes.some((t) => phaseName.includes(t)) && !phaseName.includes("bug") && !phaseName.includes("tune") && !phaseName.includes("refresh");
|
||||
if (hasFeature) return false;
|
||||
const isNfr = nfrTypes.some((t) => phaseName.includes(t)) || phaseName.includes("bug") || phaseName.includes("tune") || phaseName.includes("refresh");
|
||||
if (!isNfr) hasFeature = true;
|
||||
if (schemaBreakKeywords.some((k) => phaseName.includes(k))) hasSchemaBreak = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
if (hasSchemaBreak) return "schema-breaking";
|
||||
if (hasFeature) return "feature";
|
||||
return "nfr";
|
||||
}
|
||||
|
||||
isNfrMilestone(): boolean {
|
||||
return this.getMilestoneType() === "nfr";
|
||||
}
|
||||
|
||||
private parseProjectMd(content: string): ProjectMd {
|
||||
|
||||
Reference in New Issue
Block a user