What would be covered
Within one stable line (for example 1.x), these do not change in a breaking way:
Adding a field, route, flag or variable is not a breaking change. Removing or renaming one, or changing its meaning, is.
What would not be covered
- Experimental and beta features, including everything behind
APP_EXPERIMENTAL. See Experimental features. They can change or be removed in any release, with a note in the changelog. - Fields whose name starts with
x-. They are for tooling and may change at any time. - Undocumented routes, flags, variables and database tables. The SQLite schema is internal. Use the API.
- Multi-node and WireGuard mesh behavior while they are labelled beta in Feature status.
- Dashboard layout, copy and keyboard shortcuts.
- Generated pages such as the template catalog. Templates can be added, changed or retired.
Deprecation window
A covered item that is deprecated stays for at least two minor releases after the release that deprecates it. During that time:- The item still works as before.
- Using it produces a visible warning: a response header for the API, a line on stderr for the CLI, a log line at start for a variable or spec field.
- The docs page for the item carries a deprecation note naming the replacement and the first release that may remove it.
- The changelog lists it under the deprecating release.
Security fixes
Proposed, to be confirmed before this policy takes effect:- The latest stable minor gets security fixes as patch releases.
- The previous minor gets fixes for high and critical issues while it is inside its two-minor deprecation window.
- Older lines get no fixes. Upgrade.
- Fixes are announced in the changelog and the advisory feed. Releases stay signed.
Upgrade path guarantee
These behaviors already exist and are tested by the upgrade harness described in Upgrade safely. The policy would make them a promise:- Migrations only go forward. After the baseline release, new migrations are additive (
go test ./internal/storeenforces it). - A binary older than the database schema refuses to start, exits with status 78 and leaves the database unchanged. A downgrade through
self-upgrade --tois refused too. - Every upgrade takes a restore point first (database copy, binary, unit file). A failed health check puts the old binary and, when the schema changed, the old database back automatically.
- Upgrading is supported from the previous minor’s latest patch. Skipping minors is best effort.
Open questions
- Which release becomes the first stable line, and what evidence is required first (see the graduation criteria in Experimental features).
- Whether multi-node joins the covered surface at 1.0 or later.
- The exact warning mechanism for each surface.