# ADR 0016 — Renombre del sistema: `hammer` → `takana` - **Estado:** ACEPTADO (decisión del usuario, 2026-09-09) - ⚠ **Este fichero queda FUERA de todo barrido de renombre.** Habla *sobre* el cambio de nombre, así que necesita seguir diciendo `hammer` donde corresponde. El barrido de la etapa 5 lo pasó por arriba y lo dejó diciendo «Renombre del sistema: takana → takana»; se revirtió. Si alguien vuelve a barrer docs, excluir este fichero explícitamente. - **Reemplaza:** nada. **Afecta:** toda la superficie de CLI (regla 4 de `CLAUDE.md`). ## Contexto Los nombres propios del proyecto se reparten por **rol**, no por estética: `khipu` registra (`docs/state/build-state*.json`), `yupana` reckona sobre el khipu (`scripts/yupana.py`), `harkaq` guarda (la jaula), `qorpa` hospeda (imágenes ajenas), `churay` pone (distribución multi-origen). Cada uno dice qué hace su pieza. El único nombre que designa **el todo** es el del constructor. `takana` (quechua y aimara: *martillo, mazo*) es la traducción literal de `hammer`. Conserva la metáfora que el proyecto ya usa —forja, yunque, sellar— y mantiene el registro agentivo del resto de la familia. Es hermana de `tawasuyu`: el territorio (apps, compositor) × la herramienta (la forja). Se descartaron: `chani` (valor/precio — nombra el *hash*, no el motor; y "valor" es cosa, no rol), `tocapu` (la marca inscripta — mismo hueco que `chani`), `anta` (cobre — es materia, no rol; y no suena quechua: sin q, k, h, ll ni ñ). ## Decisión 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. 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) Nada de esto es estimación; sale de `git grep` y de leer `recipe.rs`. | qué | cuánto | consecuencia | |---|---|---| | ficheros que nombran `hammer` | 1242 (5779 ocurrencias) | radio total | | en `recipes/`, y son **comentarios** de importación | 692 | **gratis**: ver abajo | | recetas con `.hammer-zig-cc` **dentro de una fase** | 10 | **caro**: re-hashea | | recetas con `cargo_vendor_dir = ".hammer-cargo-vendor"` | 5 | **congelar**: ver abajo | | ficheros que **invocan** la CLI | 124 | migración real | | crates `hammer-*` (+ `hammerd`) | 12 | renombre de paquetes | **El hallazgo que decide todo:** `Recipe::hash_inputs` (`crates/hammer-core/src/recipe.rs:535`) no hashea el fichero crudo — construye una **lista de campos**: `source_id`, `compiler`, `target`, `link`, huella del lab, `zig_version`/`strip_debug` si están fijados, los patches, los `flags`, las **fases** (`configure`/`compile`/`install`) y los hashes de las deps. - ⇒ **Los comentarios no entran.** Renombrar «hammer» en los 692 comentarios de recetas importadas **no mueve ni un ArtifactHash**. Es churn de diff, no de build. - ⇒ **Las fases sí entran**, con etiqueta (`phase:compile=…`). Las 10 recetas que escriben `.hammer-zig-cc` lo hacen *dentro* de la fase: renombrar ese literal las re-hashea y obliga a reconstruirlas **y a todo su cono descendente**. El literal es un temporal interno del árbol de build, invisible al usuario. **Se congela como está.** - ⇒ `cargo_vendor_dir` **no** está en `hash_inputs`. Renombrar `.hammer-cargo-vendor` sería invisible al hash **pero puede cambiar los bytes del artefacto** — la misma familia de problema que «el lab está fuera de `hash_inputs`». **Se congela como está.** **Y el cron apunta a una ruta absoluta:** `*/30 * * * * /mnt/vvv/hammer/scripts/farm/cosecha-cron.sh`. Renombrar el **directorio** del repo mata el latido de la granja **en silencio** — no falla nada, simplemente deja de cosechar. El directorio es lo **último** que se toca, y con el cron parado. ## Plan por etapas 1. **Marca + este ADR.** Aditivo, no rompe nada. ← *hecho* 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.** ← *hecho (2026-09-09)*, en dos commits y en este orden, que no es cosmético: - **3a** — los `cargo build --release --bin hammer` pasan a `--bin takana --bin hammer` (6 sitios). Va **solo y primero**: el worker compila desde fuente (`farm-worker-loop.sh`) y la siembra excluye `/target`. Si se cambiaran antes las invocaciones, habría una ventana en la que el worker sincroniza scripts nuevos y sólo tiene el binario viejo — y eso **no falla ruidosamente: deja de cosechar en silencio**. - **3b** — las 49 invocaciones de `./target/release/hammer` → `takana`, en `scripts/`, `docs/runbooks/` y `CLAUDE.md`. Verificado con `bash -n`/`py_compile` los 49 (ojo: `why-differs-barrido.sh` es Python con extensión `.sh`) y, sobre todo, con el **ciclo real del cron** inmediatamente posterior al cambio: `2026-09-09T18:30:00Z → 18:32:21Z`, siembra ✓, manifiesto ✓, los 9 JSON del grafo regenerados (los produce `build-state.py`, que ahora invoca `takana`) y estado commiteado+pusheado. Cero errores. Esa es la prueba que importa: la regeneración del khipu pasa por el binario renombrado. **Excluido a propósito de la etapa 3:** - La variable de entorno `HAMMER=`. Es interfaz entre scripts y hay llamadores que la fijan; renombrarla va con la etapa 4. - `docs/evidencia/` y los `HANDOFF-*`: son **registro** de lo que se corrió ese día. Reescribir un comando dentro de una evidencia la falsifica. - `docs/state/`: generado, se regenera solo. - ADRs y docs de diseño: texto, y `hammer` sigue funcionando. Van con la etapa 5. **Cómo converge el worker** (medido el 2026-09-09, no supuesto). Su checkout vive en `/opt/hammer`, **no es un clon git** —lo pone el rsync de la siembra— y `hammer-farm.service` está `enabled` allá, corriendo `farm-worker-loop.sh` como servicio largo. En el momento del cambio el worker tenía scripts viejos y binario del 6-sep: **coherente**. Los dos estados intermedios también lo son, y por eso la 3a iba primero: - *Antes de reiniciar el servicio*: el loop viejo en memoria sigue llamando `hammer` y recompilando `--bin hammer`, que existe. Funciona. - *Después de reiniciar*: el loop nuevo compila **los dos** y usa `takana`; si `takana` todavía no existe, `rebuild_si_hace_falta` compila y devuelve 0 —salta el ciclo, no aborta—. La unit apunta a la RUTA DEL SCRIPT, no al binario, así que nada de la etapa 3 la toca. El nombre del fichero de unit y `/opt/hammer` son etapa 6. **Convergido y comprobado (2026-09-09 18:40–18:45Z).** Reiniciado `hammer-farm.service`, el worker compiló los dos binarios y **cerró un ciclo de build real con el nombre nuevo**: `✓ dunst b3:29a79859…`, BUILD-YIELD 1/1, 1 promovido. No es que «no se rompió nada visible»: el camino de construir y sellar se ejercitó entero. 4. **Crates.** ← *hecho parcialmente (2026-09-09)*. Los 10 de librería + CLI (`hammer-{core,build,bootstrap,overlay,journal,mirror,upgrade,agent,recover,cli}`) son `takana-*`. **Verificado que no mueve el corpus**: `takana hash recipes/zlib.toml` devuelve `b3:dc363f26…`, idéntico a antes. 600 tests en verde. **Dos binarios congelados, con razón medida:** - `hammerd` — paquete **y** binario. Es componente de Stage 1 de la distro (musl, busybox, hammerd, arje-zero), arje-zero lo supervisa en el sistema arrancado y `PRESEED=hammerd` lo nombra en `selfhost-verify.sh`. - `hammer-recover` — el paquete es `takana-recover`, **el binario sigue siendo `hammer-recover`**: `hammer-live-install.sh` lo copia a `/usr/sbin/hammer-recover` en sistemas **ya instalados** y hornea un hook de arranque que lo invoca por ese nombre. Renombrarlo no rompe el repo: rompe máquinas instaladas. **Una consecuencia que se anotó y resultó FALSA — corregida el 2026-09-09.** Se afirmó que al renombrar `hammer-core` los bytes de `hammerd` cambiaban —linkea contra un crate con otro nombre y el nombre va en los símbolos— y que por eso **había que rehacer el baseline `of_tree` del selfhost**. El razonamiento es correcto y la conclusión no, porque le faltaba un dato: **`recipes/hammerd.toml` pinea su fuente por `commit`, no por el árbol de trabajo** (`commit = "e9b0551213…"`). El renombre vive en el working tree; la receta construye desde un commit congelado. El cambio no la alcanza. Medido, receta por receta, con `takana hash` contra lo sellado: | componente de Stage 1 | vigente | sellado | |---|---|---| | `musl` | `ce952f72` | `ce952f72` | | `busybox` | `2a2b1280` | `2a2b1280` | | `hammerd` | `48bbbe52` | `48bbbe52` | | `arje-zero` | `b34c571b` | `b34c571b` | ⇒ **Los cuatro idénticos: la etapa 4 no movió el baseline y no hay nada que rehacer por su causa.** El baseline se moverá el día que alguien suba el `commit` de `recipes/hammerd.toml` a uno que contenga los crates renombrados — que es una decisión aparte, no un efecto colateral. **Lo que sí apareció al ir a mirar, y no es de esta campaña:** el `of_tree` del `stage1-rootfs` sellado hoy en `./store` es `b3:d152f060…`, que **no coincide con ninguna de las dos constantes del script**: `EXPECT_REF` = `9adefb82…` (toolchain Alpine) ni `RUST_EXPECT_REF` = `7fa6cb4e…` (takana-rust). Puede ser deriva vieja o corresponder a otra configuración de store —los variantes rust usan `store-rust`/`store-rust2`—; **con los datos que hay no se puede afirmar cuál**, y re-anclar un número sin correr el verify in-VM que pruebe que reproduce sería poner una constante que nadie verificó. Esta máquina **no tiene `/dev/kvm`** (4 cores, 7 GiB), así que ese verify no se corre acá. Queda como su propia tarea, con su propia máquina. 4 bis. **Variables de entorno: leen las dos, gana la nueva.** ← *hecho (2026-09-09)*. Se midió antes de tocarlas y el problema tenía otra forma que la del plan: no era «la variable `HAMMER=`», eran **14**, ~260 apariciones en 58 ficheros, **y el binario las lee**. Con knobs del instalador entre ellas, el entorno del worker trayéndolas puestas y `mirror-env.sh` exportándolas — todo eso vive **fuera del repo**, en perfiles de shell y units. Un `sed` no falla ruidosamente: la variable deja de aparecer, se toma el default y el build se comporta distinto en silencio. - **Rust:** `takana_core::env::{var, var_os}` recibe el nombre **canónico** (`TAKANA_…`) y deriva el viejo cambiando el prefijo. Se le pasa el nuevo a propósito, para que un `grep` del nombre nuevo encuentre todas las lecturas. 5 tests, **con dos controles negativos**: sin ninguna de las dos no hay valor, y un nombre sin prefijo `TAKANA_` no inventa una caída. - Migrados los 17 sitios directos **y los indirectos que el grep de `env::var("HAMMER_…")` no mostraba**: `bases_de_mirror`, las constantes de `kernel_cmd`, `ROOT_ENV` de qorpa y `env_path` de recover. `takana-recover` lleva la caída **inline**: es un mini-binario que se copia a `/usr/sbin` y no vale arrastrarle una dep entera por dos líneas. - **Scripts:** 30 lecturas pasan a `${TAKANA_X:-${HAMMER_X:-default}}`, conservando el nombre **interno** de la variable para no tocar sus 190 usos. - **Donde el script EXPORTA en vez de leer, se ponen las dos** (`mirror-env.sh` y el fragmento in-VM de `takana-bootstrap`). Ahí el lector puede ser un binario **viejo** —un worker sin recompilar, el `/usr/bin/hammer` pinado del baseline— que sólo conoce `HAMMER_*`. La caída sirve al lector nuevo; al viejo hay que seguirle dejando la suya puesta. **Verificado con el binario, no sólo con unit tests:** `HAMMER_LAB` sigue surtiendo efecto, `TAKANA_LAB` hace exactamente lo mismo, y con las dos puestas gana `TAKANA_LAB`. 605 tests en verde y `hash zlib` sigue en `b3:dc363f26…`. **Cambio de comportamiento que va dicho aparte:** el hostname por defecto de una instalación nueva pasa de `hammer` a `takana` (sólo si no se fija ninguna de las dos variables). **No se tocan:** las rutas `/var/lib/hammer` de sistemas ya instalados, el `-volid HAMMER_LIVE` del ISO (es identidad horneada en el medio) y el namespace `HARKAQ_*`, que es de otro subsistema. 5. **Texto.** ← *hecho (2026-09-09)*, en tres commits. - **5a — recetas (741, 1427 comentarios).** Cero ArtifactHash movidos, y está **medido**: se hashearon las 741 antes y después y los ficheros de hashes son idénticos byte a byte. **El guardián valió la pena.** El primer barrido filtraba por «la línea empieza con `#`» y movió el hash de `helix`, `lsof` y `steam-runtime-sniper`. La causa: una fase se escribe como `compile = …` y sus comentarios de **shell** también empiezan con `#`, pero viven dentro del **valor** — y las fases sí entran en `hash_inputs`. El barrido definitivo calcula los rangos de las cadenas multilínea de TOML y no entra ahí. Sin la línea base de hashes esto se descubría meses después, en un rebuild. - **5b — 59 docs de diseño, runbooks y ADR.** Los ADR entran porque en **este** repo son documentos vivos, no registros: el 0013 tiene 5 commits y el 0009 dos. Se comprobó antes de decidir. **Excluidos** `docs/evidencia/`, el HANDOFF de la noche de KDE y `docs/state/` (generado). **Y este fichero**, que habla *sobre* el renombre: el barrido lo dejó titulado «Renombre del sistema: takana → takana». - **5c — 250 comentarios en 151 scripts,** con el control de que el diff no toca ni una línea que no empiece por `#`. El barrido saltea heredocs, y ese guardián **disparó 3 veces**: eran los `MOTD` que el script escribe **dentro de la imagen construida** — texto del producto, no comentario. Se cambiaron aparte, como rebranding deliberado. **El hallazgo caro de la etapa 5, que en realidad es un bug que introdujo la 4:** `scripts/atribuir-fallos.py` casaba contra `hammer_build: fetch …`. Ese prefijo es el **target de `tracing`**, que por defecto es `module_path!()` — o sea **el nombre del crate**. Al renombrar `hammer-build` → `takana-build`, el target pasó a `takana_build` y el script quedó **casando nada**: no fallaba, imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado con el binario (`RUST_LOG=info` sobre zlib), no deducido. Ahora acepta las dos, y **tiene que seguir aceptándolas**: los logs viejos que ya están en disco dicen la forma vieja. *(El mensaje del commit de 5c perdió cuatro fragmentos por sustitución de comandos del shell con comillas invertidas. No se enmendó: `main` es compartida y el cron empuja cada 30 min, así que reescribir historia es peor que un mensaje incompleto. El detalle vive acá.)* **Congelados y verificados con controles:** `/opt/hammer`, `/var/lib/hammer`, `/usr/bin/hammer`, `/mnt/vvv/hammer`, la URL de gitea, `hammer-farm.service`, ~~`hammer-live-install.sh`~~, ~~`BRIEFING-hammer.md`~~, `hammerd`, `hammer-recover`, `HAMMER_LIVE`, `.hammer-zig-cc`, `.hammer-cargo-vendor` y dos identificadores más que aparecieron al barrer: > **ENMIENDA 2026-09-09 — dos de esos congelados se descongelaron por decisión del usuario** > («renombrá todos los `hammer` que vayas encontrando, como ese `hammer-install`»), al abrir el > frente del [SDD 28](../28-servidor-de-produccion.md). Renombrados: > `hammer-install.sh` → `takana-install.sh`, `hammer-live-install.sh` → `takana-live-install.sh`, > `hammer-banner.txt` → `takana-banner.txt`, `BRIEFING-hammer.md` → `BRIEFING-takana.md`. > > **Lo que hacía peligroso este renombre no era el fichero: era el PROTOCOLO.** El instalador se > inyecta en el ISO como `/usr/bin/hammer-install` y su éxito se detecta con un `grep` de > `HAMMER-INSTALL-OK` desde **tres** scripts de prueba (`iso-install-test.sh`, > `efi-install-test.sh`, `install-tui-test.sh`). Renombrar un solo lado deja los tests casando > **nada** — sin fallar, exactamente el modo en que `atribuir-fallos.py` quedó mudo al renombrar > el target de `tracing`. Se renombraron **las dos puntas** en el mismo commit > (`/usr/bin/takana-install`, `TAKANA-INSTALL-OK/FAIL`, `TAKANA_INSTALL_*`), se comprobó por > `grep` que no quedara ningún token viejo, y se **corrió** `install-tui-test.sh`: 4/4 verdes. > > **Lo que NO se tocó, y sigue congelado por la misma razón de antes**: el binario > `/usr/sbin/hammer-recover` y su hook de arranque (renombrarlo rompe **máquinas ya instaladas**, > no el repo) — sobrevive intacto dentro del script renombrado, verificado por conteo antes y > después. Tampoco `hammerd`, `hammer-edit`, `/var/lib/hammer`, `HAMMER_LIVE` ni los siete > literales de hash. Y las tres variables `TAKANA_INSTALL_*` **caen al nombre viejo** > (`${TAKANA_INSTALL_X:-${HAMMER_INSTALL_X:-}}`), porque el llamador puede ser un ISO anterior al > renombre — la misma convención que `TAKANA_ROOT_PW` unas líneas más arriba en ese script. - `hammer-build-state/1` — el `schema` del estado generado. Nadie lo valida, pero el valor de un identificador de esquema **es** ser estable; renombrarlo no gana nada. - `hammer-edit` — es una **receta con artefacto sellado**: su `name` está en la ruta del store (`store/cf075804…-hammer-edit`). Renombrarla huerfaniza el artefacto. 5 bis. **El texto que faltaba** (comentarios de `crates/`, `CLAUDE.md`, el skill de granja). ← *hecho*. 205 líneas. **Y el barrido ancho estuvo a un commit de romper el corpus entero**: el primer intento reescribía los `.rs` completos y entre las líneas de código que tocaba había **siete etiquetas de separación de dominio, que son entrada de hash**: | literal | qué es | |---|---| | `b"hammer-tree-v1"` | **el prefijo de `ArtifactHash::of_tree`** (`takana-core/src/hash.rs:60`) — la función que hashea TODOS los artefactos. Cambiarlo mueve los 4750 hashes del store | | `b"hammer-seed-v1"`, `b"hammer-stage1-rootfs-v2"`, `b"hammer-product-rootfs-v3"`, `b"hammer-product-attested-v2"`, `b"hammer-builder-rootfs-v1"` | entradas de hash de la cadena de bootstrap | | `b"hammer-attest-dev-rootkey-0001!!"` | clave raíz de atestación, `[u8; 32]` | Se revirtió y se rehízo sólo sobre comentarios, esquivando además las cadenas crudas de Rust (`r#"…"#`), porque el `SYSTEM_PROMPT` del traductor tiene líneas que empiezan como comentario. **La lección de toda la etapa 5: un literal que parece prosa puede ser entrada de hash, y la única forma de saberlo es mirar dónde se usa.** 6. **Retirar las compatibilidades.** ← *no es un barrido: son seis despliegues coordinados, y tres no se hacen sin decidirlo.* Estado al 2026-09-09: - ✅ **`--takana-bin`** con `--hammer-bin` de alias. Era la última superficie de CLI con el nombre viejo. - ✅ **Destrabado el retiro de las caídas de entorno.** Se midió que la unit del worker era el **único** sitio fuera del repo que traía una variable vieja puesta (`Environment=HAMMER_DIR=/opt/hammer`); ahora fija las dos, desplegada y verificada. - ⏳ **Retirar el binario `hammer`** — quedan 0 llamadores en el repo y el worker usa `takana`. Es la red de seguridad de lo que no se encontró: conviene esperar un ciclo completo de granja y una corrida de selfhost antes de sacarla. - ⏳ **Retirar las caídas `HAMMER_X`** — posible ya para `HAMMER_DIR`; el resto espera a confirmar que ningún entorno las trae puestas. - 🔒 **`/usr/bin/hammer` dentro del rootfs del producto** — está **dentro de un árbol que se hashea**. Moverlo cambia el hash del producto y obliga a rehacer el baseline del selfhost. Va junto con esa deuda, no antes. - ✅ **`/opt/takana` y `takana-farm.service`** (2026-09-09 ~20:15Z). Sin montajes adentro esta vez, así que el `mv` fue directo. **El orden no era cosmético:** el hub siembra por `rsync` a una ruta fija, así que el cron se sacó ANTES de mover. Al revés, la siguiente cosecha habría recreado `/opt/hammer` y el worker quedaba **partido en dos árboles** sin que nada fallara. Un detalle que el primer `sed` no casó: `systemctl restart hammer-farm` y `journalctl -u hammer-farm` nombran la unit **sin el sufijo `.service`**. **Verificado:** el worker cerró un ciclo de build real desde `/opt/takana` (`dunst` sellado, 1/1) y una cosecha completa del hub contra la ruta nueva pasó siembra, manifiesto, los nueve grafos, `static-audit` (691 estáticos, MIENTEN 0) y estado pusheado. **Dos referencias a `/opt/hammer` quedan a propósito porque siguen siendo ciertas:** `docs/23-plan-rehasheo.md` describe rutas **embebidas en artefactos ya construidos** —sus secciones `.debug` literalmente dicen `/opt/hammer/work`— y el HANDOFF de la noche de KDE es registro. Cambiarlas haría que los documentos mientan sobre lo que hay en el disco. ⚠ **Y una recaída, anotada porque es la misma trampa dos veces:** el barrido ad-hoc de este mismo cambio (`git grep -l … | sed`) NO respetó el aviso de arriba y dio vuelta cuatro afirmaciones **históricas** de este fichero, dejándolo diciendo que a las 18:40 se reinició `takana-farm.service` cuando en ese momento se llamaba `hammer-farm.service`. Corregidas a mano. La exclusión hay que ponerla en **cada** barrido, no una vez. - ✅ **`/mnt/vvv/hammer` → `/mnt/vvv/takana`, y el repo renombrado en gitea a `sergio/takana`** (2026-09-09 ~20:00Z). Se coordinó primero: se avisó a las dos sesiones `hammer-*` y `hammer-9f` contestó «vía libre», con los locks comprobados libres y sin builds en vuelo. **Lo que hacía imposible un `mv` a secas** —y no estaba en el plan— eran **cuatro bind-mounts desde `/mnt/cosecha` hacia dentro del árbol** (`store`, `work/out`, `.dev-fs/cache`, `work/tarballs`), con sus entradas en `/etc/fstab`. Secuencia: sacar el cron, desmontar los cuatro, `mv`, reescribir `fstab`, remontar, reponer el cron con la ruta nueva. **Y dos cosas más que sólo aparecieron al mirar:** - `~/hammer` era un **symlink a `/mnt/vvv/hammer`** y quedó **colgado**. Ahora hay `~/takana` y `~/hammer` apuntando los dos a `/mnt/vvv/takana`, con la misma lógica de alias que el binario. - `hammer-9f` aportó dos sitios fuera del repo con la ruta absoluta que no estaban en el inventario: `~/.config/zellij/layouts/rescate.kdl` y `~/.config/shuma/tandas.ron`. Corregidos. *Avisar sirvió para algo más que la cortesía.* **Verificado de punta a punta, no por inspección:** el ciclo del cron de las 20:00 corrió completo desde la ruta nueva (`20:00:00Z → 20:02:18Z`), regeneró los nueve JSON del grafo y **commiteó y pusheó al gitea renombrado**. Hash de zlib intacto, 1327 artefactos en el store. El token de gitea que se creó para el renombre (`write:repository`) **se revocó** al terminar; comprobado que responde 401. Los `bwrap` de otra sesión que seguían vivos no se rompieron: `bwrap` resuelve sus montajes al arrancar y el `mv` fue un rename, así que conservan el inodo. **Deuda que sigue abierta desde la etapa 4:** rehacer el baseline `of_tree` del selfhost. Etapas 2–6 no arrancan hasta que la 1 esté pusheada, y ninguna se mezcla con otra en un commit. ## La hoja de marca: los dos puntos que contradecían contratos vigentes 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. `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 ` funciona — la invocación de la hoja de marca es real. - `takana build ` 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 Los dos SVG difieren correctamente (chispa `#FFF6DE` sobre oscuro, `#17130E` sobre claro) — verificado por sha256 y por los colores presentes, no por el nombre del fichero. Ambos traen un manifiesto **C2PA** de procedencia embebido; se conserva tal cual vino, sin limpiar.