plan freebsd: traza positiva (filemon/META MODE) + taxonomía casper para cierre §3 + libarchive al catálogo

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 22:03:24 -04:00
co-authored by Claude Fable 5
parent be52e735ab
commit 8ff8c1b820
+118
View File
@@ -0,0 +1,118 @@
# Plan — qué tomar de FreeBSD
**Fecha:** 2026-07-16 · **Origen:** análisis de META MODE/filemon, Capsicum/casper y
libarchive contra el estado real de hammer (harkaq Fase 2, cierres §2/§3, catálogo Etapa G).
**Regla del análisis:** de otro kernel se toma *diseño*, no código. La única pieza de código
importable es libarchive (como receta del catálogo, igual que cualquier otra). Todo lo demás
es prior art que valida o corrige decisiones ya tomadas.
---
## 1. filemon / META MODE → la traza POSITIVA que a harkaq le falta
**Qué tiene FreeBSD.** `filemon(4)` registra en el kernel cada acceso a fichero durante un
build; `bmake` en META MODE escribe un `.meta` por target con *todo lo que el build tocó*,
normalizado. Con eso hacen auto-descubrimiento de dependencias y detección de builds impuros:
si la traza cambia, el target se reconstruye. Llevan ~12 años iterando qué normalizar (orden,
tmpdirs, accesos que no importan).
**Qué tiene hammer hoy.** harkaq mide sólo evidencia **negativa**: denegaciones Landlock bajo
política=clausura (`harkaq-audit.c` emite JSON `{path, motivo}`, `harkaq-verdict.py` clasifica
esperada/deuda). Lo que NO mide: **qué parte de la clausura concedida se usó de verdad**.
**La brecha que eso deja.** harkaq detecta *sub*-declaración (deuda) pero no
*sobre*-declaración: una dep declarada y jamás tocada es invisible, engorda la clausura, y esa
grasa se hereda directo a la política runtime derivada del cierre §3 (política más ancha de lo
necesario = evidencia más débil). La traza positiva es el dual exacto del veredicto actual.
**Tareas:**
- **T1.1 — sonda de uso positivo.** Un `harkaq-trace` que emita la lista de paths *abiertos*
por fase dentro del sandbox. Mecanismo candidato: fanotify — que ya es frente delegado por
arje (journal fanotify, ver handoff) ⇒ reutilizar ese trabajo, no abrir mecanismo nuevo.
Alternativa si fanotify dentro del userns del sandbox se complica: eBPF sobre `openat`
(BPF_SYSCALL ya es explícito en los kernels propios, commit 2b7c701).
- **T1.2 — normalización estilo `.meta`.** Orden estable, dedupe, paths relativos a la jaula,
filtrar tmpdirs / `/out` / `/src`. Las reglas de ruido viven junto a la política — la misma
fuente de verdad que los `# expect` (D3: no se calla, se clasifica; el ruido se declara,
no se pierde). Aquí es donde la experiencia de META MODE ahorra iteraciones: readdir sin
orden garantizado y accesos especulativos del compilador son las dos fuentes de ruido que
ellos ya catalogaron.
- **T1.3 — sellar la traza.** El `b3:` de la traza normalizada viaja junto al `of_tree` del
artefacto. Uso inmediato para **why-differs (cierre §2, top-2)**: dos builders que divergen
en hash se comparan primero por traza — diff de dos listas de texto ANTES que diff
estructural de binarios. El descenso por rangos de `reconcile`/`format` aplica igual.
- **T1.4 — `harkaq-suggest --poda`.** Con traza positiva, sugerir *remover* deps
declaradas-no-usadas: el dual del suggest actual (que sólo sugiere añadir). Cierra el bucle
en ambas direcciones: la clausura converge a exactamente-lo-usado.
**Riesgos.** Coste de fanotify en builds grandes (medir primero); falsos "no usados" por
accesos condicionales entre corridas (mitigación: la poda sugiere, nunca aplica sola — mismo
contrato que suggest). Piloto: 3 recetas ya instrumentadas (zlib, tar, brotli), en el worker
(el laptop no compila C).
---
## 2. Capsicum / casper → la taxonomía del cierre §3 (política runtime)
**La lección negativa.** Capsicum es más puro que Landlock (capabilities sobre fds,
`cap_enter()`), y aun así FreeBSD terminó necesitando `casper`: demonios auxiliares porque
hay una clase de necesidades — DNS, certificados TLS, syslog, random temprano, locale — que
son *servicios del mundo*, no paths, y no caben en ninguna jaula por-fichero.
**Dónde muerde en hammer.** En build: en ninguna parte — los builds son offline por
`--unshare-all`, la clase casper es vacía por construcción. En **runtime** (cierre §3: derivar
la política Landlock del binario instalado desde la clausura medida en build): la clausura de
build **no contiene** esa clase ⇒ derivar a ciegas produce binarios que revientan en el primer
`getaddrinfo`. Saber esto *antes* de arrancar Fase 3 es exactamente el valor del prior art.
**Tareas (papel, cero código hoy):**
- **T2.1 — sección "servicios del mundo" en SDD 16 (Fase 3).** La política runtime = clausura
de build **+ clases de servicio declaradas** (`dns`, `tls-certs`, `random`, `locale`,
`syslog`). Se declara por clase con nombre, nunca se ensancha en silencio — D3 aplica en
runtime igual que en build.
- **T2.2 — mapa clase→paths para musl.** Ventaja estructural de hammer: musl no tiene
nsswitch ni dlopen de módulos NSS — `dns` = `/etc/resolv.conf` + socket UDP; `tls-certs` =
`/etc/ssl/certs`; `random` = `getrandom(2)` (ni path necesita). El mapa completo cabe en
media página; en glibc esto era intratable y es la mitad de por qué casper existe.
- **T2.3 — la clase viaja en la ConcesionCapacidad.** `(blake3(binario), permisos)` gana un
campo de clases de servicio; `arje-absorb --attest-from` ya integra concesiones (PLAN-ATESTACION
§B.3) ⇒ sin formato nuevo.
---
## 3. libarchive / bsdtar → receta + extractor de referencia
El único export de código real de FreeBSD que todo el mundo usa.
- **T3.1 — `recipes/libarchive.toml`.** Receta C ⇒ worker. Nombre nuevo en el catálogo, sin
riesgo de colisión homónima (el gotcha de promote no aplica). Deps mínimas: zlib (xz/zstd
opcionales según features que se activen).
- **T3.2 — verificación cruzada de formato.** Donde hammer serializa árboles (pack/export),
extraer con bsdtar y comparar el árbol resultante contra el extractor propio = **consenso de
implementación aplicado al FORMATO** — mismo espíritu que el consenso de reconstrucción
(cierre §1) aplicado a los bytes del contenedor, no al build. Barato: un script de barrido
sobre N artefactos sellados.
- **T3.3 (opcional) — bsdtar como dep de build** para tarballs exóticos donde busybox tar se
queda corto (hoy: ninguno conocido; tener la receta lo vuelve una línea en `[deps]`).
---
## Lo que NO se toma (para no re-litigarlo)
- **Ports como corpus de recetas** — patches y Makefiles asumen BSD userland; Alpine+nixpkgs
(Etapa G) dominan estrictamente para musl-Linux.
- **FreeBSD como builder de consenso multi-kernel** — sin namespaces/bwrap/Landlock allá; el
consenso multi-kernel barato ya existe (kernel propio vs genérico).
- **bectl / ZFS boot environments** — `hammer boot menu` + `activate --from-select` ya cubren
el concepto; como mucho, robar UX de nombres/rollback más adelante.
- **bmake** — el mundo Linux necesita gmake; no reduce la deuda declarable de `/usr/bin/make`.
## Orden propuesto
1. **T2.1T2.2** — papel, una tarde, desbloquea el diseño de Fase 3 antes de escribir código.
2. **T1.1T1.3** — piloto en 3 recetas en el worker; decide si fanotify o eBPF con datos.
3. **T3.1** — receta a la próxima tanda del worker.
4. **T1.4 y T3.2** — sólo después de validar los pilotos (la poda sin traza confiable es ruido).