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 1576Shell 205Rust 111Markdown 993774 Definiciones

⎇ main crates/takana-build/tests/sin_pre_exec.rs Rust · 73 líneas · 2.9 KB Historia Quién tocó qué crudo

takana etapa 5d: comentarios de crates, CLAUDE.md y el skill de granja b818f5249 · Sergio ·

1//! Guardián de SDD 25 §7-H4: **ningún camino de spawn de takana usa `pre_exec`**.
2//!
3//! POR QUÉ. `std::process::Command` de Rust usa `posix_spawn` cuando puede, y `posix_spawn` es
4//! PLANO respecto al tamaño del padre: a 256 MB tocados, `fork+exec` costó 3 949 µs contra 231 µs
5//! (SDD 25 T1, **17×**). En cuanto se le pone un `pre_exec`, Rust apaga ese camino y cae a
6//! `fork+exec`, que copia el espacio de direcciones del padre. takana lanza builds desde un
7//! proceso que puede tener cientos de MB mapeados.
8//!
9//! Hoy `takana-build::sandbox` lanza `bwrap` sin `pre_exec` — y hasta ahora eso era SUERTE, no una
10//! regla: nadie lo comprobaba. Esto lo vuelve una regla.
11//!
12//! CUÁNDO SE PUEDE APAGAR. Si algún día hace falta de verdad (un `setsid`, un `unshare` que bwrap
13//! no cubra), la respuesta no es borrar el test: es escribir acá por qué ese caso paga los 17× y
14//! ponerlo en la lista de excepciones, para que el precio quede a la vista de quien lo lea.
15
16use std::path::{Path, PathBuf};
17
18fn raiz_del_workspace() -> PathBuf {
19    // CARGO_MANIFEST_DIR = crates/hammer-build
20    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
21        .parent()
22        .and_then(Path::parent)
23        .expect("crates/<crate> tiene dos ancestros")
24        .to_path_buf()
25}
26
27fn rs_de(dir: &Path, out: &mut Vec<PathBuf>) {
28    let Ok(rd) = std::fs::read_dir(dir) else { return };
29    for e in rd.flatten() {
30        let p = e.path();
31        if p.is_dir() {
32            rs_de(&p, out);
33        } else if p.extension().is_some_and(|x| x == "rs") {
34            out.push(p);
35        }
36    }
37}
38
39#[test]
40fn ningun_spawn_de_hammer_usa_pre_exec() {
41    let raiz = raiz_del_workspace();
42    let crates = raiz.join("crates");
43    assert!(crates.is_dir(), "no encontré {} — ¿se movió el workspace?", crates.display());
44
45    let mut fuentes = Vec::new();
46    rs_de(&crates, &mut fuentes);
47    // Un barrido que no encuentra fuentes aprueba por vacío, que es el fallo de CLAUDE.md §3.
48    assert!(fuentes.len() > 20, "sólo {} fuentes: el barrido no miró nada", fuentes.len());
49
50    let mut culpables = Vec::new();
51    for f in &fuentes {
52        if f == Path::new(file!()) || f.ends_with("tests/sin_pre_exec.rs") {
53            continue;
54        }
55        let Ok(txt) = std::fs::read_to_string(f) else { continue };
56        for (i, l) in txt.lines().enumerate() {
57            let limpia = l.trim_start();
58            if limpia.starts_with("//") || limpia.starts_with("*") {
59                continue; // documentarlo no es usarlo
60            }
61            if l.contains("pre_exec") {
62                culpables.push(format!("{}:{}: {}", f.display(), i + 1, l.trim()));
63            }
64        }
65    }
66
67    assert!(
68        culpables.is_empty(),
69        "SDD 25 §7-H4: `pre_exec` apaga el camino `posix_spawn` de Rust y devuelve el spawn a \
70         `fork+exec` (17× más caro con 256 MB en el padre, SDD 25 T1). Aparece en:\n  {}",
71        culpables.join("\n  ")
72    );
73}