gioser

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…

TOML 1572Shell 203Rust 109Markdown 993728 Definiciones

⎇ 97ceb7241181ba5e2b586b6bbc1c490c334422f4 docs/adr/0016-renombre-takana.md Markdown · 207 líneas · 13.6 KB Historia crudo

takana etapa 5b: los 59 docs de diseño, runbooks y ADR 97ceb7241 · Sergio ·

1# ADR 0016 — Renombre del sistema: `hammer` → `takana`
2
3- **Estado:** ACEPTADO (decisión del usuario, 2026-09-09)
4- ⚠ **Este fichero queda FUERA de todo barrido de renombre.** Habla *sobre* el cambio de nombre, así
5  que necesita seguir diciendo `hammer` donde corresponde. El barrido de la etapa 5 lo pasó por
6  arriba y lo dejó diciendo «Renombre del sistema: takana → takana»; se revirtió. Si alguien vuelve
7  a barrer docs, excluir este fichero explícitamente.
8- **Reemplaza:** nada. **Afecta:** toda la superficie de CLI (regla 4 de `CLAUDE.md`).
9
10## Contexto
11
12Los nombres propios del proyecto se reparten por **rol**, no por estética: `khipu` registra
13(`docs/state/build-state*.json`), `yupana` reckona sobre el khipu (`scripts/yupana.py`), `harkaq`
14guarda (la jaula), `qorpa` hospeda (imágenes ajenas), `churay` pone (distribución multi-origen).
15Cada uno dice qué hace su pieza. El único nombre que designa **el todo** es el del constructor.
16
17`takana` (quechua y aimara: *martillo, mazo*) es la traducción literal de `hammer`. Conserva la
18metáfora que el proyecto ya usa —forja, yunque, sellar— y mantiene el registro agentivo del resto de
19la familia. Es hermana de `tawasuyu`: el territorio (apps, compositor) × la herramienta (la forja).
20
21Se descartaron: `chani` (valor/precio — nombra el *hash*, no el motor; y "valor" es cosa, no rol),
22`tocapu` (la marca inscripta — mismo hueco que `chani`), `anta` (cobre — es materia, no rol; y no
23suena quechua: sin q, k, h, ll ni ñ).
24
25## Decisión
26
271. El sistema se llama **takana**. La marca vive en `docs/marca/`.
282. El renombre va **por etapas con alias**, nunca de un saque. `hammer` sigue funcionando hasta que
29   el último llamador migre.
303. Se adoptan los dos puntos de la hoja de marca que chocaban con contratos vigentes —el verbo
31   `forja` y la extensión `.tkn`—, implementados sin romper llamadores (ver §La hoja de marca).
32
33## Lo medido (2026-09-09)
34
35Nada de esto es estimación; sale de `git grep` y de leer `recipe.rs`.
36
37| qué | cuánto | consecuencia |
38|---|---|---|
39| ficheros que nombran `hammer` | 1242 (5779 ocurrencias) | radio total |
40| en `recipes/`, y son **comentarios** de importación | 692 | **gratis**: ver abajo |
41| recetas con `.hammer-zig-cc` **dentro de una fase** | 10 | **caro**: re-hashea |
42| recetas con `cargo_vendor_dir = ".hammer-cargo-vendor"` | 5 | **congelar**: ver abajo |
43| ficheros que **invocan** la CLI | 124 | migración real |
44| crates `hammer-*` (+ `hammerd`) | 12 | renombre de paquetes |
45
46**El hallazgo que decide todo:** `Recipe::hash_inputs` (`crates/hammer-core/src/recipe.rs:535`) no
47hashea el fichero crudo — construye una **lista de campos**: `source_id`, `compiler`, `target`,
48`link`, huella del lab, `zig_version`/`strip_debug` si están fijados, los patches, los `flags`, las
49**fases** (`configure`/`compile`/`install`) y los hashes de las deps.
50
51- ⇒ **Los comentarios no entran.** Renombrar «hammer» en los 692 comentarios de recetas importadas
52  **no mueve ni un ArtifactHash**. Es churn de diff, no de build.
53- ⇒ **Las fases sí entran**, con etiqueta (`phase:compile=…`). Las 10 recetas que escriben
54  `.hammer-zig-cc` lo hacen *dentro* de la fase: renombrar ese literal las re-hashea y obliga a
55  reconstruirlas **y a todo su cono descendente**. El literal es un temporal interno del árbol de
56  build, invisible al usuario. **Se congela como está.**
57- ⇒ `cargo_vendor_dir` **no** está en `hash_inputs`. Renombrar `.hammer-cargo-vendor` sería
58  invisible al hash **pero puede cambiar los bytes del artefacto** — la misma familia de problema
59  que «el lab está fuera de `hash_inputs`». **Se congela como está.**
60
61**Y el cron apunta a una ruta absoluta:** `*/30 * * * * /mnt/vvv/hammer/scripts/farm/cosecha-cron.sh`.
62Renombrar el **directorio** del repo mata el latido de la granja **en silencio** — no falla nada,
63simplemente deja de cosechar. El directorio es lo **último** que se toca, y con el cron parado.
64
65## Plan por etapas
66
671. **Marca + este ADR.** Aditivo, no rompe nada. ← *hecho*
682. **Alias.** ← *hecho (2026-09-09)*. El binario canónico es `takana`; `hammer` se sigue emitiendo.
69   Son **dos `[[bin]]` apuntando al mismo `main.rs`**, no un symlink: la siembra de la granja excluye
70   `/target`, así que un symlink hecho en el hub no existiría en el worker, y `cargo clean` lo borra.
71   Cuesta una recompilación del `main.rs` y un warning de cargo («present in multiple build targets»)
72   que se va solo en la etapa 6. Los dos nombres funcionan; no se tocó ningún llamador.
733. **Llamadores.** ← *hecho (2026-09-09)*, en dos commits y en este orden, que no es cosmético:
74   - **3a** — los `cargo build --release --bin hammer` pasan a `--bin takana --bin hammer` (6
75     sitios). Va **solo y primero**: el worker compila desde fuente (`farm-worker-loop.sh`) y la
76     siembra excluye `/target`. Si se cambiaran antes las invocaciones, habría una ventana en la
77     que el worker sincroniza scripts nuevos y sólo tiene el binario viejo — y eso **no falla
78     ruidosamente: deja de cosechar en silencio**.
79   - **3b** — las 49 invocaciones de `./target/release/hammer` → `takana`, en `scripts/`,
80     `docs/runbooks/` y `CLAUDE.md`. Verificado con `bash -n`/`py_compile` los 49 (ojo:
81     `why-differs-barrido.sh` es Python con extensión `.sh`) y, sobre todo, con el **ciclo real
82     del cron** inmediatamente posterior al cambio: `2026-09-09T18:30:00Z → 18:32:21Z`, siembra ✓,
83     manifiesto ✓, los 9 JSON del grafo regenerados (los produce `build-state.py`, que ahora invoca
84     `takana`) y estado commiteado+pusheado. Cero errores. Esa es la prueba que importa: la
85     regeneración del khipu pasa por el binario renombrado.
86
87   **Excluido a propósito de la etapa 3:**
88   - La variable de entorno `HAMMER=`. Es interfaz entre scripts y hay llamadores que la fijan;
89     renombrarla va con la etapa 4.
90   - `docs/evidencia/` y los `HANDOFF-*`: son **registro** de lo que se corrió ese día. Reescribir
91     un comando dentro de una evidencia la falsifica.
92   - `docs/state/`: generado, se regenera solo.
93   - ADRs y docs de diseño: texto, y `hammer` sigue funcionando. Van con la etapa 5.
94
95   **Cómo converge el worker** (medido el 2026-09-09, no supuesto). Su checkout vive en
96   `/opt/hammer`, **no es un clon git** —lo pone el rsync de la siembra— y `hammer-farm.service`
97   está `enabled` allá, corriendo `farm-worker-loop.sh` como servicio largo. En el momento del
98   cambio el worker tenía scripts viejos y binario del 6-sep: **coherente**. Los dos estados
99   intermedios también lo son, y por eso la 3a iba primero:
100   - *Antes de reiniciar el servicio*: el loop viejo en memoria sigue llamando `hammer` y
101     recompilando `--bin hammer`, que existe. Funciona.
102   - *Después de reiniciar*: el loop nuevo compila **los dos** y usa `takana`; si `takana` todavía
103     no existe, `rebuild_si_hace_falta` compila y devuelve 0 —salta el ciclo, no aborta—.
104
105   La unit apunta a la RUTA DEL SCRIPT, no al binario, así que nada de la etapa 3 la toca. El
106   nombre del fichero de unit y `/opt/hammer` son etapa 6.
107
108   **Convergido y comprobado (2026-09-09 18:40–18:45Z).** Reiniciado `hammer-farm.service`, el
109   worker compiló los dos binarios y **cerró un ciclo de build real con el nombre nuevo**:
110   `✓ dunst b3:29a79859…`, BUILD-YIELD 1/1, 1 promovido. No es que «no se rompió nada visible»: el
111   camino de construir y sellar se ejercitó entero.
1124. **Crates.** ← *hecho parcialmente (2026-09-09)*. Los 10 de librería + CLI
113   (`hammer-{core,build,bootstrap,overlay,journal,mirror,upgrade,agent,recover,cli}`) son
114   `takana-*`. **Verificado que no mueve el corpus**: `takana hash recipes/zlib.toml` devuelve
115   `b3:dc363f26…`, idéntico a antes. 600 tests en verde.
116
117   **Dos binarios congelados, con razón medida:**
118   - `hammerd` — paquete **y** binario. Es componente de Stage 1 de la distro (musl, busybox,
119     hammerd, arje-zero), arje-zero lo supervisa en el sistema arrancado y `PRESEED=hammerd` lo
120     nombra en `selfhost-verify.sh`.
121   - `hammer-recover` — el paquete es `takana-recover`, **el binario sigue siendo
122     `hammer-recover`**: `hammer-live-install.sh` lo copia a `/usr/sbin/hammer-recover` en sistemas
123     **ya instalados** y hornea un hook de arranque que lo invoca por ese nombre. Renombrarlo no
124     rompe el repo: rompe máquinas instaladas.
125
126   **Consecuencia que hay que anotar igual:** al renombrar `hammer-core`, los bytes de `hammerd`
127   cambian de todos modos —linkea contra un crate con otro nombre y el nombre va en los símbolos—,
128   así que **el baseline `of_tree` del selfhost hay que rehacerlo**. Es efecto de la etapa 4, no de
129   un cambio en `hammerd`.
130
1314 bis. **Variables de entorno: leen las dos, gana la nueva.** ← *hecho (2026-09-09)*.
132
133   Se midió antes de tocarlas y el problema tenía otra forma que la del plan: no era «la variable
134   `HAMMER=`», eran **14**, ~260 apariciones en 58 ficheros, **y el binario las lee**. Con knobs del
135   instalador entre ellas, el entorno del worker trayéndolas puestas y `mirror-env.sh` exportándolas
136   — todo eso vive **fuera del repo**, en perfiles de shell y units. Un `sed` no falla ruidosamente:
137   la variable deja de aparecer, se toma el default y el build se comporta distinto en silencio.
138
139   - **Rust:** `takana_core::env::{var, var_os}` recibe el nombre **canónico** (`TAKANA_…`) y deriva
140     el viejo cambiando el prefijo. Se le pasa el nuevo a propósito, para que un `grep` del nombre
141     nuevo encuentre todas las lecturas. 5 tests, **con dos controles negativos**: sin ninguna de las
142     dos no hay valor, y un nombre sin prefijo `TAKANA_` no inventa una caída.
143   - Migrados los 17 sitios directos **y los indirectos que el grep de `env::var("HAMMER_…")` no
144     mostraba**: `bases_de_mirror`, las constantes de `kernel_cmd`, `ROOT_ENV` de qorpa y `env_path`
145     de recover. `takana-recover` lleva la caída **inline**: es un mini-binario que se copia a
146     `/usr/sbin` y no vale arrastrarle una dep entera por dos líneas.
147   - **Scripts:** 30 lecturas pasan a `${TAKANA_X:-${HAMMER_X:-default}}`, conservando el nombre
148     **interno** de la variable para no tocar sus 190 usos.
149   - **Donde el script EXPORTA en vez de leer, se ponen las dos** (`mirror-env.sh` y el fragmento
150     in-VM de `takana-bootstrap`). Ahí el lector puede ser un binario **viejo** —un worker sin
151     recompilar, el `/usr/bin/hammer` pinado del baseline— que sólo conoce `HAMMER_*`. La caída
152     sirve al lector nuevo; al viejo hay que seguirle dejando la suya puesta.
153
154   **Verificado con el binario, no sólo con unit tests:** `HAMMER_LAB` sigue surtiendo efecto,
155   `TAKANA_LAB` hace exactamente lo mismo, y con las dos puestas gana `TAKANA_LAB`. 605 tests en
156   verde y `hash zlib` sigue en `b3:dc363f26…`.
157
158   **Cambio de comportamiento que va dicho aparte:** el hostname por defecto de una instalación
159   nueva pasa de `hammer` a `takana` (sólo si no se fija ninguna de las dos variables).
160
161   **No se tocan:** las rutas `/var/lib/hammer` de sistemas ya instalados, el `-volid HAMMER_LIVE`
162   del ISO (es identidad horneada en el medio) y el namespace `HARKAQ_*`, que es de otro subsistema.
163
1645. **Comentarios de recetas** (692). Gratis en hash, ruidoso en diff: va en un commit propio y solo.
1656. **Retirar el alias.** Y recién entonces, si se quiere, el directorio `/mnt/vvv/hammer` — parando
166   el cron y reescribiendo el crontab en el mismo movimiento.
167
168Etapas 2–6 no arrancan hasta que la 1 esté pusheada, y ninguna se mezcla con otra en un commit.
169
170## La hoja de marca: los dos puntos que contradecían contratos vigentes
171
172La hoja (`docs/marca/README.md`) trae dos ejemplos que chocan con contratos ya escritos. Se
173plantearon como no adoptables; **el usuario los reafirmó el 2026-09-09 y se adoptaron**. Se
174implementaron de forma que la decisión se cumpla sin romper a los llamadores existentes.
175
176### 1. `forja` — verbo de marca en castellano
177
178Choca con la **regla 4** de `CLAUDE.md` («la superficie de CLI va en inglés»). Adoptado como
179**alias de clap sobre `build`**, no como reemplazo:
180
181- `takana forja <receta>` funciona — la invocación de la hoja de marca es real.
182- `takana build <receta>` sigue siendo el **canónico**: es lo que usan los 124 llamadores, el cron
183  y los runbooks, y ninguno se tocó.
184- `CLAUDE.md` §4 quedó **enmendada** en el mismo movimiento. Cambiar el comportamiento y dejar
185  escrito el contrato viejo es peor que cualquiera de las dos opciones: el otro agente del repo
186  sigue aplicando lo que lee.
187- La excepción es **cerrada**: un alias, el que está. Otro alias es decisión de ADR.
188
189### 2. `.tkn` — extensión del paquete
190
191Choca con `.swm` (266 menciones; Etapa F entera encima). Resultó **mucho más barato de lo
192estimado**, y por una razón medida: la extensión no es lógica, es salida.
193
194- Se escribe en **un solo lugar** (`crates/hammer-cli/src/main.rs:1800`).
195- El descubrimiento de paquetes va por **índice**, no por glob: `PackageEntry.file`
196  (`crates/hammer-core/src/repo.rs:75`) guarda el nombre real de cada fichero.
197- ⇒ **Los repos existentes no se rompen y un repo mixto es válido**: un índice con entradas `.swm`
198  sigue resolviendo, y los paquetes nuevos se escriben `.tkn`. No hace falta migrar nada.
199- Cero ficheros `.swm` versionados en el repo, así que no hubo qué renombrar.
200- **`Swm`, `SwmBuild`, `swm_path`, `swm_bridge` NO se tocan.** Son nombres de tipo y de módulo, no
201  superficie de usuario; renombrarlos es churn puro dentro de la etapa 4.
202
203## Nota sobre los ficheros de marca
204
205Los dos SVG difieren correctamente (chispa `#FFF6DE` sobre oscuro, `#17130E` sobre claro) —
206verificado por sha256 y por los colores presentes, no por el nombre del fichero. Ambos traen un
207manifiesto **C2PA** de procedencia embebido; se conserva tal cual vino, sin limpiar.

0016-renombre-takana.md

ADR 0016 — Renombre del sistema: hammer → takana

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ántoconsecuencia
ficheros que nombran hammer1242 (5779 ocurrencias)radio total
en recipes/, y son comentarios de importación692gratis: ver abajo
recetas con .hammer-zig-cc dentro de una fase10caro: re-hashea
recetas con cargo_vendor_dir = ".hammer-cargo-vendor"5congelar: ver abajo
ficheros que invocan la CLI124migración real
crates hammer-* (+ hammerd)12renombre 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.

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.

    Consecuencia que hay que anotar igual: al renombrar hammer-core, los bytes de hammerd cambian de todos modos —linkea contra un crate con otro nombre y el nombre va en los símbolos—, así que el baseline of_tree del selfhost hay que rehacerlo. Es efecto de la etapa 4, no de un cambio en hammerd.

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.

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.

  1. Comentarios de recetas (692). Gratis en hash, ruidoso en diff: va en un commit propio y solo.
  2. Retirar el alias. Y recién entonces, si se quiere, el directorio /mnt/vvv/hammer — parando el cron y reescribiendo el crontab en el mismo movimiento.

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:

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.

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.