8 Commits
Author SHA1 Message Date
Sergio 97ceb72411 takana etapa 5b: los 59 docs de diseño, runbooks y ADR
645 líneas. Los ADR entran porque en este repo SON documentos vivos, no
registros inmutables: el 0013 tiene 5 commits, el 0009 dos. Eso se comprobó
antes de decidir, no se asumió por convención general.

EXCLUIDOS por ser REGISTRO o generado: docs/evidencia/ (6), el HANDOFF de la
noche de KDE (1) y docs/state/ (24, se regenera solo). Reescribir un comando
dentro de una evidencia la falsifica.

Y el ADR 0016 se excluye de todo barrido, con un aviso adentro para el próximo
que barra: habla SOBRE el renombre, así que necesita seguir diciendo 'hammer'.
El barrido se lo llevó puesto y lo dejó titulado 'Renombre del sistema: takana
→ takana'; revertido.

Congelados, verificados uno por uno 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 y
HAMMER_LIVE.
2026-09-09 19:25:51 +00:00
Sergio 1505bfad78 licencias: ffmpeg y LLVM salen del árbol — «lo decide un humano» era «lo decide la receta»
Tres que había clasificado como decisión legal y no lo eran. Las dos causas son distintas y las dos
me las estaba perdiendo por mirar sólo el árbol:

**ffmpeg → LGPL-2.1-or-later.** Su raíz trae cuatro COPYING.* y por eso el detector se planta, con
razón: el árbol solo no puede decidir. Pero el `LICENSE.md` del propio ffmpeg explica la regla —«In
combination the LGPL v2.1+ applies to FFmpeg» y «None of these parts are used by default, you have to
explicitly pass `--enable-gpl`… In this case, FFmpeg's license changes to GPL v2+»— y la respuesta la
da NUESTRA receta: no pasa `--enable-gpl` ni `--enable-version3`, y encima va con
`--disable-autodetect`. O sea que la licencia sale de cruzar el árbol con los flags, no de elegir uno
de los cuatro ficheros.

**llvm18 y clang18 → Apache-2.0 WITH LLVM-exception.** Acá el detector veía «tres licencias
distintas» en un solo `LICENSE.TXT` y se plantaba, pero el fichero ABRE diciendo «The LLVM Project is
under the Apache License v2.0 with LLVM Exceptions»: lo demás es la sección legada. La regla de
«varias licencias ⇒ decide un humano» es correcta como default y aquí el humano sólo tuvo que leer la
primera línea.

`licenses/` pasa de 48 a 49 textos: `LLVM-exception` hacía falta para poder declararla, que es el
lazo de siempre —no se declara lo que no se puede entregar—. El único sin texto canónico sigue siendo
`LicenseRef-qorpa-ajena-no-enumerable`, que es identificador nuestro y SPDX no publica.

97% (1135/1165); la cola baja de 27 a 24. Los 3 ArtifactHash, idénticos.
2026-09-05 21:26:53 +00:00
Sergio 058162c6d3 licencias: la cola de pendientes también se escribe — «lo que falta y por qué» es dato
Las 33 que quedan sólo existían en la salida del script, o sea que se perdían al cerrar la terminal.
Para quien tiene que decidirlas —y son decisiones legales, no mecánicas— «qué falta y POR QUÉ no se
puede afirmar» es tan dato como los veredictos. `docs/licencias-pendientes.tsv` las deja listadas con
su motivo: cuáles traen varios ficheros de licencia que dicen cosas distintas (gmp, ffmpeg, clang18,
llvm18, los `gi-*`), cuáles tienen un LICENSE que no reconozco y con qué frase empieza (fuse3, lsof),
y cuáles no traen nada en el árbol (boost, pigz, sqlite-shared).

Al revés que `licencias-evidencia.tsv`, ésta se REGENERA entera en cada corrida. No es un registro de
lo que se probó sino una foto de lo que queda, y una pendiente resuelta tiene que DESAPARECER de acá
—si se acumulara, la lista de trabajo mentiría hacia arriba para siempre.
2026-09-05 20:18:21 +00:00
Sergio 59a0e56a16 licencias 97% (1132/1165): «no hay fichero» y «no reconozco el texto» no son lo mismo
El script decía «sin COPYING ni declaración en el árbol» para `lsof`, `when`, `wpa_supplicant`,
`perl-xml-parser` y `fuse3` — y las cinco SÍ tienen un COPYING o un LICENSE en la raíz. Lo que
pasaba es que ninguna de mis huellas reconocía su texto, que es un problema distinto y se acciona
distinto: uno pide buscar la licencia en otro sitio, el otro pide una huella nueva o leerla. Decir lo
mismo de los dos casos mandaba a mirar donde no era. Ahora el mensaje nombra el fichero y cita su
primera línea, y con eso tres se resolvieron leyéndolas:

  · `wpa_supplicant` — su COPYING no es una licencia sino un aviso: «the project has chosen to use
    only the BSD license option for future distribution», y remite al README. El README trae las tres
    cláusulas clásicas ⇒ BSD-3-Clause. Sin seguir esa remisión no había veredicto posible.
  · `when` — «under the same terms as Perl, or, at your option, under version 2 of the GPL». «Los
    mismos términos que Perl» ES la disyunción Artistic-1.0-Perl OR GPL-1.0-or-later, y la opción de
    GPL-2 ya queda cubierta por el `-or-later`.
  · `perl-xml-parser` — su LICENSE es el texto íntegro de la Artistic License 2.0.

