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…

takana: etapa 2 del renombre + los dos puntos de la hoja de marca

Etapa 2 (ADR 0016): el binario canónico es `takana` y `hammer` se sigue
emitiendo. Son DOS [[bin]] al mismo main.rs, no un symlink: la siembra de la
granja excluye /target (un symlink del hub no existiría en el worker) y
`cargo clean` lo borraría. Ningún llamador tocado; los 124 siguen andando.

Adoptados los dos puntos de la hoja de marca que chocaban con contratos:

- `forja` como ALIAS de clap sobre `build`, no como reemplazo. El canónico
  sigue siendo el inglés, que es lo que usan scripts, cron y runbooks. Y se
  enmienda la regla 4 de CLAUDE.md en el mismo commit: cambiar el
  comportamiento dejando escrito el contrato viejo es lo peor de las dos
  opciones, porque el otro agente del repo aplica lo que lee.

- `.tkn` como extensión de paquete. Salió barato y por una razón medida: la
  extensión no es lógica sino salida — se escribe en UN solo lugar
  (main.rs:1800) y el descubrimiento va por índice, no por glob
  (PackageEntry.file, repo.rs:75). Los repos con entradas .swm siguen
  resolviendo y un repo mixto es válido; cero ficheros .swm versionados.
  Los tipos Swm/SwmBuild/swm_bridge no se tocan: son internos, van en la
  etapa 4.

287 tests en verde (hammer-cli + hammer-core), incluidos los que fabrican
repos con nombres .swm a mano — que son justamente la prueba de que la
compatibilidad hacia atrás se sostiene.

80319d9bab35edd2ab1055efc4dc43d45f18eeb1 · por Sergio · (hace 1 mes) · padre 7358a1054 · ver el árbol en este commit

Delta semántico · 2

crates/hammer-cli/src/main.rs

  • cambió de firma enum Cmd
  • cambió por dentro fn run_pack

4 archivos · +67 −21

diff --git a/CLAUDE.md b/CLAUDE.md
index d574c84d..90deb40e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -109,9 +109,15 @@ el final diciendo que todo fue bien**.
 
 ## 4. La superficie de la CLI va en INGLÉS; los mensajes, en castellano
 
-Subcomandos, flags y nombres de opciones: **inglés**, sin excepción (`build`, `hash`, `hydrate`,
-`mirror push`, `kernel closure`, `qorpa pull`). Lo que el usuario LEE —ayuda, errores, logs— va en
-castellano, y los nombres propios del proyecto son quechua (`qorpa`, `harkaq`, `yupana`, `arje`).
+Subcomandos, flags y nombres de opciones: **inglés** (`build`, `hash`, `hydrate`, `mirror push`,
+`kernel closure`, `qorpa pull`). Lo que el usuario LEE —ayuda, errores, logs— va en castellano, y
+los nombres propios del proyecto son quechua (`takana`, `qorpa`, `harkaq`, `yupana`, `arje`).
+
+**La única excepción, y es cerrada:** el ADR 0016 admite **alias de marca** en castellano sobre un
+verbo canónico —hoy uno solo, `forja` → `build`— para que la invocación de la hoja de marca
+funcione. El alias **no reemplaza nada**: el canónico sigue siendo el inglés y es el que usan los
+scripts, el cron y los runbooks. Un alias es superficie de marca; el contrato es el canónico.
+Agregar otro alias es una decisión de ADR, no algo que se hace de paso.
 
 **Por qué.** Un verbo de CLI es contrato: entra en scripts, cron y runbooks, y renombrarlo después
 rompe llamadores que nadie recuerda. Media superficie en cada idioma obliga a adivinar en cada
diff --git a/crates/hammer-cli/Cargo.toml b/crates/hammer-cli/Cargo.toml
index 509300fa..b079d684 100644
--- a/crates/hammer-cli/Cargo.toml
+++ b/crates/hammer-cli/Cargo.toml
@@ -5,7 +5,15 @@ edition.workspace = true
 license.workspace = true
 authors.workspace = true
 repository.workspace = true
