release path publishes, and an unreleasable version fails CI (R-115, R-183)
gates / gates (push) Failing after 7s
gates / gates (push) Failing after 7s
NO VERSION BUMP and nothing built: no Go code changed. The agent stays v0.120.0. scripts/release-agent.sh — THE way to release. build -> tag -> publish -> verify by INDEPENDENT download. Publishing was a separate remembered step and was forgotten three times in five days (R-111's 17 stranded releases, 0.114.0, and 0.120.0 — deployed to both demo hosts and undownloadable, so a documented-path reinstall would have silently downgraded them WHILE REPORTING SUCCESS). R-111's own closing line named this leg and closed SHIPPED without it; it recurred the same afternoon, which is the evidence that a note is not a mechanism. It tags because felhom-host-install.sh now fetches the sixteen agent config files from raw/tag/v<version>/ (R-183): a released version with no tag 404s a box mid-install, as root, on a virgin machine. It verifies by downloading what it just published and comparing the sha to what it built — the publish step's own success is a report on its own write; a fetch returning the right bytes is a different claim. It refuses a dirty/unpushed tree and refuses to re-release an existing version. It does NOT vouch: that points machines at a version and stays the operator's act. scripts/check-published-versions.py — the gate. Every v<semver> tag must have a downloadable package AND a tag tree serving the agent's configs. Registered as NOT --fast (needs network; a push must not fail because Gitea blinked), and the CI workflow now runs the FULL gate set instead of --fast — otherwise the gate would have been registered and never run, the built-but-never-wired failure this project has shipped four times. The invariant is not the one specified, and the reason was measured, not assumed: the hub artifact manifest is 401 without a per-customer passphrase and Gitea's package LISTING api is 401 without a token, while the package DOWNLOAD url and the git TAGS api are anonymous. So CI cannot ask "what is vouched" without an operator credential — whose addition is the operator's call. The tag-based invariant needs none and catches all three recorded instances. What it does not catch (the hub vouching a version never released at all) is filed as R-184.
This commit is contained in:
@@ -1,3 +1,42 @@
|
||||
## Releasing publishes, and an unreleasable version cannot pass CI (2026-08-03, R-115 + R-183) — **NO VERSION BUMP**
|
||||
|
||||
**No Go code changed, so nothing is bumped and nothing was built.** This is the release path and a
|
||||
gate; the agent stays **v0.120.0**.
|
||||
|
||||
**`scripts/release-agent.sh` — THE way to release.** Build → **tag** → publish → **verify by an
|
||||
independent download**. Publishing used to be a separate remembered step and was **forgotten three
|
||||
times in five days** (R-111's seventeen stranded releases, 0.114.0, and 0.120.0 — which sat deployed
|
||||
on both demo hosts and undownloadable, so a documented-path reinstall would have silently downgraded
|
||||
them to the pre-merge agent *while reporting success*). R-111's own closing line named this leg and
|
||||
closed SHIPPED without it; it recurred the same afternoon, which is the evidence that a note is not a
|
||||
mechanism.
|
||||
|
||||
- It **tags** because `felhom-host-install.sh` now fetches this version's sixteen config files from
|
||||
`raw/tag/v<version>/` (R-183) — a released version without a tag 404s a box mid-install, as root.
|
||||
- It **verifies by downloading what it just published** and comparing the sha to what it built. The
|
||||
publish step's own success is a report on its own write; a fetch returning the right bytes is a
|
||||
different claim, and it is the one that matters.
|
||||
- It **refuses** a dirty or unpushed tree, and refuses to re-release an existing version — one
|
||||
version name must never mean two binaries.
|
||||
- It **does NOT vouch.** Vouching points machines at a version and stays the operator's act.
|
||||
|
||||
**`scripts/check-published-versions.py` — the gate (R-115 mechanism (b)).** Every `v<semver>` tag
|
||||
must have a downloadable package AND a tag tree that serves the agent's configs. Registered in
|
||||
`agent_gates.py` as **not `--fast`** (it needs network, and a push must not fail because Gitea
|
||||
blinked), and **the CI workflow now runs the FULL gate set** rather than `--fast` — otherwise the
|
||||
gate would have been registered and never run, which is the built-but-never-wired failure this
|
||||
project has shipped four times.
|
||||
|
||||
**The invariant is NOT the one the task specified, and the reason was measured.** The task asked for
|
||||
*"the version the hub tells machines to install must be downloadable"*. That is the better invariant
|
||||
and CI cannot see it: the hub's artifact manifest answers **401** without a per-customer passphrase,
|
||||
and Gitea's package LISTING api answers **401** without a token, while the package DOWNLOAD url and
|
||||
the git TAGS api are both anonymous. Putting an operator credential into CI to close that gap is the
|
||||
operator's call, not a gate author's. The tag-based invariant needs no credential and **catches all
|
||||
three recorded instances**, because the release script creates the tag and publishes in one act.
|
||||
**What it does not catch — the hub vouching a version that was never released at all — is recorded
|
||||
as R-184 rather than assumed away.**
|
||||
|
||||
## docs — v0.120.0 PUBLISHED + vouched, and proven on two reinstalled boxes (2026-08-03, R-178) — **no version bump, nothing built**
|
||||
|
||||
**Nothing shipped in this entry.** It records an operational fact the version history could not
|
||||
|
||||
Reference in New Issue
Block a user