licencias: leer el LICENSE de verdad cuando GitHub dice «no sé» — 1053 de 1141 (92%)

Último recurso mecánico, `scripts/licencias-texto.sh`: para las 60 recetas donde la API de
GitHub devuelve NOASSERTION (el repo TIENE un LICENSE pero licensee no lo reconoce: texto
retocado, encabezado propio, dos licencias en un fichero), baja el texto y lo clasifica acá.
34 identificadas — 16 MIT, 10 Apache-2.0, 7 BSD-2-Clause, 1 BSD-3-Clause.

SÓLO PERMISIVAS, Y NO ES PEREZA. MIT, Apache-2.0, BSD, ISC, MPL-2.0 y Unlicense se
reconocen por frases inconfundibles y NO tienen variantes -only/-or-later ⇒ reconocer el
texto da el SPDX completo.

La familia GPL se deja al humano A PROPÓSITO, y la razón es sutil: el COPYING de la GPL es
IDÉNTICO tanto si el proyecto es «sólo v3» como «v3 o posterior» — lo que las distingue vive
en las cabeceras de los fuentes. Y encima el propio COPYING incluye, en su apéndice «cómo
aplicar la licencia», la frase «or (at your option) any later version», así que buscarla da
SIEMPRE positivo y parecería evidencia siendo texto de plantilla. Es exactamente la trampa
de la regla del `.a` no-PIC, donde grep contaba reubicaciones de .debug_* y mentía.

Comprobado a mano un caso que daba mala espina: el LICENSE de `conftest` empieza
«Conftest — Write tests against your config files / Copyright (C) 2019 …», que es el formato
típico de una cabecera GPL. Leído entero, dice «Licensed under the Apache License, Version
2.0». La clasificación era correcta; la sospecha, barata.

Hashes verificados sobre las 36 tocadas: idénticos.

