* 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 infbf30792), 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 inae8bb707that 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 in11918dcc. 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>
7.5 KiB
Versioning & Release Strategy
GSD follows Semantic Versioning 2.0.0 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
rcaction 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.
- Trigger
release.ymlwithaction=create,version=1.27.1,auto_cherry_pick=true(default).- Workflow detects
BASE_TAG= highestv1.27.*<v1.27.1(so1.27.1branches fromv1.27.0;1.27.2would branch fromv1.27.1). - Branches
hotfix/1.27.1fromBASE_TAG. - Auto-cherry-picks every
fix:/chore:commit onorigin/mainnot already in the base, oldest-first. Patch-equivalents are skipped viagit 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.
- Workflow detects
- (Optional) push additional manual commits to
hotfix/1.27.1. - Trigger
release.ymlwithaction=finalize. The workflow:- Runs
install-smokecross-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.
- Runs
Minor Release (Standard Cycle)
For accumulated fixes and enhancements.
- Trigger
release.ymlwith actioncreateand version (e.g.,1.28.0) - Workflow creates
release/1.28.0branch from main, bumps package.json - Trigger
release.ymlwith actionrcto publish1.28.0-rc.1tonext - Test the RC:
npx @opengsd/gsd-core@next - If issues found: fix on release branch, publish
rc.2,rc.3, etc. - Trigger
release.ymlwith actionfinalize— publishes1.28.0tolatest - Merge release branch to main
Major Release
Same as minor but uses -beta.N instead of -rc.N, signaling a longer testing cycle.
- Trigger
release.ymlwith actioncreateand version (e.g.,2.0.0) - Trigger
release.ymlwith actionrcto publish2.0.0-beta.1tonext - If issues found: fix on release branch, publish
beta.2,beta.3, etc. - Trigger
release.ymlwith actionfinalize-- publishes2.0.0tolatest - 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 atplugins[0].versionand 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)
# 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