docs: SDD 16 harkaq — Draft 2 reescrito contra la realidad del builder (bwrap, no nix)

El Draft 1 estaba escrito contra el sandbox de nix. hammer no construye con
nix: construye con bubblewrap (ADR 0004, hammer-build/src/sandbox.rs). Eso
invalidaba por irrelevancia el argumento anti-nix (§0), las FOD y su red
abierta (§6 + D8), Q5, y la Fase 3 del fetcher mediado — que el propio doc
marcaba como el mayor riesgo de cronograma, de "meses".

Fase 0 ejecutada (5 minutos, no días):
  - ABI Landlock = 10 en el laptop (techo: audit/7, TSYNC/8, quiet/10).
  - Kernel de hammer 6.16.12-metal: CONFIG_SECURITY_LANDLOCK ausente, pero
    CONFIG_LSM ya lista landlock ⇒ falta un flag, no una versión. Q2 cerrada.
  - Cero FODs: download.rs baja con curl en el HOST y --unshare-all incluye
    --unshare-net ⇒ el fetcher mediado de D8 ya está construido. Fase 3 se
    elimina.

La brecha real es otra y paga mejor: el sandbox monta un rootfs Alpine ENTERO
como capa base ⇒ política ⊋ clausura ⇒ una receta usa Alpine sin declararlo y
pasa en verde. Es el bug que la campaña de de-Alpinización caza a mano. D1 +
audit de ABI 7 lo vuelve mecánico (path/dev/ino de lo no declarado).

Encaje en el modelo de confianza (recipe.rs:229): H1 garantiza que lo
declarado PASA; harkaq que lo declarado BASTA. Complementos simétricos.

