From e26d56f82d6b4673fbeadcee0b95d985f0e6e6a9 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 09:10:04 -0700 Subject: [PATCH] =?UTF-8?q?docs(skill):=20add=20versioning=20policy=20skil?= =?UTF-8?q?l=20=E2=80=94=20prevents=20prerelease=20incidents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codifies semver versioning rules for SDK and CLI packages: - MAJOR.MINOR.PATCH only on dev/main (no prerelease suffixes) - bump-build.mjs -build.N versions are local-only, never committed - SDK + CLI versions must stay in sync (workspace resolution footgun) - Surgeon owns version bumps; other agents hands-off - prerelease-version-guard CI gate enforces the policy Motivated by PR #640 (prerelease broke workspace resolution) and PR #116 (prerelease leak on release branch). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../inbox/flight-versioning-policy.md | 32 +++++ .squad/skills/versioning-policy/SKILL.md | 119 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 .squad/decisions/inbox/flight-versioning-policy.md create mode 100644 .squad/skills/versioning-policy/SKILL.md diff --git a/.squad/decisions/inbox/flight-versioning-policy.md b/.squad/decisions/inbox/flight-versioning-policy.md new file mode 100644 index 00000000..9911fc31 --- /dev/null +++ b/.squad/decisions/inbox/flight-versioning-policy.md @@ -0,0 +1,32 @@ +# Decision: Versioning Policy — No Prerelease Versions on dev/main + +**By:** Flight (Lead) +**Date:** 2026-03-29 +**Requested by:** Dina +**Status:** DECIDED +**Confidence:** Medium (confirmed by PR #640 incident, PR #116 prerelease leak, CI gate implementation) + +## Decision + +1. **All packages use strict semver** (`MAJOR.MINOR.PATCH`). No prerelease suffixes on `dev` or `main`. +2. **Prerelease versions are ephemeral.** `bump-build.mjs` creates `-build.N` for local testing only — never committed. +3. **SDK and CLI versions must stay in sync.** Divergence silently breaks npm workspace resolution. +4. **Surgeon owns version bumps.** Other agents must not modify `version` fields in `package.json` unless fixing a prerelease leak. +5. **CI enforcement via `prerelease-version-guard`** blocks PRs with prerelease versions. `skip-version-check` label is Surgeon-only. + +## Why + +The repo had no documented versioning policy. This caused two incidents: + +- **PR #640:** Prerelease version `0.9.1-build.4` silently broke workspace resolution. The semver range `>=0.9.0` does not match prerelease versions, causing npm to install a stale registry package instead of the local workspace link. Four PRs (#637–#640) patched symptoms before the root cause was found. +- **PR #116:** Surgeon set versions to `0.9.1-build.1` instead of `0.9.1` on a release branch because there was no guidance on what constitutes a clean release version. + +## Skill Reference + +Full policy documented in `.squad/skills/versioning-policy/SKILL.md`. + +## Impact + +- All agents must follow the versioning policy when touching `package.json` +- Surgeon charter should reference this skill for release procedures +- CI pipeline enforces the policy via automated gate diff --git a/.squad/skills/versioning-policy/SKILL.md b/.squad/skills/versioning-policy/SKILL.md new file mode 100644 index 00000000..997d4c4a --- /dev/null +++ b/.squad/skills/versioning-policy/SKILL.md @@ -0,0 +1,119 @@ +--- +name: "versioning-policy" +description: "Semver versioning rules for Squad SDK and CLI — prevents prerelease version incidents" +domain: "release, versioning, npm, CI" +confidence: "medium" +source: "earned (PR #640 workspace resolution incident, PR #116 prerelease leak, CI gate implementation)" +--- + +## Context + +Squad is a monorepo with two publishable npm packages (`@bradygaster/squad-sdk` and `@bradygaster/squad-cli`) managed via npm workspaces. Version mismatches and prerelease leaks have caused production incidents — most notably PR #640, where a `-build.N` prerelease version silently broke workspace dependency resolution. + +This skill codifies the versioning rules every agent must follow. + +## 1. Version Format + +All packages use **strict semver**: `MAJOR.MINOR.PATCH` + +- ✅ `0.9.1`, `1.0.0`, `0.10.0` +- ❌ `0.9.1-build.4`, `0.9.1-preview.1`, `0.8.6.1-preview` + +No prerelease suffixes on `dev` or `main` branches — ever. + +## 2. Prerelease Versions Are Ephemeral + +The `scripts/bump-build.mjs` script creates `-build.N` versions (e.g., `0.9.1-build.4`) for **local development testing only**. + +Rules: +- `-build.N` versions are created automatically during local `npm run build` +- They are **never committed** to `dev` or `main` +- The script skips itself in CI (`CI=true` or `SKIP_BUILD_BUMP=1`) +- If you see a `-build.N` version in a PR diff, it is a bug — reject the PR + +## 3. SDK and CLI Version Sync + +Both `@bradygaster/squad-sdk` and `@bradygaster/squad-cli` **MUST have the same version** at all times. The root `package.json` version must also match. + +`bump-build.mjs` enforces this by updating all three `package.json` files in lockstep (root + `packages/squad-sdk` + `packages/squad-cli`). + +If versions diverge, workspace resolution silently breaks (see §4). + +## 4. npm Workspace Semver Footgun + +The CLI depends on the SDK via a workspace dependency with a semver range: + +```json +"@bradygaster/squad-sdk": ">=0.9.0" +``` + +**Critical:** Per the semver specification, `>=0.9.0` does **NOT** match `0.9.1-build.4`. + +Semver prerelease versions (anything with a `-` suffix) are only matched by ranges that explicitly reference the same `MAJOR.MINOR.PATCH` base with a prerelease comparator. A bare `>=0.9.0` range skips all prerelease versions. + +**What happens:** When the local SDK has version `0.9.1-build.4`, npm's workspace resolution fails to match the `>=0.9.0` range. npm then **silently installs a stale published version** from the npm registry instead of using the local workspace link. The build succeeds but runs against old SDK code. + +This is the root cause of the **PR #640 incident**, where workspace packages appeared linked but were actually running against stale registry versions. + +## 5. Who Bumps Versions + +**Surgeon (Release Manager) owns all version bumps.** + +| Agent | May modify `version` in package.json? | +|-------|---------------------------------------| +| Surgeon | ✅ Yes — sole owner of version bumps | +| Any other agent | ❌ No — unless explicitly fixing a prerelease leak | + +If you discover a prerelease version committed to `dev` or `main`, you may fix it (revert to the clean release version) without Surgeon's approval. This is a safety escape hatch, not a license to manage versions. + +## 6. Version Bump Lifecycle + +``` +┌─────────────────────────────────────────────────────────┐ +│ Development phase │ +│ Versions stay at current release: 0.9.1 │ +│ bump-build.mjs creates -build.N locally (not committed)│ +├─────────────────────────────────────────────────────────┤ +│ Pre-release testing │ +│ bump-build.mjs → 0.9.1-build.1, -build.2, ... │ +│ Local only. Never committed. Never pushed. │ +├─────────────────────────────────────────────────────────┤ +│ Release │ +│ Surgeon bumps to next version (e.g., 0.9.2 or 0.10.0) │ +│ Tags, publishes to npm registry │ +├─────────────────────────────────────────────────────────┤ +│ Post-release │ +│ Versions stay at the new release version (e.g., 0.9.2) │ +│ Development continues on clean version │ +└─────────────────────────────────────────────────────────┘ +``` + +## 7. CI Enforcement + +The **`prerelease-version-guard`** CI gate blocks any PR to `dev` or `main` that contains prerelease version strings in `package.json` files. + +- The gate scans all three `package.json` files for `-` in the version field +- PRs with prerelease versions **cannot merge** until the version is cleaned +- The `skip-version-check` label bypasses the gate — use **only** for the bump-build script's own PR (if applicable), and only with Surgeon's approval + +## 8. Incident Reference — PR #640 + +**PR #640** is the cautionary tale for this entire policy. + +**What happened:** Prerelease versions (`0.9.1-build.4`) were committed to a branch. The workspace dependency `>=0.9.0` failed to match the prerelease version per semver spec. npm silently installed a stale published SDK from the registry instead of linking the local workspace copy. Four PRs (#637–#640) attempted iterative patches before the root cause was identified. + +**Root cause:** No versioning policy existed. Agents didn't know that prerelease versions break workspace resolution, or that only Surgeon should modify versions. + +**Resolution:** This skill, the `prerelease-version-guard` CI gate, and the team decision to centralize version ownership under Surgeon. + +## Quick Reference + +| Rule | Summary | +|------|---------| +| Format | `MAJOR.MINOR.PATCH` — no prerelease on dev/main | +| Prerelease | `-build.N` is local-only, never committed | +| Sync | SDK + CLI + root must have identical versions | +| Ownership | Surgeon bumps versions; others don't touch them | +| CI gate | `prerelease-version-guard` blocks prerelease PRs | +| Escape hatch | Any agent may revert a prerelease leak to clean version | +| Footgun | `>=0.9.0` does NOT match `0.9.1-build.4` per semver |