docs: the app page's layout, the asset tag, and a version number pushed once (controller v0.316.0)
gates / gates (push) Successful in 6m46s
gates / gates (push) Successful in 6m46s
02-controller-module-map.md "The app page" gains the layout rules [DESIGN] — one column of one width, a section is a hairline not a card, a box means something (blue = the app is waiting for you, amber = something is risky, nothing else), the hero is not a box, and a success is not a banner. Plus the asset-tag rule: every shell's stylesheet address is derived from the BUILD, not the version, because the origin sends no validator and a cached copy can therefore only expire or be addressed differently. 09-update-architecture.md gains §0 [DESIGN]: a version number is pushed once. It belongs at the TOP of that document because everything below it compares versions — the floor moves a box by comparing a number, the button offers the highest tag, and a box re-pulls a tag only when the tag changes. Two images under one number is therefore not untidiness; it is a box running the wrong code that can never be told. R-1080 filed and closed: 0.315.0 was pushed three times from three different commits. Closed rather than left open because no box is stranded — exactly one guest ran it and it ran the registry's current digest, and the floor was 0.314.0 so nothing else could have taken it. audits/app-page-2026-10-15b/P0/ carries the measurement and its honest caveat: the stale Cloudflare object is no longer reproducible, because the first probe of the session forced its revalidation. What is shown is every precondition, the proof an aged entry existed (cf-cache-status EXPIRED), and the elimination of the only other candidate. The six stylesheet bodies are reduced to their sizes, sha256s and rule counts — one 99 KB file does not need six copies in git to make the point. .claude/rules/unprompted-work.md item 6, all four versioned copies: a version number is pushed once, stated as a FACT about what the build now enforces rather than as a new rule. STATUS: the operator's one look, through the public address. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
This commit is contained in:
@@ -50,6 +50,12 @@ it **first** in the morning note. A decision you cannot write in that shape is o
|
||||
on Tester 1, demo-hp and demo-felhom through the normal update path and the box walk's checks are green
|
||||
on all three — not at night unless the night brief says so. **Agent releases still stop for the
|
||||
operator's vouch.** The golden is baked weekly and vouched by the operator; CC never vouches. **No `--no-verify`.**
|
||||
**A version number is pushed once** — `felhom-controller/controller/build.sh` now refuses a second
|
||||
push of a tag that exists, and a registry it cannot reach is a refusal too. This is a FACT about
|
||||
what the build does, not a new rule: a fix for something already pushed is the next patch version,
|
||||
and a box on a bad image is moved by the normal update path, never by re-tagging. Earned on
|
||||
2026-10-15, when 0.315.0 was pushed three times from three different commits and a cache kept
|
||||
serving the first one (`09-update-architecture.md` §0).
|
||||
7. **An enumerated gap becomes a row in the same session — or, if it is small, is fixed in it** (the size rule).
|
||||
Prose is not a record.
|
||||
8. **Hungarian text is searched with ASCII fragments**, with a positive and a negative control.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Ready for the first real tester (Tester-2): yes. Tester 2 (a laptop) is off; nothing was sent to it.**
|
||||
|
||||
**Updated 2026-10-15 (evening).** Agent 0.156.1 + its bundle on all three boxes; controller 0.315.0 built (one app page with four tabs); 0.314.0 is still the floor since 13:11 UTC — raised by CC with its own token after all three test boxes ran it (the first release with no golden; vouched golden 0.313.0); hub 0.153.0 (access tokens — CC uses its own token now, not your password). Open items: see `documentation/backlog/OPEN-ITEMS.md`. Older notes, day by day:
|
||||
**Updated 2026-10-15 (evening).** Agent 0.156.1 + its bundle on all three boxes; controller 0.316.0 built (the app page in one column; a version number can now only be pushed once); 0.314.0 is still the floor since 13:11 UTC — raised by CC with its own token after all three test boxes ran it (the first release with no golden; vouched golden 0.313.0); hub 0.153.0 (access tokens — CC uses its own token now, not your password). Open items: see `documentation/backlog/OPEN-ITEMS.md`. Older notes, day by day:
|
||||
`documentation/backlog/STATUS-HISTORY.md`. Reports: `REPORT-night-2026-10-14.md`, `REPORT-immich-rollout-2026-10-14.md`, `REPORT-seo-felho-tarhely-2026-10-14.md`, `REPORT-immich-repair-2026-10-14.md`, `REPORT-power-cut-fixes-2026-10-14.md`, `REPORT-night-power-2026-10-13.md`, `REPORT-poweroff.md`.
|
||||
|
||||
## What works
|
||||
@@ -48,6 +48,7 @@
|
||||
| D10 | R-1079 | Storage that knows its physical disks (`architecture/16-storage-physical-identity.md` §12, six questions D1–D6): a same-disk second copy, „unknown" disks (VMs), the one-disk internal place and its reserve, old one-disk boxes, partitions, NAS films | **D1 (a) no same-disk copy · D2 (a) never count unknown · D3 (a) internal place, reserve max(16 GiB, 10 %) · D4 (a) a plain sentence · D5 (a) installer only · D6 (a) separate** | Other picks: more space spent on false copies, or films inside the whole-box copies | One-disk boxes keep refusing media apps; VM boxes keep counting same-disk copies | the build task |
|
||||
|
||||
## Waiting on you — do
|
||||
- **Nézd meg az AdventureLog és a Plex oldalát a demo-hp-n, a rendes címén** (`felhom.enkisfelhom.hu`). Az alkalmazás oldala mostantól egy hasábban van: egy szélesség, vékony vonalak a szakaszok között, aláhúzott fül, és doboz csak ott, ahol az alkalmazás vár rád (kék) vagy ahol valami kockázatos (sárga). A „sikeres frissítés" sáv kis szürke sorrá vált a név alatt. Ha nem nézed meg: a felület él, csak senki nem látta még böngészőben.
|
||||
- **Nézd meg az új alkalmazás oldalt a demo-hp-n (egy telepített és egy nem telepített app).** Egy alkalmazás mostantól egy oldal négy füllel (Beállítások · Adatok és mentés · Útmutató · Napló), az Indítás/Újraindítás/Leállítás a „Működés" kártyán van, és a „Vissza" az alkalmazáshoz visz, nem a listához. Mondd meg, jó-e így az elrendezés. Ha nem nézed meg: a felület él, csak senki nem látta még böngészőben — a robot a DooPlexen nem tud kattintani.
|
||||
- **The N100 sheet (about 30 minutes):** `documentation/audits/n100-lived-in-2026-10-15/SHEET.md` — install Plex and claim it, make the admins in Prowlarr/Sonarr/Radarr, add your download sources in Prowlarr, add one show and one film. Then say „done". If not: the media apps wait, safe behind their gate.
|
||||
- **Delete the test customer „Tester3” in the hub (browser only).** Its test box is already gone and switched off on purpose, so no alarm is coming. If not: a dead test customer stays in your list.
|
||||
|
||||
@@ -477,6 +477,35 @@ does not get to vouch for a version, so an overlay can neither set nor clear it.
|
||||
**[DESIGN] Guide text is DATA.** Plain text through `html/template` — no markdown, no raw HTML — so
|
||||
a step containing a tag is shown as the characters its author typed.
|
||||
|
||||
#### The app page's layout (v0.316.0, operator-approved mockup 2026-10-15)
|
||||
|
||||
**[DESIGN]** Five rules; the first three are the mockup, the last two are what they imply.
|
||||
|
||||
1. **One column of one width** (820px; the log tab alone is full width, because log lines are long).
|
||||
Boxes of differing widths read as a page assembled by accident, which is what v0.315.0 looked like.
|
||||
2. **A section is a hairline, not a card** — `padding: 28px 0` with a bottom `--line-soft`, no
|
||||
background, no border, no radius. A card says „this is a thing you act on", and most of an app
|
||||
page is a thing you READ; a card there is a promise the content cannot keep.
|
||||
3. **A box means something, and there are exactly two.** Blue (`--blue` on `--blue-dim`) when the app
|
||||
is WAITING for the household — an after-start value; amber (`--warn` on `--warn-dim`) when
|
||||
something is RISKY, such as a backup sharing a disk with the data it protects. The
|
||||
exception-colour principle, applied to shape as well as colour. Nothing informational is boxed.
|
||||
4. **The hero is not a box**: a 64px logo tile, the name, the tagline, hairline chips (state,
|
||||
lifecycle, update) and meta text (the address, the last automatic update). The tab bar is links
|
||||
with a 2px `--blue-bright` underline under the open one — no pills, no fills.
|
||||
5. **A success is not a banner.** The automatic-update SUCCESS line is meta text in the hero. It
|
||||
asked nothing of the household, so it is a date. Everything that DOES need a decision — a failed
|
||||
update, a hold, lost files, a missing drive, an interrupted install — stays a banner above the
|
||||
tabs, which is R-571's placement rule and is unchanged.
|
||||
|
||||
**[DESIGN] The stylesheet's address changes with every build.** Every shell links
|
||||
`/static/style.css?v={{.AssetTag}}`, where the tag hashes version + `GitCommit` + `BuildTime` and
|
||||
stays opaque (8 hex) because the stranger-facing share pages use the same value. The origin sends no
|
||||
ETag and no Last-Modified, so a cached copy cannot be revalidated — only expire, or be addressed
|
||||
differently. This is the „addressed differently", and it is the fix for a measured defect: a
|
||||
Cloudflare edge served 0.315.0's first stylesheet under the address its third build still asked for
|
||||
(`audits/app-page-2026-10-15b/P0/VERDICT.md`). `Cache-Control` is deliberately unchanged.
|
||||
|
||||
### `scripts/`
|
||||
| File | Class | Reason | Risk |
|
||||
|---|---|---|---|
|
||||
|
||||
@@ -20,6 +20,29 @@ source is the truth.** Nothing here is invented: every mechanism claim is cited
|
||||
|
||||
---
|
||||
|
||||
## 0. A version number is pushed once (v0.316.0, [DESIGN])
|
||||
|
||||
**[DESIGN] A controller version number names exactly one image, for ever.** `build.sh` checks the
|
||||
registry before building and refuses `--push` or `--multiarch` for a tag that already exists; a
|
||||
registry it cannot reach is a refusal too, because proving the tag is new is the point and „I could
|
||||
not ask" is not that proof. Local builds may reuse a version freely — that is iteration.
|
||||
|
||||
Why it has to be a mechanism and not a habit: **everything below compares VERSIONS.** The floor
|
||||
moves a box by comparing its version to a number; the household's button offers the highest tag; a
|
||||
box re-pulls a tag only when the tag changes. So two images sharing a number is not an untidiness,
|
||||
it is a box that runs the wrong code and **can never be told** — to the box and to the floor, its
|
||||
number is already current.
|
||||
|
||||
Measured, 2026-10-15: v0.315.0 was built and pushed three times from three different commits. A
|
||||
browser that had loaded the first build kept its stylesheet, because every build asked for the same
|
||||
`?v=0.315.0` and the origin sends no validator to revalidate against
|
||||
(`audits/app-page-2026-10-15b/P0/VERDICT.md`). The same release's asset tag closes the cache half;
|
||||
this closes the half that let it happen.
|
||||
|
||||
**A fix for something already pushed is the next patch version**, never a second push of the same
|
||||
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.
|
||||
|
||||
## 1. How an update works today, as measured
|
||||
|
||||
### 1.1 The button
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# Part 0 — why the tab bar rendered unstyled through the public address
|
||||
|
||||
**Measured 2026-10-15 ~19:55 CEST from DooPlex (Hungary, so the geo rule passes). Nothing was changed.**
|
||||
|
||||
## Verdict: (a) a cache — and the mechanism is named
|
||||
|
||||
Not (b): **exactly one box runs 0.315.0 and it runs the registry's current image.**
|
||||
|
||||
| Box | pinned tag | status |
|
||||
|---|---|---|
|
||||
| demo-hp guest 9201 | `felhom-controller:0.315.0` | Up, healthy |
|
||||
| demo-hp guest 9202 | `felhom-controller:0.314.0` | Up, healthy |
|
||||
| felhom-pve (N100) guest 9201 | `felhom-controller:0.314.0` | Up, healthy |
|
||||
| c11-appliance (Tester 1) | unreachable from DooPlex right now | — |
|
||||
|
||||
- demo-hp 9201's running image: `gitea.dooplex.hu/admin/felhom-controller@sha256:8887343011d64a2da9c65674a777a099708315063e3abc7c9463c03151dff041`
|
||||
- The registry's current `0.315.0`: `sha256:8887343011d64a2da9c65674a777a099708315063e3abc7c9463c03151dff041` — **identical**.
|
||||
- The **global floor is `0.314.0`** (read from the hub's `/configuration`), so no box could have taken
|
||||
0.315.0 by itself; the one that has it was deployed by hand. Tester 1 therefore cannot be on a
|
||||
stale 0.315.0 even though it is off right now.
|
||||
|
||||
## The four facts that make a cache the cause
|
||||
|
||||
1. **The stylesheet URL does not change between builds.** `layout.html` L12 asks for
|
||||
`/static/style.css?v={{.Version}}` → `?v=0.315.0` for all **three different** 0.315.0 builds
|
||||
(`e66d466`, `fe0228c`, `db52f5a`). The first of those had no `.app-tabs` rules at all.
|
||||
2. **The origin offers no validator.** `serveCSSHandler` (`server.go:1130`) sets only
|
||||
`Cache-Control: public, max-age=3600`. Measured on the box: **ETag present = 0, Last-Modified
|
||||
present = 0.** With neither, no client and no edge can revalidate a copy — it can only expire.
|
||||
3. **Cloudflare caches this URL and extends the browser's TTL.** Three requests in a row:
|
||||
`cf-cache-status: HIT`, `age: 99 → 100`, and `cache-control: public, max-age=14400` — Cloudflare
|
||||
rewrites the origin's 1 hour to **4 hours for the browser**.
|
||||
4. **Cloudflare held a stale entry for that exact URL.** The very first request of the session returned
|
||||
`cf-cache-status: EXPIRED` — which only happens when the edge *has* an entry that has aged past its
|
||||
TTL. Having no validator, it had to refetch the whole body.
|
||||
|
||||
## What is true right now, and the honest caveat
|
||||
|
||||
Origin, edge and box agree byte-for-byte (`sha256 c1774f63daf65c56` both sides) and all contain the
|
||||
`.app-tabs` rules. The page itself is never cached (`cf-cache-status: DYNAMIC`); only the stylesheet is.
|
||||
|
||||
**The caveat, stated rather than glossed:** the specific stale object is no longer observable — the
|
||||
first probe of this session forced its revalidation, which is exactly what `EXPIRED` records. So I
|
||||
cannot produce a `HIT` whose body lacks `.app-tabs`. What is shown is every precondition for it, the
|
||||
proof that an aged entry existed, and the elimination of the only other candidate (b).
|
||||
|
||||
## Why this authorises Part 1.2
|
||||
|
||||
The fix is not "purge the cache" — that hides the cause and returns at the next build. The fix is that
|
||||
**the stylesheet's address changes with every build**, so no cache at any layer (browser, Cloudflare,
|
||||
or anything between) can serve a previous build's CSS under an address the new build still asks for.
|
||||
`Cache-Control` stays as it is: the new URL is the fix, not a shorter cache.
|
||||
|
||||
Part 1.1 removes the precondition entirely — a version number can only be pushed once, so two
|
||||
different images can never share a number again.
|
||||
@@ -0,0 +1,11 @@
|
||||
# The stylesheet bodies are not kept — six copies of one 99 KB file. What the evidence needs is
|
||||
# their size, their sha256 and whether they carry the .app-tabs rules. Reproduce any of them with
|
||||
# curl -s 'https://felhom.enkisfelhom.hu/static/style.css?v=<tag>'
|
||||
|
||||
FILE BYTES APP_TABS SHA256
|
||||
edge1.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
edge2.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
edge3.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
origin.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
pub-bust.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
pub.css 98994 2 c1774f63daf65c5653520dba21fc686b
|
||||
@@ -0,0 +1,14 @@
|
||||
HTTP/2 200
|
||||
date: Thu, 15 Oct 2026 17:52:45 GMT
|
||||
content-type: text/css; charset=utf-8
|
||||
cache-control: public, max-age=14400
|
||||
strict-transport-security: max-age=86400
|
||||
age: 99
|
||||
last-modified: Thu, 15 Oct 2026 17:51:05 GMT
|
||||
cf-cache-status: HIT
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=HF%2FIgCiLuIzjJ5G%2BFauOO6TxF1GmCRETF6MwYBlMjEPVthuyR6t%2FfvhtFftATAPMyQJeq2XpMEjPAqZRS4losHGDEG%2FDJXgP%2FZit%2FGkpclL3hXbirbBl3wnjJRE5ZqqFYRu091UZTWE%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0adead9c111d5-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
HTTP/2 200
|
||||
date: Thu, 15 Oct 2026 17:52:45 GMT
|
||||
content-type: text/css; charset=utf-8
|
||||
cache-control: public, max-age=14400
|
||||
strict-transport-security: max-age=86400
|
||||
age: 100
|
||||
last-modified: Thu, 15 Oct 2026 17:51:05 GMT
|
||||
cf-cache-status: HIT
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Bc%2BNPGEHcXkmMFwUP2v0m0tFg%2BQTGHAbPxp8EM%2BgXoiqcVuMW2PKgQP69nygHqwLQeVsN1oQZtBZoNJcNoRb87qg323n2tkw37a8L0xXRkLEtfv3UJssz4SyEdO9nydIT4DkQ3cNYWs%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0adec4d565a8f-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
HTTP/2 200
|
||||
date: Thu, 15 Oct 2026 17:52:45 GMT
|
||||
content-type: text/css; charset=utf-8
|
||||
cache-control: public, max-age=14400
|
||||
strict-transport-security: max-age=86400
|
||||
age: 100
|
||||
last-modified: Thu, 15 Oct 2026 17:51:05 GMT
|
||||
cf-cache-status: HIT
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=P6QLBAzTUXTPRekJzLrSvesHOAGvPFXgeGClsbLokMovm6BbL4eBbPfiTui2je8iLJXPxprpllXYOXF%2BZ8AnPAx0ieKT4AEYrKxGMKw1xbJK%2BgbRFidTQIusyDnyiMQuYzmBaW3XKhk%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0adedabf49cca-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<a href="/login?next=%2Fapps%2Fadventurelog">Found</a>.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
HTTP/2 302
|
||||
date: Thu, 15 Oct 2026 17:52:47 GMT
|
||||
content-type: text/html; charset=utf-8
|
||||
location: /login?next=%2Fapps%2Fadventurelog
|
||||
strict-transport-security: max-age=86400
|
||||
cf-cache-status: DYNAMIC
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=YmplPMHLsWLWoy7RidM4MVtfIrDVPfw%2FGGlhFJwnvICgAJKbPpbyBxJPnyIG4xru8jobs1dmWqSxAKVVbzns81qeMprHAo3LUsXgoihvKztV8wp7HJnDcZju8Dm%2BBeuegOQJ61ffUGI%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0adf5f85d3a0d-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
HTTP/2 200
|
||||
date: Thu, 15 Oct 2026 17:51:10 GMT
|
||||
content-type: text/css; charset=utf-8
|
||||
cache-control: public, max-age=14400
|
||||
strict-transport-security: max-age=86400
|
||||
last-modified: Thu, 15 Oct 2026 17:51:10 GMT
|
||||
cf-cache-status: MISS
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=p%2Befhb3Eu8EOwL9ygvoAzHD9sJH4dsEYXdwNzqXOFUxPIk3yoqv5zjZtnRJwl2UUORNrcrGGfm5cKwPOARLwvpBucD8djUjF5XNb8HdsbDrgrCyTXwphFXUiLrq8jYqD6E8NHAt0hU4%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0ab9d4bc3e9e2-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
HTTP/2 200
|
||||
date: Thu, 15 Oct 2026 17:51:05 GMT
|
||||
content-type: text/css; charset=utf-8
|
||||
cache-control: public, max-age=14400
|
||||
strict-transport-security: max-age=86400
|
||||
last-modified: Thu, 15 Oct 2026 17:51:05 GMT
|
||||
cf-cache-status: EXPIRED
|
||||
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=cN1LcugsETH172R4%2BgpMOJ3ssKKTZ2tsFHQEB4SvNmsXF7n%2Fdnuial3p1TwjD4pT4X8KCrgkjCJdb0wdHx7wqxeNJ4b2lYCTszizuJZiaKSGOZTLN%2BXac1Mw3no4I020eIFnBifc%2BKU%3D"}]}
|
||||
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
server: cloudflare
|
||||
cf-ray: a4b0ab7a4965cb7b-VIE
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
|
||||
---
|
||||
|
||||
## 2026-10-15 (evening) — controller v0.316.0, one column and one image per version
|
||||
|
||||
| Row | What | Closed | Evidence |
|
||||
|---|---|---|---|
|
||||
| **R-1080** | **v0.315.0 was built and pushed THREE times from three different commits, and nothing stopped it.** (P2) Every build asked the browser for `/static/style.css?v=0.315.0`, so a cache holding the first build's stylesheet — which had no `.app-tabs` rules at all — kept serving it under the address the third build still asked for. Worse in principle than the symptom: the floor and the household's button both compare VERSIONS, so a box that pulled between the first and the last runs different code under a number that is already current, and can never be told. | CLOSED 2026-10-15 — **controller v0.316.0**, in two halves. (1) `build.sh` refuses `--push`/`--multiarch` for a tag already in the registry, before building; a registry it cannot reach is a refusal too. Six cases in `scripts/test_build_push_once.sh` against the real script with a fake docker; red-proved twice. (2) every shell's stylesheet URL is a per-build tag (version + GitCommit + BuildTime), so two builds of one version cannot share a cache entry. **No box is left on a bad image:** exactly one guest ran 0.315.0 (demo-hp 9201) and it ran the registry's current digest `8887343011d6`; the floor was 0.314.0, so nothing else could have taken it. | `audits/app-page-2026-10-15b/P0/VERDICT.md`, `felhom-controller/REPORT.md` |
|
||||
|
||||
## 2026-10-15 (evening) — controller v0.315.0, the app page
|
||||
|
||||
| Row | What | Closed | Evidence |
|
||||
|
||||
Reference in New Issue
Block a user