Ese último obligó a cerrar un lazo que yo mismo había dejado abierto: el script se niega a declarar
un SPDX cuyo TEXTO no tengamos en `licenses/`, porque la obligación legal es entregar el texto y no
el nombre. Pero `licencias-textos.sh` deriva qué textos bajar DE las licencias ya declaradas ⇒ una
licencia genuinamente nueva no podía entrar por ningún lado. El orden que lo resuelve es: declarar
con evidencia, bajar el texto, comprobar que llegó. `licenses/` pasa de 44 a 48 textos y el único que
queda sin texto canónico es `LicenseRef-qorpa-ajena-no-enumerable`, que es un identificador nuestro y
SPDX no publica.

Quedan 33. `lsof` (licencia propia de Purdue) y `fuse3` (aviso compuesto: LGPL para la librería, GPL
para las utilidades) siguen pendientes a propósito, y el resto son expresiones que decide una
persona: gmp, ffmpeg, clang18, llvm18 y los `gi-*` traen VARIOS ficheros de licencia que dicen cosas
distintas, y en ffmpeg la respuesta ni siquiera está en el árbol —la deciden los flags de la receta.

Los 3 ArtifactHash, idénticos antes y después.
2026-09-05 18:10:52 +00:00
Sergio b87835f719 licencias 96% (1129/1165): la fuente git también es evidencia, y el script deja de llamarse «tarball»
Faltaban tres recetas cuya fuente es un repo, no un tarball: `fcft`, `foot` y `glab`. El commit
pineado cumple exactamente el mismo papel que el sha256 —es el árbol EXACTO que construimos— así que
la evidencia estaba igual de disponible, sólo que por otra puerta.

`miembros_de_git()` la abre sin clonar el árbol entero: `--depth 1 --filter=blob:limit=64k` sobre el
commit. Un COPYING nunca pasa de 64k y los fuentes donde vive la concesión tampoco; los que sí pasan
—binarios, assets— son justo los que no interesan. Un repo de cientos de megas se resuelve con unos
pocos. Las tres salieron del `license:` que el propio autor escribe en su `meson.build` (fcft, foot)
y del texto del LICENSE (glab).

Los repos por SSH se saltan diciéndolo: este script hace fetch anónimo y no tiene claves. Son
`hammerd` y `portal-probe`, y ya están resueltas por otra vía (su repo es este mismo).

`analizar()` pasa a consumir un iterable de `(ruta, bytes)` en vez de abrir el tar ella misma, así
que las dos fuentes comparten TODA la lógica de veredicto: la jerarquía de evidencia, la regla de
sólo-la-raíz, la unión de identificaciones y la exigencia de que la concesión hable de la misma
versión que el COPYING. Un criterio, dos puertas.

Y el script se renombra `licencias-tarball.py` → `licencias-fuente.py`, porque el nombre viejo pasó a
ser mentira en el momento en que aprendió a leer git. Un nombre que describe la implementación de
ayer manda a la gente a buscar en el sitio equivocado.

Los 3 ArtifactHash, idénticos antes y después.
2026-09-05 18:07:17 +00:00
Sergio ab7cdf25e3 licencias: hammerd y portal-probe son MIT — su repo es el propio hammer
Las dos recetas apuntan a `ssh://gitea@git.gioser.net:2345/sergio/hammer.git`, o sea a este mismo
árbol, que declara MIT en `Cargo.toml` y trae su `LICENSE`. No hace falta clonar nada para saberlo:
la evidencia estaba en el directorio de trabajo. Los dos ArtifactHash, idénticos.
2026-09-05 15:44:55 +00:00
Sergio 96855001c6 licencias: 96% (1124/1164) — --fetch para los tarballs que no estaban en caché
Ocho paquetes más (giflib, pcre2, nghttp2, libogg, libvorbis, speexdsp, libuv, tea) con la misma
regla de evidencia. Su tarball no estaba en `work/tarballs/`, así que el modo `--fetch` lo baja a un
temporal, lo verifica contra el sha256 QUE LA RECETA PINEA —o es el árbol exacto o no se mira— y lo
borra. No se escribe en la caché de hammer a propósito: es suya, y un fichero puesto ahí por otro
camino es una vía de envenenamiento que nadie audita.