Sobreviven intactos D1 (política derivada), D2 (evidencia negativa) y D3
(cero quieting). Nuevo Q1 = el riesgo técnico real: cómo llegan los registros
AUDIT_LANDLOCK_* al lector (CAP_AUDIT_READ, auditd, userns, flags de exec).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 12:18:19 -04:00
co-authored by Claude Opus 4.8
parent e263b66ec1
commit 9478f4c065
2 changed files with 400 additions and 0 deletions
+399
View File
@@ -0,0 +1,399 @@
# SDD 16 — harkaq: la jaula de hammer
**Estado:** Draft 2 · **Fecha:** 2026-07-15 · **Nombre provisional:** *harkaq* ("el que detiene"; renombrable, ningún identificador depende del nombre)
> **Qué cambió del Draft 1.** El Draft 1 se escribió contra el sandbox de nix. hammer no usa nix
> para construir: usa bubblewrap (ADR 0004, `crates/hammer-build/src/sandbox.rs`). Eso invalidó
> por irrelevancia ~40% del documento — el argumento anti-nix, las FOD y su red abierta, y la fase
> del *fetcher mediado* que era el mayor riesgo de cronograma. Fase 0 (reconocimiento) se ejecutó
> y sus tres mediciones están en §3. El resultado neto es un proyecto **más chico, más barato y
> con un beneficio que cobra antes**. Lo que sobrevive intacto es el corazón: D1 (política
> derivada), D2 (evidencia negativa) y D3 (cero quieting).
**Tesis:** hammer es una distro cuyo autor es un modelo. Su sandbox (bwrap) fue diseñado para dar
*hermeticidad de facto* — aislar el build del host — no para *probar* hermeticidad ni para acotar
lo que el build usa **de adentro de la jaula**. harkaq cierra esa brecha sin pedirle política a
nadie: **la clausura de entradas declaradas de la receta ya es la política**. El subproducto es
más valioso que el producto — la ausencia de denegaciones bajo una política igual a la clausura
es *evidencia mecánica* de que lo declarado **basta**, encadenable en willay y consumible por iniy.
---
## 0. Por qué esto no lo resuelve bwrap
El sandbox actual (`sandbox.rs:224`) hace bien lo que se propuso hacer:
- `--unshare-all` — netns, pidns, mountns, ipcns, utsns, userns. **Sin red, ya hoy.**
- `--overlay-src <rootfs Alpine> [--overlay-src <dep>…] --tmp-overlay /` — base y deps de solo
lectura, escrituras a una capa tmpfs descartable.
- `--bind <src> /src`, `--bind <out> /out` — las únicas dos superficies RW reales.
- Entorno mínimo y fijado (`SOURCE_DATE_EPOCH`, `CC`, `-mcpu=baseline`, `CARGO_BUILD_JOBS=1`).
Eso da hermeticidad **respecto del host**. La brecha no está ahí. Está adentro:
> **El sandbox monta un rootfs Alpine entero como capa base del overlay.**
O sea `política ⊋ clausura`, por un margen enorme. Una receta puede usar cualquier header,
cualquier `.so`, cualquier binario que Alpine traiga — **sin declararlo en `deps`** — y el build
pasa en verde. El artefacto queda sellado y reproducible, y aun así arrastra una dependencia
fantasma que nadie escribió.
Ese no es un bug hipotético: es exactamente el bug que la campaña de **de-Alpinización** viene
cazando *a mano, receta por receta*, leyendo logs y adivinando. El patrón documentado (strip
`makedepends`, fase configure explícita, `.pc Requires``[deps].build`) es el parche manual de
un problema que el kernel puede diagnosticar solo.
**La inversión que hace hammer:** el sandbox de bwrap asume que quien escribe la receta sabe lo
que declaró. En hammer, quien escribe la receta es un modelo, la receta se importa
automáticamente desde nixpkgs/Alpine, y "lo que declaró" es precisamente la parte que falla.
Nadie más tiene ese problema porque nadie más tiene una distro cuyo autor sea un modelo.
**No-tesis:** esto no reemplaza a bwrap. harkaq **compone** con él (§5, D4): la jaula de mount y
namespaces sigue siendo de bwrap; harkaq agrega la política de grano fino y —lo que importa— el
canal de evidencia.
### 0.1 El lugar exacto en el modelo de confianza
De `hammer-core/src/recipe.rs:229`, sobre la evidencia H1 (proof-carrying recipes, SDD 15):
> *"Frontera honesta: garantiza que **lo declarado pasa**, no que **lo declarado basta**."*
harkaq es el complemento simétrico de esa frase, y por eso encaja sin forzar nada:
| | Pregunta | Mecanismo | Evidencia |
|---|---|---|---|
| **H1** | ¿lo declarado **pasa**? | checks corridos en el sandbox | positiva (los checks pasan) |
| **harkaq** | ¿lo declarado **basta**? | política = clausura, en el kernel | negativa (nadie denegó nada) |
Juntas cierran el cuadro: H1 dice que el artefacto *hace lo que dice*; harkaq dice que *no
necesitó nada que no dijo*. Ninguna de las dos pide confiar más en el modelo. Las dos piden
verificar más — que es el principio declarado de SDD 15 §0.
---
## 1. Metas
1. Ejecutar el builder bajo una política **derivada, no escrita**: `política = clausura(deps declaradas)`.
2. Producir, por cada build, un veredicto de hermeticidad con evidencia:
`hermético ⟺ política = clausura ∧ denegaciones = ∅`.
3. Emitir esa evidencia hacia willay/iniy, direccionada por blake3, como un `kind` nuevo junto a
la evidencia H1.
4. **Convertir la de-Alpinización en un diagnóstico mecánico**: cada denegación nombra el path,
el dev y el ino de lo que el build usó sin declarar.
5. Degradación explícita y declarada: en kernel sin Landlock, harkaq marca el build **sin
evidencia** — nunca finge.
## 2. No-metas
- No corre en wawa. Ver D6.
- No reemplaza el sandbox de bwrap; se compone encima. Defensa en capas.
- No es un contenedor de propósito general ni compite con bubblewrap/landrun.
- v1 no cubre macOS (hammer es musl/Linux).
- No promete contener un exploit de kernel. Ver §8.
- **No reabre ADR 0004.** hammer no adopta nix como backend de build. Esa opción sigue diferida
y harkaq no la necesita.
---
## 3. Fase 0 — Reconocimiento: EJECUTADA (2026-07-15)
El Draft 1 estimaba "días". Fueron cinco minutos, porque las tres preguntas tenían respuesta
mecánica. Las tres respuestas están medidas, no supuestas.
### 3.1 ABI de Landlock
Medido con el syscall (`landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)`), que
es la vía correcta: los kernels de otras fuentes traen features backporteadas y **el número de
versión del kernel miente** (RHEL 9.6 backporteó hasta ABI 5 sobre un 5.14).
| Dónde | Kernel | ABI | Veredicto |
|---|---|---|---|
| Laptop de desarrollo | 7.2.0-rc3-1-cachyos-rc | **10** | techo; todo disponible |
| Kernel de hammer | 6.16.12-metal (`recipes/linux.toml`) | **ausente** | `# CONFIG_SECURITY_LANDLOCK is not set` |
Lo que hace falta de cada ABI, y desde dónde:
| ABI | Kernel | Qué trae | Para harkaq |
|---|---|---|---|
| 2 | 5.19 | `FS_REFER` | **necesario** — sin refer no compila nada real |
| 3 | 6.2 | `FS_TRUNCATE` | necesario |
| 4 | 6.7 | `NET_BIND_TCP`, `NET_CONNECT_TCP` | **inerte** — no hay red que filtrar (§6) |
| 5 | 6.10 | `FS_IOCTL_DEV` | cierra ioctls a dispositivos |
| 6 | 6.12 | `SCOPE_ABSTRACT_UNIX_SOCKET`, `SCOPE_SIGNAL` | corta fuga lateral |
| 7 | 6.15 | **audit de denegaciones** | **este es el proyecto entero** |
| 8 | 7.0 | `RESTRICT_SELF_TSYNC` | robustez (todos los hilos) |
| 10 | — | `ADD_RULE_QUIET`, `quiet_access_*` | **deliberadamente NO usar** (D3) |
El hallazgo que ordena el diseño sigue siendo ABI 7: Linux 6.15 registra las peticiones denegadas
vía audit con el motivo — `domain`, `blockers` (p.ej. `fs.make_reg,fs.refer`) y la identificación
del objeto (`path`, `dev`, `ino` para filesystem; `opid`, `ocomm` para señales).
Traducción: **el mecanismo de traza que el Draft 1 iba a construir ya lo hace el kernel.** No hay
que instrumentar syscalls ni interponer un tracer. La evidencia sale del audit log del propio LSM,
que es un productor mucho más confiable que cualquier cosa en espacio de usuario.
### 3.2 El kernel de hammer: falta un flag, no una versión
`store/060b34a6…-linux-metal/boot/config-6.16.12-metal` dice:
```
# CONFIG_SECURITY_LANDLOCK is not set
CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,ipe,bpf"
CONFIG_SECCOMP_FILTER=y
```
Respuesta a la Q2 del Draft 1 ("¿vale la pena forzar ≥6.15 en la distro?"): **no hace falta
forzar nada.** 6.16.12 ya trae hasta ABI 8, y `CONFIG_LSM` ya lista `landlock` de primero. Falta
sólo compilarlo: un `scripts/config -e SECURITY_LANDLOCK` junto a los otros ajustes de la fase
`configure` de `recipes/linux.toml` (`SECURITY_PATH` entra por `select`). Cuesta un rebuild
(~35min) y cambia el hash del kernel. Es el único trabajo de infraestructura del proyecto.
seccomp ya está `=y` en ambos kernels. No hay trabajo ahí.
### 3.3 Las FODs: no existen. El fetcher mediado: ya está construido
El Draft 1 dedicaba §6 entero + D8 al problema de las derivaciones de salida fija y su red
abierta, y ponía el *fetcher mediado* en Fase 3 llamándolo *"el mayor riesgo de alcance del
proyecto"*, de *"meses"*.
Ese trabajo está hecho desde siempre, por construcción:
- `crates/hammer-build/src/download.rs` corre `curl` **en el host**, fuera del sandbox.
- El builder recibe **bytes** vía `--bind <src> /src`. Nunca un socket.
- `--unshare-all` incluye `--unshare-net`: netns vacío para **todo** build, sin excepciones,
porque no existe la categoría "derivación que necesita red".
Eso *es* la jaula con ventanilla que D8 proponía construir. hammer nunca tuvo el agujero de las
FOD porque nunca tuvo FODs: separar el fetch del build fue una decisión temprana y silenciosa que
resultó ser la correcta por razones de seguridad que nadie había escrito todavía. Queda escrita acá.
**Fase 3 se elimina del plan.** El riesgo de cronograma desaparece.
---
## 4. Arquitectura
```
receta (escrita/importada por el agente)
├─ deps declaradas (paths del store, por hash)
┌──────────────────────────────────────────────────────────┐
│ harkaq-policy (puro, testeable sin kernel) │
│ clausura(deps) → PolicySpec { │
│ fs_ro: [store paths de la clausura + base runtime]│
│ fs_rw: [/src, /out, /tmp, /cache] │
│ scoped: UNIX_ABSTRACT | SIGNAL │
│ } │
│ PolicyId = blake3(postcard(PolicySpec)) │
└───────────────────────────┬──────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ harkaq-exec (musl, Rust) — DENTRO de bwrap │
│ bwrap ya dio: ns, overlay, /src, /out, sin red │
│ 1. landlock: PolicySpec → ruleset (best-effort/ABI) │
│ 2. seccomp-bpf: allowlist (D4), vía --seccomp <fd> │
│ 3. no_new_privs, drop caps, exec builder │
└───────────────────────────┬──────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ harkaq-audit (lector de AUDIT_LANDLOCK_*) │
│ denegaciones → Denial { blockers, path, dev, ino, ... }│
└───────────────────────────┬──────────────────────────────┘
Verdict { PolicyId, recipe_hash, artifact_hash, denials[] }
blake3 ──► CAS ──► willay ──► iniy
```
Ley de dependencia: `harkaq-policy` no conoce el kernel (función pura de `Recipe``PolicySpec`,
testeable con `cargo test` en cualquier máquina, incluso sin Landlock). `harkaq-exec` no conoce
la receta. El acoplamiento vive sólo en `hammer-build`.
Nota de encaje: `Sandbox::bwrap_args` ya construye la lista de deps (`self.deps`) — es
literalmente el input de `clausura()`. Y `merge_deps_layer()` ya las funde en una capa. El
`PolicySpec` se deriva de datos que la struct `Sandbox` ya tiene en la mano.
---
## 5. Decisiones cerradas
### D1 — La política se deriva, no se escribe
Es el corazón, y sobrevive al Draft 1 sin un rasguño. Todo sandbox del mundo muere en la
ergonomía: alguien mantiene a mano un perfil de permisos, nadie lo revisa, todos terminan en
permisivo. hammer no tiene ese problema porque **la receta ya declara sus deps por hash**.
`clausura(deps)` es el conjunto exacto de rutas de solo lectura. Cero configuración humana,
precisión igual a la del direccionamiento por contenido.
Corolario: no existe "modo permisivo". Una receta que necesita más de lo que declara está mal
escrita, y ese es exactamente el diagnóstico que queremos que el agente reciba — hoy lo
producimos leyendo logs a mano y llamándolo de-Alpinización.
### D2 — La evidencia es negativa, y por eso es barata
**No se traza lo permitido.** La tentación es loguear todo acceso para "probar" qué tocó el build;
eso exige fanotify o eBPF, cuesta rendimiento y produce un río de datos que nadie audita.
La formulación correcta es la contrapositiva:
> `hermético(build) ⟺ política = clausura(deps) ∧ denegaciones = ∅`
Si la política concede *exactamente* la clausura declarada y el kernel no denegó nada, entonces el
build no usó nada fuera de lo declarado. **La política es la afirmación; la ausencia de
denegaciones es la prueba.** Coste de la traza: un lector de audit y una lista casi siempre vacía.
Esto convierte la reproducibilidad de hammer, que hoy es una promesa arquitectónica verificable
sólo rebuildeando, en un certificado por build.
### D3 — Cero quieting. Las denegaciones son el producto
ABI 10 permite suprimir selectivamente logs de accesos denegados por objeto (`LANDLOCK_ADD_RULE_QUIET`,
campos `quiet_access_*`). Es una feature excelente para sandboxear apps de escritorio ruidosas —
y **veneno para harkaq**. Silenciar una denegación es destruir la única evidencia que produce el
sistema. En harkaq `quiet_*` está prohibido por diseño; una denegación esperada no se calla, se
*clasifica* en el `Verdict`.
(De la propia doc del kernel: el objeto queda marcado como quiet si al menos una llamada lo pidió,
y llamadas posteriores sin el flag no lo limpian — es pegajoso. Razón extra para no tocarlo.)
Este laptop reporta ABI 10, así que la feature está a un flag de distancia. La disciplina es no
usarla.
### D4 — Landlock no basta; seccomp es obligatorio, no opcional
Landlock cubre fs, puertos TCP e IPC scoping. No cubre `ptrace`, `bpf`, `userfaultfd`, `keyctl`,
`io_uring`, montajes, ni la mitad de la superficie interesante. seccomp-bpf con allowlist por
syscall es la otra mitad de la jaula.
Buena noticia de composición: **bwrap acepta `--seccomp <fd>`**. No hay que reemplazar el
launcher; se le pasa el filtro al que ya tenemos. `CONFIG_SECCOMP_FILTER=y` en ambos kernels.
`io_uring` va explícitamente denegado en v1 (superficie de kernel enorme, y bypassea buena parte
del análisis por-syscall). Si un builder lo necesita, que lo justifique.
### D5 — Herencia y TSYNC
Las restricciones de Landlock se heredan automáticamente por `fork()` y `exec()`, así que todo el
árbol de procesos del build queda contenido sin trabajo extra — que es exactamente lo que hace
falta cuando `Sandbox::run` lanza `/bin/sh -c` que lanza make que lanza `zig cc`. Con ABI 8
disponible (6.16.12 lo tiene), usar `RESTRICT_SELF_TSYNC` para cubrir todos los hilos.
### D6 — harkaq es órgano de hammer, no de la suite. Rompe la paridad wawa, y está bien
Landlock, seccomp y cgroups son Linux puro; en `x86_64-unknown-none` no existen. Esto viola el
principio de paridad Linux/wawa que gobierna el resto del ecosistema, y hay que decirlo en voz
alta antes de que alguien lo cobre.
El costo es aceptable porque **el bucle de build del agente es una actividad Linux por
definición**. wawa nunca compila nada: consume artefactos atestados del CAS. La frontera de
confianza de wawa es la atestación; la de hammer es la jaula. Son mecanismos distintos para
posiciones distintas del pipeline, y eso es coherente, no inconsistente.
### D7 — Fallo cerrado, y honesto sobre el ABI
- `abi_minima = V3` para intentar el build (sin `REFER` y `TRUNCATE` no compila software real).
- `abi_evidencia = V7` para emitir un `Verdict` con evidencia.
- Entre V3 y V7: el build corre, el `Verdict` sale `SinEvidencia`, iniy lo trata con
`uncertainty` alta en vez de creerle.
- Sin Landlock (el kernel de hammer **hoy**): `SinEvidencia`, y el build corre igual bajo el bwrap
de siempre. harkaq es inerte, no un muro.
Nunca se emite evidencia que el kernel no respaldó. Se consulta el ABI con el syscall, jamás
`uname`.
### D8 — La red ya está cerrada; harkaq no la toca
(Reemplaza al D8 del Draft 1, que trataba de las FOD.)
`--unshare-all` ⇒ netns vacío ⇒ los derechos de red de ABI 4 son **inertes**. No se implementan.
Si algún día un build necesitara red, la respuesta no es abrir el netns: es extender el fetcher
del host (§3.3), que es el embudo con hash donde ancla el CAS y donde willay puede auditar.
`SCOPE_ABSTRACT_UNIX_SOCKET` (ABI 6) sí se usa: cierra la fuga simétrica hacia sockets abstractos.
Ojo con la semántica documentada — un socket datagram ya conectado antes del scoping puede seguir
enviando; y el scoping no admite reglas: si un dominio está scoped, no hay forma de permitir un
recurso puntual fuera. Es todo-o-nada, lo cual para nosotros está bien.
---
## 6. Fases
**Fase 0 — Reconocimiento.****CERRADA (2026-07-15)**. Ver §3. Salidas: ABI 10 en el laptop,
Landlock ausente-pero-a-un-flag en el kernel de hammer, cero FODs y fetcher ya construido.
**Fase 1 — El hito demostrable (una tarde).**
Encender `SECURITY_LANDLOCK` en `recipes/linux.toml`. Tomar **una** receta real de hammer.
Derivar su política de la clausura. Correrla bajo Landlock+seccomp dentro del bwrap actual. Emitir
el `Verdict` con `denials = []`.
Luego correr **una receta que sepamos no de-Alpinizada** y mostrar que la jaula nombra exactamente
qué usó sin declarar, con path/dev/ino.
**Ese par de corridas es el argumento entero del proyecto**, y se enseña en dos minutos.
> Cambio respecto del Draft 1: el segundo acto era una derivación de juguete que leía
> `/etc/passwd`. Una receta real no de-Alpinizada es *mejor demo* (es el problema que de verdad
> tenemos) y de paso le entrega valor inmediato a una campaña en curso.
**Fase 2 — `harkaq-policy` completo + medir la brecha.** Clausura real, `/src`, `/out`, `/tmp`,
`/cache`, `/proc` y `/dev` mínimos, y el **runtime base** (sin `/bin/sh` ni la libc del rootfs no
arranca nada — ver Q3). Correr contra N recetas del catálogo y medir la tasa de falsos positivos.
*Métrica de éxito: <5% de recetas necesitan excepción.*
El delta entre `política = clausura` y `política = clausura + base Alpine` **es** la medida
cuantitativa de la deuda de de-Alpinización del catálogo. Ese número no existe hoy.
**Fase 3 — El bucle epistémico.** `Verdict → willay → iniy`, como `kind` nuevo junto a la
evidencia H1 (§0.1). Aquí el agente empieza a recibir su propio reflejo: una receta cuyo build
denegó cosas es una receta de la que el sistema desconfía, y esa desconfianza es un número, no una
vibra.
*(La Fase 3 del Draft 1 —el fetcher mediado— se eliminó: ya existe. Ver §3.3.)*
---
## 7. Riesgos y honestidades
- **El kernel es la TCB.** harkaq no contiene un exploit de kernel. Landlock+seccomp reduce
superficie; no la elimina. Si el modelo de amenaza incluye "la IA encuentra un 0-day de kernel",
la respuesta correcta es microVM, no LSM. Decir esto en el README, no en letra chica.
- **La entrega de la evidencia es el único riesgo técnico serio que queda.** Ver Q1. Todo el
proyecto cuelga de poder leer los registros `AUDIT_LANDLOCK_*` de forma confiable desde el
proceso que orquesta el build. Si eso no se resuelve limpio, harkaq queda sin producto.
- **Falsos positivos matan proyectos de sandboxing.** Si el 30% de los builds necesita excepción
manual, harkaq se desactiva y queda como decoración. La Fase 2 existe para descubrir esto
temprano y barato. Atenuante: acá un "falso positivo" suele ser un **verdadero positivo de
de-Alpinización**, y el catálogo tiene ~750 recetas para probarlo.
- **Domesticar el vocabulario.** harkaq no prueba que un build fue hermético. Prueba que *bajo el
supuesto de que el kernel y la derivación de política son correctos*, el build no accedió fuera
de su clausura declarada. Es una afirmación fuerte y defendible. La versión sin asteriscos es la
que te van a cobrar. (Mismo criterio que SDD 15 §0: "verificado bajo supuestos nombrados".)
- **Competencia.** Como proyecto OSS genérico, "sandbox para agentes" es un espacio poblado (ya
existe landrun) y la ventana no es infinita. Como el ejecutor de hammer, no compite con nadie: el
diferenciador no es la jaula, es que **la política sale del hash y la evidencia entra al grafo de
confianza**. Nadie más tiene CAS + log monótono + grafo para cerrar ese bucle.
- **El rebuild del kernel cambia su hash.** Encender `SECURITY_LANDLOCK` invalida
`060b34a6…-linux-metal` y lo que dependa de él. Es esperado y barato, pero hay que agendarlo, no
descubrirlo.
---
## 8. Preguntas abiertas
- **Q1 (Fase 1, la que importa):** ¿cómo llegan los registros `AUDIT_LANDLOCK_*` a `harkaq-audit`?
El subsistema de audit del kernel pide `CAP_AUDIT_READ` para leer por netlink, y suele tener un
único consumidor (`auditd`) con el que habría que competir o coordinar. Además el build corre
bajo `--unshare-all` (userns) y `exec`ea varias veces, lo cual interactúa con los flags de
logging de `restrict_self` (`LOG_NEW_EXEC_ON` y compañía). **Esto se prueba antes que nada**: si
la evidencia no sale del kernel de forma confiable, no hay proyecto. Es el primer experimento,
no el último.
- **Q2 (Fase 2):** ¿qué es exactamente el "runtime base" que toda receta necesita y ninguna
declara (`/bin/sh`, la libc del rootfs, `/opt/zig`)? ¿Va en la clausura implícitamente, o se
declara y se vuelve parte del hash de la receta? *Esta es la decisión de diseño de verdad*, y
determina si la métrica de la Fase 2 mide deuda real o ruido.
- **Q3 (Fase 2):** ¿`/proc` y `/dev` mínimos rompen builds reales? (`/proc/self` suele hacer falta;
`/proc/sys` casi nunca.) bwrap ya monta `--proc /proc --dev /dev`.
- **Q4:** ¿el `Verdict` entra en `Recipe::hash_inputs`? Por simetría con `Evidence` (H1), **no**:
hermeticidad es comportamiento, no identidad. Confirmar con el mismo criterio de `recipe.rs:228`.
*(Las Q1/Q4/Q5 del Draft 1 —el vector page-cache de `copy.fail`, la fracción de FODs, y si harkaq
envuelve o reemplaza a nix— se eliminan: eran todas sobre nix.)*
+1
View File
@@ -20,6 +20,7 @@ discrepancia, o se corrige el código o se actualiza el SDD con un commit que ex
| 10 | [Roadmap](10-roadmap.md) | Fases, MVP, primer entregable |
| 11 | [Bootstrap from-scratch](11-bootstrap.md) | Track posterior: Stage 0/1/2, auto-alojamiento, semilla pinned |
| 12 | [`arje` como init real del Stage 1](12-init-real.md) | Contrato de runtime: seed card, hammerd supervisado, `CRASHED` real |
| 16 | [harkaq: la jaula de hammer](16-harkaq-jaula.md) | Landlock+seccomp sobre el bwrap actual; política = clausura; evidencia negativa de hermeticidad |
### Runbooks (operativos)