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>
This commit is contained in:
2026-08-08 00:42:08 -04:00
co-authored by Claude Opus 5
parent fbd586f9b2
commit 1eb469337d
4 changed files with 92 additions and 5 deletions
+1 -2
View File
@@ -95,8 +95,7 @@ Debian tuvo Iceweasel. Lo mismo con otros. Decidir por adelantado: cumplir o reb
## 3. Infraestructura pública ## 3. Infraestructura pública
1. **Espejo de paquetes e imágenes.** Dimensionado: el store son 126 G, pero **el 79% es información 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
de depuración** ⇒ separar `-debug` en paquetes aparte baja el espejo a ~30 G. Ver
[SDD 17](17-cierres-frontera.md) y la nota de capacidad. [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 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 fuera de línea**, claves de firma rotables, y un procedimiento escrito de qué hacer si se filtra
+1 -2
View File
@@ -149,8 +149,7 @@ lanzamiento** si se sale sin navegador propio.
## I.3 Infraestructura pública ## I.3 Infraestructura pública
1. **Espejo de paquetes e imágenes.** Dimensionado real: el store son 128 G, pero **el 79% es 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).
información de depuración** ⇒ separando `-debug` en paquetes aparte el espejo baja a **~30 G**.
2. **Cadena de firma de release.** Hoy hay firma de índice. Falta el nivel de arriba: **clave raíz 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. 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. Firma sin gestión de claves es teatro.
+47 -1
View File
@@ -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** | | 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 | | 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 | | 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 | | 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…) | | 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** 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** 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. - **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.
+43
View File
@@ -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)"