Dos correcciones al criterio, las dos porque produjo una afirmación falsa:

  · `gmp` salía GPL-3.0-or-later. Su `COPYING` es la GPLv3, pero al lado trae `COPYING.LESSERv3` y
    `COPYINGv2` porque la biblioteca es LGPL. La regla anterior —«el `COPYING` a secas gana al
    sufijado»— arregla socat, cuyo `COPYING.OpenSSL` es una excepción, y rompe gmp, donde el extra
    nombra otra VERSIÓN y no una dep. Esa diferencia es demasiado fina para codificarla sin
    equivocarse, así que ahora se identifican TODOS los ficheros de la raíz y sólo hay veredicto si
    dicen lo mismo. gmp, ffmpeg y los tres `gi-*` quedan pendientes, que es lo correcto: en ffmpeg
    la respuesta ni siquiera está en el árbol, la deciden los flags de la receta.

  · Pero «varios ficheros» no es «ambigüedad»: el `COPYING` de pcre2 son dos líneas apuntando a
    `LICENCE.md`, y los dos dicen BSD-3. Por eso se unen las identificaciones en vez de contar
    ficheros — ambiguo es que digan cosas DISTINTAS.

Y el TSV pasa a ser ACUMULATIVO. Una receta ya sembrada sale del conjunto de entrada porque ya tiene
`license`, así que regenerar el fichero entero borraba su cita — y la cita es el rastro de
auditoría, lo único que deja revisar un veredicto sin repetir el trabajo. Un fichero de evidencia
que se olvida de lo que ya probó no es evidencia.

Los 10 ArtifactHash afectados, idénticos antes y después.
2026-09-05 15:43:51 +00:00
Sergio ba1fb2d3a8 licencias: 95% (1114/1164) — la evidencia sale del tarball pineado, offline
`licencias.sh --sembrar` escribe desde una tabla curada a mano y `licencias-desambiguar.sh` resuelve
`-only` vs `-or-later` preguntándole a la búsqueda de código de GitHub. Los dos dejan fuera lo mismo:
lo que nadie curó y lo que no vive en GitHub.

Pero `work/tarballs/` indexa cada tarball por su sha256, así que el árbol EXACTO que la receta pinea
ya está en disco: la declaración del propio autor, en el commit que construimos, sin red. De las 76
sin licencia, 55 tenían su tarball cacheado y 25 salieron con evidencia citable.

`scripts/licencias-tarball.py` la busca en tres niveles: la declaración del autor (`Cargo.toml`,
`meson.build`), un único fichero en `LICENSES/` (REUSE, que usa KDE), y el texto del COPYING más la
CONCESIÓN buscada en las cabeceras de los fuentes — excluyendo COPYING/LICENSE, porque el apéndice
de la GPL trae literalmente «or (at your option) any later version» y buscarla ahí da siempre
positivo siendo plantilla. Es la regla que ya fijó `licencias-desambiguar.sh`, aplicada al árbol
pineado en vez de a GitHub.

La primera versión resolvía 40, y CUATRO estaban mal. Las dejo escritas porque son la forma del
error, no accidentes:

  · `socat` salía BSD-2 por su `COPYING.OpenSSL`, que es la excepción, no la licencia. Un `COPYING`
    a secas gana ahora a cualquier sufijado.
  · `pigz` salía Apache-2.0 por `zopfli/COPYING`: la licencia de una pieza VENDORIZADA leída como la
    del contenedor. Sólo se mira la raíz.
  · `openssh` salía MIT porque su `LICENCE` es un compendio de cuatro y me quedaba con la primera
    que pegara. Si el texto trae varias, no hay veredicto: lo compone un humano.
  · `nano` salía GPL-3.0-**or-later** citando el «either version 2» de su `aclocal.m4` — plantilla de
    autotools, no del proyecto, y encima de otra versión. Ahora la cita tiene que venir de un fichero
    del autor Y hablar de la misma versión mayor que el COPYING.

Y dos bugs míos que producían el mismo daño en silencio: la marca de BSD-3 era «Neither the name of»,
que libpcap y libzip no usan («The names of the authors may not be used to endorse») ⇒ se declaraban
BSD-2; y el mayor de versión lo sacaba de `"GPL-3.0".rsplit("-",1)[0][-1]`, que da «L», así que la
comprobación de coherencia rechazaba TODA cita válida.

La validación final no es una regex: un identificador vale si tenemos su texto en `licenses/`. La
obligación legal es acompañar el binario del TEXTO, así que un SPDX que no podemos entregar no
adelanta nada y sí crea una afirmación que no se sostiene. Eso es lo que atrapa el «GPL2+» que meson
deja escribir en `gsd-schemas` y `libgdm`, que no es un SPDX sino taquigrafía.

Nada se sembró a ojo: cada línea de `docs/licencias-evidencia.tsv` lleva la cita que la decidió, y
las 50 que quedan salen listadas con lo que SÍ se encontró en vez de rellenarse.

Comprobado que no se invalida nada: los 26 ArtifactHash afectados son idénticos antes y después
(`license` no está en `hash_inputs`) — medido, no supuesto.
2026-09-05 15:34:35 +00:00