compat: SemVer version windows between app and server
Both sides now declare what they will talk to, and enforce it. Two axes kept
deliberately separate, because conflating them is the trap:
protocol_version — CAN these builds talk. The correctness axis. Below 1.0.0
the minor is the breaking axis, per SemVer §4.
release window — MAY they, per policy. [min, max), advertised in the
profile, overridable by the operator.
The server refuses out-of-window apps with 426 and a body naming both versions
and the accepted range; the app checks the profile in both directions before a
run rather than discovering mid-measurement that it will be refused.
Three rules that shape the rest:
- GET /v1/profile is never gated. It is where a refused client learns which
version it needs; gating it leaves the user with a network error instead of
an answer, which is precisely the confusion this exists to remove.
- An unparseable or absent version is "unknown", and is allowed. Development
builds report "dev", and a client too old to send the header cannot be
identified anyway.
- Bounds sit at breaking boundaries, not at releases, so shipping a patch
never requires editing a range. The app's server minimum is 0.4.2 for a
stated reason: earlier multi-homed servers mis-addressed granted sends and
the client measured 100% downstream loss that never happened.
The app's versionCode is now derived from its SemVer instead of being a second
number someone has to remember to bump.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
277e33da75
commit
0c5b021b63
@@ -32,10 +32,25 @@ Keep prober result IDs aligned with the measurement-schema test-type registry.
|
||||
|
||||
## Versioning
|
||||
|
||||
Prefer **patch** bumps (`server-v0.3.1`) for additive/incremental work; reserve **minor** bumps
|
||||
for real milestones. Don't burn through minor versions. Tags are namespaced: `server-v*` for the
|
||||
Go server, `v*` for the app. Pushing a `server-v*` tag runs CI → binaries + Gitea release +
|
||||
registry image; the server on fmr can `--self-update` from those releases.
|
||||
Both artifacts are **SemVer**. Prefer **patch** bumps (`server-v0.3.1`) for additive/incremental
|
||||
work; reserve **minor** bumps for real milestones. Don't burn through minor versions. Tags are
|
||||
namespaced: `server-v*` for the Go server, `v*` for the app. Pushing a `server-v*` tag runs CI →
|
||||
binaries + Gitea release + registry image; the server on fmr can `--self-update` from those
|
||||
releases.
|
||||
|
||||
The app's version lives once, as `appVersionName` in `app/build.gradle.kts`; **`versionCode` is
|
||||
derived from it** (`major*1e6 + minor*1e4 + patch*10`). Never set it by hand — a second number a
|
||||
human has to remember to bump eventually disagrees with the first.
|
||||
|
||||
**Versions are load-bearing** (probe-protocol.md §8): the server refuses apps outside its window
|
||||
with `426`, and the app refuses servers outside its own. Two axes, kept separate:
|
||||
- `protocol_version` — *can* they talk. The correctness axis; below 1.0.0 the **minor** is the
|
||||
breaking axis.
|
||||
- release-version window — *may* they, per policy. `[min, max)`, bounds at breaking boundaries so
|
||||
a patch never strands a fleet. Client bounds: `Compat.kt`. Server: `ECHOLOT_MIN/MAX_APP_VERSION`.
|
||||
|
||||
Raise a minimum only when older peers are actively harmful, and say why in the constant's comment.
|
||||
`GET /v1/profile` must stay ungated — it is how a refused client learns what it needs.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -130,6 +145,12 @@ First build downloads AGP/Compose/Shizuku from Google Maven + Maven Central.
|
||||
Shizuku, **toggle Wireless debugging off/on** — Shizuku keeps running (separate process), a fresh
|
||||
port + mDNS record appear, and the beacon/connector recover. Plan the Shizuku-tier dev loop
|
||||
around this (or USB, if ever available).
|
||||
- **Empty-jar race with the IDE.** VSCodium's Java/Kotlin extension runs its own Gradle daemon on
|
||||
the same project; when it overlaps a CLI build, a module's `build/libs/*.jar` can end up
|
||||
containing only a manifest, and Gradle then considers `jar` up-to-date. Dependent modules fail
|
||||
with "Unresolved reference" on symbols that plainly exist. Fix: `rm -f <module>/build/libs/*.jar`
|
||||
and re-run the `jar` task. Suspect this whenever a reference resolves in one module but not in
|
||||
its consumer.
|
||||
- As of the AGP 9.2.0 / Gradle 9.6.0 / Kotlin 2.2.10 bump, JDK 17+ (including 25) works —
|
||||
AGP 9 requires Gradle 9.1.0+ and Kotlin 2.2.10+ as its minimum KGP version. On machines with
|
||||
Android Studio, its `jbr` directory works as `JAVA_HOME`.
|
||||
|
||||
Reference in New Issue
Block a user