Fase 4 — provenance en hammer export (sidecar de receta en el store)
Hasta ahora `hammer export` emitía sólo `file_drop` con `content_b64`. Eso reproducía byte-a-byte pero perdía la receta: el receptor obtenía binarios opacos, sin manera de auditarlos ni de recompilarlos desde fuente. Esta fase cierra el hueco para los artefactos producidos por `hammer-build::build`. Mecanismo: - `Store` reserva `.hammer/recipe.toml` (`RECIPE_SIDECAR_REL`) dentro de cada artefacto. `hammer-build::build` lo escribe antes de sellar, así queda inmutable junto con el árbol. - `Store::recipe_for_dir` / `recipe_for_hash` lo leen de vuelta. Si el artefacto es viejo y no trae sidecar, devuelven `None` sin fallar. - `Recipe::to_toml` (nuevo) hace el roundtrip. Lógica del export (función pura `build_export_mutations`): 1. Aplica semánticas de Delete: invalida estados previos del mismo path. 2. Particiona los eventos sobrevivientes en (a) los que tienen `artifact_hash` con receta sidecar y (b) el resto. 3. Por cada grupo de (a) emite UN `source_patch` con repo+commit+build de la receta y `expected_hash = artifact_hash`. El `target_bin` es el primer path alfabético del grupo; el receptor hidrata el árbol completo al aplicar. 4. Patches de la receta se concatenan inline en el `source_patch.patch`. 5. Los eventos del bucket (b) caen al fallback `file_drop` con `content_b64 + content_hash` (orden alfabético). Limitaciones explícitas: - `SourcePatch` sólo modela `Source::Git`. Recetas con `tarball` se reportan por stderr y caen a file_drop. Extender el SWM para tarballs es trabajo aparte. - Si la receta tiene patches pero alguno no se puede leer, no se inlina; `expected_hash` sigue siendo el gate de integridad para detectar la divergencia. CLI: el subcomando `Export` ahora recibe `--store` para resolver artefactos. Defaults igual que antes (`/store`). Tests (12 nuevos): - hammer-core (5): `Recipe::to_toml` roundtrip; `Store::recipe_for_dir` sin/con sidecar; `Store::recipe_for_hash` por prefijo + hash inexistente. - hammer-cli (7): export sin store; semánticas de Delete; hydrate con sidecar emite source_patch agrupando dos archivos; hydrate sin sidecar cae a file_drop contando `missing_recipe`; mix trazable + external; path ilegible sólo warning.
This commit is contained in:
+5
-3
@@ -67,9 +67,11 @@ pre-requisito de validación.
|
||||
- [x] CLI: `hammer apply [--prefix DIR] [--base-ref base.json]`,
|
||||
`hammer swm-verify`, `hammer export --journal DIR > out.swm`.
|
||||
- [ ] `patch_url` / `content_url` remotos (hoy sólo inline).
|
||||
- [ ] Provenance en `export`: mapa artefacto→receta para emitir `source_patch` en vez de
|
||||
`file_drop`. Hoy se emiten file_drops con `content_b64`, lo que reproduce byte-a-byte
|
||||
pero pierde la receta original.
|
||||
- [x] Provenance en `export`: mapa artefacto→receta vía sidecar `.hammer/recipe.toml` que
|
||||
`hammer-build::build` escribe dentro del artefacto antes de sellar. `hammer export`
|
||||
agrupa eventos por `artifact_hash` y emite UN `source_patch` por grupo cuya receta
|
||||
sea recuperable; lo demás cae al fallback `file_drop`. Source `git` modelado;
|
||||
`tarball` cae a file_drop con warning (pendiente extender SourcePatch).
|
||||
- [ ] Firma `signature` (ed25519) y `TrustStore` local.
|
||||
- **Hecho cuando:** exportas un cambio, lo aplicas en otra máquina y reproduce idéntico.
|
||||
✅ Demostrado en `crates/hammer-cli/tests/swm_roundtrip.rs` para
|
||||
|
||||
Reference in New Issue
Block a user