Files
hammer/docs/05-journal.md
T
sergioandClaude Opus 4.8 8bf1623044 Scaffold inicial: workspace Rust + SDDs completos
Arranque del proyecto hammer (distro AI-nativa: laboratorio funcional en el
sótano, terminal mutable clásica arriba, integración de IA programadora).

- Workspace Rust (compila, tests verdes): hammer-core, hammer-build,
  hammer-cli (bin `hammer`), hammerd.
- SDDs 00-10 + 6 ADRs en docs/ con toda la arquitectura.
- Esqueletos navegables mapeados a las fases del roadmap; Fase 0/1 listas
  para implementar el sandbox real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:06:04 +00:00

4.1 KiB

SDD 05 — Diario de mutaciones

Este es el insight central de hammer: el diario es tu configuración del sistema — sin ser declarativa. No declaras tu sistema en un archivo de texto antes de vivirlo; vives el sistema imperativamente, y el propio sistema deriva, a posteriori, un mapa de tu desviación respecto a la base limpia construida por el laboratorio.

Esto rompe la falsa dicotomía declarativo vs imperativo, y resuelve dos problemas a la vez:

  • El de Arch/Gentoo: con los meses se pudren en archivos huérfanos porque el gestor pierde el rastro de lo que el usuario hizo a mano.
  • El de Nix: para evitar lo anterior, te ata las manos (todo debe declararse antes).

1. El mecanismo

Un daemon ultraligero (hammerd) usa fanotify a nivel de kernel para registrar exclusivamente las mutaciones sobre los directorios del sistema (/bin, /sbin, /lib, /etc). No bloquea ninguna acción. Te deja destruir, mover y crear archivos a tu antojo. Pero anota, en silencio, un diario de modificaciones.

fanotify sobre inotify: cobertura a nivel de superbloque/mount, eventos de modificación con info de PID/UID, y menor coste que vigilar recursivamente cada subdirectorio.

2. Qué registra (y qué no)

Registra mutaciones del FHS gestionado:

  • creación / reemplazo / borrado de archivos en /bin, /sbin, /lib, /etc,
  • qué los originó (PID, UID, y si fue una hidratación de hammer, el artifact_hash),
  • ediciones de archivos de config en /etc.

No registra:

  • actividad efímera en /tmp, /run, /proc, /sys, /dev,
  • lecturas/ejecuciones (sólo mutaciones),
  • nada dentro de un overlay activo (el ruido del experimento no entra; sólo el commit).

3. Formato del diario

Log append-only de texto plano (JSON-líneas), legible con cat/grep/jq. Cada línea es un evento atómico. (Los timestamps los provee el daemon; el formato no impone reloj de construcción.)

{"ts":"2026-06-06T18:40:01Z","op":"replace","path":"/bin/grep","by":{"uid":1000,"pid":4821},"artifact":"b3:9f2a…","note":"hydrate grep@perl-default"}
{"ts":"2026-06-06T18:41:12Z","op":"edit","path":"/etc/network.conf","by":{"uid":1000,"pid":4990},"diff_hash":"b3:7c1d…"}
{"ts":"2026-06-06T18:42:03Z","op":"manual-replace","path":"/bin/ls","by":{"uid":1000,"pid":5102},"artifact":null,"note":"usuario pisó ls a mano"}

artifact: null + op: manual-replace ⇒ el usuario reemplazó algo a mano fuera del flujo de hammer. Eso no es un error; es información. El diario distingue "mutación trazable" (vino de una receta/artefacto conocido) de "mutación opaca" (pisada manual), sin prohibir ninguna.

4. Exportar: del diario al .swm

hammer export lee el diario, lo recorta al delta relevante respecto a una base conocida, y produce un manifiesto .swm (SDD 06):

  • base = el conjunto de commits fijados + versión de distro de los que partiste.
  • mutations = las mutaciones trazables convertidas a recetas (source_patch) y las ediciones de config (config_edit), más reglas de init si aplican.
  • Las mutaciones opacas (pisadas manuales sin artefacto) se reportan como advertencia: no se pueden compartir como receta reproducible. hammer te dice exactamente cuáles y por qué.

Así, exportar el diario = exportar tu distro, pero sólo la parte que es reproducible y verificable. Lo que pisaste a ciegas, lo sabes y decides qué hacer con ello.

5. Replicar en otra máquina

No copias una config abstracta: exportas el diario de tus acciones humanas sobre el metal. La otra máquina, partiendo de la misma base, reproduce las recetas y aplica las ediciones. Tu sistema se replica desde su historia, no desde una declaración.

6. Interfaz

// hammerd / hammer-core
pub struct Journal { path: PathBuf }
impl Journal {
    pub fn record(&self, ev: MutationEvent) -> Result<()>;
    pub fn since(&self, base: &BaseRef) -> Result<Vec<MutationEvent>>;
    pub fn export_swm(&self, base: &BaseRef) -> Result<(Swm, Vec<OpaqueWarning>)>;
}

CLI: hammer journal (ver/seguir el diario) · hammer export [--base <ref>] > my.swm.