Release channels¶
The three TraceApps (CookTrace, LiftTrace, NutriTrace) publish across three parallel channels. Same model for all of them.
Stable¶
Regular releases follow strict MAJOR.MINOR.PATCH semver. Every stable release:
- Lives on the app's GitHub Releases page marked "Latest" (for example
v1.2.3). - Publishes multi-arch Docker images tagged
:X.Y.Z,:X.Y,:X, and:latest. - Uploads a signed Android APK to the release assets.
- Bumps
package.json,src/lib/version.js, AndroidversionCode+versionName, and adds aCHANGELOG.mdblock.
Stable is what non-tester users install. If a tag is not stable, it will not be marked "Latest" on GitHub.
dev-latest (rolling)¶
dev-latest is a floating GitHub pre-release. Every dev-worthy build overwrites the same tag with a fresh APK; no version bump, no CHANGELOG entry, no release notes. It is the primary channel for testers who want "always the newest thing."
The :dev Docker tag is the equivalent on the container side. It auto-publishes on every push to the dev branch. dev-latest and :dev refresh in step.
Silent overwrite is the whole point. Doc fixes, small refactors, incremental improvements, and iteration on in-flight features all land here without any release-notes ceremony. If a tester's install upgrade path is "redownload the APK and reinstall," they get the newest thing every time.
Milestone v<version>-dev.N¶
Numbered dev pre-releases exist for feature milestones testers should be able to pin, install intentionally, or reference by name in bug reports. Examples: a new AI capability, a new wearable integration, a big backup change.
Each numbered milestone gets:
- A permanent GitHub pre-release at
v<version>-dev.Nwith tester-facing notes. - A
## [X.Y.Z-dev.N] - <date>block inCHANGELOG.md, capturing the delta since the previous milestone or the last stable. - A version bump in
package.jsonandsrc/lib/version.js. AndroidversionCodeandversionNameare NOT bumped on dev iterations. - A Docker tag
ghcr.io/traceapps/<app>:X.Y.Z-dev.Nalongside:dev. - A refresh of
dev-latestto point at the same commit.
The <version> reflects what will land as the next stable release. After NT v1.0.3, the next milestone dev build is v1.0.4-dev.1 (patch-worthy) or v1.1.0-dev.1 (minor-worthy).
How Docker tags map¶
| Tag | Channel | Updates when |
|---|---|---|
:X.Y.Z (e.g. 1.2.3) |
Stable | Never; immutable pin |
:X.Y (e.g. 1.2) |
Stable | Any 1.2.z patch release |
:X (e.g. 1) |
Stable | Any 1.y.z minor or patch |
:latest |
Stable | Every stable release |
:X.Y.Z-dev.N |
Milestone dev | Never; immutable pin to that milestone |
:dev |
Rolling dev | Every push to the dev branch |
Legacy :X.Y.Z-rc.N tags from before the semver switch remain in the registry; no new -rc tags are cut.
How Android APKs map¶
All APKs, stable and dev, are signed with the shared TraceApps keystore. That has two consequences:
- Upgrades work in place. A newer APK installs straight over an older one. Local SQLite, cached images, and preferences all survive.
- Cross-channel upgrades work too. Moving from stable to
dev-latest, from a numbered milestone to stable, or fromdev-latestto a milestone does not wipe anything, because Android checks the signing key, not the channel.
Downgrades still fail. Android refuses an APK with a lower versionCode, and a forced downgrade via uninstall wipes the app's private storage. Back up first via Settings if you plan to move backwards.
How to pick¶
- Most testers: install
dev-latestand let it float. Redownload from the same URL whenever you want the newest build. - Reporting a bug: if the maintainer asked you to try a specific milestone, or you want a stable label to reference, install a numbered
v<version>-dev.N. - Everyone else: install the latest stable release. It is what non-tester users are running.