985f0ba63c
gates / gates (push) Successful in 30s
R-273's owed guards are both built and closed. R-291 records what CI stopped covering and why, so it can be widened deliberately rather than discovered. R-292 is new and was found by a test failing for the wrong reason: artifact_sha_invalid conflates "version missing", "registry unreachable" and "bad sha" into one message. v0.102.0 works around it by ORDERING -- the probes run first, so an unreachable registry is reported as unreachable -- but the message itself is untouched. CONTEXT gains the rule this session is about: a check and the policy it enforces must read the same number from the same place, or they drift and the drift looks like a defect in something else. Two corollaries, both of which cost something: a bounded check must print what it stopped covering on every run, and an unreadable policy is INCONCLUSIVE rather than unbounded. Stated in the report rather than glossed: Part 4 (finding receipts for the twelve downgraded claims) was NOT done and is a shortfall, not a decision -- splitting it would have produced exactly the half-checked green the exercise exists to prevent. Part 5 was droppable and dropped. The tag-push green is not re-proved tonight and is not claimed; the evidence offered is runs 190 and 216.
153 lines
9.4 KiB
Markdown
153 lines
9.4 KiB
Markdown
# REPORT — the guards, and one thing I could not establish (2026-08-09 evening)
|
||
|
||
No machine touched. Both demo boxes stayed offline and in transit; nothing here needed them.
|
||
|
||
**Parts 1, 2 and 3 are done. Part 4 and Part 5 are NOT done** — see §6 and §8. Part 5 was marked
|
||
droppable and was dropped; **Part 4 was not marked droppable and I ran out of session before it**,
|
||
which is a shortfall rather than a decision.
|
||
|
||
---
|
||
|
||
## 1. Part 1.1 — the deleter: **NOT ESTABLISHED**
|
||
|
||
**This prompt's account is not corroborated by any source I can reach**, and the prompt itself said
|
||
not to take its word for it.
|
||
|
||
| claim in the prompt | what I found |
|
||
|---|---|
|
||
| "the register records … pruned to the newest ten … 33 deletions, all HTTP 204" | **No such row exists.** The only prune-adjacent row is **R-210**, which is `WAITING-ON-OPERATOR`, says in terms *"Nothing was deleted; this is a list, not an action"*, and concerns **local Docker images on DooPlex**, not the Gitea registry |
|
||
| "newest ten per package" | **Not visible in the current state.** `felhom-agent` generic holds 10, but `felhom-controller` and `felhom-hub` container packages hold **19 each** |
|
||
|
||
Everything else I could reach is silent, and silence here is not evidence of anything:
|
||
`package_cleanup_rule` is **empty**; `package_version` has **no soft-delete column**, so a deletion
|
||
leaves no row; Gitea's `action` feed carries **no package operation at all** across 2026-08-08 →
|
||
2026-08-09 and nothing whatever on the evening of 08-08; the Gitea pod has **53 days uptime, 0
|
||
restarts**.
|
||
|
||
**And I withdrew one of my own claims.** R-287 said *"no DELETE on the packages API appears in 48 h of
|
||
Gitea router logs"*. Re-checked: `kubectl logs --since=72h` returns nothing older than **2026-08-09
|
||
16:35** and contains **zero** `api/packages` lines even for requests I made myself. **The log never
|
||
covered the window, so its silence was never evidence.** Withdrawn in the register.
|
||
|
||
**What remains established, unchanged:** `v0.120.0` downloadable at 2026-08-08 14:29 UTC (run 267
|
||
printed `ok v0.120.0`), 404 by 2026-08-09 09:30 UTC (run 284), and `0.128.0` published at 14:47 UTC —
|
||
eighteen minutes after the good run. **It may be unestablishable from this side: Gitea keeps no
|
||
package-deletion trail.**
|
||
|
||
Per §8 I halted that part's attribution and carried on; the rest is independent.
|
||
|
||
## 2. The number, and the two places that read it
|
||
|
||
`felhom-agent/scripts/retention-policy.json` → `generic_versions_kept: 10`.
|
||
|
||
Read by **`scripts/check-published-versions.py`** (bounds its assertion) and referenced by the prune
|
||
procedure. The file states, in its own header, that ten is an **observed state and not a located
|
||
ruling**, and that the principled bound is the hub's vouched `min_agent` floor — nothing can install
|
||
below it — which needs network the gate does not have.
|
||
|
||
**What CI no longer covers:** *a released version older than the retention window is no longer
|
||
asserted downloadable.* Its **git tag and config tree are still asserted**; only the binary's presence
|
||
is dropped. The check **prints the dropped versions every run**:
|
||
|
||
```
|
||
11 released version(s); retention policy keeps the newest 10
|
||
NOT ASSERTED (older than the retention window …): 0.120.0
|
||
^ these versions still have git TAGS … what is no longer asserted is the BINARY's presence.
|
||
```
|
||
|
||
Three controls: green at 10 naming what it dropped (**exit 0**); widened to 11 the evicted version
|
||
re-enters and convicts (**exit 1**, `FAIL v0.120.0`); the policy file removed → **exit 2 INCONCLUSIVE**,
|
||
naming the path it tried — never silently unbounded.
|
||
|
||
## 3. `felhom-agent` green
|
||
|
||
```
|
||
reuse-refs OK · instructions OK · published OK · release-complete OK · all agent gates OK
|
||
```
|
||
|
||
**At `main`: green**, pushed as `53d047a`, and the pre-push hook ran the same entry point.
|
||
**At a tag: not re-proved tonight, and I will not claim it.** The available evidence is that the gate
|
||
is ref-independent — it enumerates from the Gitea tags API, and runs **190** (`v0.126.0`) and **216**
|
||
(`v0.127.0`) were tag pushes that passed. Minting a tag purely to prove it would have published a
|
||
release, which this session forbids.
|
||
|
||
## 4. Red-proofs
|
||
|
||
| # | mutation | asserted applied | outcome |
|
||
|---|---|---|---|
|
||
| 1 | **tag check removed** | `grep -c` → 1 | **scenario A FAILED, reporting `flash = "artifacts_set"`** — Friday's exact defect returned: the manifest saved with no tag |
|
||
| 2 | package check removed | `grep -c` → 1 | scenario B FAILED, `flash = "artifacts_set"` |
|
||
| 3 | inconclusive branch mapped onto success | `grep -c` → 2 | scenario E FAILED |
|
||
|
||
All reverted; `grep -c MUTATION` → **0**; all seven tests green again.
|
||
|
||
**Red-proof 3, stated precisely rather than flatteringly:** with the inconclusive branch mapped onto
|
||
success the save did **not** complete — it fell through to `artifact_sha_invalid`. So the mutation
|
||
proves the guard is load-bearing for *the message the operator sees*, not for the save itself. That is
|
||
the honest reading, and it is exactly the defect scenario E exists to prevent: the operator being told
|
||
"missing or invalid" when the truth is "I could not reach the registry".
|
||
|
||
## 5. The five scenarios, as the operator sees them
|
||
|
||
| | outcome | the message |
|
||
|---|---|---|
|
||
| **A** tag missing | REFUSED | *"Refused: that version has no usable git tag. The installer fetches an agent's config files from `raw/tag/v<version>/configs/`, so a version published without its tag makes every fresh install and reinstall fail at step 5 of 8 — as root, on a virgin machine. … Fix it by pushing the tag: `git tag -a v<version> <released-commit> && git push origin v<version>`"* |
|
||
| **B** package pruned | REFUSED | *"Refused: that version's artifact is not downloadable. The version is tagged but its package is not in the registry, so a box would 404 fetching the binary itself. … Publish it — `bash scripts/release-agent.sh <version>`"* |
|
||
| **C** no checksum | REFUSED | the pre-existing *"Couldn't set the checksum …"* — see the note below |
|
||
| **D** both good | **SAVES**, `artifacts_set`, byte-identical behaviour | — |
|
||
| **E** registry unreachable | REFUSED | *"Refused: could not verify — this does not mean anything is missing. … It refuses rather than saving with a warning, because a warning beside a success reads as a success. … There is deliberately no override: the registry is on your own server, so if it is unreachable the vouch can wait."* |
|
||
|
||
**Scenario C changed shape because my first draft modelled nothing real,** and that is worth recording.
|
||
With a Gitea client configured, `resolveArtifactSHA` fetches the sha **authoritatively and ignores what
|
||
was submitted** — so "submit an empty sha" cannot produce an empty stored sha. The genuine shape is
|
||
Gitea answering with no `sha256`, and the **existing** refusal already owns it. The test now pins the
|
||
guarantee (*the manifest is unchanged*) rather than a mechanism I had invented.
|
||
|
||
**No override was built, and none is wanted.** §8's halt condition did not trigger.
|
||
|
||
## 6. Part 4 — NOT DONE
|
||
|
||
The twelve downgraded claims were not re-examined and no receipts were searched for. **The honest-grey
|
||
count is therefore still the twelve from last night, unverified in either direction**, and
|
||
`where-felhom-stands.*` is untouched. This is the session's shortfall: Parts 1–3 took the budget, and
|
||
splitting Part 4 in half would have produced exactly the kind of half-checked green the whole exercise
|
||
exists to prevent.
|
||
|
||
**Whether the "code moved under the proof" rule can fire at all** is therefore still open from last
|
||
night, where it fired **zero** times out of twelve — every downgrade came from missing evidence, not
|
||
from decayed evidence. My reading remains that it *can* fire but will stay rare until rows cite
|
||
evidence at all, which is R-290.
|
||
|
||
## 7. Hub deployed
|
||
|
||
**v0.102.0**, live and verified: deploy image `gitea.dooplex.hu/admin/felhom-hub:0.102.0`, rollout
|
||
complete, and the page footer reads `0.102.0`. Manifest commit **`36bcd12`**; code commit `b55fc17`.
|
||
The image was verified **served by the registry before** the manifest was bumped, not after. ArgoCD's
|
||
`felhom` app has `automated.enabled: false`, so the sync was triggered explicitly — **no
|
||
`kubectl set image` at any point.**
|
||
|
||
## 8. Part 5 — dropped, as marked
|
||
|
||
Not started. It was explicitly droppable and it is the only part that touches customer-facing wording,
|
||
which is where a rushed edit does most harm.
|
||
|
||
## 9. Register
|
||
|
||
**Ceiling R-290 → R-292.** Opened **R-291** (the narrowing, with its reason, so it can be widened
|
||
deliberately) and **R-292** (`artifact_sha_invalid` conflates three facts — found by scenario E
|
||
failing, worked around by ordering, message untouched). Closed: **R-273's owed-guards tail**, both
|
||
guards built. Corrected: **R-287**, twice.
|
||
|
||
## 10. Observations — noticed, not acted on
|
||
|
||
- **R-292 is the interesting one.** A test I wrote to check a new guard failed for a reason that had
|
||
nothing to do with the guard, and that reason was a real pre-existing defect. The five scenarios
|
||
earned their keep before the feature shipped.
|
||
- **The golden gets no tag probe.** It is fetched by version and has no config tree, so a tag probe
|
||
would assert something the installer never does. Deliberate, and stated in the code.
|
||
- **The gate is skipped entirely when no Gitea client is configured**, or a hub without registry
|
||
credentials could never vouch anything. Pinned by its own test, and worth knowing: the guard is only
|
||
as present as the client is.
|
||
- `check-release-complete` runs in `--fast`, so a missing tag is now caught by the **pre-push hook**,
|
||
earlier than CI.
|