1# Plan — botar busybox, MEDIDO
2
3**Fecha:** 2026-09-21 · **Instrumento:** los 401 symlinks de applet del artefacto sellado
4`2a2b1280…-busybox` (contados en el store del worker), cruzados con el estado y la membresía de
5perfil de cada receta en `docs/state/build-state.json` y con `grep '[deps]' recipes/*.toml`.
6**Tabla applet-por-applet:** `docs/state/busybox-applets.tsv` (401 filas, generada, no escrita a mano).
7
8## Por qué existe este documento
9
10La pregunta fue «¿qué hay que hacer para botar busybox?», con la sospecha de que faltaba escribir
11mucho userland en Rust. **El número dice lo contrario, y el hueco está en otro lado:**
12
13> De los 401 applets, **148 ya tienen dueño sellado Y en perfil** (el applet es redundante en la
14> imagen), **125 tienen dueño sellado que NO viaja en ninguna imagen** (trabajo hecho y no cobrado),
15> y de los **128 sin dueño, 105 son basura que se borra**. El trabajo de escritura real son
16> **23 applets** repartidos en 8 piezas.
17
18Es la lección de `foot` y del §D de `plan-barrido-perfiles-y-servicios.md` otra vez: `uutils`,
19`findutils`, `findutils-xargs`, `diffutils` y **`brush`** están todos `sealed` con `perfiles: []`.
20Se construyeron, se sellaron, y ninguna imagen los lleva.
21
22## Son TRES frentes, no uno — y esto es lo que hace que «botar busybox» se lea como imposible
23
24Mezclarlos es el error que cuesta el trabajo. Tienen dificultad, dueño y riesgo distintos:
25
26| frente | qué es busybox ahí | dificultad |
27|---|---|---|
28| **A · Sandbox de build** | `[deps] build = [… "busybox" …]` en **24 recetas** — es el `sh`+coreutils que el sandbox del lab trae (`recipes/jq.toml:5-7`, `recipes/zlib-ng.toml:11`). Más el `/toolchain` mixto de Alpine con el swap de `docs/11-bootstrap.md:234-240` | media — no es runtime, no toca el producto |
29| **B · Runtime del producto** | los applets de `/bin` y `/sbin` de las imágenes. `USERLAND_COMPONENTS` (`crates/takana-bootstrap/src/lib.rs:406`) ya los ensombrece con los binarios Rust y retira el homónimo de los otros dirs (`lib.rs:676`) | **baja — la máquina ya está construida, falta munición** |
30| **C · Stage 1 / self-host / atestación** | `STAGE1_COMPONENTS` (`lib.rs:172`, el 4/4), `ATTEST_PATHS` como raíz-de-confianza (`lib.rs:465`), y el `exec` de las cards de `getty` y `sshd` (`lib.rs:429`, `:240`) | **alta — es el ADR 0008, y toca la evidencia de reproducibilidad `of_tree=9adefb82…`** |
31
32⚠ **La membresía de perfil de busybox es del frente A, no del B.** `busybox` figura en `cli`,
33`servidor`, los cuatro escritorios y `metal-tigerlake`, pero **no está declarado como raíz en
34`docs/state/targets.toml`** (los únicos hits ahí son comentarios). Llega por la clausura, porque 24
35recetas lo declaran build-dep: `abseil-cpp chrony cronie crun dwarves firmware-tigerlake
36ia-modelo-embeddings intel-ucode jq libmnl libnftnl linux linux-firmware llama-cpp logrotate
37nftables opensmtpd popt protobuf qdrant sof-firmware valkey wireless-regdb zlib-ng`. **Sacarlo de
38las imágenes empieza por ahí y no requiere escribir ni una línea de userland.**
39
40## El reparto de los 401
41
42| estado del dueño | n | qué significa |
43|---|---|---|
44| **sellada + en perfil** | 148 | el reemplazo ya viaja en la imagen: el applet es redundante hoy |
45| **sellada, sin perfil** | 125 | construido, sellado, y no viaja: falta declararlo |
46| **sin dueño** | 128 | de los cuales **105 son `BORRAR`** y **23 son trabajo real** |
47
48### 148 · Ya cubiertos y en la imagen — el applet sobra
49
50`util-linux` 48 · `iproute2` 19 · `procps-ng` 12 · `shadow` 14 · `kbd` 12 · `xz` 6 · `iputils` 5 ·
51`e2fsprogs` 5 · `bzip2` 3 · `cronie` 3 · `dhcpcd` 3 · `ncurses` 2 · `dosfstools` 2 · `chrony` 2 ·
52`vim` 2 · `less` `lsof` `pciutils` `usbutils` `mandoc` `socat` `patch` `binutils` `tar` `wget` 1 c/u.
53
54⚠ **24 de estos 148 NO son drop-in**, y están marcados en el TSV. El caso grande es la red:
55`iproute2` da `ip`/`ss`, **no** `ifconfig`/`route`/`arp`/`netstat` — eso es net-tools, que no está en
56el corpus. Igual con `addgroup`/`adduser` (shadow da `groupadd`/`useradd`), `udhcpc` (dhcpcd es otro
57cliente con otro contrato de hooks) y `nc` (socat tiene otra sintaxis). **Cada uno de esos 24 es una
58migración de llamadores, no un borrado.** Mirar quién los invoca en `scripts/` y en las cards antes.
59
60### 125 · Sellados y sin viajar — la munición que ya está fabricada
61
62| dueño | n | qué cubre |
63|---|---|---|
64| `uutils` | 90 | todo el núcleo POSIX: `ls cp mv rm cat head tail sort cut tr wc stat date dd chmod chown …` |
65| `arje-zero` | 20 | `init linuxrc runlevel halt poweroff reboot run-init switch_root` + los 12 de runit (`runsv sv svc svlogd chpst envdir setuidgid softlimit start-stop-daemon …`) |
66| `hammerd` | 4 | `syslogd klogd logger logread` |
67| `brush` | 3 | **`sh ash hush`** |
68| `gzip` | 3 | `gzip gunzip zcat` |
69| `diffutils` | 2 | `diff cmp` |
70| `findutils` / `findutils-xargs` / `libarchive` | 3 | `find` · `xargs` · `cpio` |
71
72**Los 24 de `arje-zero` y `hammerd` no cuestan nada**: el reemplazo ya corre en el producto. Son
73applets instalados que nadie ejecuta. Salen del `defconfig` y se prueba que la imagen arranque igual.
74
75### 128 · Sin dueño
76
77**105 se borran** (no se reemplazan, salen del `defconfig`): `dpkg dpkg-deb rpm rpm2cpio httpd ftpd
78ftpget ftpput tftp tftpd telnet telnetd inetd dnsd sendmail popmaildir lpd lpq lpr ubi* nand*
79nbd-client i2c* hdparm fdformat setserial powertop bootchartd fbsplash conspy ether-wake udhcpd
80udpsvd tcpsvd watchdog whois tree which unzip …` (lista completa en el TSV).
81
82**23 son el trabajo real:**
83
84| pieza | applets | qué es |
85|---|---|---|
86| **kmod** | `insmod rmmod lsmod modprobe depmod modinfo` (6) | no hay receta kmod en el corpus. En Rust: `finit_module` + parseo de `modules.dep`. Bien acotado |
87| **psmisc** | `killall killall5 pstree fuser` (4) | **`procps-ng` NO los trae.** Traer receta psmisc (C) o escribir |
88| **grep POSIX** | `grep egrep fgrep` (3) | `grep` GNU está sellado (sin perfil) como puente. El Rust nativo se escribe sobre `grep-matcher`/`grep-regex`/`grep-searcher` |
89| **gestor de /dev** | `mdev makedevs uevent` (3) | decisión: lo absorbe arje, o entra una receta eudev/mdevd |
90| **bc** | `bc dc` (2) | traer receta |
91| **getty** | `getty cttyhack` (2) | hoy la card de getty ejecuta `/bin/busybox` (`lib.rs:429`) |
92| **awk** | `awk` (1) | decisión abierta, ver abajo |
93| **sed** | `sed` (1) | `sed` GNU sellado y en los 7 perfiles; el Rust nativo está por escribir |
94| **dns** | `nslookup` (1) | traer receta bind-tools/doggo |
95
96## Las tres clases de reemplazo — y cuándo forkear (nunca)
97
98La pregunta era si hay que forkear los que «existen pero no son exactos». **No, y hay tres clases
99distintas que conviene no mezclar:**
100
101**1 · Adopción exacta.** `uutils/coreutils`, `uutils/findutils`, `uutils/diffutils`: reimplementación
102madura, MIT, receta Cargo con commit pinneado (ADR 0006), multicall. El patrón está probado y
103documentado en la cabecera de `recipes/uutils.toml`. Lo que falta de esta clase es
104**`uutils/procps`** y **`uutils/util-linux`** — receta calcada, coste bajo. ⚠ **Verificar su estado
105upstream antes de prometer los 60 applets que cubrirían**: `util-linux` en Rust era embrionario.
106
107**2 · «Existe pero no es exacto» — y forkear es la trampa.** `ripgrep` no es `grep` POSIX, `sd` no es
108`sed`, `fd` no es `find` (por eso la receta buena es `uutils/findutils` y no `fd`), `procs` no es
109`ps`, `bottom` no es `top`, `helix` no es `vi`. Todas están selladas y en los 7 perfiles, y **ninguna
110sirve de reemplazo**: cambian las banderas. Forkear ripgrep para que hable POSIX es peor que
111escribir — heredás su arquitectura de recursión+ignore y peleás contra ella para siempre. Lo correcto
112es usarlas **como librerías**: `grep-matcher`/`grep-regex`/`grep-searcher` están publicadas
113justamente para eso, y un `grep` POSIX encima son unos cientos de líneas.
114
115**3 · `awk` es el caso feo, y hay que decidirlo, no resolverlo de paso.** `recipes/goawk.toml` existe
116y está sellada, pero **goawk es Go, no Rust** — no cumple la premisa de soberanía de cadena de la
117Etapa C. `frawk` es Rust pero es otro dialecto (JIT, semántica propia). `gawk` es C con extensiones
118GNU que los `configure` del corpus sí usan. Las tres opciones son legítimas y ninguna es gratis.
119
120## El bloqueante, y la buena noticia
121
122**Sin `sh` POSIX no se bota busybox en ningún frente**: es el `exec` de las cards, el `/bin/sh` del
123producto y el shell del sandbox. Lo esperado era que fuera un proyecto de meses.
124
125**`recipes/brush.toml` (0.4.0, reubeno/brush, MIT, Rust, compat bash) está `sealed`.** Compila
126estático musl con zig cc y produce `/usr/bin/brush`.
127
128⚠ **Y está sin validar como `sh`.** La receta es un import crudo de nixpkgs y lo dice en su primera
129línea: «PUNTO DE PARTIDA, no final». No está en ningún perfil, nadie lo ejecutó como `/bin/sh`, y el
130sandbox de build es el consumidor más duro que existe (`configure` de autotools). **La unidad de
131trabajo #1 es medirlo, no adoptarlo.**
132
133## Orden de ataque
134
135Cada paso es una unidad de trabajo con su criterio de terminado. Los tres primeros **no tocan el
136frente C** y se pueden hacer hoy.
137
1381. **Recortar el `defconfig`.** Sacar los 105 de `BORRAR` + los 24 que `arje-zero`/`hammerd` ya
139 reemplazan = **129 applets menos, cero código escrito**. Terminado cuando la imagen arranca, el
140 E2E de QEMU pasa y `find . -type l | wc -l` baja de 401 a ~272.
1412. **Declarar la munición que ya existe.** `uutils`, `findutils`, `findutils-xargs`, `diffutils`,
142 `brush`, `gzip`, `libarchive` a los perfiles de `targets.toml`. Terminado cuando `build-state.py`
143 los marca con perfil y la imagen los lleva.
1443. **Medir `brush` como `/bin/sh`.** Correr con él los `configure` de tres recetas autotools del
145 corpus y el `product-boot-test.sh`. Terminado con un veredicto escrito: sirve, o falla en X.
1464. **Las dos recetas de adopción baratas** (`uutils/procps`, `uutils/util-linux`), previa
147 verificación de madurez upstream. Cubren ~60 applets de los 148 «ya cubiertos por C».
1485. **`grep` y `sed` POSIX en Rust.** Es la escritura de mejor relación coste/beneficio y desbloquea
149 el `/toolchain` del frente A.
1506. **Migrar los 24 build-deps.** Cambiar `busybox` por el conjunto real en `[deps] build` de las 24
151 recetas. Terminado cuando `busybox` sale de los 7 perfiles.
1527. **La cola larga:** kmod, psmisc, gestor de /dev, getty, bc, dns. Después del shell, no antes.
1538. **ADR — `awk`**, y **ADR — el frente C** (sustituir busybox en `STAGE1_COMPONENTS` y
154 `ATTEST_PATHS`). No antes de que 1–7 estén cerrados.
155
156## La métrica, y el guardián que falta
157
158`docs/state/busybox-applets.tsv` convierte esto en un número que baja: **401 → 272 → … → 0**.
159Regenerarlo es contar los symlinks del artefacto sellado y cruzarlos con `build-state.json`.
160
161**Falta un guardián**, y sin él el paso 1 se deshace solo: un script que falle si alguna receta,
162script o card invoca un applet que ya salió del `defconfig`. Hoy nada lo detectaría — el fallo
163aparecería en boot, en otra máquina, semanas después.
164
165## Lo que este documento NO midió (y hay que decirlo así)
166
167- **El reparto applet→destino es juicio, no medida.** Lo medido son los 401 symlinks, el estado
168 `sealed`/perfiles de cada receta y las 24 recetas con `busybox` en `[deps] build`. La asignación de
169 dueño la escribí yo y hay que revisarla receta a receta.
170- **No se verificó la equivalencia de banderas de ninguna pareja.** Los 24 marcados `NO-drop-in` son
171 los que sé que difieren; el resto dice `sin-verificar` y eso es literal, no una forma de decir «va
172 a andar».
173- **No se midió qué applets usa el producto de verdad.** El `defconfig` instala 401 porque nadie
174 eligió; cuáles se ejecutan en una imagen viva no está medido. Eso abarataría el paso 1.
175- **`uutils/procps` y `uutils/util-linux` no se verificaron upstream.** Los ~60 applets que les
176 atribuyo son una hipótesis de trabajo.
plan-botar-busybox.md
Plan — botar busybox, MEDIDO
Fecha: 2026-09-21 · Instrumento: los 401 symlinks de applet del artefacto sellado
2a2b1280…-busybox (contados en el store del worker), cruzados con el estado y la membresía de
perfil de cada receta en docs/state/build-state.json y con grep '[deps]' recipes/*.toml.
Tabla applet-por-applet: docs/state/busybox-applets.tsv (401 filas, generada, no escrita a mano).
Por qué existe este documento
La pregunta fue «¿qué hay que hacer para botar busybox?», con la sospecha de que faltaba escribir
mucho userland en Rust. El número dice lo contrario, y el hueco está en otro lado:
De los 401 applets, 148 ya tienen dueño sellado Y en perfil (el applet es redundante en la
imagen), 125 tienen dueño sellado que NO viaja en ninguna imagen (trabajo hecho y no cobrado),
y de los 128 sin dueño, 105 son basura que se borra. El trabajo de escritura real son
23 applets repartidos en 8 piezas.
Es la lección de foot y del §D de plan-barrido-perfiles-y-servicios.md otra vez: uutils,
findutils, findutils-xargs, diffutils y brush están todos sealed con perfiles: [].
Se construyeron, se sellaron, y ninguna imagen los lleva.
Son TRES frentes, no uno — y esto es lo que hace que «botar busybox» se lea como imposible
Mezclarlos es el error que cuesta el trabajo. Tienen dificultad, dueño y riesgo distintos:
| frente | qué es busybox ahí | dificultad |
| A · Sandbox de build | [deps] build = [… "busybox" …] en 24 recetas — es el sh+coreutils que el sandbox del lab trae (recipes/jq.toml:5-7, recipes/zlib-ng.toml:11). Más el /toolchain mixto de Alpine con el swap de docs/11-bootstrap.md:234-240 | media — no es runtime, no toca el producto |
| B · Runtime del producto | los applets de /bin y /sbin de las imágenes. USERLAND_COMPONENTS (crates/takana-bootstrap/src/lib.rs:406) ya los ensombrece con los binarios Rust y retira el homónimo de los otros dirs (lib.rs:676) | baja — la máquina ya está construida, falta munición |
| C · Stage 1 / self-host / atestación | STAGE1_COMPONENTS (lib.rs:172, el 4/4), ATTEST_PATHS como raíz-de-confianza (lib.rs:465), y el exec de las cards de getty y sshd (lib.rs:429, :240) | alta — es el ADR 0008, y toca la evidencia de reproducibilidad of_tree=9adefb82… |
⚠ La membresía de perfil de busybox es del frente A, no del B. busybox figura en cli,
servidor, los cuatro escritorios y metal-tigerlake, pero no está declarado como raíz en
docs/state/targets.toml (los únicos hits ahí son comentarios). Llega por la clausura, porque 24
recetas lo declaran build-dep: abseil-cpp chrony cronie crun dwarves firmware-tigerlake ia-modelo-embeddings intel-ucode jq libmnl libnftnl linux linux-firmware llama-cpp logrotate nftables opensmtpd popt protobuf qdrant sof-firmware valkey wireless-regdb zlib-ng. Sacarlo de
las imágenes empieza por ahí y no requiere escribir ni una línea de userland.
El reparto de los 401
| estado del dueño | n | qué significa |
| sellada + en perfil | 148 | el reemplazo ya viaja en la imagen: el applet es redundante hoy |
| sellada, sin perfil | 125 | construido, sellado, y no viaja: falta declararlo |
| sin dueño | 128 | de los cuales 105 son BORRAR y 23 son trabajo real |
148 · Ya cubiertos y en la imagen — el applet sobra
util-linux 48 · iproute2 19 · procps-ng 12 · shadow 14 · kbd 12 · xz 6 · iputils 5 ·
e2fsprogs 5 · bzip2 3 · cronie 3 · dhcpcd 3 · ncurses 2 · dosfstools 2 · chrony 2 ·
vim 2 · less lsof pciutils usbutils mandoc socat patch binutils tar wget 1 c/u.
⚠ 24 de estos 148 NO son drop-in, y están marcados en el TSV. El caso grande es la red:
iproute2 da ip/ss, no ifconfig/route/arp/netstat — eso es net-tools, que no está en
el corpus. Igual con addgroup/adduser (shadow da groupadd/useradd), udhcpc (dhcpcd es otro
cliente con otro contrato de hooks) y nc (socat tiene otra sintaxis). Cada uno de esos 24 es una
migración de llamadores, no un borrado. Mirar quién los invoca en scripts/ y en las cards antes.
125 · Sellados y sin viajar — la munición que ya está fabricada
| dueño | n | qué cubre |
uutils | 90 | todo el núcleo POSIX: ls cp mv rm cat head tail sort cut tr wc stat date dd chmod chown … |
arje-zero | 20 | init linuxrc runlevel halt poweroff reboot run-init switch_root + los 12 de runit (runsv sv svc svlogd chpst envdir setuidgid softlimit start-stop-daemon …) |
hammerd | 4 | syslogd klogd logger logread |
brush | 3 | sh ash hush |
gzip | 3 | gzip gunzip zcat |
diffutils | 2 | diff cmp |
findutils / findutils-xargs / libarchive | 3 | find · xargs · cpio |
Los 24 de arje-zero y hammerd no cuestan nada: el reemplazo ya corre en el producto. Son
applets instalados que nadie ejecuta. Salen del defconfig y se prueba que la imagen arranque igual.
128 · Sin dueño
105 se borran (no se reemplazan, salen del defconfig): dpkg dpkg-deb rpm rpm2cpio httpd ftpd ftpget ftpput tftp tftpd telnet telnetd inetd dnsd sendmail popmaildir lpd lpq lpr ubi* nand* nbd-client i2c* hdparm fdformat setserial powertop bootchartd fbsplash conspy ether-wake udhcpd udpsvd tcpsvd watchdog whois tree which unzip … (lista completa en el TSV).
23 son el trabajo real:
| pieza | applets | qué es |
| kmod | insmod rmmod lsmod modprobe depmod modinfo (6) | no hay receta kmod en el corpus. En Rust: finit_module + parseo de modules.dep. Bien acotado |
| psmisc | killall killall5 pstree fuser (4) | procps-ng NO los trae. Traer receta psmisc (C) o escribir |
| grep POSIX | grep egrep fgrep (3) | grep GNU está sellado (sin perfil) como puente. El Rust nativo se escribe sobre grep-matcher/grep-regex/grep-searcher |
| gestor de /dev | mdev makedevs uevent (3) | decisión: lo absorbe arje, o entra una receta eudev/mdevd |
| bc | bc dc (2) | traer receta |
| getty | getty cttyhack (2) | hoy la card de getty ejecuta /bin/busybox (lib.rs:429) |
| awk | awk (1) | decisión abierta, ver abajo |
| sed | sed (1) | sed GNU sellado y en los 7 perfiles; el Rust nativo está por escribir |
| dns | nslookup (1) | traer receta bind-tools/doggo |
Las tres clases de reemplazo — y cuándo forkear (nunca)
La pregunta era si hay que forkear los que «existen pero no son exactos». No, y hay tres clases
distintas que conviene no mezclar:
1 · Adopción exacta. uutils/coreutils, uutils/findutils, uutils/diffutils: reimplementación
madura, MIT, receta Cargo con commit pinneado (ADR 0006), multicall. El patrón está probado y
documentado en la cabecera de recipes/uutils.toml. Lo que falta de esta clase es
uutils/procps y uutils/util-linux — receta calcada, coste bajo. ⚠ Verificar su estado
upstream antes de prometer los 60 applets que cubrirían: util-linux en Rust era embrionario.
2 · «Existe pero no es exacto» — y forkear es la trampa. ripgrep no es grep POSIX, sd no es
sed, fd no es find (por eso la receta buena es uutils/findutils y no fd), procs no es
ps, bottom no es top, helix no es vi. Todas están selladas y en los 7 perfiles, y ninguna
sirve de reemplazo: cambian las banderas. Forkear ripgrep para que hable POSIX es peor que
escribir — heredás su arquitectura de recursión+ignore y peleás contra ella para siempre. Lo correcto
es usarlas como librerías: grep-matcher/grep-regex/grep-searcher están publicadas
justamente para eso, y un grep POSIX encima son unos cientos de líneas.
3 · awk es el caso feo, y hay que decidirlo, no resolverlo de paso. recipes/goawk.toml existe
y está sellada, pero goawk es Go, no Rust — no cumple la premisa de soberanía de cadena de la
Etapa C. frawk es Rust pero es otro dialecto (JIT, semántica propia). gawk es C con extensiones
GNU que los configure del corpus sí usan. Las tres opciones son legítimas y ninguna es gratis.
El bloqueante, y la buena noticia
Sin sh POSIX no se bota busybox en ningún frente: es el exec de las cards, el /bin/sh del
producto y el shell del sandbox. Lo esperado era que fuera un proyecto de meses.
recipes/brush.toml (0.4.0, reubeno/brush, MIT, Rust, compat bash) está sealed. Compila
estático musl con zig cc y produce /usr/bin/brush.
⚠ Y está sin validar como sh. La receta es un import crudo de nixpkgs y lo dice en su primera
línea: «PUNTO DE PARTIDA, no final». No está en ningún perfil, nadie lo ejecutó como /bin/sh, y el
sandbox de build es el consumidor más duro que existe (configure de autotools). La unidad de
trabajo #1 es medirlo, no adoptarlo.
Orden de ataque
Cada paso es una unidad de trabajo con su criterio de terminado. Los tres primeros no tocan el
frente C y se pueden hacer hoy.
- Recortar el
defconfig. Sacar los 105 de BORRAR + los 24 que arje-zero/hammerd ya
reemplazan = 129 applets menos, cero código escrito. Terminado cuando la imagen arranca, el
E2E de QEMU pasa y find . -type l | wc -l baja de 401 a ~272.
- Declarar la munición que ya existe.
uutils, findutils, findutils-xargs, diffutils,
brush, gzip, libarchive a los perfiles de targets.toml. Terminado cuando build-state.py
los marca con perfil y la imagen los lleva.
- Medir
brush como /bin/sh. Correr con él los configure de tres recetas autotools del
corpus y el product-boot-test.sh. Terminado con un veredicto escrito: sirve, o falla en X.
- Las dos recetas de adopción baratas (
uutils/procps, uutils/util-linux), previa
verificación de madurez upstream. Cubren ~60 applets de los 148 «ya cubiertos por C».
grep y sed POSIX en Rust. Es la escritura de mejor relación coste/beneficio y desbloquea
el /toolchain del frente A.
- Migrar los 24 build-deps. Cambiar
busybox por el conjunto real en [deps] build de las 24
recetas. Terminado cuando busybox sale de los 7 perfiles.
- La cola larga: kmod, psmisc, gestor de /dev, getty, bc, dns. Después del shell, no antes.
- ADR —
awk, y ADR — el frente C (sustituir busybox en STAGE1_COMPONENTS y
ATTEST_PATHS). No antes de que 1–7 estén cerrados.
La métrica, y el guardián que falta
docs/state/busybox-applets.tsv convierte esto en un número que baja: 401 → 272 → … → 0.
Regenerarlo es contar los symlinks del artefacto sellado y cruzarlos con build-state.json.
Falta un guardián, y sin él el paso 1 se deshace solo: un script que falle si alguna receta,
script o card invoca un applet que ya salió del defconfig. Hoy nada lo detectaría — el fallo
aparecería en boot, en otra máquina, semanas después.
Lo que este documento NO midió (y hay que decirlo así)
- El reparto applet→destino es juicio, no medida. Lo medido son los 401 symlinks, el estado
sealed/perfiles de cada receta y las 24 recetas con busybox en [deps] build. La asignación de
dueño la escribí yo y hay que revisarla receta a receta.
- No se verificó la equivalencia de banderas de ninguna pareja. Los 24 marcados
NO-drop-in son
los que sé que difieren; el resto dice sin-verificar y eso es literal, no una forma de decir «va
a andar».
- No se midió qué applets usa el producto de verdad. El
defconfig instala 401 porque nadie
eligió; cuáles se ejecutan en una imagen viva no está medido. Eso abarataría el paso 1.
uutils/procps y uutils/util-linux no se verificaron upstream. Los ~60 applets que les
atribuyo son una hipótesis de trabajo.