hub v0.155.0: the floor can never deliver a withdrawn controller build (R-1085); RomM/Ghost evidence
gates / gates (push) Successful in 6m44s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-16 12:24:39 +02:00
parent 920c1aaf84
commit b17e9e993c
28 changed files with 955 additions and 6 deletions
@@ -43,6 +43,24 @@ this closes the half that let it happen.
number. A box already on the bad image is moved by the normal update path — never by re-tagging,
which would be the same defect wearing the fix's clothes.
**[DESIGN] A withdrawn build is never selected (hub v0.155.0, R-1081, R-1085).** The rule above
leaves the spoiled numbers in the registry, so nothing may pick them. Two controller tags hold
other code than their number says: **`0.315.0`** (re-pushed with v0.316.0's code under it) and
**`0.316.3`** (built from a working copy holding another session's uncommitted files). The
household's button and the daily auto-update take the HIGHEST tag and cannot reach them; the
**floor** targets a version exactly, so the floor is where the guard lives, in two halves:
- **at input** — both floor forms (global and per customer, by session or by token) and the
confirm dialog's impact probe refuse a listed tag (`flash=floor_spoiled`; the probe answers
`valid:false, spoiled:true`). The check is its own, NOT inside `normalizeFloorInput`, which also
validates agent and golden numbers;
- **at serve time** — `store.ResolveManagedFloor` HOLDS a listed floor (served as none,
`HeldSpoiled`, its own reason text) however it arrived: a value stored before the refusal, or the
config/env default (which no form checks; the hub also warns about it at start). The stored
value is not rewritten; the Configuration and customer pages say „withdrawn".
The list is `hub/internal/store/spoiled_tags.go`; the hand deploy reads the same list as a marked
line in the `felhom-build-deploy` skill, and a test fails when the two differ. A new spoiled
build is added to both in the same commit.
## 1. How an update works today, as measured
### 1.1 The button