Quedan 88, ya sin vía mecánica: los repos donde ni la API ni el texto deciden, la familia
GPL sin desambiguar, y tarballs de sitios propios (gmplib, xiph, sr.ht, codeberg…).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-07 14:06:59 -04:00
co-authored by Claude Opus 5
parent 0225aa4e08
commit 487e155f74
38 changed files with 153 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
# licencias-texto.tsv — GENERADO por scripts/licencias-texto.sh. No editar a mano.
# Clasificación por el TEXTO del fichero LICENSE del repo, para los casos en que la API de
# GitHub dice NOASSERTION. SÓLO permisivas (MIT/Apache/BSD/ISC/MPL/Unlicense): no tienen
# variantes -only/-or-later, así que reconocer el texto da el SPDX completo. La familia GPL
# se deja al humano A PROPÓSITO: su COPYING es idéntico en «sólo v3» y «v3 o posterior», y
# encima incluye la frase «or (at your option) any later version» en su apéndice de plantilla
# ⇒ buscarla da siempre positivo y parece evidencia sin serlo.
# Tercera columna: owner/repo:fichero del que se leyó. Total 34
amass Apache-2.0 OWASP/Amass:LICENSE
conftest Apache-2.0 open-policy-agent/conftest:LICENSE
dejavu-fonts MIT dejavu-fonts/dejavu-fonts:LICENSE
dsq Apache-2.0 multiprocessio/dsq:LICENSE.md
duf MIT muesli/duf:LICENSE
eksctl Apache-2.0 weaveworks/eksctl:LICENSE
evcxr Apache-2.0 google/evcxr:LICENSE
fq MIT wader/fq:LICENSE
git-lfs MIT git-lfs/git-lfs:LICENSE.md
gitsign Apache-2.0 sigstore/gitsign:LICENSE
gobetween MIT yyyar/gobetween:LICENSE
go-migrate MIT golang-migrate/migrate:LICENSE
goose MIT pressly/goose:LICENSE
icu4c MIT unicode-org/icu:LICENSE
itstool MIT sabotage-linux/gettext-tiny:LICENSE
jq MIT jqlang/jq:COPYING
k0sctl Apache-2.0 k0sproject/k0sctl:LICENSE
kubeval Apache-2.0 instrumenta/kubeval:LICENSE
libevent BSD-2-Clause libevent/libevent:LICENSE
libpsl MIT rockdaboot/libpsl:LICENSE
libsass MIT sass/libsass:LICENSE
libva MIT intel/libva:COPYING
linux-pam BSD-2-Clause linux-pam/linux-pam:COPYING
miller BSD-2-Clause johnkerl/miller:LICENSE.txt
musl-fts BSD-3-Clause void-linux/musl-fts:COPYING
oniguruma BSD-2-Clause kkos/oniguruma:COPYING
p11-kit BSD-2-Clause p11-glue/p11-kit:COPYING
popeye Apache-2.0 derailed/popeye:LICENSE
qtkeychain BSD-2-Clause frankosterfeld/qtkeychain:COPYING
richgo MIT kyoh86/richgo:LICENSE
sassc MIT sass/sassc:LICENSE
shadow BSD-2-Clause shadow-maint/shadow:COPYING
utf8proc MIT JuliaLang/utf8proc:LICENSE.md
vulkan-loader Apache-2.0 KhronosGroup/Vulkan-Loader:LICENSE.txt
1 # licencias-texto.tsv — GENERADO por scripts/licencias-texto.sh. No editar a mano.
2 # Clasificación por el TEXTO del fichero LICENSE del repo, para los casos en que la API de
3 # GitHub dice NOASSERTION. SÓLO permisivas (MIT/Apache/BSD/ISC/MPL/Unlicense): no tienen
4 # variantes -only/-or-later, así que reconocer el texto da el SPDX completo. La familia GPL
5 # se deja al humano A PROPÓSITO: su COPYING es idéntico en «sólo v3» y «v3 o posterior», y
6 # encima incluye la frase «or (at your option) any later version» en su apéndice de plantilla
7 # ⇒ buscarla da siempre positivo y parece evidencia sin serlo.
8 # Tercera columna: owner/repo:fichero del que se leyó. Total 34
9 amass Apache-2.0 OWASP/Amass:LICENSE
10 conftest Apache-2.0 open-policy-agent/conftest:LICENSE
11 dejavu-fonts MIT dejavu-fonts/dejavu-fonts:LICENSE
12 dsq Apache-2.0 multiprocessio/dsq:LICENSE.md
13 duf MIT muesli/duf:LICENSE
14 eksctl Apache-2.0 weaveworks/eksctl:LICENSE
15 evcxr Apache-2.0 google/evcxr:LICENSE
16 fq MIT wader/fq:LICENSE
17 git-lfs MIT git-lfs/git-lfs:LICENSE.md
18 gitsign Apache-2.0 sigstore/gitsign:LICENSE
19 gobetween MIT yyyar/gobetween:LICENSE
20 go-migrate MIT golang-migrate/migrate:LICENSE
21 goose MIT pressly/goose:LICENSE
22 icu4c MIT unicode-org/icu:LICENSE
23 itstool MIT sabotage-linux/gettext-tiny:LICENSE
24 jq MIT jqlang/jq:COPYING
25 k0sctl Apache-2.0 k0sproject/k0sctl:LICENSE
26 kubeval Apache-2.0 instrumenta/kubeval:LICENSE
27 libevent BSD-2-Clause libevent/libevent:LICENSE
28 libpsl MIT rockdaboot/libpsl:LICENSE
29 libsass MIT sass/libsass:LICENSE
30 libva MIT intel/libva:COPYING
31 linux-pam BSD-2-Clause linux-pam/linux-pam:COPYING
32 miller BSD-2-Clause johnkerl/miller:LICENSE.txt
33 musl-fts BSD-3-Clause void-linux/musl-fts:COPYING
34 oniguruma BSD-2-Clause kkos/oniguruma:COPYING
35 p11-kit BSD-2-Clause p11-glue/p11-kit:COPYING
36 popeye Apache-2.0 derailed/popeye:LICENSE
37 qtkeychain BSD-2-Clause frankosterfeld/qtkeychain:COPYING
38 richgo MIT kyoh86/richgo:LICENSE
39 sassc MIT sass/sassc:LICENSE
40 shadow BSD-2-Clause shadow-maint/shadow:COPYING
41 utf8proc MIT JuliaLang/utf8proc:LICENSE.md
42 vulkan-loader Apache-2.0 KhronosGroup/Vulkan-Loader:LICENSE.txt
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "amass"
version = "5.1.1"
license = "Apache-2.0"
[source]
repo = "https://github.com/OWASP/Amass"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "conftest"
version = "0.63.0"
license = "Apache-2.0"
[source]
repo = "https://github.com/open-policy-agent/conftest"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "dsq"
version = "0.23.0"
license = "Apache-2.0"
[source]
repo = "https://github.com/multiprocessio/dsq"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "duf"
version = "0.9.1"
license = "MIT"
[source]
repo = "https://github.com/muesli/duf"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "eksctl"
version = "0.226.0"
license = "Apache-2.0"
[source]
repo = "https://github.com/weaveworks/eksctl"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "evcxr"
version = "0.21.1"
license = "Apache-2.0"
[source]
repo = "https://github.com/google/evcxr"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "fq"
version = "0.17.0"
license = "MIT"
[source]
repo = "https://github.com/wader/fq"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "git-lfs"
version = "3.7.1"
license = "MIT"
[source]
repo = "https://github.com/git-lfs/git-lfs"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "gitsign"
version = "0.16.1"
license = "Apache-2.0"
[source]
repo = "https://github.com/sigstore/gitsign"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "go-migrate"
version = "4.19.1"
license = "MIT"
[source]
repo = "https://github.com/golang-migrate/migrate"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "gobetween"
version = "0.8.1"
license = "MIT"
[source]
repo = "https://github.com/yyyar/gobetween"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "goose"
version = "3.27.1"
license = "MIT"
[source]
repo = "https://github.com/pressly/goose"
@@ -2,6 +2,7 @@
# sin ellas el escritorio renderiza sin texto legible. Data-only: copia los .ttf a /usr/share/fonts.
name = "dejavu-fonts"
version = "2.37"
license = "MIT"
[source]
tarball = "https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_2_37/dejavu-fonts-ttf-2.37.tar.bz2"
+1
View File
@@ -3,6 +3,7 @@
# el tarball descomprime a `icu/source/` → todas las fases entran con `cd source`. musl, shared.
name = "icu4c"
version = "77.1"
license = "MIT"
[source]
tarball = "https://github.com/unicode-org/icu/releases/download/release-77-1/icu4c-77_1-src.tgz"
+1
View File
@@ -16,6 +16,7 @@
# ISLA DINÁMICA: shared, igual que el resto de la onda 3.
name = "libpsl"
version = "0.21.5"
license = "MIT"
[source]
tarball = "https://github.com/rockdaboot/libpsl/releases/download/0.21.5/libpsl-0.21.5.tar.gz"
+1
View File
@@ -13,6 +13,7 @@
# ser es el enlace tardío.
name = "p11-kit"
version = "0.26.4"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/p11-glue/p11-kit/releases/download/0.26.4/p11-kit-0.26.4.tar.xz"
+1
View File
@@ -2,6 +2,7 @@
# sin ellas el escritorio renderiza sin texto legible. Data-only: copia los .ttf a /usr/share/fonts.
name = "dejavu-fonts"
version = "2.37"
license = "MIT"
[source]
tarball = "https://github.com/dejavu-fonts/dejavu-fonts/releases/download/version_2_37/dejavu-fonts-ttf-2.37.tar.bz2"
+1
View File
@@ -3,6 +3,7 @@
# el tarball descomprime a `icu/source/` → todas las fases entran con `cd source`. musl, shared.
name = "icu4c"
version = "77.1"
license = "MIT"
[source]
tarball = "https://github.com/unicode-org/icu/releases/download/release-77-1/icu4c-77_1-src.tgz"
+1
View File
@@ -7,6 +7,7 @@
# arrastrar más cadena; el driver DRM es el que usa kpipewire).
name = "libva"
version = "2.22.0"
license = "MIT"
[source]
tarball = "https://github.com/intel/libva/archive/refs/tags/2.22.0.tar.gz"
+1
View File
@@ -3,6 +3,7 @@
# (sin autotools): fts.c → libfts.so + libfts.a + fts.h en /usr.
name = "musl-fts"
version = "1.2.7"
license = "BSD-3-Clause"
[source]
tarball = "https://github.com/void-linux/musl-fts/archive/refs/tags/v1.2.7.tar.gz"
+1
View File
@@ -9,6 +9,7 @@
# OJO: el tag de git es `0.16.0`, SIN prefijo `v` (v0.16.0 da 404).
name = "qtkeychain"
version = "0.16.0"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/frankosterfeld/qtkeychain/archive/refs/tags/0.16.0.tar.gz"
+1
View File
@@ -5,6 +5,7 @@
# sellado ⇒ lo apago (no es esencial para libvulkan.so). Python3 sólo si LOADER_CODEGEN (default OFF).
name = "vulkan-loader"
version = "1.4.350.1"
license = "Apache-2.0"
[source]
tarball = "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-1.4.350.1.tar.gz"
+1
View File
@@ -4,6 +4,7 @@
# lo que necesita appstream/libadwaita aquí. Satisface i18n.itstool_join de meson. [source]=carrier.
name = "itstool"
version = "2.0.7"
license = "MIT"
[source]
tarball = "https://github.com/sabotage-linux/gettext-tiny/archive/refs/tags/v0.3.2.tar.gz"
+1
View File
@@ -24,6 +24,7 @@
name = "jq"
version = "1.8.1"
license = "MIT"
[source]
tarball = "https://github.com/jqlang/jq/releases/download/jq-1.8.1/jq-1.8.1.tar.gz"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "k0sctl"
version = "0.31.0"
license = "Apache-2.0"
[source]
repo = "https://github.com/k0sproject/k0sctl"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "kubeval"
version = "0.16.1"
license = "Apache-2.0"
[source]
repo = "https://github.com/instrumenta/kubeval"
+1
View File
@@ -1,6 +1,7 @@
# libevent 2.1.12 — lib C base (de-Alpinizada, Etapa G). compiler=zig-cc (migrado de gcc, matar-gcc 2026-07-16), configure-split, estático.
name = "libevent"
version = "2.1.12"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz"
+1
View File
@@ -2,6 +2,7 @@
# Makefile propio; BUILD=static + CXX=zig c++. Primer ladrillo C++ del stack GUI.
name = "libsass"
version = "3.6.6"
license = "MIT"
[source]
tarball = "https://github.com/sass/libsass/archive/refs/tags/3.6.6.tar.gz"
+1
View File
@@ -4,6 +4,7 @@
# Build mínimo: sin docs (evita xmlto/docbook), sin NLS, sin examples. autotools split (como expat).
name = "linux-pam"
version = "1.6.1"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/linux-pam/linux-pam/releases/download/v1.6.1/Linux-PAM-1.6.1.tar.xz"
+1
View File
@@ -1,6 +1,7 @@
# miller — receta Go (Etapa G frente Go). main en ./cmd/mlr, binario `mlr`.
name = "miller"
version = "6.18.1"
license = "BSD-2-Clause"
[source]
repo = "https://github.com/johnkerl/miller"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "oniguruma"
version = "6.9.10"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/kkos/oniguruma/releases/download/v6.9.10/onig-6.9.10.tar.gz"
+1
View File
@@ -4,6 +4,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "popeye"
version = "0.22.1"
license = "Apache-2.0"
[source]
repo = "https://github.com/derailed/popeye"
+1
View File
@@ -9,6 +9,7 @@
# - las deps van con su nombre NIX; remapealas a las recetas del corpus si difieren.
name = "richgo"
version = "0.3.12"
license = "MIT"
[source]
repo = "https://github.com/kyoh86/richgo"
+1
View File
@@ -2,6 +2,7 @@
# Linkea libsass (C++) ⇒ CC='zig c++' (trae libc++ al link). SASS_LIBSASS_PATH=/usr halla headers+lib.
name = "sassc"
version = "3.6.2"
license = "MIT"
[source]
tarball = "https://github.com/sass/sassc/archive/refs/tags/3.6.2.tar.gz"
+1
View File
@@ -3,6 +3,7 @@
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "shadow"
version = "4.18.0"
license = "BSD-2-Clause"
[source]
tarball = "https://github.com/shadow-maint/shadow/releases/download/4.18.0/shadow-4.18.0.tar.xz"
+1
View File
@@ -3,6 +3,7 @@
# sha256 del tarball (el wrapper lo calcula), y adaptar build/install del shell de abuild.
name = "utf8proc"
version = "2.11.3"
license = "MIT"
[source]
tarball = "https://github.com/JuliaLang/utf8proc/archive/v2.11.3/utf8proc-2.11.3.tar.gz"
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# licencias-texto.sh — último recurso: LEER el fichero LICENSE del repo y clasificarlo por su texto.
#
# ── PARA QUÉ, SI YA ESTÁ licencias-detectar.sh ─────────────────────────────────────────────────
# Aquél pregunta a GitHub «¿qué licencia detectás?» y GitHub a veces contesta NOASSERTION: el repo
# tiene un LICENSE pero licensee no lo reconoce (texto retocado, dos licencias en un fichero, un
# encabezado propio…). Quedaron 66 recetas así. Éste baja el TEXTO y lo clasifica acá.
#
# ── SÓLO LICENCIAS PERMISIVAS, Y ESO NO ES PEREZA ──────────────────────────────────────────────
# MIT, Apache-2.0, BSD, ISC y MPL-2.0 se identifican por frases inconfundibles y **no tienen
# variantes `-only` / `-or-later`** ⇒ reconocer el texto basta para dar el SPDX completo.
#
# La familia GPL NO se clasifica acá, a propósito. El fichero COPYING de la GPL es el mismo tanto si
# el proyecto es «sólo v3» como «v3 o posterior»: lo que distingue una de otra vive en las CABECERAS
# DE LOS FUENTES, no en el COPYING. Peor todavía: el propio COPYING incluye, en su apéndice «cómo
# aplicar la licencia», la frase «either version 3 of the License, or (at your option) any later
# version» — o sea que buscar esa frase en el COPYING da SIEMPRE positivo y **parecería** evidencia
# siendo puro texto de plantilla. Es la trampa exacta de la regla del `.a` no-PIC, donde `grep`
# contaba reubicaciones de `.debug_*` y mentía. Las GPL se dejan al humano.
#
# Uso: scripts/licencias-texto.sh (escribe docs/licencias-texto.tsv)
set -uo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
SALIDA="${SALIDA:-docs/licencias-texto.tsv}"
JOBS="${JOBS:-12}"
command -v gh >/dev/null && gh auth status >/dev/null 2>&1 || { echo "!! 'gh' ausente o sin auth"; exit 1; }
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
./scripts/licencias.sh --faltan 2>/dev/null | while IFS= read -r n; do
f=$(ls "recipes/$n.toml" 2>/dev/null | head -1)
[ -z "$f" ] && f=$(ls recipes/incoming-*/"$n.toml" 2>/dev/null | head -1)
[ -z "$f" ] && continue
u=$(grep -m1 -E '^[[:space:]]*(tarball|repo)[[:space:]]*=' "$f" 2>/dev/null)
case "$u" in *github.com*) ;; *) continue ;; esac
slug=$(printf '%s\n' "$u" | sed -E 's#.*github\.com[:/]+([^/"]+)/([^/"]+).*#\1/\2#; s/\.git$//')
case "$slug" in */*) printf '%s\t%s\n' "$n" "$slug" ;; esac
done | sort -u > "$TMP/obj.tsv"
echo "==> a inspeccionar: $(wc -l < "$TMP/obj.tsv")"
export TMP
xargs -P "$JOBS" -I{} sh -c '
n=$(printf "%s" "{}" | cut -f1); slug=$(printf "%s" "{}" | cut -f2)
for fich in LICENSE LICENSE.md LICENSE.txt COPYING LICENCE license; do
c=$(gh api "repos/$slug/contents/$fich" --jq ".content" 2>/dev/null) || continue
[ -z "$c" ] && continue
t=$(printf "%s" "$c" | base64 -d 2>/dev/null | head -60 | tr "[:upper:]" "[:lower:]" | tr -s " \n" " ")
[ -z "$t" ] && continue
lic=""
case "$t" in
*"apache license"*"version 2.0"*) lic="Apache-2.0" ;;
*"mozilla public license version 2.0"*) lic="MPL-2.0" ;;
*"permission is hereby granted, free of charge"*) lic="MIT" ;;
*"permission to use, copy, modify, and/or distribute this software for any purpose"*) lic="ISC" ;;
*"neither the name of"*"may be used to endorse or promote"*) lic="BSD-3-Clause" ;;
*"redistributions in binary form must reproduce"*) lic="BSD-2-Clause" ;;
*"this is free and unencumbered software released into the public domain"*) lic="Unlicense" ;;
esac
[ -n "$lic" ] && printf "%s\t%s\t%s:%s\n" "$n" "$lic" "$slug" "$fich" >> "$TMP/ok.tsv"
break
done
' < "$TMP/obj.tsv"
N=$(wc -l < "$TMP/ok.tsv" 2>/dev/null || echo 0)
{
echo "# licencias-texto.tsv — GENERADO por scripts/licencias-texto.sh. No editar a mano."
echo "# Clasificación por el TEXTO del fichero LICENSE del repo, para los casos en que la API de"
echo "# GitHub dice NOASSERTION. SÓLO permisivas (MIT/Apache/BSD/ISC/MPL/Unlicense): no tienen"
echo "# variantes -only/-or-later, así que reconocer el texto da el SPDX completo. La familia GPL"
echo "# se deja al humano A PROPÓSITO: su COPYING es idéntico en «sólo v3» y «v3 o posterior», y"
echo "# encima incluye la frase «or (at your option) any later version» en su apéndice de plantilla"
echo "# ⇒ buscarla da siempre positivo y parece evidencia sin serlo."
echo "# Tercera columna: owner/repo:fichero del que se leyó. Total $N"
sort "$TMP/ok.tsv" 2>/dev/null
} > "$SALIDA"
echo "==> $N clasificadas por texto → $SALIDA"