chore(metodo): re-estampado 2026-08-23 (A43: el > de blockquote · D102: la casilla) + bloque eol=lf acotado

This commit is contained in:
sirxavor 2026-08-23 14:09:28 +02:00
parent 0979e5bb51
commit be753157cf
5 changed files with 225 additions and 31 deletions

12
.gitattributes vendored Normal file
View File

@ -0,0 +1,12 @@
# >>> metodo:eol
# Gestionado por `metodo init/update` — NO editar a mano (se re-estampa).
# ACOTADO a los dos globs que el linter recorre: los `*.md` de RAÍZ y `doc/*.md` (glob de shell,
# sólo hijos directos). Es HIGIENE, no una avería: medido el 2026-08-23 en hermes-hub con dos
# worktrees a la misma profundidad —uno con 14 ficheros en CRLF y otro con 0—, `metodo check`
# da EXACTAMENTE la misma salida. Se fija el EOL para que el árbol no dependa de cómo se hizo
# cada checkout, no porque el linter se rompa.
# ⛔ Nunca `* text=auto` aquí: hay repos con binarios en LFS y con PDF versionados — ESO sí es
# destructivo y está medido.
/*.md text eol=lf
doc/*.md text eol=lf
# <<< metodo:eol

View File

@ -1,2 +1,2 @@
140cf44bc4d8e9eff08cd4f6466df22c897efa2c6c6f83662a747e3348a4f2bd metodo.md a0a8a9cb931436c37973ea2d882294c2dcbe79af713528488506c749f9b6ad21 metodo.md
09189db5840b85e18a71aad9073b0642c9845dbcab08eccda2c83494d521d994 bin/metodo 502f5a70de21a41c2a1fee1f149bcab7767d277469282884273f5c98c2b4db41 bin/metodo

View File

@ -1,5 +1,5 @@
# Copia vendorizada del Método (raíl C11). Gestionada por 'metodo init/update'. # Copia vendorizada del Método (raíl C11). Gestionada por 'metodo init/update'.
master: metodo master: metodo
version: 2026-08-22 version: 2026-08-23
estado: vendored estado: vendored
adopted_commit: 6a10eab342a477846ab5f3e67f8ab17169f12807 adopted_commit: 6a10eab342a477846ab5f3e67f8ab17169f12807

View File

@ -101,33 +101,64 @@ _IDPFX='D|A|B|G|H|C|M|R|F|E|P'
# ── el reconocedor de ids ──────────────────────────────────────────────────── # ── el reconocedor de ids ────────────────────────────────────────────────────
# ⚠️ Está en **awk y no en un `grep -oE` encadenado**, y el motivo es el LÍMITE POR LA DERECHA # ⚠️ Está en **awk y no en un `grep -oE` encadenado**, y el motivo es el LÍMITE POR LA DERECHA
# (`D100`): no se puede expresar sin lookahead. Se intentó con un segundo `grep -vE` y el filtro # (`D101`): no se puede expresar sin lookahead. Se intentó con un segundo `grep -vE` y el filtro
# casaba `D1` + `7` dentro de `D17` ⇒ **declaraba sub-id a todo id de dos cifras**. Aquí el id y su # casaba `D1` + `7` dentro de `D17` ⇒ **declaraba sub-id a todo id de dos cifras**. Aquí el id y su
# cola se miran POR SEPARADO, que es la única forma de que la pregunta sea la que parece. # cola se miran POR SEPARADO, que es la única forma de que la pregunta sea la que parece.
# #
# modo `def` → **id DEFINIDO**: posición de definición (fila de tabla `|` o item de lista `-*`, # modo `def` → **id DEFINIDO**: POSICIÓN de definición + adorno (negrita, tachado, comilla
# con su adorno: negrita, tachado y comilla invertida) + prefijo de `_IDPFX`. Así # invertida) + prefijo de `_IDPFX`. Así una MENCIÓN inline («ver D5») no define
# una MENCIÓN inline («ver D5») no define nada y no da falsos positivos. # nada y no da falsos positivos. Las posiciones, y de dónde salió cada una:
# modo `forma` → **¿tiene esta línea FORMA de definición?**, con CUALQUIER prefijo de letra y # · `|` fila de tabla · `-`/`*`/`_` item de lista (desde el día uno)
# CUALQUIER adorno (casilla `- [ ]`/`- [x]` incluida — un item cerrado define tanto # · `[ ]`/`[x]`/`[~]` **casilla de ítem** — `D102`, disparada el 2026-08-23:
# como uno abierto). Es a propósito agnóstico de `_IDPFX`: un detector de ceguera # `- [ ] **M5.1**` define un id tan real como el de una decisión, y eran
# construido sobre el vocabulario que audita sólo caza la ceguera de ADORNO, jamás # **403 líneas** del árbol sin auditar.
# la de PREFIJO, que es el gate-sin-sujeto un piso más arriba. Sólo se usa cuando # · `>` **blockquote** — `A43` del edge, 2026-08-23: tres decisiones de USUARIO
# el estricto ha visto 0. # de Xavier (`D23`/`D24`/`D25`) vivían ahí y **ningún censo las vio nunca**;
# peor, `check_decisiones_en_backlog` declaraba `ok` sobre ellas.
# ⛔ **Un `>` a secas NO basta, y esto es lo que separa la señal del ruido**: en
# markdown el `>` va en **TODAS** las líneas de un párrafo citado, así que una
# línea de continuación que empieza por un id («> `D6` del Método):*») no define
# nada. Medido en el árbol: admitirlo a secas metía **4 falsos positivos**
# (asgard `H33`, hub `R9`, JISR `G9`, medusa `A2`) y **3 más** en el propio
# fichero del edge (`D6`, `P11`, `D3`).
# ⇒ cuando la posición es SÓLO `>` se exige **negrita**; si el `>` viene con un
# marcador de lista o tabla detrás (`> - **D5**`), manda ése y no hace falta.
# Con la regla: 3/3 las tres `D` de `A43`, 0 falsos positivos en todo el árbol.
# modo `forma` → **¿tiene esta línea FORMA de definición?**, con CUALQUIER prefijo de letra,
# CUALQUIER adorno y `>` **a secas** (sin exigir negrita). Es a propósito agnóstico
# de `_IDPFX`, del adorno, del límite y **de la restricción de posición**: un
# detector de ceguera construido sobre el criterio que audita sólo caza la ceguera
# que ya se le ha quitado. Es la **cuarta cara** de la misma familia —prefijo
# (`gate-sin-sujeto`), adorno, límite, y ahora POSICIÓN—, y es literalmente por
# qué `A43` no saltó: las tres líneas de blockquote salían **0** también aquí
# (medido: 0/3 antes, 3/3 después), así que no estaban ni en la nota ni en el
# `no adm.` del censo. Estaban en ningún sitio.
# #
# El LÍMITE POR LA DERECHA vale para los dos: `P9b`/`P9c` NO son `P9`, `E8.a` NO es `E8` y # El LÍMITE POR LA DERECHA vale sólo para el estricto: `P9b`/`P9c` NO son `P9`, `E8.a` NO es `E8` y
# `R5-bis` NO es `R5` —son **sub-ids**, no colisiones, y contarlos como el padre fabricaba # `R5-bis` NO es `R5` —son **sub-ids**, no colisiones, y contarlos como el padre fabricaba
# duplicados que no existen—; y `E2E` («end-to-end») no es un id en absoluto. Ninguno de los dos # duplicados que no existen—; y `E2E` («end-to-end») no es un id en absoluto. Ninguno de los dos
# casos se puede distinguir del otro por su forma, así que ninguno cuenta como definición. # casos se puede distinguir del otro por su forma, así que ninguno cuenta como definición.
_id_scan() { # $1 = fichero · $2 = def|forma _id_scan() { # $1 = fichero · $2 = def|defnr|subid|forma
awk -v pfx="$_IDPFX" -v modo="$2" ' awk -v pfx="$_IDPFX" -v modo="$2" '
{ if (modo != "forma") { if (match($0, "^[[:space:]]*[|*_-]+[[:space:]]*[*~`]*") == 0) next } { if (modo != "forma") { if (match($0, "^[[:space:]]*(>[[:space:]]*)*[|*_-]*[[:space:]]*([[].[]][[:space:]]*)?[*~`]*") == 0) next }
else { if (match($0, "^[[:space:]]*[|*_-][[:space:]]*([[].[]])?[^[:alnum:]]*") == 0) next } # ⚠️ El laxo NO lleva el grupo `(>[[:space:]]*)*` del estricto, y NO es un olvido: su adorno
# es `[^[:alnum:]]*`, que ya se traga el `>`. Se midió — con el grupo puesto, su mutación
# NO mataba ni una cara, o sea era código que no se puede romper. Quien deja aquí la
# capacidad de ver el blockquote es la GUARDA de abajo, y por eso su clase lleva el `>`.
else { if (match($0, "^[[:space:]]*[|*_-]?[[:space:]]*([[].[]])?[^[:alnum:]]*") == 0) next }
pre = substr($0, 1, RLENGTH)
# Con todo opcional, el patrón casa la cadena VACÍA en cualquier línea ⇒ hace falta exigir
# que se haya visto AL MENOS un marcador de posición. Sin esto, una frase que empieza por
# un id sería una definición.
if (pre !~ /[|*>_-]/) next
# ⛔ El `>` de markdown NO marca «aquí empieza algo»: marca «esta línea está citada», y va en
# todas las del párrafo. Sólo cuenta como posición si trae NEGRITA (o un marcador de lista).
if (modo != "forma" && pre ~ /^[[:space:]]*>/ && pre !~ /[|_-]/ && pre !~ /\*\*/) next
rest = substr($0, RLENGTH + 1) rest = substr($0, RLENGTH + 1)
re = (modo == "forma") ? "^[A-Z][A-Z]?[0-9]+" : "^(" pfx ")[0-9]+" re = (modo == "forma") ? "^[A-Z][A-Z]?[0-9]+" : "^(" pfx ")[0-9]+"
if (match(rest, re) == 0) next if (match(rest, re) == 0) next
id = substr(rest, 1, RLENGTH); cola = substr(rest, RLENGTH + 1) id = substr(rest, 1, RLENGTH); cola = substr(rest, RLENGTH + 1)
# ⚠️ El LÍMITE POR LA DERECHA (`D100`) NO se aplica al modo `forma`: ese es el detector de # ⚠️ El LÍMITE POR LA DERECHA (`D101`) NO se aplica al modo `forma`: ese es el detector de
# «el sujeto está y no lo veo», y un detector que descarta lo mismo que el criterio deja de # «el sujeto está y no lo veo», y un detector que descarta lo mismo que el criterio deja de
# detectar nada. Se midió: con el límite puesto, medusa decía 12 líneas con forma de id # detectar nada. Se midió: con el límite puesto, medusa decía 12 líneas con forma de id
# donde hay 49. Es la MISMA lección que ya obligó a hacerlo agnóstico de prefijo. # donde hay 49. Es la MISMA lección que ya obligó a hacerlo agnóstico de prefijo.
@ -382,6 +413,56 @@ check_decisiones_en_backlog() {
return 0 return 0
} }
# ── Check 9 · decisiones con forma de PROSA, sin id (nota) ───────────────────
# `A43`(c), 2026-08-23. ⛔ **El linter NO intenta leer prosa**: reconocer decisiones por su
# contenido es un pozo, y la decisión (superadmin) fue explícita en no bajar ahí. Esto no lee
# prosa — mira un **marcador que el autor ya escribió**, en MAYÚSCULAS, y pregunta una sola cosa:
# ¿hay un id de registro cerca? Si no lo hay, saca **nota**. Señala, no gatea.
#
# La cicatriz: `I11.14` del hub —decisión de XAVIER, con dueño y fecha en su propia ficha— nunca
# tuvo id. Camino del registro se resumió, y el resumen **invertía el sujeto** («al edge le
# consta» por «a este hub le consta») y **perdía la mitad estrecha** («de ese llamante»): habría
# entrado en el registro mintiendo desde la primera línea. Un id no es burocracia — es lo que
# ata una decisión a **su texto**.
#
# ⚠️ La forma canónica sigue siendo UNA (`D6`): una entrada en `doc/decisiones.md` con id. Esta
# nota sólo dice *«aquí hay una decisión escrita a mano y sin número»*; **quién le pone el número
# es su dueño**, no una sesión de paso y desde luego no el linter.
_PROSA_MARCA='DECISI' # MAYÚSCULAS a propósito: «la decisión de X» en prosa corriente no es marca
_PROSA_CERCA=2 # líneas arriba/abajo donde vale un id de registro para dar por citada
_PROSA_TOPE=5 # tope de notas por fichero — y lo que caiga fuera se DICE, no se calla
check_decisiones_en_prosa() {
hdr "decisiones con forma de prosa, sin id (D6 · A43)"
local any=0 f base out n total line txt
for f in "$ROOT/doc/backlog.md" "$ROOT/doc/AVISOS.md"; do
[ -f "$f" ] || continue
any=1; base=$(basename "$f")
# El id "cerca" se busca como `D<n>` —el vocabulario del REGISTRO— y no como id cualquiera:
# `I11.14` es el id del ÍTEM, y tenerlo al lado es justo el caso que hay que denunciar.
out=$(awk -v M="$_PROSA_MARCA" -v N="$_PROSA_CERCA" '
{ L[NR]=$0 }
END { for (i=1;i<=NR;i++) {
if (L[i] !~ M) continue
cerca=0
for (j=i-N; j<=i+N; j++) if (j>=1 && j<=NR && L[j] ~ /D[0-9]+/) cerca=1
if (!cerca) print i "\t" substr(L[i], 1, 110) } }' "$f")
total=$(printf '%s\n' "$out" | grep -c '[^[:space:]]')
if [ "$total" -eq 0 ]; then
ok "$base: ningún marcador de decisión sin id de registro cerca"
continue
fi
n=0
while IFS=$'\t' read -r line txt; do
[ -n "$line" ] || continue
n=$((n+1)); [ "$n" -gt "$_PROSA_TOPE" ] && continue
warn "decisión con forma de prosa, sin id — $base:$line · ${txt} … ⇒ si es una decisión, va a doc/decisiones.md con id y su TEXTO ÍNTEGRO (D6); si no lo es, baja el marcador a minúsculas"
done <<< "$out"
[ "$total" -gt "$_PROSA_TOPE" ] && warn "$base: y ${total} en total — sólo se listan las primeras ${_PROSA_TOPE} (el tope se dice, no se calla)"
done
[ "$any" -eq 0 ] && skip "sin doc/backlog.md ni doc/AVISOS.md (repo sin corpus de estado)"
return 0
}
# ── plantillas de doc/ (sólo se crean si faltan — brownfield: no pisar) ─────── # ── plantillas de doc/ (sólo se crean si faltan — brownfield: no pisar) ───────
_scaffold_docs() { # $1 = repo destino _scaffold_docs() { # $1 = repo destino
# La casa de docs es UNA y se llama doc/ (el linter ancla ahí el corpus de estado). # La casa de docs es UNA y se llama doc/ (el linter ancla ahí el corpus de estado).
@ -462,6 +543,98 @@ EOF
EOF EOF
} }
# ── el `.gitattributes` de RAÍZ (bloque gestionado) ──────────────────────────
# ⚰️ **OJO CON EL MOTIVO: el que se escribió primero era FALSO y está medido como tal.** Se dijo
# —y lo decía ya el ítem de partida— que un `git worktree add` limpio hacía que `metodo check`
# contara **el doble** (299 avisos contra 123). Es cierto que los cuenta, pero **no por el EOL**:
# medido el 2026-08-23 con dos worktrees del hub **a la misma profundidad**, uno con 14 ficheros
# en CRLF y otro con 0, la salida del linter es **IDÉNTICA** —mismos 123 avisos, mismas 6 notas,
# mismos 19 enlaces rotos—. Los 176 de más eran **enlaces relativos que salen del repo**
# (`../../../workflows/…`), que sólo resuelven desde el árbol de trabajo: se estaba midiendo la
# UBICACIÓN del checkout, no su final de línea. Y el mecanismo que se le atribuía tampoco existe:
# `check_links` captura hasta el `)` y el `\r` va **después**, al final de la línea.
#
# ⇒ **`metodo check` es EOL-independiente, y eso ya es un resultado**: retira una hipótesis que
# estaba a punto de convertirse en doctrina. Es la TERCERA vez que un mecanismo del CRLF se cae
# al carearlo con su consumidor real (antes: `kubectl` normalizando el `\r` en dos de las cinco
# mordidas registradas).
#
# ⇒ Entonces **por qué se estampa igual**, dicho sin inflarlo: por **higiene y uniformidad**, y
# porque el principio *«lo que un gate o un instrumento lee se fija en LF»* ya estaba aprobado por
# Xavier para los SUJETOS de los arneses —donde sí hay cicatriz medida: un `sed` anclado en `$`
# se apaga—. Aquí **no hay cicatriz**: el coste es cero y el beneficio es que el árbol deja de
# depender de cómo se hizo cada checkout. ⚠️ Si algún día estorba, se quita sin perder nada.
#
# ⛔ **ACOTADO, y NUNCA `* text=auto`.** Esto sí está medido, y en el sentido destructivo: en
# `Solidaria` hay **15 PDF** bajo `app/templates/`, y un `text` sobre ellos les reescribe en cada
# checkout los bytes que parezcan finales de línea; `hermes-hub` tiene binarios en LFS y su propio
# `.gitattributes` documenta por qué no la pone. Aquí se declaran **exactamente los dos globs que
# el linter recorre** — los `*.md` de RAÍZ y `doc/*.md` — y ni un patrón más.
#
# ⚠️ **Declarar NO es refrescar, y renormalizar el ÍNDICE tampoco**: `git add --renormalize` deja
# el worktree en CRLF (`i/lf w/crlf`), y `git checkout --` a secas **salta** los ficheros que el
# caché de `stat` da por al día. Hay que **borrarlos y volver a sacarlos**. Por eso el estampado
# **mide** (`git ls-files --eol`) y lo dice en voz alta.
_GA_OPEN='# >>> metodo:eol'
_GA_CLOSE='# <<< metodo:eol'
_ga_block() { # el bloque COMPLETO (marcadores incluidos) por stdout
cat <<'GAB'
# >>> metodo:eol
# Gestionado por `metodo init/update` — NO editar a mano (se re-estampa).
# ACOTADO a los dos globs que el linter recorre: los `*.md` de RAÍZ y `doc/*.md` (glob de shell,
# sólo hijos directos). Es HIGIENE, no una avería: medido el 2026-08-23 en hermes-hub con dos
# worktrees a la misma profundidad —uno con 14 ficheros en CRLF y otro con 0—, `metodo check`
# da EXACTAMENTE la misma salida. Se fija el EOL para que el árbol no dependa de cómo se hizo
# cada checkout, no porque el linter se rompa.
# ⛔ Nunca `* text=auto` aquí: hay repos con binarios en LFS y con PDF versionados — ESO sí es
# destructivo y está medido.
/*.md text eol=lf
doc/*.md text eol=lf
# <<< metodo:eol
GAB
}
_stamp_gitattributes() { # $1 = repo destino
local ga="$1/.gitattributes" blk tmp a b
blk=$(mktemp); _ga_block > "$blk"; tmp=$(mktemp)
if [ ! -f "$ga" ]; then
cat "$blk" > "$ga"; rm -f "$blk" "$tmp"; echo " .gitattributes creado con el bloque eol (*.md de raíz · doc/*.md)"; return
fi
a=$(grep -nxF "$_GA_OPEN" "$ga" | head -1 | cut -d: -f1)
b=$(grep -nxF "$_GA_CLOSE" "$ga" | head -1 | cut -d: -f1)
if [ -n "$a" ] && [ -n "$b" ] && [ "$b" -ge "$a" ]; then
# ⛔ Se sustituye SÓLO el bloque, y con `head`/`tail`, NO con `awk`/`sed`. Medido el
# 2026-08-23 en Git Bash: **awk y sed abren en modo texto y se comen el `\r`** ⇒ reescribir el
# fichero entero con ellos NORMALIZA en silencio los bytes de un fichero que no es nuestro
# (`hermes-hub`, `kubernetes` y `mcp-edge` tienen su `.gitattributes` en CRLF o mixto).
# `head`/`tail` cortan por línea sin tocar los bytes que no atraviesan.
{ head -n $((a-1)) "$ga"; cat "$blk"; tail -n +$((b+1)) "$ga"; } > "$tmp" && mv "$tmp" "$ga"
rm -f "$blk"; echo " .gitattributes: bloque eol re-estampado (sólo el bloque; el resto, byte a byte)"; return
fi
# Existe y no lo lleva: se AÑADE AL FINAL. En gitattributes gana la última regla que casa, así
# que el bloque no puede quedar tapado por lo que el repo ya declarara para `.md`.
{ [ -s "$ga" ] && printf '\n'; cat "$blk"; } >> "$ga"
rm -f "$blk" "$tmp"; echo " .gitattributes: bloque eol añadido al final (lo de antes, intacto)"
}
# ⚠️ Los dos pathspec llevan `:(glob)` a propósito: sin él, el `*` de git cruza `/` y `doc/*.md`
# se tragaría `doc/img/README.md`, que el linter NO lee. La verificación tiene que mirar el
# MISMO conjunto que declara el bloque — si mira otro, es un gate sin sujeto.
_GA_SUJETOS=":(glob)*.md :(glob)doc/*.md"
_ga_verifica() { # $1 = repo destino — «declarar NO es refrescar»: se MIDE el worktree
local tgt="$1" crlf
git -C "$tgt" rev-parse --git-dir >/dev/null 2>&1 || return 0
crlf=$(git -C "$tgt" ls-files --eol -- $_GA_SUJETOS 2>/dev/null | awk '$2=="w/crlf"' | wc -l)
if [ "${crlf:-0}" -gt 0 ]; then
echo " ⚠ .gitattributes declarado pero el worktree NO está refrescado: ${crlf} fichero(s) en CRLF."
echo " ⇒ git -C $tgt add --renormalize -- $_GA_SUJETOS (y commitea)"
echo " Sin esto el linter sigue midiendo el CHECKOUT y no el repo."
else
echo " eol verificado: *.md de raíz y doc/*.md en LF en el worktree (git ls-files --eol)"
fi
}
# ── el PUNTERO de enrutado (bloque gestionado en CLAUDE.md) ────────────────── # ── el PUNTERO de enrutado (bloque gestionado en CLAUDE.md) ──────────────────
# Por qué en CLAUDE.md y sólo ahí: es el ÚNICO fichero que el harness carga solo en toda sesión # Por qué en CLAUDE.md y sólo ahí: es el ÚNICO fichero que el harness carga solo en toda sesión
# sobre el repo. Un puntero en cualquier otro sitio reproduce la enfermedad que viene a curar # sobre el repo. Un puntero en cualquier otro sitio reproduce la enfermedad que viene a curar
@ -550,6 +723,8 @@ Etiquetas: [NUEVA-REGLA] · [REFINA Cn] · [Cn-NO-ENCAJA] · [FALSA]. Se cosecha
--- ---
EOF EOF
_scaffold_docs "$tgt" _scaffold_docs "$tgt"
_stamp_gitattributes "$tgt"
_ga_verifica "$tgt"
_stamp_pointer "$tgt" _stamp_pointer "$tgt"
echo "metodo init: $tgt inicializado — .metodo/ (máster $mver) + doc/ de CUATRO capas (backlog · decisiones · AVISOS · bitácora)." echo "metodo init: $tgt inicializado — .metodo/ (máster $mver) + doc/ de CUATRO capas (backlog · decisiones · AVISOS · bitácora)."
echo " siguiente: siembra doc/backlog.md con el trabajo abierto de hoy y corre 'metodo check .'" echo " siguiente: siembra doc/backlog.md con el trabajo abierto de hoy y corre 'metodo check .'"
@ -571,6 +746,8 @@ cmd_update() {
[ -n "$adopt" ] && echo "adopted_commit: $adopt"; } > "$md/VERSION" [ -n "$adopt" ] && echo "adopted_commit: $adopt"; } > "$md/VERSION"
_write_checksums "$md" || echo " (aviso: sin sha256 → CHECKSUMS no escrito)" _write_checksums "$md" || echo " (aviso: sin sha256 → CHECKSUMS no escrito)"
printf '* text eol=lf\n' > "$md/.gitattributes" printf '* text eol=lf\n' > "$md/.gitattributes"
_stamp_gitattributes "$tgt"
_ga_verifica "$tgt"
_stamp_pointer "$tgt" _stamp_pointer "$tgt"
echo "metodo update: $tgt actualizado al máster $mver (metodo.md + linter, byte a byte); realimentacion.md y adopted_commit preservados." echo "metodo update: $tgt actualizado al máster $mver (metodo.md + linter, byte a byte); realimentacion.md y adopted_commit preservados."
} }
@ -591,6 +768,7 @@ cmd_check() {
check_commits check_commits
check_decisiones check_decisiones
check_decisiones_en_backlog check_decisiones_en_backlog
check_decisiones_en_prosa
check_pointer check_pointer
hdr "resultado" hdr "resultado"
local rc=0 local rc=0

View File

@ -85,16 +85,18 @@ en su sector**. Y es esto, dicho por él:
**Regla operativa**: antes de escribir *«pero si te comprometen X…»*, pregúntate **contra qué lo **Regla operativa**: antes de escribir *«pero si te comprometen X…»*, pregúntate **contra qué lo
comparas**. Si la alternativa real que Xavier tiene hoy es peor, la propuesta no mejora nada — solo comparas**. Si la alternativa real que Xavier tiene hoy es peor, la propuesta no mejora nada — solo
añade dificultad, y eso lo prohíbe `D23`. añade dificultad, y eso lo prohíbe `I11·D23` (de `hermes-hub`: «la vara de medir es el COSTE
PARA EL OPERADOR»).
⇒ ⛔ **Y el error que esto evita, cometido CUATRO veces el 2026-08-18: una decisión lleva ÁMBITO DE ⇒ ⛔ **Y el error que esto evita, cometido CUATRO veces el 2026-08-18: una decisión lleva ÁMBITO DE
AMENAZA, y leerla fuera de su ámbito la hace parecer mala.** *(Xavier, ordenando: «no estoy diciendo AMENAZA, y leerla fuera de su ámbito la hace parecer mala.** *(Xavier, ordenando: «no estoy diciendo
que no valore la captura de un hub — lo pondremos en el backlog por detrás, con su apartado. Ahora que no valore la captura de un hub — lo pondremos en el backlog por detrás, con su apartado. Ahora
estamos en el apartado de **“y si capturan un edge”**, y para eso hay una CRL y unos procedimientos estamos en el apartado de **“y si capturan un edge”**, y para eso hay una CRL y unos procedimientos
que mis equipos de hoy **ni tienen**».)* La orquestadora evaluó `D25` —del apartado del **edge** que mis equipos de hoy **ni tienen**».)* La orquestadora evaluó `D25` —del **edge**, apartado
contra la captura de un **hub**, y la decisión salía mal cuatro veces seguidas. **No estaba mal: se `E14`; ⚠️ **sigue sin entrada en su registro**, ver `A43` de `hermes-edge/doc/AVISOS.md`, así que
estaba midiendo con la vara de otra sección.** esta cita no se puede calificar todavía— contra la captura de un **hub**, y la decisión salía mal
cuatro veces seguidas. **No estaba mal: se estaba midiendo con la vara de otra sección.**
**Regla**: antes de objetar, pregúntate **de qué apartado es la decisión**. Si tu objeción vive en **Regla**: antes de objetar, pregúntate **de qué apartado es la decisión**. Si tu objeción vive en
otro, no es una objeción: es una **entrada para ese otro apartado** — y se escribe allí, no aquí. otro, no es una objeción: es una **entrada para ese otro apartado** — y se escribe allí, no aquí.
⭐ Y el corolario que lo hace útil en vez de burocrático: **objetar sigue siendo bienvenido**. Lo que ⭐ Y el corolario que lo hace útil en vez de burocrático: **objetar sigue siendo bienvenido**. Lo que
@ -499,8 +501,9 @@ mismo valor da el nombre público **y** direcciona secretos, rutas o etiquetas,
visible **re-direcciona lo invisible**, y en silencio. *(Cicatriz 2026-07-31, cazada antes de visible **re-direcciona lo invisible**, y en silencio. *(Cicatriz 2026-07-31, cazada antes de
aplicar: `hubName` gobernaba también los **paths de Vault** — con `hermes.hub` el `trimSuffix "-hub"` aplicar: `hubName` gobernaba también los **paths de Vault** — con `hermes.hub` el `trimSuffix "-hub"`
no recortaba nada y el hub habría ido a buscar su clave WireGuard y su **clave Rosenpass** —la que no recortaba nada y el hub habría ido a buscar su clave WireGuard y su **clave Rosenpass** —la que
`D10` prohíbe regenerar— a rutas inexistentes. La sesión partió **identidad** de **nombre público** `hermes-hub`·`D100` prohíbe regenerar; era `F13·D10` hasta que el 2026-08-22 se renumeró al
antes de tocar nada.)* contador del hub, precisamente porque el id chocaba con el del edge— a rutas inexistentes. La
sesión partió **identidad** de **nombre público** antes de tocar nada.)*
⇒ Antes de renombrar, **escribe qué se deriva de ese valor**. Lo que dice quién eres y lo que dice ⇒ Antes de renombrar, **escribe qué se deriva de ese valor**. Lo que dice quién eres y lo que dice
dónde están tus cosas tienen que ser campos distintos, aunque hoy coincidan. Y donde el derivado dónde están tus cosas tienen que ser campos distintos, aunque hoy coincidan. Y donde el derivado
tenga formato obligado (una etiqueta de kernel, un path), **que la plantilla falle al renderizar** tenga formato obligado (una etiqueta de kernel, un path), **que la plantilla falle al renderizar**
@ -634,8 +637,9 @@ la suite sale verde sobre un cableado roto. Dos veces en la misma semana (2026-0
- `GET /links` —el endpoint del panel— llamaba a `LNK.status` con un `cfg` **declarado y sin - `GET /links` —el endpoint del panel— llamaba a `LNK.status` con un `cfg` **declarado y sin
asignar**, así que el peldaño de identidad llegaba **vacío**. Los tests pasaban **porque le pasan asignar**, así que el peldaño de identidad llegaba **vacío**. Los tests pasaban **porque le pasan
`cfg` a mano**. `cfg` a mano**.
- Un mutante que derivaba el sufijo de una LAN del dominio del router —la invención que `D8` - Un mutante que derivaba el sufijo de una LAN del dominio del router —la invención que `F11·D8`
prohíbe— **no rompió ni una aserción**, porque los tests de `D8` **no pasaban registro de router**. de `hermes-edge` prohíbe— **no rompió ni una aserción**, porque sus tests **no pasaban registro
de router**.
⇒ Pregunta por cada test que pasa: **¿de dónde sale ese argumento en producción?** Si lo fabrica el ⇒ Pregunta por cada test que pasa: **¿de dónde sale ese argumento en producción?** Si lo fabrica el
test, ahí no hay cobertura — hay una simulación de que la hay. El testigo tiene que **entrar por test, ahí no hay cobertura — hay una simulación de que la hay. El testigo tiene que **entrar por
donde entra el usuario**. donde entra el usuario**.
@ -998,11 +1002,11 @@ servicio funciona: dice que alguna de ellas funciona.**
**Y su hermano, que es el que nadie busca: la ABUNDANCIA de recursos esconde el derroche.** Medir **Y su hermano, que es el que nadie busca: la ABUNDANCIA de recursos esconde el derroche.** Medir
siempre en el aparato más holgado no certifica nada del más apretado — y el defecto no está latente, siempre en el aparato más holgado no certifica nada del más apretado — y el defecto no está latente,
está **ocurriendo**, solo que sobra sitio para pagarlo. *(Cicatriz `P12`, 2026-08-02: con `D10` un está **ocurriendo**, solo que sobra sitio para pagarlo. *(Cicatriz `P12`, 2026-08-02: con `F13·D10`
edge **sin binario de Rosenpass** seguía bajándose la pubkey del hub —**524.160 B**— en el bucle de —la del **edge**, «PQ siempre que se pueda»— un edge **sin binario de Rosenpass** seguía bajándose
20 s **y por cada hub**. En un Brume 2 (6,8 GB de overlay) no se nota **jamás**; en un GL-AR300M eran la pubkey del hub —**524.160 B**— en el bucle de 20 s **y por cada hub**. En un Brume 2 (6,8 GB de
**1 MB sobre 212 KB libres**. Se descubrió porque el aparato pequeño lo hizo visible, no porque overlay) no se nota **jamás**; en un GL-AR300M eran **1 MB sobre 212 KB libres**. Se descubrió
alguien lo buscara.)* porque el aparato pequeño lo hizo visible, no porque alguien lo buscara.)*
⇒ Pregunta cuando una medida salga limpia: **¿en qué aparato la he tomado, y qué le sobraba?** Disco, ⇒ Pregunta cuando una medida salga limpia: **¿en qué aparato la he tomado, y qué le sobraba?** Disco,
RAM, CPU y ancho de banda son todos amortiguadores que convierten un fallo en una estadística que RAM, CPU y ancho de banda son todos amortiguadores que convierten un fallo en una estadística que
nadie mira. La flota real se parece al más pobre, no al banco. nadie mira. La flota real se parece al más pobre, no al banco.