etapa 3: el ahorro real es ~60%, no 79% — la cifra publicada medía otra cosa
El «79%» que este plan y los SDD 19/20 venían citando era **el 79% del CONTENIDO BINARIO**,
medido sobre una muestra de .so/.a. Es cierto y es la cifra equivocada para planificar, porque un
artefacto no es sólo binarios: trae cabeceras, datos, iconos, locales, .pc y documentación, que
no encogen.
MEDIDO con `scripts/medir-debug.sh` (suma los tamaños reales de las secciones .debug_* vía
readelf -S y los compara con el tamaño del árbol, sin reconstruir nada):
40 artefactos · 876 MB · 27%
100 artefactos · 2955 MB · 38% (truncada a 60 ficheros/artefacto)
250 artefactos · 8874 MB · 60% ← la que manda: sin truncar, ~7% del store
La varianza es alta porque unos pocos artefactos grandes dominan el total, así que el número
necesitaba validación independiente — y la tiene: el piloto de la etapa 2, donde se reconstruyó y
se pesó de verdad, dio bison −50% y appstream −68%. Los dos ENCIERRAN el 60% de la muestra
grande. El modelo predice lo que el rebuild produjo.
CIFRAS CORREGIDAS, con el store en 127 G:
se venía diciendo medido
reserva de disco ~96 G ~76 G
store tras el split ~30 G ~51 G
espejo público ~30 G ~51 G
Sigue siendo el mayor ahorro disponible en el proyecto —76 G no es poco— pero no es lo
prometido, y la diferencia importa para dimensionar el alojamiento del espejo, que es una
decisión con factura.
LA LECCIÓN: una cifra medida sobre una cosa (contenido binario) se citó durante semanas como si
midiera otra (tamaño de artefacto), y llegó a tres documentos. El número no era falso; LA UNIDAD
sí. Cuando un número vaya a decidir un gasto, hay que volver a la medición original y comprobar
QUÉ estaba midiendo.
Corregido en los tres sitios donde se había propagado.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semantic delta
No definition changed: this change is text, documentation or data.
4 files · +92 −5
diff --git a/docs/19-lanzamiento-publico.md b/docs/19-lanzamiento-publico.md
index 4f9da2d7..94b29e2c 100644
--- a/docs/19-lanzamiento-publico.md
+++ b/docs/19-lanzamiento-publico.md
@@ -95,8 +95,7 @@ Debian tuvo Iceweasel. Lo mismo con otros. Decidir por adelantado: cumplir o reb
## 3. Infraestructura pública
-1. **Espejo de paquetes e imágenes.** Dimensionado: el store son 126 G, pero **el 79% es información
- de depuración** ⇒ separar `-debug` en paquetes aparte baja el espejo a ~30 G. Ver
+1. **Espejo de paquetes e imágenes.** Dimensionado: el store son 126 G, pero **~60% es información de depuración** ⇒ separar `-debug` en paquetes aparte baja el espejo a **~51 G** (medido en la etapa 3 del SDD 23; el «79%» que se citaba era sobre el CONTENIDO BINARIO, no sobre el tamaño de artefacto). Ver
[SDD 17](17-cierres-frontera.md) y la nota de capacidad.
2. **Cadena de firma de release.** Hoy hay firma de índice. Falta el nivel de arriba: una **clave raíz
fuera de línea**, claves de firma rotables, y un procedimiento escrito de qué hacer si se filtra
diff --git a/docs/20-catalogo-publicable-y-completa.md b/docs/20-catalogo-publicable-y-completa.md
index 095f61cf..89fe7e51 100644
--- a/docs/20-catalogo-publicable-y-completa.md
+++ b/docs/20-catalogo-publicable-y-completa.md
@@ -149,8 +149,7 @@ lanzamiento** si se sale sin navegador propio.
## I.3 Infraestructura pública
-1. **Espejo de paquetes e imágenes.** Dimensionado real: el store son 128 G, pero **el 79% es
- información de depuración** ⇒ separando `-debug` en paquetes aparte el espejo baja a **~30 G**.
+1. **Espejo de paquetes e imágenes.** Dimensionado real: el store son 128 G, pero **~60% es información de depuración** ⇒ separando `-debug` en paquetes aparte el espejo baja a **~51 G** (medido en la etapa 3 del SDD 23; el «79%» que se citaba era sobre el CONTENIDO BINARIO, no sobre el tamaño de artefacto).
2. **Cadena de firma de release.** Hoy hay firma de índice. Falta el nivel de arriba: **clave raíz
fuera de línea**, claves de firma rotables y un procedimiento escrito para cuando se filtre una.
Firma sin gestión de claves es teatro.
diff --git a/docs/23-plan-rehasheo.md b/docs/23-plan-rehasheo.md
index 79f17fb8..07c33892 100644
--- a/docs/23-plan-rehasheo.md
+++ b/docs/23-plan-rehasheo.md
@@ -169,7 +169,7 @@ elegante de romper el corpus.
| 0 | `lab_version` en `hash_inputs` (opcional, no fijado) | los 1153 hashes actuales **no se mueven** |
| 1 | Verificación AMPLIA de reproducibilidad: apartar y reconstruir una muestra de ~30 recetas de clases distintas (C, Rust, Go, meson, cmake) y comparar con `why-differs` | **0 divergencias**; si alguna diverge, ESO es el trabajo real y esta campaña se pospone |
| 2 | Piloto del split de debug en **5 recetas** representativas | los `-debug` salen, el binario sigue funcionando, y el rebuild reproduce bit a bit |
-| 3 | Medir de verdad el ahorro sobre esas 5 y extrapolar | si el ahorro real se aleja mucho del 79% teórico, se replantea |
+| 3 | Medir de verdad el ahorro y extrapolar — ✅ **HECHO, ver §6** | el ahorro real es **~60%**, no 79%: se replanteó |
| 4 | Aplicar al corpus por tandas, con la granja | cada tanda: `store-gc` + `why-differs` sobre una muestra |
| 5 | Regenerar grafos, perfiles y el espejo | los perfiles siguen cerrando (`escritorio-sway` 121/121, KDE 162/162…) |
@@ -185,3 +185,49 @@ reconstruir con deps cacheadas, como se hizo con `wl-clipboard`.
- **No** strippear artefactos ya sellados: rompe la evidencia, que es el invariante del proyecto.
- **No** meter la flag en el lab sin `lab_version`: §3.
- **No** empezar por el corpus entero: §4 empieza por 5 recetas, y con razón.
+
+
+---
+
+## 6. Etapa 3 — el ahorro real es ~60%, no 79%, y las cifras publicadas estaban infladas
+
+El «79%» que este documento y los SDD 19/20 venían citando era **el 79% del CONTENIDO BINARIO**,
+medido sobre una muestra de `.so`/`.a`. Es cierto y es la cifra equivocada para planificar, porque
+un artefacto no es sólo binarios: trae cabeceras, datos, iconos, locales, `.pc` y documentación,
+que no encogen.
+
+**Medido con `scripts/medir-debug.sh`** (suma los tamaños reales de las secciones `.debug_*` vía
+`readelf -S` y los compara con el tamaño del árbol, sin reconstruir nada):
+
+| muestra | artefactos | volumen | debug / artefacto |
+|---|---:|---:|---:|
+| pequeña | 40 | 876 MB | 27% |
+| media (truncada a 60 ficheros/artefacto) | 100 | 2 955 MB | 38% |
+| **grande, sin truncar** | **250** | **8 874 MB** | **60%** |
+
+La varianza es alta porque unos pocos artefactos grandes dominan el total. **La muestra grande es la
+que manda** (cubre ~7% del store), y encaja con lo único que está medido de verdad —el piloto de la
+etapa 2, donde se reconstruyó y se pesó:
+
+- `bison` 6 M → 3 M = **−50%**
+- `appstream` 56 M → 18 M = **−68%**
+
+Los dos **encierran** el 60% de la muestra grande. Ésa es la validación: el modelo predice lo que el
+rebuild real produjo.
+
+### Las cifras corregidas
+Con el store en **127 G** y un ahorro de ~60%:
+
+| | se venía diciendo | medido |
+|---|---|---|
+| reserva de disco | ~96 G | **~76 G** |
+| store tras el split | ~30 G | **~51 G** |
+| espejo público | ~30 G | **~51 G** |
+
+Sigue siendo el mayor ahorro disponible en el proyecto —76 G no es poco— pero **no es lo prometido**,
+y la diferencia importa para dimensionar el alojamiento del espejo, que es una decisión con factura.
+
+> **La lección:** una cifra medida sobre una cosa (contenido binario) se citó durante semanas como si
+> midiera otra (tamaño de artefacto), y llegó a tres documentos. El número no era falso; **la unidad
+> sí**. Cuando un número vaya a decidir un gasto, conviene volver a la medición original y comprobar
+> QUÉ estaba midiendo.
diff --git a/scripts/medir-debug.sh b/scripts/medir-debug.sh
new file mode 100755
index 00000000..f86d167f
--- /dev/null
+++ b/scripts/medir-debug.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+# medir-debug.sh — cuánto pesa REALMENTE la info de depuración en el store. Etapa 3 del SDD 23.
+#
+# ── POR QUÉ NO BASTA EL «79%» QUE SE VENÍA CITANDO ─────────────────────────────────────────────
+# Ese número era «el 79% del CONTENIDO BINARIO son secciones .debug_*», medido sobre una muestra de
+# `.so`/`.a`. Es cierto y es engañoso para planificar, porque un artefacto NO es sólo binarios: trae
+# cabeceras, datos, iconos, locales, `.pc`, documentación. El ahorro que importa es sobre el TAMAÑO
+# DEL ARTEFACTO, y ése es necesariamente menor.
+#
+# El piloto lo confirmó: bison bajó 6M→3M (−50%) y appstream 56M→18M (−68%), los dos lejos del 79%.
+# Extrapolar con la cifra bonita habría prometido ~96 G de ahorro y entregado bastante menos.
+#
+# ── EL MÉTODO ──────────────────────────────────────────────────────────────────────────────────
+# Para cada artefacto: sumar el tamaño de las secciones `.debug_*` de cada ELF (`readelf -S`, que da
+# los tamaños reales) y compararlo con el tamaño total del árbol. No reconstruye nada, así que se
+# puede correr sobre cientos de artefactos en minutos en vez de días.
+#
+# Uso: scripts/medir-debug.sh [N] (N = cuántos artefactos muestrear, def 120)
+set -uo pipefail
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
+STORE="${STORE:-./store}"; N="${1:-120}"
+
+tot_kb=0; dbg_kb=0; n=0
+printf "%-30s %10s %10s %6s\n" "artefacto" "total" "debug" "%"
+for d in $(ls -d "$STORE"/*/ 2>/dev/null | shuf -n "$N" --random-source=/dev/urandom); do
+ [ -d "$d" ] || continue
+ t=$(du -sk "$d" 2>/dev/null | cut -f1); [ -n "$t" ] || continue
+ # Sumar .debug_* de todos los ELF del árbol. `readelf -S` imprime tamaños en hex.
+ b=$(find "$d" -type f \( -perm -u+x -o -name '*.so*' -o -name '*.a' \) 2>/dev/null | while read -r f; do
+ readelf -S "$f" 2>/dev/null | awk '/\.debug_/{getline; print strtonum("0x" $1)}'
+ done | awk '{s+=$1} END{print int(s/1024)}')
+ b=${b:-0}
+ [ "$t" -eq 0 ] && continue
+ n=$((n+1)); tot_kb=$((tot_kb+t)); dbg_kb=$((dbg_kb+b))
+ pct=$(( b * 100 / t ))
+ [ "$pct" -ge 40 ] && printf "%-30s %9sK %9sK %5s%%\n" "$(basename "$d" | cut -c66-95)" "$t" "$b" "$pct"
+done
+
+echo "──────────────────────────────────────────────────────────────"
+echo " artefactos medidos: $n"
+echo " total: $((tot_kb/1024)) MB · debug: $((dbg_kb/1024)) MB"
+[ "$tot_kb" -gt 0 ] && echo " ⇒ la info de depuración es el $(( dbg_kb * 100 / tot_kb ))% del TAMAÑO DE ARTEFACTO"
+echo " (el «79%» que se citaba era sobre el contenido BINARIO, no sobre el artefacto — ver cabecera)"