# Importada de nixpkgs por `takana import-nix` (Etapa G). PUNTO DE PARTIDA, no final: # - el build usa el lab de takana (zig-cc / musl estático), NO el stdenv de nix ⇒ revisá # compiler/link/phases y adaptá hasta que compile. # - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren. name = "aichat" version = "0.30.0" license = "MIT OR Apache-2.0" [source] repo = "https://github.com/sigoden/aichat" commit = "430416d914896c3534c04b84c0226910c64e3e66" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" flags = ["--bin", "aichat"] [build.phases] # ── ⚠ SIN ESTO, aichat NO ES REPRODUCIBLE ────────────────────────────────────────────────────── # Medido el 2026-09-05 con `scripts/verificar-repro.sh`: dos reconstrucciones seguidas, misma # máquina y mismo lab, dan `usr/bin/aichat` distintos en `.rodata`. El primer byte que cambia cae # dentro de un JSON de *stopwords* por idioma embebido en el binario, y lo que difiere es el ORDEN # de los idiomas — una build empieza por `"sl"`, la otra por `"fi"`. # # La causa está en el `build.rs` del crate `stop-words` 0.8.1 (transitivo, vía bm25): arma un # `HashMap>` y lo serializa con `serde_json::to_string`. El `HashMap` de Rust # usa `RandomState`, o sea una semilla ALEATORIA POR PROCESO ⇒ el orden de serialización cambia en # cada compilación, y ese JSON se hornea en el binario. `BTreeMap` serializa en orden de clave y es # determinista; es un arreglo de una palabra que upstream no hizo. # # El `.cargo-checksum.json` se vacía por la misma razón que en `recipes/firefox.toml`: cargo # verifica el sha de CADA fichero vendorizado y no ofrece forma de recalcularlo, así que se deja el # checksum del paquete y se vacía la lista de ficheros (lo mismo hace el APKBUILD de Alpine). # # Los `[ -f ]` fallan RUIDOSO a propósito: si mañana la cadena de deps deja de traer stop-words, lo # que no queremos es que el parche se salte en silencio y el binario vuelva a ser aleatorio sin que # nadie se entere — que es exactamente cómo esto llegó hasta acá. configure = ''' set -e f=vendor/stop-words/build.rs [ -f "$f" ] || { echo "FALTA $f — ¿cambió la cadena de deps? Ver la nota de arriba." >&2; exit 1; } sed -i 's/HashMap/BTreeMap/g' "$f" grep -q 'BTreeMap>' "$f" || { echo "el sed no agarró en $f" >&2; exit 1; } c=vendor/stop-words/.cargo-checksum.json [ -f "$c" ] || { echo "FALTA $c" >&2; exit 1; } sed -i 's/\("files":{\)[^}]*/\1/' "$c" ''' install = "mkdir -p /out/usr/bin && cp target/release/aichat /out/usr/bin/aichat"