chore(version): bring frontend/package.json into the version lockstep (0.3.6) (#497)

Pre-v0.3.6 release sweep found frontend/package.json stuck at 0.3.5 while the
other three version files were 0.3.6. package.json drives the runtime
`__APP_VERSION__` (vite.config.js), so a v0.3.6 build was calling itself "v0.3.5"
in the first-run footer AND in every auto bug report (undercutting the bug-report
feature). Root cause: the release.yml version-bump job only bumped the trio
(tauri.conf.json / Cargo.toml / pyproject.toml), never package.json, and no test
guarded the lockstep.

- Bump frontend/package.json 0.3.5 → 0.3.6 (matches the trip; `--frozen-lockfile`
  still passes — the version field doesn't affect the bun lock graph).
- Add frontend/package.json to the release.yml version-bump job (set absolutely
  via jq so any prior drift self-heals on the next release).
- Add tests/test_app_version.py::test_all_version_files_in_lockstep — fails CI if
  the four files ever diverge again.
- CLAUDE.md versioning rule updated: it's now FOUR lockstep files, not three
  (docs-sync).

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Palash Debnath
2026-06-16 17:59:44 +05:30
committed by GitHub
co-authored by mergetest Claude Opus 4.8
parent f46ea1fbf6
commit 6044765f09
4 changed files with 35 additions and 3 deletions
+7 -1
View File
@@ -725,10 +725,16 @@ jobs:
tmp=$(mktemp)
jq --arg v "$NEXT" '.version = $v' frontend/src-tauri/tauri.conf.json > "$tmp"
mv "$tmp" frontend/src-tauri/tauri.conf.json
# frontend/package.json drives __APP_VERSION__ (vite.config.js) — the
# first-run footer + every auto bug report. Keep it in lockstep too,
# set absolutely (jq) so any prior drift self-heals. (#248-sweep finding)
tmp=$(mktemp)
jq --arg v "$NEXT" '.version = $v' frontend/package.json > "$tmp"
mv "$tmp" frontend/package.json
sed -i "0,/^version = \"$CURRENT\"/s//version = \"$NEXT\"/" frontend/src-tauri/Cargo.toml
sed -i "0,/^version = \"$CURRENT\"/s//version = \"$NEXT\"/" pyproject.toml
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add frontend/src-tauri/tauri.conf.json frontend/src-tauri/Cargo.toml pyproject.toml
git add frontend/src-tauri/tauri.conf.json frontend/package.json frontend/src-tauri/Cargo.toml pyproject.toml
git commit -m "chore(version): main -> $NEXT after $GITHUB_REF_NAME release"
git push origin main
+1 -1
View File
@@ -190,7 +190,7 @@ Everything else (new engines, fancy features) is downstream of "the thing instal
<!-- GSD:conventions-start source:CONVENTIONS.md -->
## Conventions
**Versioning (hard rule, owner-set 2026-06-11):** main is always **latest release + 1 patch**. The moment `vX.Y.Z` is released, main's version files (`frontend/src-tauri/tauri.conf.json`, `frontend/src-tauri/Cargo.toml`, `pyproject.toml` — keep all three in lockstep) bump to `X.Y.(Z+1)`. Consequences:
**Versioning (hard rule, owner-set 2026-06-11):** main is always **latest release + 1 patch**. The moment `vX.Y.Z` is released, main's version files (`frontend/src-tauri/tauri.conf.json`, `frontend/src-tauri/Cargo.toml`, `pyproject.toml`, **and `frontend/package.json`** — keep all **four** in lockstep; `package.json` drives the runtime `__APP_VERSION__` via vite, shown in the first-run footer + every auto bug report, so a drift ships a build that misreports its own version — guarded by `tests/test_app_version.py::test_all_version_files_in_lockstep`) bump to `X.Y.(Z+1)`. Consequences:
- Every PR and preview build identifies as the **next** version. Preview builds stamp `X.Y.(Z+1)-N` (run number), which semver-sorts **above** the last stable `X.Y.Z` — the updater ordering is natural, no comparator tricks needed.
- Releasing = tag `vX.Y.(Z+1)` from main (version files already match), then immediately bump main to `X.Y.(Z+2)`. The post-release bump is automated by the `version-bump` job in release.yml; if it fails, do it manually in the same day.
- Docker: `ghcr.io/debpalash/omnivoice-studio:latest` = **main** (rolling preview); `:X.Y.Z` + `:X.Y` + `:stable` = tagged releases. `:latest` is the preview channel by design — stable users pin `:stable` or a version tag.
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "omnivoice-studio",
"private": true,
"version": "0.3.5",
"version": "0.3.6",
"license": "AGPL-3.0-only",
"type": "module",
"scripts": {
+26
View File
@@ -14,3 +14,29 @@ def test_app_version_matches_installed_package_metadata():
# In any synced env the package is installed; APP_VERSION must equal it
# (i.e. it's read from pyproject, not hardcoded).
assert APP_VERSION == version("omnivoice")
def test_all_version_files_in_lockstep():
"""The FOUR version files must agree: pyproject.toml,
frontend/src-tauri/{tauri.conf.json,Cargo.toml}, and frontend/package.json.
package.json drives the runtime ``__APP_VERSION__`` (vite.config.js), which
shows in the first-run footer and EVERY auto bug report — so a drift ships a
v0.3.6 build that calls itself v0.3.5. The release.yml version-bump job was
bumping only the first three; package.json drifted unnoticed. Catch it in CI.
"""
import json
from pathlib import Path
root = Path(__file__).resolve().parents[1]
def _toml_version(p: Path) -> str:
return re.search(r'(?m)^version\s*=\s*"([^"]+)"', p.read_text()).group(1)
versions = {
"pyproject.toml": _toml_version(root / "pyproject.toml"),
"Cargo.toml": _toml_version(root / "frontend/src-tauri/Cargo.toml"),
"tauri.conf.json": json.loads((root / "frontend/src-tauri/tauri.conf.json").read_text())["version"],
"package.json": json.loads((root / "frontend/package.json").read_text())["version"],
}
assert len(set(versions.values())) == 1, f"version files drifted: {versions}"