harkaq: primer barrido en la granja — la deuda irreducible de la muestra es perl (§4.10)

harkaq-farm-setup.sh: provisiona un worker para barrer (idempotente; gatea por
ABI>=7 y aborta si no llega — con la golden vieja el barrido daría SinEvidencia
en TODO). Deriva el runtime base DEL ROOTFS DEL WORKER, no copia el del laptop:
es por-rootfs (§4.3) y los sonames dependen de la versión de Alpine.

Barrido: 24 recetas, 14 con veredicto. Primer número crudo: 4 irreducibles (29%).
ERA FALSO, y por dos motivos propios:

1. GAP DE POLÍTICA. Los `list` salían sólo de los ancestros de la clausura ⇒ una
   receta SIN deps (bash) no generaba ni uno y todo escaneo del árbol caía como
   denegación (/usr/lib). Listar NO es leer: Landlock separa READ_DIR de
   READ_FILE ⇒ la estructura del árbol es CONTRATO. Se puede `ls /usr/lib` sin
   leer un solo fichero no declarado; la deuda es leer lo ajeno, no saber que
   existe. Idem /var/tmp: con --tmp-overlay / es scratch descartable, como /tmp.
2. La heurística del catálogo es por NOMBRE y un fichero no se llama como su
   paquete: /usr/bin/ranlib lo trae `binutils`, /usr/bin/diff lo trae
   `diffutils`. El único que sabe la verdad es el STORE (conoce la lista de
   ficheros de cada artefacto) — y el worker tiene 103 artefactos contra los
   cientos del hub.

⇒ EL WORKER MIDE, EL HUB CLASIFICA. Misma separación que lector/clasificador: el
que tiene el privilegio —o los datos— hace lo mínimo. Reclasificado en el hub:
    bash             ranlib,/usr/lib,/var/tmp → nada (gap de política)
    doas             /usr/bin/diff            → nada (diffutils lo provee)
    ca-certificates  /usr/bin/perl            → /usr/bin/perl
    curl             /usr/bin/perl            → /usr/bin/perl

RESULTADO: la deuda irreducible de toda la muestra es UN path — /usr/bin/perl
(2 de 14 = 14%). No hay recipes/perl.toml ni artefacto: deuda genuina y nombrada.
Todo lo demás era declarable (make ×10, ranlib→binutils, diff→diffutils).

Sigue por encima del <5% del §7, pero el perfil es el que importa: NO hay cola
larga de sorpresas. La deuda de un catálogo entero se resume en "declarar make" y
"no tenemos perl".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 17:50:34 -04:00
co-authored by Claude Opus 4.8
parent ea28a3dbcc
commit 13233ee4e9
4 changed files with 153 additions and 2 deletions
+15 -1
View File
@@ -257,7 +257,21 @@ impl Sandbox {
// del rootfs Alpine y no ve al host ⇒ contrato, no deuda. Lo destapó brotli, cuyo
// configure lee /proc/cpuinfo y /proc/meminfo para dimensionar el paralelismo.
"ro /proc",
"list /", "list /opt",
// LISTAR la estructura del árbol no es deuda: Landlock separa READ_DIR de READ_FILE,
// así que esto deja hacer `ls /usr/lib` sin poder LEER un solo fichero no declarado.
// La deuda de de-Alpinización es leer/ejecutar lo ajeno, no saber que existe.
//
// Sin esto, una receta SIN deps no genera ni un `list` (los `list` salían sólo de los
// ancestros de la clausura) ⇒ todo escaneo del árbol caía como denegación. El barrido
// en la granja marcaba a bash como deuda IRREDUCIBLE por `/usr/lib`, que es un gap de
// política, no una dependencia de Alpine — un falso positivo de los que matan el
// proyecto (§7).
"list /", "list /opt", "list /usr", "list /usr/bin", "list /usr/lib",
"list /usr/include", "list /usr/share", "list /usr/libexec", "list /usr/local",
"list /lib", "list /bin", "list /sbin", "list /usr/sbin", "list /etc", "list /var",
// `--tmp-overlay /` hace la raíz escribible con una capa tmpfs descartable: escribir
// en /var/tmp no toca el rootfs Alpine ni sobrevive al build. Es scratch, como /tmp.
"rw /var/tmp",
]
.iter()
.map(|s| s.to_string())