-description = "El binario `hammer`: orquesta build, hydrate, try/commit, apply/export y ctl."
+description = "El binario `takana`: orquesta build, hydrate, try/commit, apply/export y ctl."
+
+# ADR 0016 — renombre hammer→takana, etapa 2. Los DOS binarios se emiten a
+# propósito, en vez de un symlink: la siembra de la granja excluye `/target`, así
+# que un symlink hecho en el hub no existiría en el worker, y `cargo clean` lo
+# borra. Dos `[[bin]]` sobreviven a las dos cosas. `hammer` se retira en la etapa 6.
+[[bin]]
+name = "takana"
+path = "src/main.rs"
 
 [[bin]]
 name = "hammer"
diff --git a/crates/hammer-cli/src/main.rs b/crates/hammer-cli/src/main.rs
index 75c16144..398fe311 100644
--- a/crates/hammer-cli/src/main.rs
+++ b/crates/hammer-cli/src/main.rs
@@ -19,10 +19,10 @@ const DEFAULT_REPO: &str = "/var/lib/hammer/repo";
 
 #[derive(Parser)]
 #[command(
-    name = "hammer",
+    name = "takana",
     version,
     about = "Laboratorio funcional en el sótano, terminal mutable arriba.",
-    long_about = "hammer: distro AI-nativa. Ver docs/ para el diseño completo."
+    long_about = "takana: la forja determinista de tawasuyu — distro AI-nativa. Ver docs/ para el diseño completo."
 )]
 struct Cli {
     /// Ruta del content-addressed store.
@@ -36,6 +36,12 @@ struct Cli {
 #[derive(Subcommand)]
 enum Cmd {
     /// [Fase 0] Compila una receta y la sella en el store.
+    ///
+    /// `forja` es alias de marca (ADR 0016): el verbo CANÓNICO sigue siendo `build` —
+    /// es el que usan los 124 llamadores, el cron y los runbooks. El alias existe para
+    /// que la invocación de la hoja de marca (`takana forja …`) funcione, no para
+    /// reemplazarlo.
+    #[command(alias = "forja")]
     Build {
         /// Ruta a la receta TOML.
         recipe: String,
@@ -1788,7 +1794,10 @@ fn run_pack(
     if let Some(repo_dir) = repo {
         // Publicar: el repo asigna la identidad (nombre+versión de la receta). El `.swm` en sí
         // no lleva nombre — el índice es el namespace. Upsert por nombre (idempotente).
-        let file_name = format!("{}-{}.swm", recipe.name, recipe.version);
+        // ADR 0016: los paquetes nuevos se escriben `.tkn`. Los repos existentes NO se
+        // rompen — `PackageEntry.file` guarda el nombre real de cada fichero, así que un
+        // índice con entradas `.swm` sigue resolviendo y un repo mixto es válido.
+        let file_name = format!("{}-{}.tkn", recipe.name, recipe.version);
         std::fs::create_dir_all(repo_dir)?;
         std::fs::write(repo_dir.join(&file_name), &yaml)?;
         let mut index = hammer_core::RepoIndex::load(repo_dir)?;
diff --git a/docs/adr/0016-renombre-takana.md b/docs/adr/0016-renombre-takana.md
index 8b4c7a7a..2a86a830 100644
--- a/docs/adr/0016-renombre-takana.md
+++ b/docs/adr/0016-renombre-takana.md
@@ -23,7 +23,8 @@ suena quechua: sin q, k, h, ll ni ñ).
 1. El sistema se llama **takana**. La marca vive en `docs/marca/`.
 2. El renombre va **por etapas con alias**, nunca de un saque. `hammer` sigue funcionando hasta que
    el último llamador migre.
-3. Dos cosas de la hoja de marca **no** se adoptan (ver §Choques).
+3. Se adoptan los dos puntos de la hoja de marca que chocaban con contratos vigentes —el verbo
+   `forja` y la extensión `.tkn`—, implementados sin romper llamadores (ver §La hoja de marca).
 
 ## Lo medido (2026-09-09)
 
@@ -60,9 +61,11 @@ simplemente deja de cosechar. El directorio es lo **último** que se toca, y con
 ## Plan por etapas
 
 1. **Marca + este ADR.** Aditivo, no rompe nada. ← *hecho*
-2. **Alias.** El binario pasa a llamarse `takana`; `hammer` queda como symlink en `target/release/`.
-   A partir de acá los dos nombres funcionan y nada se rompe, ni acá ni en el worker (que arrastra
-   binario viejo: la siembra excluye `/target`).
+2. **Alias.** ← *hecho (2026-09-09)*. El binario canónico es `takana`; `hammer` se sigue emitiendo.
+   Son **dos `[[bin]]` apuntando al mismo `main.rs`**, no un symlink: la siembra de la granja excluye
+   `/target`, así que un symlink hecho en el hub no existiría en el worker, y `cargo clean` lo borra.
+   Cuesta una recompilación del `main.rs` y un warning de cargo («present in multiple build targets»)
+   que se va solo en la etapa 6. Los dos nombres funcionan; no se tocó ningún llamador.
 3. **Llamadores** (124 ficheros): `scripts/`, `scripts/farm/`, runbooks, `CLAUDE.md`. En tandas
    chicas, con `flock -o` cuando toque algo que construya.
 4. **Crates** `hammer-*` → `takana-*` y `hammerd` → `takanad`.
@@ -72,18 +75,38 @@ simplemente deja de cosechar. El directorio es lo **último** que se toca, y con
 
 Etapas 2–6 no arrancan hasta que la 1 esté pusheada, y ninguna se mezcla con otra en un commit.
 
-## Choques con la hoja de marca
+## La hoja de marca: los dos puntos que contradecían contratos vigentes
 
-La hoja (`docs/marca/README.md`) es la referencia de identidad visual y de voz. Dos ejemplos suyos
-contradicen contratos ya vigentes y **no se adoptan**:
+La hoja (`docs/marca/README.md`) trae dos ejemplos que chocan con contratos ya escritos. Se
+plantearon como no adoptables; **el usuario los reafirmó el 2026-09-09 y se adoptaron**. Se
+implementaron de forma que la decisión se cumpla sin romper a los llamadores existentes.
 
-1. **`takana forja sistema.tkn`** — `forja` es un verbo en castellano y la **regla 4** manda la
-   superficie de CLI en inglés, sin excepción: el verbo es `build`. La voz de marca en castellano
-   rige lo que el usuario **lee** (ayuda, errores, logs), no lo que **teclea**. «Forjado en 41 s.»
-   es correcto; `takana forja` no.
-2. **`.tkn`** — el formato de paquete es **`.swm`** (266 menciones; Etapa F completa: pack, repo,
-   install, deps, firma, DB, HTTP). Cambiar la extensión rompe repos e instalaciones existentes por
-   una razón puramente cosmética. Queda `.swm`.
+### 1. `forja` — verbo de marca en castellano
+
+Choca con la **regla 4** de `CLAUDE.md` («la superficie de CLI va en inglés»). Adoptado como
+**alias de clap sobre `build`**, no como reemplazo:
+
+- `takana forja <receta>` funciona — la invocación de la hoja de marca es real.
+- `takana build <receta>` sigue siendo el **canónico**: es lo que usan los 124 llamadores, el cron
+  y los runbooks, y ninguno se tocó.
+- `CLAUDE.md` §4 quedó **enmendada** en el mismo movimiento. Cambiar el comportamiento y dejar
+  escrito el contrato viejo es peor que cualquiera de las dos opciones: el otro agente del repo
+  sigue aplicando lo que lee.
+- La excepción es **cerrada**: un alias, el que está. Otro alias es decisión de ADR.
+
+### 2. `.tkn` — extensión del paquete
+
+Choca con `.swm` (266 menciones; Etapa F entera encima). Resultó **mucho más barato de lo
+estimado**, y por una razón medida: la extensión no es lógica, es salida.
+
+- Se escribe en **un solo lugar** (`crates/hammer-cli/src/main.rs:1800`).
+- El descubrimiento de paquetes va por **índice**, no por glob: `PackageEntry.file`
+  (`crates/hammer-core/src/repo.rs:75`) guarda el nombre real de cada fichero.
+- ⇒ **Los repos existentes no se rompen y un repo mixto es válido**: un índice con entradas `.swm`
+  sigue resolviendo, y los paquetes nuevos se escriben `.tkn`. No hace falta migrar nada.
+- Cero ficheros `.swm` versionados en el repo, así que no hubo qué renombrar.
+- **`Swm`, `SwmBuild`, `swm_path`, `swm_bridge` NO se tocan.** Son nombres de tipo y de módulo, no
+  superficie de usuario; renombrarlos es churn puro dentro de la etapa 4.
 
 ## Nota sobre los ficheros de marca