Skip to content

Commit 56e9d80

Browse files
authored
feat: decouple STANDARDS_VERSION from meta release VERSION (#66)
* feat: decouple STANDARDS_VERSION from meta release VERSION Add STANDARDS_VERSION file (1.10.0) as the single source of truth for the ecosystem standards surface. The drift checker and scaffold now read this file instead of VERSION, so registry additions and other meta-repo releases no longer force a fleet-wide re-stamp. - Add STANDARDS_VERSION at repo root containing 1.10.0 - Update scripts/drift_check/cli.py to read STANDARDS_VERSION - Update scaffold/create-tool.py to stamp from STANDARDS_VERSION - Update standards/versioning.md to define both files and when each moves - Bump VERSION to 1.12.0 Signed-off-by: fOuttaMyPaint <154358121+TMHSDigital@users.noreply.github.com> * fix: update test fixtures to write STANDARDS_VERSION instead of VERSION Signed-off-by: fOuttaMyPaint <154358121+TMHSDigital@users.noreply.github.com> --------- Signed-off-by: fOuttaMyPaint <154358121+TMHSDigital@users.noreply.github.com>
1 parent 44aacdc commit 56e9d80

7 files changed

Lines changed: 38 additions & 25 deletions

File tree

STANDARDS_VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.10.0

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.11.0
1+
1.12.0

scaffold/create-tool.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121

2222
TEMPLATES_DIR = Path(__file__).parent / "templates"
23-
VERSION_FILE = Path(__file__).parent.parent / "VERSION"
23+
STANDARDS_VERSION_FILE = Path(__file__).parent.parent / "STANDARDS_VERSION"
2424

2525
LICENSE_FILES = {
2626
"cc-by-nc-nd-4.0": "CC-BY-NC-ND-4.0",
@@ -42,23 +42,23 @@ def slugify(name: str) -> str:
4242

4343

4444
def read_standards_version() -> str:
45-
"""Read the meta-repo VERSION at generation time.
45+
"""Read the meta-repo STANDARDS_VERSION at generation time.
4646
4747
New tool repos are pre-aligned with the current standards version, so the
48-
value here is not a runtime decision. If VERSION is missing or unreadable,
49-
fail loudly rather than silently substituting a default - a wrong version
50-
would defeat the drift-checker invariant.
48+
value here is not a runtime decision. If STANDARDS_VERSION is missing or
49+
unreadable, fail loudly rather than silently substituting a default - a
50+
wrong version would defeat the drift-checker invariant.
5151
"""
5252
try:
53-
raw = VERSION_FILE.read_text(encoding="utf-8").strip()
53+
raw = STANDARDS_VERSION_FILE.read_text(encoding="utf-8").strip()
5454
except FileNotFoundError:
5555
print(
56-
f"Error: VERSION file not found at {VERSION_FILE}. "
56+
f"Error: STANDARDS_VERSION file not found at {STANDARDS_VERSION_FILE}. "
5757
"The scaffold must run from a working copy of Developer-Tools-Directory."
5858
)
5959
sys.exit(1)
6060
except OSError as e:
61-
print(f"Error: could not read {VERSION_FILE}: {e}")
61+
print(f"Error: could not read {STANDARDS_VERSION_FILE}: {e}")
6262
sys.exit(1)
6363
if not re.fullmatch(r"\d+\.\d+\.\d+", raw):
6464
print(

scripts/drift_check/cli.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,19 @@
8686

8787

8888
def _find_repo_root() -> Path:
89-
"""Walk up from this file to the repo that contains ``VERSION``."""
89+
"""Walk up from this file to the repo that contains ``STANDARDS_VERSION``."""
9090
here = Path(__file__).resolve()
9191
for candidate in (here.parent, *here.parents):
92-
if (candidate / "VERSION").is_file():
92+
if (candidate / "STANDARDS_VERSION").is_file():
9393
return candidate
9494
return here.parents[2]
9595

9696

9797
def _read_meta_version(repo_root: Path) -> Version:
98-
raw = (repo_root / "VERSION").read_text(encoding="utf-8").strip()
98+
raw = (repo_root / "STANDARDS_VERSION").read_text(encoding="utf-8").strip()
9999
v = parse_version(raw)
100100
if v is None:
101-
raise SystemExit(f"meta-repo VERSION is not a valid semver: {raw!r}")
101+
raise SystemExit(f"meta-repo STANDARDS_VERSION is not a valid semver: {raw!r}")
102102
return v
103103

104104

@@ -199,7 +199,7 @@ def build_parser() -> argparse.ArgumentParser:
199199
default=None,
200200
help=(
201201
"path to the meta-repo root for resolving standards/*.md references "
202-
"(defaults to the repo that contains VERSION)"
202+
"(defaults to the repo that contains STANDARDS_VERSION)"
203203
),
204204
)
205205
p.add_argument(
@@ -355,7 +355,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
355355
except SystemExit:
356356
raise
357357
except Exception as exc: # pragma: no cover - defensive
358-
print(f"error: cannot read VERSION: {exc}", file=sys.stderr)
358+
print(f"error: cannot read STANDARDS_VERSION: {exc}", file=sys.stderr)
359359
return 2
360360

361361
try:

standards/versioning.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,24 @@ The release workflow auto-generates release notes grouped by commit type:
7272

7373
`CHANGELOG.md` is maintained manually for curated, human-readable release history. It is not auto-generated.
7474

75-
## What a MINOR bump means for ecosystem standards
75+
## Two version files in the meta-repo
7676

77-
The meta-repo's `VERSION` file carries the ecosystem-wide standards version. It follows the same SemVer rules, but each component has a second, standards-specific meaning for tool repos that embed a `standards-version` signal in their agent files.
77+
The meta-repo root contains two separate version files that serve distinct purposes and move independently.
7878

79-
- **MAJOR** (e.g., `1.x.y``2.0.0`) — an incompatible change to the standards themselves. New required elements, removed fields, or restructured file conventions that existing tool repos will fail to validate against without re-alignment.
80-
- **MINOR** (e.g., `1.6.x``1.7.0`) — ecosystem standards changed in a way that tool repos need to re-align with. Typical triggers: new required elements in agent files, changed frontmatter schemas, new required standards references, restructured validation rules, or new checks in the drift checker that introduce findings for existing tool-repo content. A mechanical rollout session across the tool repos is typically scheduled after a MINOR bump.
81-
- **PATCH** (e.g., `1.7.0``1.7.1`) — bug fixes, clarifications, or additions that do not change the standards surface. Tool repos with a PATCH-behind signal are reported as `info` by the drift checker — visible in verbose runs but not blocking CI.
79+
### `VERSION` - meta-repo release version
8280

83-
The drift checker enforces this mapping via the `same-major-minor` signal policy (see `standards/drift-checker.config.json`). Tool repos whose `standards-version` differs from the meta-repo's `VERSION` in MAJOR or MINOR are reported as `error`; PATCH differences are `info`; tool values ahead of meta are `warn` (either an in-flight rollout or a missed meta-repo bump, both worth surfacing).
81+
Tracks the release history of the meta-repo itself (registry additions, scaffold changes, doc updates, new CI workflows). Bumped by `release.yml` on every qualifying push to `main` using the same conventional-commit rules as tool repos. Registry additions (`feat:`) force a MINOR bump here. This number appears in GitHub Releases and the release changelog but has no direct meaning to tool repos.
82+
83+
### `STANDARDS_VERSION` - ecosystem standards surface version
84+
85+
Tracks the version of the standards that tool repos are expected to comply with. Tool repos embed this value in their `<!-- standards-version: X.Y.Z -->` markers in CLAUDE.md, AGENTS.md, and ROADMAP.md. The drift checker compares each tool repo's embedded marker against this file, not against `VERSION`.
86+
87+
`STANDARDS_VERSION` moves **only** when the standards surface actually changes in a way that requires tool repos to update:
88+
89+
- **MAJOR** (e.g., `1.x.y` to `2.0.0`) - an incompatible change to the standards themselves. New required elements, removed fields, or restructured file conventions that existing tool repos will fail to validate against without re-alignment.
90+
- **MINOR** (e.g., `1.6.x` to `1.7.0`) - standards changed in a way that tool repos need to re-align with. Typical triggers: new required elements in agent files, changed frontmatter schemas, new required standards references, restructured validation rules, or new checks in the drift checker that introduce findings for existing tool-repo content. A fleet-wide re-stamp session is typically scheduled after a MINOR bump.
91+
- **PATCH** (e.g., `1.7.0` to `1.7.1`) - clarifications or additions that do not change the standards surface. Tool repos with a PATCH-behind marker are reported as `info` by the drift checker - visible in verbose runs but not blocking CI.
92+
93+
Registry-only changes, scaffold improvements, docs additions, and other meta-repo work that does not change what tool repos are required to contain **do not** bump `STANDARDS_VERSION`, even if they bump `VERSION`.
94+
95+
The drift checker enforces this mapping via the `same-major-minor` signal policy (see `standards/drift-checker.config.json`). Tool repos whose `standards-version` marker differs from `STANDARDS_VERSION` in MAJOR or MINOR are reported as `error`; PATCH differences are `info`; tool values ahead of meta are `warn`.

tests/test_cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010
@pytest.fixture
1111
def meta_repo(tmp_path: Path) -> Path:
12-
"""Isolated meta-repo for CLI tests. Pins meta VERSION to 1.6.3 so that
12+
"""Isolated meta-repo for CLI tests. Pins STANDARDS_VERSION to 1.6.3 so that
1313
the on-disk fixtures (which still carry 1.6.3 signals) read as clean."""
1414
root = tmp_path / "meta"
1515
root.mkdir()
16-
(root / "VERSION").write_text("1.6.3", encoding="utf-8")
16+
(root / "STANDARDS_VERSION").write_text("1.6.3", encoding="utf-8")
1717
(root / "standards").mkdir()
1818
(root / "standards" / "required-refs.json").write_text(
1919
'{"version": 1, "requirements": {"cursor-plugin": {}, "mcp-server": {}}}',

tests/test_cli_remote_flags.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
def meta_repo(tmp_path: Path) -> Path:
1717
root = tmp_path / "meta"
1818
root.mkdir()
19-
(root / "VERSION").write_text("1.6.3", encoding="utf-8")
19+
(root / "STANDARDS_VERSION").write_text("1.6.3", encoding="utf-8")
2020
(root / "standards").mkdir()
2121
(root / "standards" / "required-refs.json").write_text(
2222
'{"version": 1, "requirements": {"cursor-plugin": {}, "mcp-server": {}}}',
@@ -48,7 +48,7 @@ def test_remote_without_token_errors(capsys, meta_repo: Path, monkeypatch):
4848
def test_all_without_registry_errors(capsys, tmp_path: Path):
4949
bare = tmp_path / "bare-meta"
5050
bare.mkdir()
51-
(bare / "VERSION").write_text("1.6.3", encoding="utf-8")
51+
(bare / "STANDARDS_VERSION").write_text("1.6.3", encoding="utf-8")
5252
rc = cli.main([
5353
"--all",
5454
"--meta-repo", str(bare),

0 commit comments

Comments
 (0)