fix(docs): correct the Hub size claims, and gate them so they cannot rot again
DOCKER_HUB.md claimed ~1.1 GB for :latest while Docker Hub served 1.37 GB --
20% wrong, drifting quietly across eight releases, and POSTed to Docker Hub by
update-description every time. It is the first number a stranger reads about
this image.
Root cause is structural, not carelessness: every OTHER claim check-doc-drift.sh
guards is anchored to a build file (a pin, an ARG, a placeholder), so it cannot
rot without someone editing the thing it describes. Nothing in this repo states
the image size, so nothing measured it.
Corrected against measured full_size after v1.9.2 published (amd64/arm64):
:latest ~1.1 -> ~1.23 GB (1.228 / 1.211)
:latest-studio ~1.15 -> ~1.25 GB (1.255 / 1.238)
:base-latest ~1.0 -> ~1.17 GB (1.167 / 1.151)
full_size tracks the FIRST manifest entry (amd64), not the sum across arches --
measured: full_size=1.228, amd64=1.228, arm64=1.211, sum=2.439 -- which is what
the table's per-arch "Size (compressed)" column claims.
New check 8 gates those claims against Hub. Fails on drift; SKIPS LOUDLY via a
new skip() helper (counted, named in the summary) when curl/python3 are absent,
the API is unreachable, or SKIP_SIZE_CHECK=1. A skip is deliberately neither OK
nor a failure: printing an unverified claim as OK is the habit this file exists
to break, and failing on Docker Hub's uptime would hold releases hostage to a
third party. Not wired into hooks/pre-push, so pushes stay offline.
Two bugs caught by writing the expected exit code down before running the check:
1. The tolerance would have missed its own motivating case. The percentage is
computed against the MEASURED size, but the 20% first chosen came from the
claim-relative figure; the real drift was |1.1-1.37|/1.37 = 19.7% and would
have passed. Now 15%, inside a window with both bounds measured: above the
largest legitimate skew (11.4%, a claim describing the published release
while the next tag changes the size) and below the rot it must catch.
2. A `|| true` on the python invocation made the gate FAIL OPEN -- it printed
DRIFT and exited 0. Removed; the outer `|| SIZE_RC=$?` satisfies set -e
without swallowing the code. Verified two-sided: 19% drift exits 1 at the
default tolerance and 0 at SIZE_TOLERANCE_PCT=25, so the threshold does the
work rather than the ordering.
NOT covered, and the script says so where a reader will see it: README.md's
~3.2 GB figures are UNCOMPRESSED and the registry exposes compressed sizes only,
so measuring them needs a real pull. A green check 8 says nothing about them.
Verified: check-doc-drift.sh rc=0 on the corrected tree, rc=1 on injected drift,
rc=0 with --warn-only, SKIP+rc=0 on the offline path (proxy to a dead port);
shellcheck clean at default severity (the sed single-quote SC2016 carries a
disable with its reason); lint-shell.sh 16 files clean.
This commit is contained in:
@@ -11,6 +11,66 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
||||
|
||||
---
|
||||
|
||||
## Unreleased
|
||||
|
||||
**The size numbers on the Docker Hub page were the only claim in these docs with
|
||||
nothing in the repo to check them against, and they had gone 20% wrong across
|
||||
eight releases.** Every other claim `scripts/check-doc-drift.sh` guards is
|
||||
anchored to a build file — a pin, an `ARG`, a placeholder — so it cannot rot
|
||||
without someone editing the thing it describes. Nothing in this repo states the
|
||||
image size, so `DOCKER_HUB.md`'s `~1.1 GB` simply drifted while the image grew,
|
||||
and `update-description` POSTed it to Docker Hub every release. It is the first
|
||||
number a stranger reads about this image.
|
||||
|
||||
Corrected against Docker Hub's measured `full_size`, 2026-09-14 after v1.9.2
|
||||
published (amd64 / arm64, compressed):
|
||||
|
||||
| Row | Claimed | Measured | Now says |
|
||||
|---|---|---|---|
|
||||
| `:latest` | ~1.1 GB | 1.228 / 1.211 | ~1.23 GB |
|
||||
| `:latest-studio` | ~1.15 GB | 1.255 / 1.238 | ~1.25 GB |
|
||||
| `:base-latest`, `:base-<hash>` | ~1.0 GB | 1.167 / 1.151 | ~1.17 GB |
|
||||
|
||||
`full_size` is the right field because it tracks the **first manifest entry**
|
||||
(amd64), not the sum across architectures — measured on v1.9.2:
|
||||
`full_size=1.228`, `amd64=1.228`, `arm64=1.211`, `sum=2.439`. That matches the
|
||||
table's per-arch "Size (compressed)" column.
|
||||
|
||||
**New check 8 in `scripts/check-doc-drift.sh`: size claims vs Hub's measured
|
||||
`full_size`,** so this class cannot rot silently again. It fails on drift beyond
|
||||
tolerance, and **skips loudly** — a new `skip()` helper, counted and named in the
|
||||
summary — when `curl`/`python3` are missing, the API is unreachable, or
|
||||
`SKIP_SIZE_CHECK=1`. Skips are deliberately neither `OK` nor a failure: printing
|
||||
an unverified claim as OK is the habit this file exists to break, while failing
|
||||
on Docker Hub's uptime would make every release hostage to a third party. Not in
|
||||
`hooks/pre-push` (that runs `lint-shell.sh` only), so pushes do not hit the
|
||||
network.
|
||||
|
||||
Two bugs were caught while building it, both by writing the expected exit code
|
||||
down *before* running the check:
|
||||
|
||||
- **The tolerance would have missed its own motivating case.** The percentage is
|
||||
computed against the *measured* size, but the 20% first chosen came from the
|
||||
claim-relative figure. The real drift was `|1.1 − 1.37| / 1.37 = 19.7%` — it
|
||||
would have passed. Now 15%, sitting inside a window whose bounds are both
|
||||
measured: above the largest legitimate skew (a claim describing the published
|
||||
release while the next tag changes the size — v1.9.1's 1.37 against v1.9.2's
|
||||
1.23 = 11.4%) and below the rot it exists to catch (19.7%).
|
||||
- **A `|| true` on the python invocation made the gate fail open.** It printed
|
||||
`DRIFT` and exited 0 — a gate that reports the defect and passes anyway.
|
||||
Removed; the outer `|| SIZE_RC=$?` is what satisfies `set -e` without
|
||||
swallowing the code. Verified two-sided afterwards: a 19% drift exits 1 at the
|
||||
default tolerance and 0 at `SIZE_TOLERANCE_PCT=25`, so the threshold is doing
|
||||
the work rather than the ordering.
|
||||
|
||||
**Explicitly NOT covered:** `README.md`'s `~3.2 GB` figures are *uncompressed*
|
||||
on-disk sizes, and the registry exposes compressed sizes only (manifest layer
|
||||
sizes are compressed; the config blob carries no uncompressed totals). Measuring
|
||||
them needs a real pull, so they remain unverified — a green check 8 says nothing
|
||||
about them, and the script says so where a reader will see it.
|
||||
|
||||
---
|
||||
|
||||
## v1.9.2 — 2026-09-14
|
||||
|
||||
**The v1.9.1 residual is attributed and fixed: it was mostly npm's own download
|
||||
|
||||
Reference in New Issue
Block a user