Files
msd-core/VERSIONING.md
Tom Boucher 1adf6d2245 fix(#3620): point the docs at files that actually exist (#3658)
* fix(3620): point the docs at files that actually exist

docproof found 34 stale references; the reporter hand-read all 34 and reported the 8 that
are real, explaining why the other 26 are deliberate (files the documents themselves label
legacy or "superseded by", and one pre-Diataxis link label whose target still resolves).
Those 26 are left alone — re-touching them would contradict the issue's own analysis.

Every claim was re-verified against git ls-files at HEAD before editing.

docs/INVENTORY.md said its roster is anchored by six drift-control tests. Five are gone
(commands-doc-parity, agents-doc-parity, cli-modules-doc-parity, hooks-doc-parity in
5d8a8c4d; command-count-sync in fbf30792), so the sentence now names the one that exists.
Whether one test is sufficient coverage is a maintainer question the issue explicitly
declined to answer, so no new drift tests are proposed here.

The four translations were a revision further behind, each naming a seventh test deleted in
ae8bb707 that the English file had already dropped. All four now match.

Renamed targets corrected in CONTEXT.md, VERSIONING.md, docs/CONFIGURATION.md and the
update workflow. The new test names carry no issue-NNN- prefix, which is what
lint-regression-test-names requires, so they are the correct targets.

docs/TESTING-SUITES.md is the one that could cost somebody time: it INSTRUCTED contributors
to add an acknowledgment to the legacy drift-ack file, which CONTRIBUTING.md says to never
use. Rewritten from the real workflow — per-PR fragments under the drift-acks directory,
and a spent base-side ack is re-armed by rewording that fragment's reason in place, never
by adding a duplicate, since two sources naming one path is a hard error.

docs/skills/discovery-contract.md's heading named a query module deleted in 11918dcc. The
section was REMOVED rather than retargeted: its documented behavior (skip the deprecated
root) is not what the surviving code does — skill-manifest includes that root marked
deprecated:true — so retargeting would have documented something false.

Found and fixed inline, same class: VERSIONING.md described an SDK bundling step the
release workflow does not have (zero such mentions in that file); CONFIGURATION.md and four
translations named a dead model-catalog triple collapsed by ADR-457.

Dead config removed: the changeset lint's user-facing prefix list still carried two retired
sdk entries. git ls-files -- 'sdk/*' returns nothing. No test pins that array.

Left deliberately: the comment explaining the retired catalog path, the install regression
test that reconstructs the old broken layout to prove it fails, and the generated
test-timings cache. Each is a legitimate mention of a dead path, not drift.

Note lint-removed-but-needed cannot catch this class: it diffs baseRef...HEAD, so it only
sees files deleted in the change under review. These were orphaned by PRs that predate the
lint. A repo-wide existence audit would need a suppression mechanism for the 26 deliberate
mentions above; that is a feature, not part of this fix.

Fixes #3620

* chore(3620): backfill changeset PR number (#3658)

---------

Co-authored-by: sim <sim@local>
2026-08-19 01:54:01 -04:00

161 lines
7.5 KiB
Markdown

# Versioning & Release Strategy
GSD follows [Semantic Versioning 2.0.0](https://semver.org/) with three release tiers mapped to npm dist-tags.
## Release Tiers
| Tier | What ships | Version format | npm tag | Branch | Install |
|------|-----------|---------------|---------|--------|---------|
| **Patch** | Bug fixes only | `1.27.1` | `latest` | `hotfix/1.27.1` | `npx @opengsd/gsd-core@latest` |
| **Minor** | Fixes + enhancements | `1.28.0` | `latest` (after RC) | `release/1.28.0` | `npx @opengsd/gsd-core@next` (RC) |
| **Major** | Fixes + enhancements + features | `2.0.0` | `latest` (after beta) | `release/2.0.0` | `npx @opengsd/gsd-core@next` (beta) |
## npm Dist-Tags
Only two tags, following Angular/Next.js convention:
| Tag | Meaning | Installed by |
|-----|---------|-------------|
| `latest` | Stable production release | `npm install @opengsd/gsd-core` (default) |
| `next` | Pre-release (RC or beta) | `npm install @opengsd/gsd-core@next` (opt-in) |
The version string (`-rc.1` vs `-beta.1`) communicates stability level. Users never get pre-releases unless they explicitly opt in.
## Semver Rules
| Increment | When | Examples |
|-----------|------|----------|
| **PATCH** (1.27.x) | Bug fixes, typo corrections, test additions | Hook filter fix, config corruption fix |
| **MINOR** (1.x.0) | Non-breaking enhancements, new commands, new runtime support | New workflow command, discuss-mode feature |
| **MAJOR** (x.0.0) | Breaking changes to config format, CLI flags, or runtime API; new features that alter existing behavior | Removing a command, changing config schema |
## Pre-Release Version Progression
Major and minor releases use different pre-release types:
```
Minor: 1.28.0-rc.1 → 1.28.0-rc.2 → 1.28.0
Major: 2.0.0-beta.1 → 2.0.0-beta.2 → 2.0.0
```
- **beta** (major releases only): Feature-complete but not fully tested. API mostly stable. Used for major releases to signal a longer testing cycle.
- **rc** (minor releases only): Production-ready candidate. Only critical fixes expected.
- Each version uses one pre-release type throughout its cycle. The `rc` action in the release workflow automatically selects the correct type based on the version.
## Branch Structure
```
main ← stable, always deployable
│
├── hotfix/1.27.1 ← patch: cherry-pick fix from main, publish to latest
│
├── release/1.28.0 ← minor: accumulate fixes + enhancements, RC cycle
│ ├── v1.28.0-rc.1 ← tag: published to next
│ └── v1.28.0 ← tag: promoted to latest
│
├── release/2.0.0 ← major: features + breaking changes, beta cycle
│ ├── v2.0.0-beta.1 ← tag: published to next
│ ├── v2.0.0-beta.2 ← tag: published to next
│ └── v2.0.0 ← tag: promoted to latest
│
├── fix/1200-bug-description ← bug fix branch (merges to main)
├── feat/925-feature-name ← feature branch (merges to main)
└── chore/1206-maintenance ← maintenance branch (merges to main)
```
## Release Workflows
### Patch Release (Hotfix)
For fixes that need to ship without waiting for the next minor.
A hotfix `vX.YY.Z` cumulatively includes everything in `vX.YY.{Z-1}` plus every `fix:`/`chore:` commit landed on `main` since that base. The base tag is the anchor — `git cherry $BASE_TAG main` reveals exactly which commits are still unshipped, and the new `vX.YY.Z` tag becomes the next hotfix's base, so the cycle is self-documenting.
#### How to dispatch a hotfix
Hotfixes are dispatched via the **Release workflow (`release.yml`)** with a patch version (X.Y.Z). There is no separate hotfix workflow.
1. Trigger `release.yml` with `action=create`, `version=1.27.1`, `auto_cherry_pick=true` (default).
- Workflow detects `BASE_TAG` = highest `v1.27.*` < `v1.27.1` (so `1.27.1` branches from `v1.27.0`; `1.27.2` would branch from `v1.27.1`).
- Branches `hotfix/1.27.1` from `BASE_TAG`.
- Auto-cherry-picks every `fix:`/`chore:` commit on `origin/main` not already in the base, oldest-first. Patch-equivalents are skipped via `git cherry`. `feat:`/`refactor:` are **never** auto-included.
- On conflict the workflow halts with the offending SHA. Resolve manually on the branch, then re-run finalize with `auto_cherry_pick=false`.
- Bumps `package.json`, pushes the branch, and lists every included SHA in the run summary.
2. (Optional) push additional manual commits to `hotfix/1.27.1`.
3. Trigger `release.yml` with `action=finalize`. The workflow:
- Runs `install-smoke` cross-platform gate.
- Runs full test suite + coverage.
- Promotes CHANGELOG from merged fragments.
- Tags `v1.27.1`, publishes to `@latest`, re-points `@next → v1.27.1`.
- Opens merge-back PR against `main`.
### Minor Release (Standard Cycle)
For accumulated fixes and enhancements.
1. Trigger `release.yml` with action `create` and version (e.g., `1.28.0`)
2. Workflow creates `release/1.28.0` branch from main, bumps package.json
3. Trigger `release.yml` with action `rc` to publish `1.28.0-rc.1` to `next`
4. Test the RC: `npx @opengsd/gsd-core@next`
5. If issues found: fix on release branch, publish `rc.2`, `rc.3`, etc.
6. Trigger `release.yml` with action `finalize` — publishes `1.28.0` to `latest`
7. Merge release branch to main
### Major Release
Same as minor but uses `-beta.N` instead of `-rc.N`, signaling a longer testing cycle.
1. Trigger `release.yml` with action `create` and version (e.g., `2.0.0`)
2. Trigger `release.yml` with action `rc` to publish `2.0.0-beta.1` to `next`
3. If issues found: fix on release branch, publish `beta.2`, `beta.3`, etc.
4. Trigger `release.yml` with action `finalize` -- publishes `2.0.0` to `latest`
5. Merge release branch to main
## Conventional Commits
Branch names map to commit types:
| Branch prefix | Commit type | Version bump |
|--------------|-------------|-------------|
| `fix/` | `fix:` | PATCH |
| `feat/` | `feat:` | MINOR |
| `hotfix/` | `fix:` | PATCH (immediate) |
| `chore/` | `chore:` | none |
| `docs/` | `docs:` | none |
| `refactor/` | `refactor:` | none |
## Manifest Version Sync
Certain runtime-integration manifests carry a `version` field that must always
match `package.json`:
- `.claude-plugin/plugin.json` — Claude Code plugin manifest (issue #766)
- `gemini-extension.json` — Gemini CLI extension manifest (issue #775)
- `.claude-plugin/marketplace.json` — Claude plugin marketplace manifest; its
version lives at `plugins[0].version` and is stamped via a nested versionKey
descriptor (issue #1855)
The `version` npm lifecycle script (`scripts/sync-manifest-versions.cjs --stage`)
stamps these files automatically on every `npm version` call, and stages them so
they are included in the release commit alongside `package.json`.
To add a new manifest that must track the package version, register its path
(and, if its version field is not top-level, its dotted `versionKey`) in the
`VERSIONED_MANIFESTS` array in `scripts/sync-manifest-versions.cjs`. A
regression test (`tests/manifest-version-sync.test.cjs`) enforces this:
it scans all committed JSON files for a matching `version` field and fails if any
are missing from the registry.
## Publishing Commands (Reference)
```bash
# Stable release (sets latest tag automatically)
npm publish
# Pre-release (must use --tag to avoid overwriting latest)
npm publish --tag next
# Verify what latest and next point to
npm dist-tag ls @opengsd/gsd-core
```