Files
felhom.eu/REPORT.md
T
admin 985f0ba63c
gates / gates (push) Successful in 30s
Record the guards, the narrowing, and the two things I could not do
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.
2026-08-09 19:28:45 +02:00

9.4 KiB
Raw Blame History

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.jsongeneric_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 MUTATION0; 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 13 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.