> 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…
hydrate: un artefacto VACÍO ya no se proyecta como éxito
Tercer sitio con la misma pregunta mal hecha, encontrado con el grep que la lección del
commit anterior pedía hacer: `has` (tapado 2026-08-10), `seal` (tapado hoy) y `hydrate`,
que seguía con `is_dir()` pelado. Un directorio vacío pasaba el chequeo, proyectaba 0
ficheros y devolvía un HydrateReport de éxito.
Duele especial acá porque el escritorio se hidrata así (`hammer hydrate <hash> --into`,
137/137 en KDE): un FHS proyectado desde nada sale «OK» y falla mucho más tarde, sin
rastro de qué artefacto faltaba.
Queda a propósito sin tocar `hammer-mirror::index`: ahí el vacío se autocorrige, porque
indexa por `of_tree` y el contenido difiere del origen ⇒ el sync lo trae.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
diff --git a/crates/hammer-build/src/hydrate.rs b/crates/hammer-build/src/hydrate.rs
index 9635bd40..35d9e9d9 100644
--- a/crates/hammer-build/src/hydrate.rs
+++ b/crates/hammer-build/src/hydrate.rs
@@ -62,9 +62,17 @@ pub fn hydrate(
mode: LinkMode,
dynamic: Option<&DynamicSpec>,
) -> hammer_core::Result<HydrateReport> {
- if !artifact_dir.is_dir() {
+ // `is_dir()` a secas acepta un directorio VACÍO: hydrate proyectaría 0 ficheros y devolvería
+ // un HydrateReport de éxito. Es el mismo agujero que ya se tapó en `Store::has` (2026-08-10) y
+ // en `Store::seal` (2026-08-29): un vacío no es un artefacto, es un nombre. Acá duele especial
+ // porque el escritorio se hidrata así (`hammer hydrate <hash> --into`), y un FHS proyectado
+ // desde nada sale "OK" y falla mucho más tarde, sin rastro de cuál artefacto faltaba.
+ let vacio = std::fs::read_dir(artifact_dir)
+ .map(|mut e| e.next().is_none())
+ .unwrap_or(true);
+ if !artifact_dir.is_dir() || vacio {
return Err(hammer_core::Error::Store(format!(
- "artefacto inexistente: {}",
+ "artefacto inexistente o VACÍO: {}",
artifact_dir.display()
)));
}