tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1182Shell 87Rust 63Markdown 541592 Sutichaykuna

recipes: arje-zero como receta puente Cargo a tawasuyu (track arje, build-side)

Puente concreto hacia "arje es el init de hammer" (ADR 0007): recipes/arje-zero.toml
construye el init PID 1 de arje con el lab de hammer.

- Cargo recipe: fuente = monorepo tawasuyu a commit fijado (el de la migración A0
  arje-cas → BLAKE3, así el CAS es coherente con hammer), -p arje-zero, estático
  con zig cc; deps vendoreadas en el fetch (Lote 6) ⇒ build --offline
- prueba que el lab cruza al repo de tawasuyu y produce el binario del init; NO es
  PID 1 todavía (eso es el paso "init real": seed card + arje-bus + hammerd Card)
- nuevo test que escanea recipes/ y valida que toda receta parsea + hashea offline

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

778c3900ea4911f1f8973bb8aa0d2ae9625ae684 · ruwaq Sergio · (4 killa ñawpaq) · tayta 02827f62c · kay commitpi sach'ata qhaway

Semántico sayk'uy · 1

crates/hammer-bootstrap/src/lib.rs

3 qillqakuna · +56 −2

diff --git a/crates/hammer-bootstrap/src/lib.rs b/crates/hammer-bootstrap/src/lib.rs
index 1bf338a7..be5a8f6a 100644
--- a/crates/hammer-bootstrap/src/lib.rs
+++ b/crates/hammer-bootstrap/src/lib.rs
@@ -692,4 +692,27 @@ mod tests {
             assert!(h.as_str().starts_with("b3:"), "hash con prefijo b3:");
         }
     }
+
+    #[test]
+    fn all_shipped_recipes_parse_and_hash() {
+        // Toda receta en recipes/ (incluida arje-zero, el puente Cargo a tawasuyu) debe parsear y
+        // hashear offline. Cubre las que no están en STAGE1_COMPONENTS y futuras.
+        let recipes_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../recipes");
+        let tmp = tempfile::tempdir().unwrap();
+        let store = Store::open(tmp.path().join("store")).unwrap();
+        let mut count = 0;
+        for entry in std::fs::read_dir(&recipes_dir).unwrap() {
+            let path = entry.unwrap().path();
+            if path.extension().and_then(|e| e.to_str()) != Some("toml") {
+                continue;
+            }
+            let r = Recipe::load_from_path(&path)
+                .unwrap_or_else(|e| panic!("parse {}: {e}", path.display()));
+            let h = hammer_build::artifact_hash(&r, &store)
+                .unwrap_or_else(|e| panic!("hash {}: {e}", path.display()));
+            assert!(h.as_str().starts_with("b3:"), "{}: hash con prefijo b3:", path.display());
+            count += 1;
+        }
+        assert!(count >= 5, "esperaba ≥5 recetas (grep/musl/busybox/hammerd/arje-zero), vi {count}");
+    }
 }
diff --git a/docs/11-bootstrap.md b/docs/11-bootstrap.md
index 92f50343..0b07844b 100644
--- a/docs/11-bootstrap.md
+++ b/docs/11-bootstrap.md
@@ -129,8 +129,12 @@ pub fn all(seed: &SeedSpec, store: &Store) -> Result<BootstrapManifest>;
 ensambla un rootfs FHS por hardlink y lo sella; el `RootfsHash` se deriva del **contenido** (hashes
 de componentes + init), no del árbol en disco, así que es reproducible. El PID 1 provisional es el
 `init` de busybox vía `/etc/inittab`, que arranca `hammerd` como servicio respawn. `hammerd` es una
-receta Cargo (repo pinned + deps vendoreadas en el fetch para build `--offline`). Falta sólo
-sustituir el init provisional por `arje` (ADR 0007), que entrega el `CRASHED` real.
+receta Cargo (repo pinned + deps vendoreadas en el fetch para build `--offline`). `arje`
+([ADR 0007](adr/0007-arje-como-init-propio.md)) ya tiene su **receta puente** `recipes/arje-zero.toml`
+(Cargo, fuente = monorepo tawasuyu pinned al commit de la migración del CAS a BLAKE3, `-p arje-zero`):
+prueba que el lab construye el init, pero todavía **no** es PID 1. Falta el paso "init real":
+arje-zero como PID 1 del rootfs con su seed card, `arje-bus` y hammerd como Card de servicio, que
+entrega el `CRASHED` real.
 
 `SeedSpec { kind, version, url, sha256 }` es la identidad pinned de la semilla; `seed_hash()`
 deriva el `ArtifactHash` de `(kind, version, sha256)` — no del `url` ni del host, así que
diff --git a/recipes/arje-zero.toml b/recipes/arje-zero.toml
new file mode 100644
index 00000000..da48d8e2
--- /dev/null
+++ b/recipes/arje-zero.toml
@@ -0,0 +1,27 @@
+# arje-zero — init PID 1 de arje (ADR 0007), construido por el lab de hammer como **puente
+# build-side** hacia "arje es el init de hammer".
+#
+# Receta Cargo: la fuente es el monorepo tawasuyu a un commit fijado (ADR 0006), `-p arje-zero`
+# para construir sólo ese binario; las deps se vendorean en el fetch (Lote 6) ⇒ build `--offline`
+# hermético. Estático con zig cc cross al target — lo que pide un PID 1 (sin loader del host).
+#
+# Es un PUENTE, no el init todavía: prueba que el lab cruza al repo de tawasuyu y produce el
+# binario del init. Hacerlo PID 1 del rootfs (seed `card.json`, `arje-bus`, hammerd como Card de
+# servicio) es el paso "init real" posterior (plan B.2 + contrato de runtime de arje). El plan C.3
+# prefiere extraer arje-zero a un front-door standalone para no vendorear el monorepo entero;
+# sourcearlo del monorepo pinned es el interino, igual que hammerd desde el repo hammer.
+
+name    = "arje-zero"
+version = "0.0.1"
+
+[source]
+# El `commit` es el identificador inmutable (la URL es sólo locator, no entra al hash). Fijado en
+# el commit de la migración A0 (arje-cas → BLAKE3), para que el CAS sea coherente con hammer.
+repo   = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git"
+commit = "35ec8ef9e55049e9c1f58e2938aab189ad2be451"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+link     = "static"
+flags    = ["-p", "arje-zero"]