diff --git a/.claude/agent-memory/archgate-developer/MEMORY.md b/.claude/agent-memory/archgate-developer/MEMORY.md index c0c79134..c4ae6e2a 100644 --- a/.claude/agent-memory/archgate-developer/MEMORY.md +++ b/.claude/agent-memory/archgate-developer/MEMORY.md @@ -14,6 +14,7 @@ Skipping steps 2 or 3 is a workflow violation. The user should NEVER have to inv - **Minimum version** (`>=1.2.21`): Enforced in `src/cli.ts`, documented in CLAUDE.md "Technology Stack". This is the user-facing requirement. - **Pinned version** (`1.3.14`): Set in `.prototools`, referenced in ADR risk sections (ARCH-005, ARCH-006) and CLAUDE.md "Toolchain" section. This is the dev toolchain version. +- **Pre-1.0 release bump policy**: breaking changes bump MINOR, not major — enforced by the `getNextVersion` cap in `.simple-release.js`. v1.0.0 must be an explicit decision (force via the `version` bump option), never an automatic consequence of a `feat!` commit. - These are intentionally different. When upgrading the pinned version, update `.prototools` + ADR risk sections + CLAUDE.md toolchain. Do NOT change the minimum unless a new Bun API is required. ## Git Workflow diff --git a/.simple-release.js b/.simple-release.js index df59a555..fc22ab3e 100644 --- a/.simple-release.js +++ b/.simple-release.js @@ -3,6 +3,36 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { NpmProject } from "@simple-release/npm"; class ArchgateProject extends NpmProject { + /** + * Pre-1.0 semver policy: breaking changes bump the MINOR version, not + * the major. The project ships no support guarantees yet, so v1.0.0 + * must be an explicit decision — force it via the `version` (or `as`) + * bump option when the time comes — never an automatic consequence of + * a `feat!`/BREAKING CHANGE commit landing on main. + * + * `bump()` derives its version from this method, so capping here keeps + * the manifest writes, changelog, release PR title, and tag consistent. + */ + async getNextVersion(options) { + const next = await super.getNextVersion(options); + + // Respect explicit overrides and no-op results. + if (!next || options?.version || options?.as) { + return next; + } + + const current = await this.manifest.getVersion(); + const isPreMajor = current?.startsWith("0."); + const bumpsToMajor = !next.startsWith("0."); + + if (isPreMajor && bumpsToMajor) { + const minor = Number(current.split(".")[1] ?? 0); + return `0.${minor + 1}.0`; + } + + return next; + } + async bump(options) { const result = await super.bump(options);