# REPORT — felhom-agent, 2026-08-09 (gates only) **No release. No version bump. No binary published. `scripts/` only** — nothing that runs on a customer's machine changed, and the agent stays **v0.128.0** at `28ba8593b8`. ## What changed | file | why | |---|---| | `scripts/retention-policy.json` **(new)** | THE retention number, in one place, with its reasoning and its honesty about where the number came from | | `scripts/check-published-versions.py` | reads that number; bounds its assertion to the newest N; **prints what it stopped covering** | | `scripts/check-release-complete.py` **(new)** | asserts the CHANGELOG-head version is tagged, placed in this history, and published | | `scripts/agent_gates.py` | registers the new gate; legs 1–2 are offline so it runs in `--fast` too | ## The coupling defect, and the fix The prune keeps the newest N; the published-versions check demanded that **every** tag be downloadable. Nothing connected them, so CI went red at `28ba8593b8` — a commit whose own run had been **green the day before** — and would have gone red again at the next publish when `0.121.0` was evicted. Both now read `generic_versions_kept` from one file. **What CI no longer covers:** a released version **older than the retention window** is no longer asserted downloadable. Its git tag and its config tree are still asserted; only the binary's presence is dropped. The check names the dropped versions on every run. **The number is not a located ruling.** `generic_versions_kept: 10` is what the registry demonstrably holds; no register row records a prune, and container packages hold 19 each. The file says so in its own header. The principled bound is the hub's vouched `min_agent` floor — nothing can install below it — and that is recorded as the follow-up. ## Controls, all three run | control | expected | got | |---|---|---| | live run, policy = 10 | green, and it names `0.120.0` as not asserted | **exit 0**, and it did | | widen policy to 11 | `0.120.0` re-enters the window and convicts | **exit 1**, `FAIL v0.120.0` | | policy file removed | INCONCLUSIVE, never silently unbounded | **exit 2**, naming the path it tried | ## Red-proof of the new gate Mutation: `CHANGELOG.md` head repointed to `## v0.129.0` — never tagged, never published. Asserted applied (`grep -c '^## v0.129.0'` → 1). Result **exit 1**, both legs convicting: ``` - TAG v0.129.0 DOES NOT EXIST. … without the tag every install 404s mid-run, as root. Fix: git tag -a v0.129.0 && git push origin v0.129.0 - PACKAGE 0.129.0 IS NOT PUBLISHED (HTTP 404 …). Fix: bash scripts/release-agent.sh 0.129.0 ``` Reverted; `git status` clean on `CHANGELOG.md`. ## Green gate `python3 scripts/agent_gates.py` — `reuse-refs OK · instructions OK · published OK · release-complete OK · all agent gates OK`. ## Not done here The deleter of `0.120.0` is **still not established** and a second attempt failed — Gitea keeps no package-deletion trail, its container log no longer reaches the window, and the activity feed carries no package operation. Recorded in R-287, including the withdrawal of my own earlier over-claim that the router logs showed no DELETE: they do not cover the window, so they never said anything.